Skip to content

Training

dmri train composes conf/train.yaml, generates training and validation data from the configured simulator, builds the model, and runs the JAX training loop. Use Hydra overrides to change a run; the saved Hydra config records the resolved settings but is not a guarantee of exact reproducibility.

Choose how the run executes

One local process

dmri train infrastructure/launcher=local infrastructure/partition=none \
  run.name=local_test tracking.enabled=false training.max_train_hours=1

Without --multirun or hydra.mode=MULTIRUN, training runs directly in the calling process. The launcher config is not invoked. This is the simplest mode for development and for one-machine training.

Experiment files commonly put architecture values under hydra.sweeper.params. Those values are sweep parameters and are ignored in a single run. Either provide the same values as direct overrides or run the experiment as a multirun.

Local Hydra multirun

dmri train --multirun +experiment/train=b3s_2_4_6_128 \
  infrastructure/launcher=local infrastructure/partition=none

Hydra expands the preset's sweep parameters and Submitit starts each job locally. Comma-separated values add sweep dimensions. Each job receives a numbered output subdirectory.

SLURM

dmri train --multirun +experiment/train=b3s_2_4_6_128 \
  infrastructure/launcher=slurm infrastructure/partition=h100_long

The SLURM launcher maps hydra.launcher values to a submitted job. Supplied partition presets set queue, time, CPU, memory, and GPU fields and normally set hydra.mode=MULTIRUN; inspect and select a preset that exists at your site. hydra.launcher.timeout_min is the scheduler limit, while training.max_train_hours is enforced inside training. They are independent.

Compose a training config

The base config selects these groups:

conf/
|-- train.yaml
|-- experiment/train/
|-- simulator/
|   `-- acquisition/
|-- model/
|   |-- embedding_net/
|   |-- model_selection_net/
|   `-- inference_net/
|-- training/
|   |-- dataloader/
|   `-- optimizer/
`-- infrastructure/
    |-- launcher/
    `-- partition/

experiment/train presets select groups and define sweep parameters. The other groups can also be selected directly:

dmri train simulator=ball3stick_shared simulator/acquisition=multi \
  model=dmri training/dataloader=datastream \
  training/optimizer=adamw infrastructure/launcher=local \
  infrastructure/partition=none

Common scalar overrides are:

dmri train run.seed=7 run.name=my_run \
  tracking.enabled=false \
  training.dataloader.train_loader.batch_size=1024 \
  training.optimizer.learning_rate=3e-4 \
  training.max_train_hours=12

The current simulator schema separates the structural signal model from data generation:

simulator:
  model_class: my_package.models.MyModel
  posterior_score: false
  mask_prior: {}
  acquisitions:
    - _target_: my_package.acquisition.random_acquisition
      _partial_: true
      num_acquisitions: 128

model_class must resolve to a MultiCompartment subclass. Every acquisition entry must instantiate to a callable, which is why function targets use _partial_: true. A supplied simulator/acquisition group writes the same simulator.acquisitions list.

Steps, validation, and stopping

One optimizer update increments the training step by one. The loop performs training.inner_steps updates before logging, checking elapsed time, validating, or saving by cadence. training.checkpoint_freq, training.eval_freq, and the optional training.restart_every are rounded down to a multiple of inner_steps; a positive value smaller than inner_steps becomes one full block. Add the last setting with +training.restart_every=<steps> because it is absent from the base config.

training.max_train_hours is the only configured completion limit. Elapsed time is checked after a block, and the loop writes a regular checkpoint before stopping on that limit. There is no supported maximum-step setting. The loop can also stop when a non-finite loss cannot be recovered from a regular checkpoint. Signals and scheduler termination do not cause a final save.

Periodic validation computes mask and parameter negative log likelihood and, when configured, KSD. With EMA enabled, validation uses EMA parameters. The sum of the two negative log likelihood values selects the best checkpoint; KSD does not select it.

Outputs

A single job writes to:

results/<run.name>/<timestamp>/
|-- .hydra/
|   |-- config.yaml
|   |-- hydra.yaml
|   `-- overrides.yaml
|-- artifact.yaml
|-- checkpoints/
|   |-- <step>/
|   `-- best/
|       `-- <step>/
`-- train_script.log

A multirun writes jobs below results/<run.name>/<timestamp>/<hydra.job.num>/. artifact.yaml contains only the model config and the simulator model class needed to rebuild the model. The full .hydra/config.yaml also contains acquisitions, training, and tracking settings.

Regular checkpoints are numeric directories immediately under checkpoints/. Orbax retains three by default; set +training.checkpoint.max_checkpoints=<count> to change this. The latest checkpoint is the highest retained regular step. When best-checkpoint tracking is enabled, checkpoints/best/ retains one validation-selected step.

Every regular or best checkpoint contains raw parameters, optimizer state, model state, step, loss, and RNG state. When training.track_ema=true, it also contains params_ema and EMA state. EMA does not replace raw parameters.

Resume training

Resume searches only the current job's checkpoints/ directory and restores the latest regular checkpoint, not checkpoints/best/. A new command normally creates a new timestamped directory, so training.continue_training=true alone does not locate an earlier run. Point Hydra at the existing job directory:

dmri train infrastructure/launcher=local infrastructure/partition=none \
  hydra.run.dir=/absolute/path/to/existing/run \
  training.continue_training=true

For a resumed multirun, preserve the original mapping of jobs to directories by setting hydra.sweep.dir and hydra.sweep.subdir to the existing layout.

Normal resume restores parameters, model state, optimizer state, EMA state, RNG, and step when present. training.restart_optimizer=true rebuilds optimizer state after loading. training.partial_restore=true requests an Orbax partial parameter restore and also rebuilds optimizer and EMA state. Simulation buffers, loader position, and background producer state are not checkpointed, so a resumed run should not be described as an exact continuation of sample order.

Load a checkpoint in Python

from flax import nnx
from dmri.train.utils import load_checkpoint

checkpoint, model, simulator_model = load_checkpoint(
    "/absolute/path/to/results/my_run/2026-08-02_12-00-00",
    which="best",
)
params = checkpoint.get("params_ema", checkpoint["params"])
nnx.update(model, params)
model.eval()

which accepts "latest", "best", or an integer regular step. Loading returns the checkpoint payload and a rebuilt model; it does not apply the returned parameters to that model. Choose params_ema explicitly when wanted, with params as the fallback.

Hand off to evaluation

For a run at /work/results/my_run/2026-08-02_12-00-00, evaluation expects the parent as checkpoint.path and the run directory name as checkpoint.model_name:

dmri eval \
  checkpoint.path=/work/results/my_run \
  checkpoint.model_name=2026-08-02_12-00-00 \
  checkpoint.which=best \
  evaluation.input.path=/work/data/subject

For a multirun, use the numbered job directory in the same way: its parent is checkpoint.path and its job number is checkpoint.model_name. Evaluation uses checkpoint.params_name=params_ema by default and falls back to params if the selected checkpoint has no EMA parameters. See the evaluation guide for input, sampling, metrics, and export settings.

Bundle or publish a checkpoint

from dmri.train.utils import bundle_checkpoint, upload_checkpoint_to_hub

bundle_checkpoint(run_dir, "bundles", model_name="my_model")
upload_checkpoint_to_hub(
    run_dir,
    "owner/models",
    model_name="my_model",
    private=True,
)

Both functions include best and latest by default. which also accepts "best", "latest", "all", or an integer regular step. A bundle stores the model under <output_dir>/<model_name>/ with config.yaml, artifact.yaml, and the selected checkpoint tree.