forked from coqui-ai/Trainer
-
Notifications
You must be signed in to change notification settings - Fork 3
/
model.py
200 lines (156 loc) · 7.22 KB
/
model.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
from abc import ABC, abstractmethod
from typing import TYPE_CHECKING, Any, Optional
import torch
from torch import nn
from trainer.trainer_utils import is_apex_available
if is_apex_available():
from apex import amp
if TYPE_CHECKING:
from trainer.trainer import Trainer
# pylint: skip-file
class TrainerModel(ABC, nn.Module):
"""Abstract 🐸TTS class. Every new 🐸TTS model must inherit this."""
@abstractmethod
def forward(self, input: torch.Tensor, *args, aux_input: Optional[dict[str, Any]] = None, **kwargs) -> dict:
"""Forward ... for the model mainly used in training.
You can be flexible here and use different number of arguments and argument names since it is intended to be
used by `train_step()` without exposing it out of the model.
Args:
input (torch.Tensor): Input tensor.
aux_input (Dict): Auxiliary model inputs like embeddings, durations or any other sorts of inputs.
Returns:
Dict: Model outputs. Main model output must be named as "model_outputs".
"""
if aux_input is None:
aux_input = {}
outputs_dict = {"model_outputs": None}
...
return outputs_dict
def format_batch(self, batch: dict) -> dict:
"""Format batch returned by the data loader before sending it to the model.
If not implemented, model uses the batch as is.
Can be used for data augmentation, feature ectraction, etc.
"""
return batch
def format_batch_on_device(self, batch: dict) -> dict:
"""Format batch on device before sending it to the model.
If not implemented, model uses the batch as is.
Can be used for data augmentation, feature ectraction, etc.`
"""
return batch
def train_step(self, *args: Any, **kwargs: Any) -> tuple[dict, dict]:
"""Perform a single training step. Run the model forward ... and compute losses.
Args:
batch (Dict): Input tensors.
criterion (nn.Module): Loss layer designed for the model.
optimizer_idx (int): Index of optimizer to use. 0 for the generator and 1 for the discriminator networks.
Returns:
Tuple[Dict, Dict]: Model ouputs and computed losses.
"""
msg = " [!] `train_step()` is not implemented."
raise NotImplementedError(msg)
def train_log(self, *args: Any, **kwargs: Any) -> None:
"""Create visualizations and waveform examples for training.
For example, here you can plot spectrograms and generate sample sample waveforms from these spectrograms to
be projected onto Tensorboard.
Args:
batch (Dict): Model inputs used at the previous training step.
outputs (Dict): Model outputs generated at the previoud training step.
logger (Logger): Logger instance to log training plots.
assets (Dict): Assets to be used for logging from the trainer's closure.
steps (int): Number of training steps taken so far.
Returns:
Tuple[Dict, np.ndarray]: training plots and output waveform.
"""
msg = " [!] `train_log()` is not implemented."
raise NotImplementedError(msg)
@torch.no_grad()
def eval_step(self, *args: Any, **kwargs: Any):
"""Perform a single evaluation step.
Run the model forward ... and compute losses. In most cases, you can
call `train_step()` with no changes.
Args:
batch (Dict): Input tensors.
criterion (nn.Module): Loss layer designed for the model.
optimizer_idx (int): Index of optimizer to use. 0 for the generator and 1 for the discriminator networks.
Returns:
Tuple[Dict, Dict]: Model ouputs and computed losses.
"""
msg = " [!] `eval_step()` is not implemented."
raise NotImplementedError(msg)
def eval_log(self, *args: Any, **kwargs: Any) -> None:
"""The same as `train_log()`."""
msg = " [!] `eval_log()` is not implemented."
raise NotImplementedError(msg)
@abstractmethod
def get_data_loader(*args: Any, **kwargs: Any) -> torch.utils.data.DataLoader:
"""Get data loader for the model.
Args:
config (TrainerConfig): Configuration object.
assets (Dict): Additional assets to be used for data loading.
is_eval (bool): If True, returns evaluation data loader.
samples (Union[List[Dict], List[List]]): List of samples to be used for data loading.
verbose (bool): If True, prints data loading information.
num_gpus (int): Number of GPUs used for training.
rank (int): Rank of the current GPU.
Returns:
torch.utils.data.DataLoader: Data loader for the model.
"""
...
msg = " [!] `get_data_loader()` is not implemented."
raise NotImplementedError(msg)
def init_for_training(self) -> None:
"""Initialize model for training."""
def optimize(self, *args: Any, **kwargs: Any) -> tuple[dict, dict, float]:
"""Model specific optimization step that must perform the following steps.
1. Forward pass
2. Compute loss
3. Backward pass
4. Update weights.
Use `self.scaled_backward()` instead of `loss.backward()` to be able to use Mixed Precision Training.
Args:
batch (Dict): Input tensors.
trainer (Trainer): Trainer instance to be able to access the training closure.
Returns:
Tuple[Dict, Dict, float]: Model outputs, loss dictionary and grad_norm value.
"""
msg = " [!] `optimize()` is not implemented."
raise NotImplementedError(msg)
def scaled_backward(
self,
loss: torch.Tensor,
trainer: "Trainer",
optimizer: torch.optim.Optimizer,
*args: Any,
**kwargs: Any,
) -> tuple[float, bool]:
"""Backward pass with gradient scaling for custom `optimize` calls.
Args:
loss (torch.Tensor): Loss to be backpropagated.
trainer (Trainer): Trainer instance to be able to access the training closure.
optimizer (Optimizer): Optimizer for APEX AMP based scaled `backward` calls.
"""
if trainer.use_amp_scaler:
if trainer.use_apex:
# https://nvidia.github.io/apex/advanced.html?highlight=accumulate#backward-passes-with-multiple-optimizers
with amp.scale_loss(loss, optimizer) as scaled_loss:
scaled_loss.backward()
else:
# model optimizer step in mixed precision mode
trainer.scaler.scale(loss).backward()
else:
# main model optimizer step
loss.backward()
# def get_optimizer(self) -> Union["Optimizer", List["Optimizer"]]:
# """Setup an return optimizer or optimizers."""
# ...
# def get_lr(self) -> Union[float, List[float]]:
# """Return learning rate(s).
# Returns:
# Union[float, List[float]]: Model's initial learning rates.
# """
# ...
# def get_scheduler(self, optimizer: torch.optim.Optimizer):
# ...
# def get_criterion(self):
# ...