CONCEPTS

App Loop

App Loop

Tutorial: Task and App LoopSee also: Examples: Pipelines, API: language

The ML Experiment Lifecycle

config file
    ↓  laco.load
DictConfig
    ↓  laco.instantiate (per field)
real objects (model, optimizer, …)
    ↓  training loop
results
    ↓  laco.save
archived config

@L.task and laco.main wire up the middle two steps automatically.

@L.task

@L.task
def run(model: nn.Module, optimizer: torch.optim.Optimizer, num_steps: int = 1000):
    for step in range(num_steps):
        ...

@L.task wraps the function so it accepts a DictConfig and automatically:

  1. Inspects the function signature.
  2. For each parameter, calls OmegaConf.select(cfg, param_name).
  3. If the selected value is a DictConfig node, calls laco.instantiate on it.
  4. Fills in default values for parameters not present in the config.
  5. Raises MissingMandatoryValue for required parameters with no default and no config value.
  6. Calls the wrapped function with the resolved arguments.

*args (VAR_POSITIONAL) parameters are skipped: they cannot be represented in a keyed config.

laco.main

import laco

def run(model, optimizer, num_steps=1000):
    ...

if __name__ == "__main__":
    laco.main("train", config_path="configs")(run)()

laco.main(config_name, config_path, version_base) wraps @hydra.main, applies an implicit @L.task to the wrapped function, and exposes the full Hydra CLI.

Hydra CLI Overrides

python train.py model.out_features=512 optimizer.lr=5e-4

Any config key can be overridden from the command line. Hydra validates types against the schema if @L.config is used.

Multirun

python train.py -m optimizer=sgd,adam lr=1e-3,1e-4

Hydra's multirun mode runs the Cartesian product of the sweep. All Hydra launchers and sweepers (submitit, joblib, Optuna) work out of the box because laco.main delegates to the standard @hydra.main infrastructure.

__main__ Pattern

# configs/pipelines/mnist_train.py
import laco.language as L

@L.task
def task(model, optimizer, loader, num_steps=1000):
    ...

if __name__ == "__main__":
    import laco
    laco.main("mnist_train", config_path=".")(task)()

The module is a valid Laco config file (importable via laco.load) and also a runnable script with Hydra CLI support.