torchabc 0.2.4__tar.gz → 0.3.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {torchabc-0.2.4 → torchabc-0.3.0}/PKG-INFO +126 -46
- {torchabc-0.2.4 → torchabc-0.3.0}/README.md +125 -45
- {torchabc-0.2.4 → torchabc-0.3.0}/pyproject.toml +7 -1
- {torchabc-0.2.4 → torchabc-0.3.0}/torchabc/__init__.py +141 -174
- {torchabc-0.2.4 → torchabc-0.3.0}/torchabc/cli.py +18 -21
- {torchabc-0.2.4 → torchabc-0.3.0}/LICENSE +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.3
|
|
2
2
|
Name: torchabc
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.3.0
|
|
4
4
|
Summary: A simple abstract class for training and inference in PyTorch.
|
|
5
5
|
License: MIT
|
|
6
6
|
Author: Emanuele Guidotti
|
|
@@ -50,73 +50,141 @@ Generate a template using the command line interface.
|
|
|
50
50
|
torchabc --create template.py
|
|
51
51
|
```
|
|
52
52
|
|
|
53
|
-
|
|
53
|
+
Fill out the template.
|
|
54
54
|
|
|
55
55
|
```py
|
|
56
|
+
from torchabc import TorchABC
|
|
57
|
+
from functools import cached_property
|
|
58
|
+
|
|
59
|
+
|
|
56
60
|
class ClassName(TorchABC):
|
|
61
|
+
"""A concrete subclass of the TorchABC abstract class.
|
|
62
|
+
|
|
63
|
+
Use this template to implement your own model by following these steps:
|
|
64
|
+
- replace ClassName with the name of your model,
|
|
65
|
+
- replace this docstring with a description of your model,
|
|
66
|
+
- implement the methods below to define the core logic of your model,
|
|
67
|
+
- access the hyperparameters passed during initialization with `self.hparams`.
|
|
68
|
+
"""
|
|
57
69
|
|
|
58
70
|
@cached_property
|
|
59
71
|
def dataloaders(self):
|
|
72
|
+
"""The dataloaders.
|
|
73
|
+
|
|
74
|
+
Returns a dictionary containing multiple `DataLoader` instances. The keys of
|
|
75
|
+
the dictionary are the names of the dataloaders (e.g., 'train', 'val', 'test'),
|
|
76
|
+
and the values are the corresponding `torch.utils.data.DataLoader` objects.
|
|
77
|
+
"""
|
|
60
78
|
raise NotImplementedError
|
|
61
79
|
|
|
62
|
-
|
|
80
|
+
@staticmethod
|
|
81
|
+
def preprocess(data, flag='predict'):
|
|
82
|
+
"""The preprocessing step.
|
|
83
|
+
|
|
84
|
+
Transforms the raw data of an individual sample into the corresponding tensor(s).
|
|
85
|
+
|
|
86
|
+
Parameters
|
|
87
|
+
----------
|
|
88
|
+
data : Any
|
|
89
|
+
The raw data.
|
|
90
|
+
flag : str, optional
|
|
91
|
+
A flag indicating how to transform the data. The default transforms the
|
|
92
|
+
input data for inference. You can use additional flags, for instance,
|
|
93
|
+
to perform data augmentation or transform the targets during training or validation.
|
|
94
|
+
|
|
95
|
+
Returns
|
|
96
|
+
-------
|
|
97
|
+
Union[Tensor, Iterable[Tensor]]
|
|
98
|
+
The preprocessed data.
|
|
99
|
+
"""
|
|
63
100
|
return data
|
|
64
|
-
|
|
101
|
+
|
|
65
102
|
@cached_property
|
|
66
103
|
def network(self):
|
|
104
|
+
"""The neural network.
|
|
105
|
+
|
|
106
|
+
Returns a `torch.nn.Module` whose input and output tensors assume the
|
|
107
|
+
batch size is the first dimension: (batch_size, ...).
|
|
108
|
+
"""
|
|
67
109
|
raise NotImplementedError
|
|
68
110
|
|
|
69
111
|
@cached_property
|
|
70
112
|
def optimizer(self):
|
|
113
|
+
"""The optimizer for training the network.
|
|
114
|
+
|
|
115
|
+
Returns a `torch.optim.Optimizer` configured for `self.network.parameters()`.
|
|
116
|
+
"""
|
|
71
117
|
raise NotImplementedError
|
|
72
118
|
|
|
73
119
|
@cached_property
|
|
74
120
|
def scheduler(self):
|
|
121
|
+
"""The learning rate scheduler for the optimizer.
|
|
122
|
+
|
|
123
|
+
Returns a `torch.optim.lr_scheduler.LRScheduler` or `torch.optim.lr_scheduler.ReduceLROnPlateau`
|
|
124
|
+
configured for `self.optimizer`.
|
|
125
|
+
"""
|
|
75
126
|
return None
|
|
76
127
|
|
|
77
|
-
|
|
128
|
+
@staticmethod
|
|
129
|
+
def loss(outputs, targets):
|
|
130
|
+
"""The loss function.
|
|
131
|
+
|
|
132
|
+
Compute the loss to train the neural network.
|
|
133
|
+
|
|
134
|
+
Parameters
|
|
135
|
+
----------
|
|
136
|
+
outputs : Union[Tensor, Iterable[Tensor]]
|
|
137
|
+
The tensor(s) returned by the forward pass of `self.network`.
|
|
138
|
+
targets : Union[Tensor, Iterable[Tensor]]
|
|
139
|
+
The tensor(s) giving the target values.
|
|
140
|
+
|
|
141
|
+
Returns
|
|
142
|
+
-------
|
|
143
|
+
Tensor
|
|
144
|
+
A scalar tensor giving the loss value.
|
|
145
|
+
"""
|
|
78
146
|
raise NotImplementedError
|
|
79
|
-
|
|
80
|
-
def metrics(self, outputs: torch.Tensor, targets: torch.Tensor) -> Dict[str, float]:
|
|
81
|
-
return {}
|
|
82
|
-
|
|
83
|
-
def postprocess(self, outputs: torch.Tensor) -> Any:
|
|
84
|
-
return outputs
|
|
85
|
-
```
|
|
86
|
-
|
|
87
|
-
Fill out the template with the dataloaders, preprocessing and postprocessing steps, the neural network, optimizer, scheduler, loss, and optional evaluation metrics.
|
|
88
|
-
|
|
89
|
-
#### `dataloaders`: the dataloaders for training and evaluation
|
|
90
|
-
|
|
91
|
-
This method defines and returns a dictionary containing the [`DataLoader`](https://pytorch.org/docs/stable/data.html#torch.utils.data.DataLoader) instances for the training, validation, and testing datasets. The dictionary's keys should correspond to the names of the datasets (e.g., 'train', 'val', 'test'), and the values should be their respective `DataLoader` objects. Any transformation of the raw input data for each dataset should be implemented within the `preprocess` method of this class. The `preprocess` method should then be passed as the `transform` argument of the [`Dataset`](https://pytorch.org/docs/stable/data.html#torch.utils.data.Dataset) instances.
|
|
92
|
-
|
|
93
|
-
#### `preprocess`: preprocessing
|
|
94
|
-
|
|
95
|
-
This method processes the data differently depending on a `flag`. When `flag` is empty (the default), the data are assumed to represent the model's input used for inference. When `flag` has a specific value, the method may perform different preprocessing steps, such as transforming the target or augmenting the input for training.
|
|
96
|
-
|
|
97
|
-
#### `network`: the neural network
|
|
98
147
|
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
148
|
+
@staticmethod
|
|
149
|
+
def metrics(outputs, targets):
|
|
150
|
+
"""The evaluation metrics.
|
|
151
|
+
|
|
152
|
+
Compute additional evaluation metrics.
|
|
153
|
+
|
|
154
|
+
Parameters
|
|
155
|
+
----------
|
|
156
|
+
outputs : Union[Tensor, Iterable[Tensor]]
|
|
157
|
+
The tensor(s) returned by the forward pass of `self.network`.
|
|
158
|
+
targets : Union[Tensor, Iterable[Tensor]]
|
|
159
|
+
The tensor(s) giving the target values.
|
|
160
|
+
|
|
161
|
+
Returns
|
|
162
|
+
-------
|
|
163
|
+
Dict[str, float]
|
|
164
|
+
A dictionary where the keys are the names of the metrics and the
|
|
165
|
+
values are the corresponding scores.
|
|
166
|
+
"""
|
|
167
|
+
return {}
|
|
110
168
|
|
|
111
|
-
|
|
169
|
+
@staticmethod
|
|
170
|
+
def postprocess(outputs):
|
|
171
|
+
"""The postprocessing step.
|
|
112
172
|
|
|
113
|
-
|
|
173
|
+
Transforms the neural network outputs into the final predictions.
|
|
114
174
|
|
|
115
|
-
|
|
175
|
+
Parameters
|
|
176
|
+
----------
|
|
177
|
+
outputs : Union[Tensor, Iterable[Tensor]]
|
|
178
|
+
The tensor(s) returned by the forward pass of `self.network`.
|
|
116
179
|
|
|
117
|
-
|
|
180
|
+
Returns
|
|
181
|
+
-------
|
|
182
|
+
Any
|
|
183
|
+
The postprocessed outputs.
|
|
184
|
+
"""
|
|
185
|
+
return outputs
|
|
118
186
|
|
|
119
|
-
|
|
187
|
+
```
|
|
120
188
|
|
|
121
189
|
## Usage
|
|
122
190
|
|
|
@@ -140,15 +208,13 @@ The `device` is the [`torch.device`](https://pytorch.org/docs/stable/tensor_attr
|
|
|
140
208
|
|
|
141
209
|
#### Logger
|
|
142
210
|
|
|
143
|
-
A logging function that takes a dictionary in input. The default prints to standard output. You can can easily log with [wandb](https://pypi.org/project/wandb/)
|
|
211
|
+
A logging function that takes a dictionary in input. The default prints to standard output. You can can easily log with [wandb](https://pypi.org/project/wandb/) or with any other custom logger.
|
|
144
212
|
|
|
145
213
|
```py
|
|
146
214
|
import wandb
|
|
147
215
|
model = ClassName(logger=wandb.log)
|
|
148
216
|
```
|
|
149
217
|
|
|
150
|
-
or with any other custom logger.
|
|
151
|
-
|
|
152
218
|
#### Hyperparameters
|
|
153
219
|
|
|
154
220
|
You will typically use several parameters to control the behavior of `ClassName`, such as the learning rate or batch size. These parameters should be passed during the initialization
|
|
@@ -179,9 +245,9 @@ where
|
|
|
179
245
|
- `on` is the name of the training dataloader. Defaults to 'train'.
|
|
180
246
|
- `val` is the name of the validation dataloader. Defaults to 'val'.
|
|
181
247
|
- `gas` is the number of gradient accumulation steps. Defaults to 1 (no gradient accumulation).
|
|
182
|
-
- `callback` is a function that is called after each epoch. It should accept two arguments: the instance itself and a list of dictionaries containing
|
|
248
|
+
- `callback` is a function that is called after each epoch. It should accept two arguments: the instance itself and a list of dictionaries containing logging info up to the current epoch. When this function returns `True`, training stops.
|
|
183
249
|
|
|
184
|
-
This method returns a list of dictionaries containing
|
|
250
|
+
This method returns a list of dictionaries containing logging info.
|
|
185
251
|
|
|
186
252
|
### Checkpoints
|
|
187
253
|
|
|
@@ -212,7 +278,7 @@ Evaluate the model with
|
|
|
212
278
|
model.eval(on='test')
|
|
213
279
|
```
|
|
214
280
|
|
|
215
|
-
where `on` is the name of the dataloader to evaluate on. This should be one of the keys in the `dataloaders`. This method returns a dictionary containing the evaluation metrics.
|
|
281
|
+
where `on` is the name of the dataloader to evaluate on. This should be one of the keys in the `dataloaders`. This method returns a dictionary containing the loss and evaluation metrics.
|
|
216
282
|
|
|
217
283
|
### Inference
|
|
218
284
|
|
|
@@ -230,6 +296,20 @@ Get started with simple self-contained examples:
|
|
|
230
296
|
|
|
231
297
|
- [MNIST classification](https://github.com/eguidotti/torchabc/blob/main/examples/mnist.py)
|
|
232
298
|
|
|
299
|
+
### Run the examples
|
|
300
|
+
|
|
301
|
+
Install the dependencies
|
|
302
|
+
|
|
303
|
+
```
|
|
304
|
+
poetry install --with examples
|
|
305
|
+
```
|
|
306
|
+
|
|
307
|
+
Run the examples by replacing `<name>` with one of the filenames in the [examples](https://github.com/eguidotti/torchabc/tree/main/examples) folder
|
|
308
|
+
|
|
309
|
+
```
|
|
310
|
+
poetry run python examples/<name>.py
|
|
311
|
+
```
|
|
312
|
+
|
|
233
313
|
## Contribute
|
|
234
314
|
|
|
235
315
|
Contributions are welcome! Submit pull requests with new [examples](https://github.com/eguidotti/torchabc/tree/main/examples) or improvements to the core [`TorchABC`](https://github.com/eguidotti/torchabc/blob/main/torchabc/__init__.py) class itself.
|
|
@@ -30,73 +30,141 @@ Generate a template using the command line interface.
|
|
|
30
30
|
torchabc --create template.py
|
|
31
31
|
```
|
|
32
32
|
|
|
33
|
-
|
|
33
|
+
Fill out the template.
|
|
34
34
|
|
|
35
35
|
```py
|
|
36
|
+
from torchabc import TorchABC
|
|
37
|
+
from functools import cached_property
|
|
38
|
+
|
|
39
|
+
|
|
36
40
|
class ClassName(TorchABC):
|
|
41
|
+
"""A concrete subclass of the TorchABC abstract class.
|
|
42
|
+
|
|
43
|
+
Use this template to implement your own model by following these steps:
|
|
44
|
+
- replace ClassName with the name of your model,
|
|
45
|
+
- replace this docstring with a description of your model,
|
|
46
|
+
- implement the methods below to define the core logic of your model,
|
|
47
|
+
- access the hyperparameters passed during initialization with `self.hparams`.
|
|
48
|
+
"""
|
|
37
49
|
|
|
38
50
|
@cached_property
|
|
39
51
|
def dataloaders(self):
|
|
52
|
+
"""The dataloaders.
|
|
53
|
+
|
|
54
|
+
Returns a dictionary containing multiple `DataLoader` instances. The keys of
|
|
55
|
+
the dictionary are the names of the dataloaders (e.g., 'train', 'val', 'test'),
|
|
56
|
+
and the values are the corresponding `torch.utils.data.DataLoader` objects.
|
|
57
|
+
"""
|
|
40
58
|
raise NotImplementedError
|
|
41
59
|
|
|
42
|
-
|
|
60
|
+
@staticmethod
|
|
61
|
+
def preprocess(data, flag='predict'):
|
|
62
|
+
"""The preprocessing step.
|
|
63
|
+
|
|
64
|
+
Transforms the raw data of an individual sample into the corresponding tensor(s).
|
|
65
|
+
|
|
66
|
+
Parameters
|
|
67
|
+
----------
|
|
68
|
+
data : Any
|
|
69
|
+
The raw data.
|
|
70
|
+
flag : str, optional
|
|
71
|
+
A flag indicating how to transform the data. The default transforms the
|
|
72
|
+
input data for inference. You can use additional flags, for instance,
|
|
73
|
+
to perform data augmentation or transform the targets during training or validation.
|
|
74
|
+
|
|
75
|
+
Returns
|
|
76
|
+
-------
|
|
77
|
+
Union[Tensor, Iterable[Tensor]]
|
|
78
|
+
The preprocessed data.
|
|
79
|
+
"""
|
|
43
80
|
return data
|
|
44
|
-
|
|
81
|
+
|
|
45
82
|
@cached_property
|
|
46
83
|
def network(self):
|
|
84
|
+
"""The neural network.
|
|
85
|
+
|
|
86
|
+
Returns a `torch.nn.Module` whose input and output tensors assume the
|
|
87
|
+
batch size is the first dimension: (batch_size, ...).
|
|
88
|
+
"""
|
|
47
89
|
raise NotImplementedError
|
|
48
90
|
|
|
49
91
|
@cached_property
|
|
50
92
|
def optimizer(self):
|
|
93
|
+
"""The optimizer for training the network.
|
|
94
|
+
|
|
95
|
+
Returns a `torch.optim.Optimizer` configured for `self.network.parameters()`.
|
|
96
|
+
"""
|
|
51
97
|
raise NotImplementedError
|
|
52
98
|
|
|
53
99
|
@cached_property
|
|
54
100
|
def scheduler(self):
|
|
101
|
+
"""The learning rate scheduler for the optimizer.
|
|
102
|
+
|
|
103
|
+
Returns a `torch.optim.lr_scheduler.LRScheduler` or `torch.optim.lr_scheduler.ReduceLROnPlateau`
|
|
104
|
+
configured for `self.optimizer`.
|
|
105
|
+
"""
|
|
55
106
|
return None
|
|
56
107
|
|
|
57
|
-
|
|
108
|
+
@staticmethod
|
|
109
|
+
def loss(outputs, targets):
|
|
110
|
+
"""The loss function.
|
|
111
|
+
|
|
112
|
+
Compute the loss to train the neural network.
|
|
113
|
+
|
|
114
|
+
Parameters
|
|
115
|
+
----------
|
|
116
|
+
outputs : Union[Tensor, Iterable[Tensor]]
|
|
117
|
+
The tensor(s) returned by the forward pass of `self.network`.
|
|
118
|
+
targets : Union[Tensor, Iterable[Tensor]]
|
|
119
|
+
The tensor(s) giving the target values.
|
|
120
|
+
|
|
121
|
+
Returns
|
|
122
|
+
-------
|
|
123
|
+
Tensor
|
|
124
|
+
A scalar tensor giving the loss value.
|
|
125
|
+
"""
|
|
58
126
|
raise NotImplementedError
|
|
59
|
-
|
|
60
|
-
def metrics(self, outputs: torch.Tensor, targets: torch.Tensor) -> Dict[str, float]:
|
|
61
|
-
return {}
|
|
62
|
-
|
|
63
|
-
def postprocess(self, outputs: torch.Tensor) -> Any:
|
|
64
|
-
return outputs
|
|
65
|
-
```
|
|
66
|
-
|
|
67
|
-
Fill out the template with the dataloaders, preprocessing and postprocessing steps, the neural network, optimizer, scheduler, loss, and optional evaluation metrics.
|
|
68
|
-
|
|
69
|
-
#### `dataloaders`: the dataloaders for training and evaluation
|
|
70
|
-
|
|
71
|
-
This method defines and returns a dictionary containing the [`DataLoader`](https://pytorch.org/docs/stable/data.html#torch.utils.data.DataLoader) instances for the training, validation, and testing datasets. The dictionary's keys should correspond to the names of the datasets (e.g., 'train', 'val', 'test'), and the values should be their respective `DataLoader` objects. Any transformation of the raw input data for each dataset should be implemented within the `preprocess` method of this class. The `preprocess` method should then be passed as the `transform` argument of the [`Dataset`](https://pytorch.org/docs/stable/data.html#torch.utils.data.Dataset) instances.
|
|
72
|
-
|
|
73
|
-
#### `preprocess`: preprocessing
|
|
74
|
-
|
|
75
|
-
This method processes the data differently depending on a `flag`. When `flag` is empty (the default), the data are assumed to represent the model's input used for inference. When `flag` has a specific value, the method may perform different preprocessing steps, such as transforming the target or augmenting the input for training.
|
|
76
|
-
|
|
77
|
-
#### `network`: the neural network
|
|
78
127
|
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
128
|
+
@staticmethod
|
|
129
|
+
def metrics(outputs, targets):
|
|
130
|
+
"""The evaluation metrics.
|
|
131
|
+
|
|
132
|
+
Compute additional evaluation metrics.
|
|
133
|
+
|
|
134
|
+
Parameters
|
|
135
|
+
----------
|
|
136
|
+
outputs : Union[Tensor, Iterable[Tensor]]
|
|
137
|
+
The tensor(s) returned by the forward pass of `self.network`.
|
|
138
|
+
targets : Union[Tensor, Iterable[Tensor]]
|
|
139
|
+
The tensor(s) giving the target values.
|
|
140
|
+
|
|
141
|
+
Returns
|
|
142
|
+
-------
|
|
143
|
+
Dict[str, float]
|
|
144
|
+
A dictionary where the keys are the names of the metrics and the
|
|
145
|
+
values are the corresponding scores.
|
|
146
|
+
"""
|
|
147
|
+
return {}
|
|
90
148
|
|
|
91
|
-
|
|
149
|
+
@staticmethod
|
|
150
|
+
def postprocess(outputs):
|
|
151
|
+
"""The postprocessing step.
|
|
92
152
|
|
|
93
|
-
|
|
153
|
+
Transforms the neural network outputs into the final predictions.
|
|
94
154
|
|
|
95
|
-
|
|
155
|
+
Parameters
|
|
156
|
+
----------
|
|
157
|
+
outputs : Union[Tensor, Iterable[Tensor]]
|
|
158
|
+
The tensor(s) returned by the forward pass of `self.network`.
|
|
96
159
|
|
|
97
|
-
|
|
160
|
+
Returns
|
|
161
|
+
-------
|
|
162
|
+
Any
|
|
163
|
+
The postprocessed outputs.
|
|
164
|
+
"""
|
|
165
|
+
return outputs
|
|
98
166
|
|
|
99
|
-
|
|
167
|
+
```
|
|
100
168
|
|
|
101
169
|
## Usage
|
|
102
170
|
|
|
@@ -120,15 +188,13 @@ The `device` is the [`torch.device`](https://pytorch.org/docs/stable/tensor_attr
|
|
|
120
188
|
|
|
121
189
|
#### Logger
|
|
122
190
|
|
|
123
|
-
A logging function that takes a dictionary in input. The default prints to standard output. You can can easily log with [wandb](https://pypi.org/project/wandb/)
|
|
191
|
+
A logging function that takes a dictionary in input. The default prints to standard output. You can can easily log with [wandb](https://pypi.org/project/wandb/) or with any other custom logger.
|
|
124
192
|
|
|
125
193
|
```py
|
|
126
194
|
import wandb
|
|
127
195
|
model = ClassName(logger=wandb.log)
|
|
128
196
|
```
|
|
129
197
|
|
|
130
|
-
or with any other custom logger.
|
|
131
|
-
|
|
132
198
|
#### Hyperparameters
|
|
133
199
|
|
|
134
200
|
You will typically use several parameters to control the behavior of `ClassName`, such as the learning rate or batch size. These parameters should be passed during the initialization
|
|
@@ -159,9 +225,9 @@ where
|
|
|
159
225
|
- `on` is the name of the training dataloader. Defaults to 'train'.
|
|
160
226
|
- `val` is the name of the validation dataloader. Defaults to 'val'.
|
|
161
227
|
- `gas` is the number of gradient accumulation steps. Defaults to 1 (no gradient accumulation).
|
|
162
|
-
- `callback` is a function that is called after each epoch. It should accept two arguments: the instance itself and a list of dictionaries containing
|
|
228
|
+
- `callback` is a function that is called after each epoch. It should accept two arguments: the instance itself and a list of dictionaries containing logging info up to the current epoch. When this function returns `True`, training stops.
|
|
163
229
|
|
|
164
|
-
This method returns a list of dictionaries containing
|
|
230
|
+
This method returns a list of dictionaries containing logging info.
|
|
165
231
|
|
|
166
232
|
### Checkpoints
|
|
167
233
|
|
|
@@ -192,7 +258,7 @@ Evaluate the model with
|
|
|
192
258
|
model.eval(on='test')
|
|
193
259
|
```
|
|
194
260
|
|
|
195
|
-
where `on` is the name of the dataloader to evaluate on. This should be one of the keys in the `dataloaders`. This method returns a dictionary containing the evaluation metrics.
|
|
261
|
+
where `on` is the name of the dataloader to evaluate on. This should be one of the keys in the `dataloaders`. This method returns a dictionary containing the loss and evaluation metrics.
|
|
196
262
|
|
|
197
263
|
### Inference
|
|
198
264
|
|
|
@@ -210,6 +276,20 @@ Get started with simple self-contained examples:
|
|
|
210
276
|
|
|
211
277
|
- [MNIST classification](https://github.com/eguidotti/torchabc/blob/main/examples/mnist.py)
|
|
212
278
|
|
|
279
|
+
### Run the examples
|
|
280
|
+
|
|
281
|
+
Install the dependencies
|
|
282
|
+
|
|
283
|
+
```
|
|
284
|
+
poetry install --with examples
|
|
285
|
+
```
|
|
286
|
+
|
|
287
|
+
Run the examples by replacing `<name>` with one of the filenames in the [examples](https://github.com/eguidotti/torchabc/tree/main/examples) folder
|
|
288
|
+
|
|
289
|
+
```
|
|
290
|
+
poetry run python examples/<name>.py
|
|
291
|
+
```
|
|
292
|
+
|
|
213
293
|
## Contribute
|
|
214
294
|
|
|
215
295
|
Contributions are welcome! Submit pull requests with new [examples](https://github.com/eguidotti/torchabc/tree/main/examples) or improvements to the core [`TorchABC`](https://github.com/eguidotti/torchabc/blob/main/torchabc/__init__.py) class itself.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "torchabc"
|
|
3
|
-
version = "0.
|
|
3
|
+
version = "0.3.0"
|
|
4
4
|
description = "A simple abstract class for training and inference in PyTorch."
|
|
5
5
|
authors = [
|
|
6
6
|
{name = "Emanuele Guidotti",email = "emanuele.guidotti@usi.ch"}
|
|
@@ -15,6 +15,12 @@ dependencies = [
|
|
|
15
15
|
[tool.poetry.scripts]
|
|
16
16
|
torchabc = "torchabc.cli:main"
|
|
17
17
|
|
|
18
|
+
[tool.poetry.group.examples]
|
|
19
|
+
optional = true
|
|
20
|
+
|
|
21
|
+
[tool.poetry.group.examples.dependencies]
|
|
22
|
+
torchvision = "^0.22.0"
|
|
23
|
+
|
|
18
24
|
[project.urls]
|
|
19
25
|
homepage = "https://github.com/eguidotti/torchabc"
|
|
20
26
|
repository = "https://github.com/eguidotti/torchabc"
|
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
import abc
|
|
2
2
|
import torch
|
|
3
|
+
from torch import Tensor
|
|
4
|
+
from torch.utils.data import default_collate
|
|
3
5
|
from functools import cached_property
|
|
4
6
|
from types import SimpleNamespace
|
|
5
|
-
from typing import Any, Union, Dict, List, Callable
|
|
7
|
+
from typing import Any, Iterable, Union, Dict, List, Callable
|
|
6
8
|
|
|
7
9
|
|
|
8
10
|
class TorchABC(abc.ABC):
|
|
@@ -31,8 +33,6 @@ class TorchABC(abc.ABC):
|
|
|
31
33
|
The function used for logging.
|
|
32
34
|
hparams : SimpleNamespace
|
|
33
35
|
A namespace containing the hyperparameters.
|
|
34
|
-
epoch : int
|
|
35
|
-
The last epoch seen during training.
|
|
36
36
|
"""
|
|
37
37
|
super().__init__()
|
|
38
38
|
if device is not None:
|
|
@@ -45,205 +45,139 @@ class TorchABC(abc.ABC):
|
|
|
45
45
|
self.device = torch.device("cpu")
|
|
46
46
|
self.logger = logger
|
|
47
47
|
self.hparams = SimpleNamespace(**hparams)
|
|
48
|
-
self.epoch = 0
|
|
49
|
-
|
|
50
|
-
@abc.abstractmethod
|
|
51
|
-
@cached_property
|
|
52
|
-
def network(self) -> torch.nn.Module:
|
|
53
|
-
"""The neural network.
|
|
54
|
-
|
|
55
|
-
Returns a `torch.nn.Module` whose input and output tensors assume the
|
|
56
|
-
batch size is the first dimension: (batch_size, ...).
|
|
57
|
-
"""
|
|
58
|
-
pass
|
|
59
|
-
|
|
60
|
-
@abc.abstractmethod
|
|
61
|
-
@cached_property
|
|
62
|
-
def optimizer(self) -> torch.optim.Optimizer:
|
|
63
|
-
"""The optimizer for training the network.
|
|
64
|
-
|
|
65
|
-
Returns a `torch.optim.Optimizer` configured for `self.network.parameters()`.
|
|
66
|
-
"""
|
|
67
|
-
pass
|
|
68
|
-
|
|
69
|
-
@abc.abstractmethod
|
|
70
|
-
@cached_property
|
|
71
|
-
def scheduler(self) -> Union[None, torch.optim.lr_scheduler.LRScheduler, torch.optim.lr_scheduler.ReduceLROnPlateau]:
|
|
72
|
-
"""The learning rate scheduler for the optimizer.
|
|
73
|
-
|
|
74
|
-
Returns a `torch.optim.lr_scheduler.LRScheduler` or `torch.optim.lr_scheduler.ReduceLROnPlateau`
|
|
75
|
-
configured for `self.optimizer`.
|
|
76
|
-
"""
|
|
77
|
-
pass
|
|
78
48
|
|
|
79
49
|
@abc.abstractmethod
|
|
80
50
|
@cached_property
|
|
81
51
|
def dataloaders(self) -> Dict[str, torch.utils.data.DataLoader]:
|
|
82
|
-
"""The dataloaders
|
|
83
|
-
|
|
84
|
-
This method defines and returns a dictionary containing the `DataLoader` instances
|
|
85
|
-
for the training, validation, and testing datasets. The keys of the dictionary
|
|
86
|
-
should correspond to the names of the datasets (e.g., 'train', 'val', 'test'),
|
|
87
|
-
and the values should be their respective `torch.utils.data.DataLoader` objects.
|
|
52
|
+
"""The dataloaders.
|
|
88
53
|
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
If you require custom collation logic (i.e., a specific way to merge a list of
|
|
94
|
-
samples into a batch beyond the default behavior), you should implement this
|
|
95
|
-
logic in the `collate` method of this class. The `collate` method should then be
|
|
96
|
-
passed to the `collate_fn` argument when creating the `DataLoader` instances.
|
|
54
|
+
Returns a dictionary containing multiple `DataLoader` instances. The keys of
|
|
55
|
+
the dictionary are the names of the dataloaders (e.g., 'train', 'val', 'test'),
|
|
56
|
+
and the values are the corresponding `torch.utils.data.DataLoader` objects.
|
|
97
57
|
"""
|
|
98
58
|
pass
|
|
99
59
|
|
|
60
|
+
@staticmethod
|
|
100
61
|
@abc.abstractmethod
|
|
101
|
-
def preprocess(
|
|
102
|
-
"""
|
|
62
|
+
def preprocess(data: Any, flag: str = 'predict') -> Union[Tensor, Iterable[Tensor]]:
|
|
63
|
+
"""The preprocessing step.
|
|
103
64
|
|
|
104
|
-
|
|
105
|
-
When `flag` is empty (the default), the `data` are assumed to represent the
|
|
106
|
-
model's input that is used for inference. When `flag` has a specific value,
|
|
107
|
-
the method may perform different preprocessing steps such as transforming
|
|
108
|
-
the target or augmenting the input for training.
|
|
65
|
+
Transforms the raw data of an individual sample into the corresponding tensor(s).
|
|
109
66
|
|
|
110
67
|
Parameters
|
|
111
68
|
----------
|
|
112
69
|
data : Any
|
|
113
|
-
The raw
|
|
70
|
+
The raw data.
|
|
114
71
|
flag : str, optional
|
|
115
|
-
A
|
|
116
|
-
|
|
72
|
+
A flag indicating how to transform the data. The default transforms the
|
|
73
|
+
input data for inference. You can use additional flags, for instance,
|
|
74
|
+
to perform data augmentation or transform the targets during training or validation.
|
|
117
75
|
|
|
118
76
|
Returns
|
|
119
77
|
-------
|
|
120
|
-
|
|
78
|
+
Union[Tensor, Iterable[Tensor]]
|
|
121
79
|
The preprocessed data.
|
|
122
80
|
"""
|
|
123
81
|
pass
|
|
124
82
|
|
|
125
83
|
@abc.abstractmethod
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
This method transforms the outputs of the neural network to
|
|
130
|
-
generate the final predictions.
|
|
131
|
-
|
|
132
|
-
Parameters
|
|
133
|
-
----------
|
|
134
|
-
outputs : torch.Tensor
|
|
135
|
-
The output tensor from `self.network`.
|
|
84
|
+
@cached_property
|
|
85
|
+
def network(self) -> torch.nn.Module:
|
|
86
|
+
"""The neural network.
|
|
136
87
|
|
|
137
|
-
Returns
|
|
138
|
-
|
|
139
|
-
Any
|
|
140
|
-
The postprocessed outputs.
|
|
88
|
+
Returns a `torch.nn.Module` whose input and output tensors assume the
|
|
89
|
+
batch size is the first dimension: (batch_size, ...).
|
|
141
90
|
"""
|
|
142
91
|
pass
|
|
143
92
|
|
|
144
93
|
@abc.abstractmethod
|
|
145
|
-
|
|
146
|
-
|
|
94
|
+
@cached_property
|
|
95
|
+
def optimizer(self) -> torch.optim.Optimizer:
|
|
96
|
+
"""The optimizer for training the network.
|
|
147
97
|
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
98
|
+
Returns a `torch.optim.Optimizer` configured for `self.network.parameters()`.
|
|
99
|
+
"""
|
|
100
|
+
pass
|
|
151
101
|
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
targets : torch.Tensor
|
|
157
|
-
The targets corresponding to the outputs.
|
|
102
|
+
@abc.abstractmethod
|
|
103
|
+
@cached_property
|
|
104
|
+
def scheduler(self) -> Union[None, torch.optim.lr_scheduler.LRScheduler, torch.optim.lr_scheduler.ReduceLROnPlateau]:
|
|
105
|
+
"""The learning rate scheduler for the optimizer.
|
|
158
106
|
|
|
159
|
-
Returns
|
|
160
|
-
|
|
161
|
-
torch.Tensor
|
|
162
|
-
A scalar tensor representing the computed loss value.
|
|
107
|
+
Returns a `torch.optim.lr_scheduler.LRScheduler` or `torch.optim.lr_scheduler.ReduceLROnPlateau`
|
|
108
|
+
configured for `self.optimizer`.
|
|
163
109
|
"""
|
|
164
110
|
pass
|
|
165
111
|
|
|
112
|
+
@staticmethod
|
|
166
113
|
@abc.abstractmethod
|
|
167
|
-
def
|
|
168
|
-
"""
|
|
114
|
+
def loss(outputs: Union[Tensor, Iterable[Tensor]], targets: Union[Tensor, Iterable[Tensor]]) -> Tensor:
|
|
115
|
+
"""The loss function.
|
|
169
116
|
|
|
170
|
-
|
|
171
|
-
between the neural network `outputs` and the corresponding `targets`.
|
|
172
|
-
Unlike `self.loss`, which is primarily used for training, these metrics
|
|
173
|
-
are only used for evaluation and they do not need to be differentiable.
|
|
117
|
+
Compute the loss to train the neural network.
|
|
174
118
|
|
|
175
119
|
Parameters
|
|
176
120
|
----------
|
|
177
|
-
outputs :
|
|
178
|
-
The tensor
|
|
179
|
-
targets :
|
|
180
|
-
The
|
|
121
|
+
outputs : Union[Tensor, Iterable[Tensor]]
|
|
122
|
+
The tensor(s) returned by the forward pass of `self.network`.
|
|
123
|
+
targets : Union[Tensor, Iterable[Tensor]]
|
|
124
|
+
The tensor(s) giving the target values.
|
|
181
125
|
|
|
182
126
|
Returns
|
|
183
127
|
-------
|
|
184
|
-
|
|
185
|
-
A
|
|
186
|
-
values are the corresponding metric scores.
|
|
128
|
+
Tensor
|
|
129
|
+
A scalar tensor giving the loss value.
|
|
187
130
|
"""
|
|
188
131
|
pass
|
|
189
132
|
|
|
190
|
-
|
|
191
|
-
|
|
133
|
+
@staticmethod
|
|
134
|
+
@abc.abstractmethod
|
|
135
|
+
def metrics(outputs: Union[Tensor, Iterable[Tensor]], targets: Union[Tensor, Iterable[Tensor]]) -> Dict[str, float]:
|
|
136
|
+
"""The evaluation metrics.
|
|
192
137
|
|
|
193
|
-
|
|
194
|
-
used as the default function for collation in dataloaders. For custom data types,
|
|
195
|
-
overwrite this function and pass it as the `collate_fn` argument to the dataloader.
|
|
138
|
+
Compute additional evaluation metrics.
|
|
196
139
|
|
|
197
140
|
Parameters
|
|
198
141
|
----------
|
|
199
|
-
|
|
200
|
-
The
|
|
142
|
+
outputs : Union[Tensor, Iterable[Tensor]]
|
|
143
|
+
The tensor(s) returned by the forward pass of `self.network`.
|
|
144
|
+
targets : Union[Tensor, Iterable[Tensor]]
|
|
145
|
+
The tensor(s) giving the target values.
|
|
201
146
|
|
|
202
147
|
Returns
|
|
203
148
|
-------
|
|
204
|
-
|
|
205
|
-
|
|
149
|
+
Dict[str, float]
|
|
150
|
+
A dictionary where the keys are the names of the metrics and the
|
|
151
|
+
values are the corresponding scores.
|
|
206
152
|
"""
|
|
207
|
-
|
|
153
|
+
pass
|
|
208
154
|
|
|
209
|
-
|
|
210
|
-
|
|
155
|
+
@staticmethod
|
|
156
|
+
@abc.abstractmethod
|
|
157
|
+
def postprocess(outputs: Union[Tensor, Iterable[Tensor]]) -> Any:
|
|
158
|
+
"""The postprocessing step.
|
|
211
159
|
|
|
212
|
-
|
|
213
|
-
moving tensors, lists, tuples, and dictionaries. For custom data types, overwrite
|
|
214
|
-
this function to implement the necessary logic for moving the data to the device.
|
|
160
|
+
Transforms the neural network outputs into the final predictions.
|
|
215
161
|
|
|
216
162
|
Parameters
|
|
217
163
|
----------
|
|
218
|
-
|
|
219
|
-
The
|
|
164
|
+
outputs : Union[Tensor, Iterable[Tensor]]
|
|
165
|
+
The tensor(s) returned by the forward pass of `self.network`.
|
|
220
166
|
|
|
221
167
|
Returns
|
|
222
168
|
-------
|
|
223
169
|
Any
|
|
224
|
-
The
|
|
170
|
+
The postprocessed outputs.
|
|
225
171
|
"""
|
|
226
|
-
|
|
227
|
-
return data.to(self.device)
|
|
228
|
-
elif isinstance(data, list):
|
|
229
|
-
return [self.move(item) for item in data]
|
|
230
|
-
elif isinstance(data, tuple):
|
|
231
|
-
return tuple(self.move(item) for item in data)
|
|
232
|
-
elif isinstance(data, dict):
|
|
233
|
-
return {key: self.move(value) for key, value in data.items()}
|
|
234
|
-
else:
|
|
235
|
-
raise TypeError(
|
|
236
|
-
f"Unsupported data type: {type(data)}. "
|
|
237
|
-
"Please implement the move method for custom data types."
|
|
238
|
-
)
|
|
172
|
+
pass
|
|
239
173
|
|
|
240
174
|
def train(self, epochs: int, on: str = 'train', val: str = 'val', gas: int = 1, callback: Callable = None) -> List[dict]:
|
|
241
175
|
"""Train the model.
|
|
242
176
|
|
|
243
177
|
This method sets the network to training mode, iterates through the training dataloader
|
|
244
178
|
for the given number of epochs, performs forward and backward passes, optimizes the
|
|
245
|
-
model parameters, and logs the training loss and metrics. It optionally performs
|
|
246
|
-
after each epoch.
|
|
179
|
+
model parameters, and logs the training loss and metrics. It optionally performs
|
|
180
|
+
validation after each epoch.
|
|
247
181
|
|
|
248
182
|
Parameters
|
|
249
183
|
----------
|
|
@@ -257,22 +191,21 @@ class TorchABC(abc.ABC):
|
|
|
257
191
|
The number of gradient accumulation steps. Defaults to 1 (no gradient accumulation).
|
|
258
192
|
callback : Callable, optional
|
|
259
193
|
A callback function that is called after each epoch. It should accept two arguments:
|
|
260
|
-
the instance itself and a list of dictionaries containing
|
|
261
|
-
When this function returns True, training stops.
|
|
194
|
+
the instance itself and a list of dictionaries containing logging info up to the
|
|
195
|
+
current epoch. When this function returns True, training stops.
|
|
262
196
|
|
|
263
197
|
Returns
|
|
264
198
|
-------
|
|
265
199
|
list
|
|
266
|
-
A list of dictionaries containing
|
|
200
|
+
A list of dictionaries containing logging info.
|
|
267
201
|
"""
|
|
268
202
|
logs, log_batch, log_epoch = [], {}, {}
|
|
269
|
-
for epoch in range(
|
|
270
|
-
|
|
203
|
+
for epoch in range(1, 1 + epochs):
|
|
204
|
+
loss_gas = 0
|
|
271
205
|
self.network.train()
|
|
272
|
-
self.network.to(self.device)
|
|
273
206
|
self.optimizer.zero_grad()
|
|
274
|
-
loss_gas = 0
|
|
275
207
|
for batch, (inputs, targets) in enumerate(self.dataloaders[on], start=1):
|
|
208
|
+
self.network.to(self.device)
|
|
276
209
|
inputs, targets = self.move((inputs, targets))
|
|
277
210
|
outputs = self.network(inputs)
|
|
278
211
|
loss = self.loss(outputs, targets)
|
|
@@ -318,68 +251,104 @@ class TorchABC(abc.ABC):
|
|
|
318
251
|
break
|
|
319
252
|
return logs
|
|
320
253
|
|
|
321
|
-
def eval(self, on: str) -> Dict[str, float]:
|
|
254
|
+
def eval(self, on: str, reduction: Union[str, Callable] = 'mean') -> Dict[str, float]:
|
|
322
255
|
"""Evaluate the model.
|
|
323
256
|
|
|
324
|
-
This method sets the network to evaluation mode, iterates through the
|
|
325
|
-
|
|
326
|
-
the results. No gradients are computed during this process.
|
|
257
|
+
This method sets the network to evaluation mode, iterates through the given
|
|
258
|
+
dataloader, calculates the loss and metrics, and returns the results.
|
|
327
259
|
|
|
328
260
|
Parameters
|
|
329
261
|
----------
|
|
330
262
|
on : str
|
|
331
|
-
The name of the dataloader to evaluate on. This
|
|
332
|
-
|
|
263
|
+
The name of the dataloader to evaluate on. This is one of the keys
|
|
264
|
+
in `self.dataloaders`.
|
|
265
|
+
reduction : Union[str, Callable]
|
|
266
|
+
Specifies the reduction to apply to batch statistics. Possible values
|
|
267
|
+
are 'mean' to compute the average of the evaluation metrics across batches,
|
|
268
|
+
'sum' to compute their sum, or a callable function that takes as input a
|
|
269
|
+
list of floats and a metric name and returns a scalar.
|
|
333
270
|
|
|
334
271
|
Returns
|
|
335
272
|
-------
|
|
336
273
|
dict
|
|
337
274
|
A dictionary containing the loss and evaluation metrics.
|
|
338
275
|
"""
|
|
276
|
+
metrics_lst = []
|
|
339
277
|
self.network.eval()
|
|
340
|
-
tot_loss, num_batches = 0, 0
|
|
341
|
-
all_outputs, all_targets = [], []
|
|
342
278
|
with torch.no_grad():
|
|
343
|
-
self.network.to(self.device)
|
|
344
279
|
for inputs, targets in self.dataloaders[on]:
|
|
280
|
+
self.network.to(self.device)
|
|
345
281
|
inputs, targets = self.move((inputs, targets))
|
|
346
282
|
outputs = self.network(inputs)
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
283
|
+
metrics = self.metrics(outputs, targets)
|
|
284
|
+
metrics['loss'] = self.loss(outputs, targets).item()
|
|
285
|
+
metrics_lst.append(metrics)
|
|
286
|
+
if isinstance(reduction, str):
|
|
287
|
+
reduce = lambda x, _: getattr(torch, reduction)(torch.tensor(x)).item()
|
|
288
|
+
else:
|
|
289
|
+
reduce = reduction
|
|
290
|
+
return {
|
|
291
|
+
name: reduce([metrics[name] for metrics in metrics_lst], name)
|
|
292
|
+
for name in metrics_lst[0]
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
def predict(self, data: Iterable[Any]) -> Any:
|
|
356
296
|
"""Predict the raw data.
|
|
357
297
|
|
|
358
|
-
This method sets the network to evaluation mode, preprocesses and
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
return the final prediction.
|
|
298
|
+
This method sets the network to evaluation mode, preprocesses and collates
|
|
299
|
+
the raw input data, performs a forward pass, postprocesses the outputs,
|
|
300
|
+
and returns the final predictions.
|
|
362
301
|
|
|
363
302
|
Parameters
|
|
364
303
|
----------
|
|
365
|
-
data : Any
|
|
366
|
-
The raw input data
|
|
304
|
+
data : Iterable[Any]
|
|
305
|
+
The raw input data.
|
|
367
306
|
|
|
368
307
|
Returns
|
|
369
308
|
-------
|
|
370
309
|
Any
|
|
371
|
-
The
|
|
310
|
+
The predictions.
|
|
372
311
|
"""
|
|
373
312
|
self.network.eval()
|
|
374
|
-
self.network.to(self.device)
|
|
375
313
|
with torch.no_grad():
|
|
376
|
-
|
|
377
|
-
batch =
|
|
378
|
-
|
|
379
|
-
inputs = self.move(
|
|
314
|
+
data = [self.preprocess(d, flag='predict') for d in data]
|
|
315
|
+
batch = default_collate(data)
|
|
316
|
+
self.network.to(self.device)
|
|
317
|
+
inputs = self.move(batch)
|
|
380
318
|
outputs = self.network(inputs)
|
|
381
|
-
|
|
382
|
-
|
|
319
|
+
return self.postprocess(outputs)
|
|
320
|
+
|
|
321
|
+
def move(self, data: Union[Tensor, Iterable[Tensor]]) -> Union[Tensor, Iterable[Tensor]]:
|
|
322
|
+
"""Move data to the current device.
|
|
323
|
+
|
|
324
|
+
This method moves the data to the device specified by `self.device`. It supports
|
|
325
|
+
moving tensors, or lists, tuples, and dictionaries of tensors. For custom data
|
|
326
|
+
structures, overwrite this function to implement the necessary logic for moving
|
|
327
|
+
the data to the device.
|
|
328
|
+
|
|
329
|
+
Parameters
|
|
330
|
+
----------
|
|
331
|
+
data : Union[Tensor, Iterable[Tensor]]
|
|
332
|
+
The data to move to the current device.
|
|
333
|
+
|
|
334
|
+
Returns
|
|
335
|
+
-------
|
|
336
|
+
Union[Tensor, Iterable[Tensor]]
|
|
337
|
+
The data moved to the current device.
|
|
338
|
+
"""
|
|
339
|
+
if isinstance(data, Tensor):
|
|
340
|
+
return data.to(self.device)
|
|
341
|
+
elif isinstance(data, list):
|
|
342
|
+
return [self.move(item) for item in data]
|
|
343
|
+
elif isinstance(data, tuple):
|
|
344
|
+
return tuple(self.move(item) for item in data)
|
|
345
|
+
elif isinstance(data, dict):
|
|
346
|
+
return {key: self.move(value) for key, value in data.items()}
|
|
347
|
+
else:
|
|
348
|
+
raise TypeError(
|
|
349
|
+
f"Unsupported data type: {type(data)}. "
|
|
350
|
+
"Please implement the method `move` for custom data types."
|
|
351
|
+
)
|
|
383
352
|
|
|
384
353
|
def save(self, checkpoint: str) -> None:
|
|
385
354
|
"""Save checkpoint.
|
|
@@ -391,7 +360,6 @@ class TorchABC(abc.ABC):
|
|
|
391
360
|
"""
|
|
392
361
|
torch.save({
|
|
393
362
|
'hparams': self.hparams.__dict__,
|
|
394
|
-
'epoch': self.epoch,
|
|
395
363
|
'network_state_dict': self.network.state_dict(),
|
|
396
364
|
'optimizer_state_dict': self.optimizer.state_dict(),
|
|
397
365
|
'scheduler_state_dict': self.scheduler.state_dict() if self.scheduler else None,
|
|
@@ -408,7 +376,6 @@ class TorchABC(abc.ABC):
|
|
|
408
376
|
"""
|
|
409
377
|
checkpoint = torch.load(checkpoint, map_location=self.device)
|
|
410
378
|
self.hparams = SimpleNamespace(**checkpoint['hparams'])
|
|
411
|
-
self.epoch = checkpoint['epoch']
|
|
412
379
|
self.network.load_state_dict(checkpoint['network_state_dict'])
|
|
413
380
|
self.optimizer.load_state_dict(checkpoint['optimizer_state_dict'])
|
|
414
381
|
if checkpoint['scheduler_state_dict']:
|
|
@@ -11,7 +11,7 @@ def main():
|
|
|
11
11
|
args = parser.parse_args()
|
|
12
12
|
|
|
13
13
|
cached_properties = {}
|
|
14
|
-
|
|
14
|
+
static_methods = {}
|
|
15
15
|
defaults = {
|
|
16
16
|
'scheduler': 'return None',
|
|
17
17
|
'metrics': 'return {}',
|
|
@@ -23,15 +23,20 @@ def main():
|
|
|
23
23
|
if hasattr(member, '__isabstractmethod__'):
|
|
24
24
|
if isinstance(TorchABC.__dict__.get(name), cached_property):
|
|
25
25
|
cached_properties[name] = member.__doc__ or ""
|
|
26
|
-
elif
|
|
26
|
+
elif isinstance(TorchABC.__dict__.get(name), staticmethod):
|
|
27
27
|
sig = inspect.signature(member)
|
|
28
|
-
|
|
28
|
+
sig = sig.replace(
|
|
29
|
+
parameters=[
|
|
30
|
+
param.replace(annotation=inspect.Parameter.empty)
|
|
31
|
+
for param in sig.parameters.values()
|
|
32
|
+
],
|
|
33
|
+
return_annotation=inspect.Signature.empty
|
|
34
|
+
)
|
|
35
|
+
static_methods[name] = (sig, member.__doc__ or "")
|
|
29
36
|
|
|
30
37
|
template = """
|
|
31
|
-
import torch
|
|
32
38
|
from torchabc import TorchABC
|
|
33
39
|
from functools import cached_property
|
|
34
|
-
from typing import Any, Dict
|
|
35
40
|
|
|
36
41
|
|
|
37
42
|
class ClassName(TorchABC):"""
|
|
@@ -41,10 +46,10 @@ class ClassName(TorchABC):"""
|
|
|
41
46
|
\"\"\"A concrete subclass of the TorchABC abstract class.
|
|
42
47
|
|
|
43
48
|
Use this template to implement your own model by following these steps:
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
49
|
+
- replace ClassName with the name of your model,
|
|
50
|
+
- replace this docstring with a description of your model,
|
|
51
|
+
- implement the methods below to define the core logic of your model,
|
|
52
|
+
- access the hyperparameters passed during initialization with `self.hparams`.
|
|
48
53
|
\"\"\""""
|
|
49
54
|
|
|
50
55
|
template += """
|
|
@@ -62,26 +67,18 @@ class ClassName(TorchABC):"""
|
|
|
62
67
|
template += f"""
|
|
63
68
|
{defaults[name] if name in defaults else 'raise NotImplementedError'}
|
|
64
69
|
"""
|
|
65
|
-
elif name in
|
|
66
|
-
sig, doc =
|
|
70
|
+
elif name in static_methods:
|
|
71
|
+
sig, doc = static_methods[name]
|
|
67
72
|
template += f"""
|
|
73
|
+
@staticmethod
|
|
68
74
|
def {name}{sig}:"""
|
|
69
75
|
if not args.min:
|
|
70
76
|
template += f"""
|
|
71
77
|
\"\"\"{doc}\"\"\""""
|
|
72
78
|
template += f"""
|
|
73
79
|
{defaults[name] if name in defaults else 'raise NotImplementedError'}
|
|
74
|
-
"""
|
|
75
|
-
|
|
76
|
-
if not args.min:
|
|
77
|
-
template += f"""
|
|
78
|
-
|
|
79
|
-
if __name__ == "__main__":
|
|
80
|
-
# Example usage
|
|
81
|
-
model = ClassName()
|
|
82
|
-
model.train(epochs=1)
|
|
83
80
|
"""
|
|
84
|
-
|
|
81
|
+
|
|
85
82
|
with open(args.create, "x") as f:
|
|
86
83
|
f.write(template.lstrip())
|
|
87
84
|
|
|
File without changes
|