ESPnet3 LightningModule wrapper for model training and data integration. This wrapper keeps the common ESPnet3 model contract unchanged: ```python loss, stats, weight = model(**batch) ``` Most models should continue to return a single scalar loss tensor. The training loop
| 26 | |
| 27 | |
| 28 | class ESPnetLightningModule(lightning.LightningModule): |
| 29 | """ESPnet3 LightningModule wrapper for model training and data integration. |
| 30 | |
| 31 | This wrapper keeps the common ESPnet3 model contract unchanged: |
| 32 | |
| 33 | ```python |
| 34 | loss, stats, weight = model(**batch) |
| 35 | ``` |
| 36 | |
| 37 | Most models should continue to return a single scalar loss tensor. The training |
| 38 | loop then behaves exactly like conventional Lightning single-optimizer training. |
| 39 | |
| 40 | When multiple optimizers are configured, the same return value is expected, |
| 41 | but the `loss` field must carry optimizer routing information through |
| 42 | `OptimizationStep`. |
| 43 | The model still returns one `stats` dict and one optional `weight` value; only |
| 44 | the type of `loss` changes. |
| 45 | |
| 46 | Example: |
| 47 | Single optimizer path: |
| 48 | ```python |
| 49 | def forward(self, **batch): |
| 50 | loss = ... |
| 51 | stats = {"loss": loss.detach(), "acc": acc.detach()} |
| 52 | weight = torch.tensor(batch_size, device=loss.device) |
| 53 | return loss, stats, weight |
| 54 | ``` |
| 55 | |
| 56 | GAN-style path updating both optimizers in a single batch: |
| 57 | ```python |
| 58 | def forward(self, **batch): |
| 59 | g_loss = ... |
| 60 | d_loss = ... |
| 61 | stats = { |
| 62 | "generator_loss": g_loss.detach(), |
| 63 | "discriminator_loss": d_loss.detach(), |
| 64 | } |
| 65 | return [ |
| 66 | OptimizationStep(loss=g_loss, name="generator"), |
| 67 | OptimizationStep(loss=d_loss, name="discriminator"), |
| 68 | ], stats, None |
| 69 | ``` |
| 70 | |
| 71 | GAN-style path updating only the generator for one batch: |
| 72 | ```python |
| 73 | def forward(self, **batch): |
| 74 | g_loss = ... |
| 75 | stats = {"generator_loss": g_loss.detach()} |
| 76 | return OptimizationStep(loss=g_loss, name="generator"), stats, None |
| 77 | ``` |
| 78 | |
| 79 | Notes: |
| 80 | - Returning `OptimizationStep` with the single optimizer is forbidden. |
| 81 | - In the multi-optimizer path, only optimizers named by returned |
| 82 | `OptimizationStep` objects are touched for that batch. Optimizers omitted |
| 83 | from the list are left untouched entirely. |
| 84 | - The order of `OptimizationStep` entries is the exact backward/step order. |
| 85 | - NaN or Inf in any returned loss causes the whole batch to be skipped on |
no outgoing calls
searching dependent graphs…