Running experiments ==================== The :class:`~libdamp.experiment.Experiment` base class and the ``scripts/run.py`` entry point together provide a complete, configuration-driven training loop for experiments with ``libdamp``. The main goal is to reduce training boilerplate code while maximizing flexibility of the individual experiment setup and ensuring reproducibility. The Experiment class --------------------- :class:`~libdamp.experiment.Experiment` is a `Lightning `_ ``LightningModule`` subclass that defines the training/validation/test step structure common to all ``libdamp`` experiments. To define a new experiment, subclass it and implement the usual Lightning hooks (``forward()``, ``training_step()``, ``validation_step()``, ``configure_optimizers()``, ...), composing the model out of :mod:`libdamp.generators`, :mod:`libdamp.processors`, and ``libdamp.models``:: import gin import libdamp @gin.configurable class MyExperiment(libdamp.Experiment): def __init__(self, fs, **kwargs): super().__init__(**kwargs) self.fs = fs self.osc = libdamp.generators.HarmonicOsc(N=512, fs=fs) self.envelope = libdamp.processors.GainEnvelope() self.loss_fn = libdamp.RMSLoss() def forward(self, f0, amplitudes, gain): self.osc.update(f0=f0, a=amplitudes) x = self.osc.generate() self.envelope.update(g=gain) return self.envelope.process(x) def training_step(self, batch, batch_idx): y, f0, amplitudes, gain = batch y_hat = self(f0, amplitudes, gain) loss = self.loss_fn(y, y_hat) self.log("train_loss", loss) return loss All constructor parameters of :class:`~libdamp.experiment.Experiment` itself (batch size, number of epochs, checkpointing, logging, ...) are marked ``gin.REQUIRED`` and are meant to be set in a `gin-config `_ configuration file rather than hardcoded, so the same experiment class can be reused across many training runs that only differ in configuration. :meth:`~libdamp.experiment.Experiment.log_audio` is a ready-made helper for logging example audio (predictions and, once, the reference) to disk and optionally MLflow. Running an experiment with run.py ---------------------------------- ``scripts/run.py`` is the command-line entry point that turns an :class:`~libdamp.experiment.Experiment` subclass and a gin config into a full training run. The gin config selects which experiment and datasets to use via the ``libdamp()`` binding:: libdamp.experiment = @MyExperiment() libdamp.train_dataset = @MyTrainDataset() libdamp.val_dataset = @MyValDataset() # optional libdamp.test_dataset = @MyTestDataset() # optional MyExperiment.fs = 16000.0 # ... plus all the gin.REQUIRED Experiment parameters (batch_size, max_epochs, save_path, ...) and is then run with: .. code-block:: console python scripts/run.py --config path/to/config.gin --seed 0 Command-line options: - ``-c, --config`` (required): one or more gin config files, merged in order. - ``--config-path``: additional directories to search for gin files included from a config (via gin's ``include`` statement). - ``--seed``: fixed random seed for reproducible runs (default: ``0``). Given the resolved configuration, ``run.py`` then takes care of the rest of the training boilerplate so individual experiments don't have to: - builds the train/validation ``DataLoader``\\ s from the configured datasets; - sets up logging (CSV always, plus TensorBoard and/or MLflow if enabled) and writes the fully-resolved ("operative") gin config alongside the run for reproducibility; - configures checkpointing (best-``n`` and/or last-epoch) and early stopping based on ``val_loss``, and optionally resumes from a previous checkpoint's weights; - runs training via a Lightning ``Trainer`` configured from the experiment's parameters (accelerator, devices, gradient accumulation/clipping, validation interval, ``fast_dev_run`` for quick smoke tests, ...); - runs a final test pass with both the best and the last checkpoint, if a test dataset was given. API reference -------------- .. automodule:: libdamp.experiment :members: :show-inheritance: