HOW-TO

Migrate from argparse

Migrate from argparse

Tutorial: Why Laco?See also: Getting Started

Before: argparse

# train.py (argparse version)
import argparse, torch, torch.nn as nn

def main():
    p = argparse.ArgumentParser()
    p.add_argument("--lr", type=float, default=1e-3)
    p.add_argument("--hidden", type=int, default=256)
    p.add_argument("--epochs", type=int, default=10)
    args = p.parse_args()

    model = nn.Sequential(
        nn.Linear(784, args.hidden),
        nn.ReLU(),
        nn.Linear(args.hidden, 10),
    )
    optimizer = torch.optim.Adam(model.parameters(), lr=args.lr)
    for epoch in range(args.epochs):
        ...   # training loop

if __name__ == "__main__":
    main()

Step 1: Extract Hyperparameters

Create a config file with @L.params for the scalar hyperparameters:

# configs/train.py
import laco.language as L
import torch.nn as nn, torch.optim as optim

@L.params
class hps:
    lr: float = 1e-3
    hidden: int = 256
    epochs: int = 10

model = L.call(nn.Sequential)(
    L.call(nn.Linear)(in_features=784, out_features=hps.hidden),
    L.call(nn.ReLU)(),
    L.call(nn.Linear)(in_features=hps.hidden, out_features=10),
)
optimizer = L.partial(optim.Adam)(lr=hps.lr)

Step 2: Load and Instantiate

# train.py
import laco

cfg = laco.load("configs/train.py")
model = laco.instantiate(cfg.model)
optimizer_factory = laco.instantiate(cfg.optimizer)
optimizer = optimizer_factory(params=model.parameters())
epochs = cfg.hps.epochs

Override from CLI:

python train.py  # uses defaults
laco run configs/train.py hps.lr=5e-4 hps.hidden=512

Step 3: Add @L.task

# configs/train.py (updated)
import laco.language as L
import torch.nn as nn, torch.optim as optim

@L.params
class hps:
    lr: float = 1e-3
    hidden: int = 256
    epochs: int = 10

model = L.call(nn.Sequential)(
    L.call(nn.Linear)(in_features=784, out_features=hps.hidden),
    L.call(nn.ReLU)(),
    L.call(nn.Linear)(in_features=hps.hidden, out_features=10),
)
optimizer = L.partial(optim.Adam)(lr=hps.lr)

@L.task
def task(model, optimizer, hps):
    opt = optimizer(params=model.parameters())
    for epoch in range(hps.epochs):
        ...   # training loop
laco run configs/train.py hps.lr=5e-4

Step 4: Full Hydra App (Optional)

# train.py
import laco

def run(model, optimizer, hps): ...

if __name__ == "__main__":
    laco.main("train", config_path="configs")(run)()
python train.py hps.lr=5e-4
python train.py -m hps.lr=1e-3,1e-4   # sweep

Common Pitfalls

  • Hard-coded class strings: replace "torch.nn.ReLU" magic strings with real imports: L.call(nn.ReLU)().
  • Mutable defaults: use L.call(list)() instead of default=[] in @L.params.
  • Positional args: @L.task skips *args; use keyword-only params.