Configuration system#
Primus experiments are described in YAML. The loader resolves environment variables, extends: inheritance, and module/model/platform presets before training starts. This document focuses on the Python configuration pipeline (primus/core/config/ and primus/core/launcher/parser.py).
Related documentation
Topic |
Location |
|---|---|
CLI launcher and |
|
Backend parameter references |
Megatron parameters, TorchTitan parameters, MaxText parameters |
Overview: Three-layer YAML#
A typical experiment ties together:
Experiment YAML—your run: identity, workspace, and a
modulessection naming framework presets plus overrides.Module preset—training defaults for a backend (optimizer, schedule, parallelism hooks) under
primus/configs/modules/<framework>/.Model preset—architecture and tokenizer metadata under
primus/configs/models/<framework>/.
All of these are deep-merged (see primus/core/config/yaml_loader.py and primus/core/config/merge_utils.py). A platform preset (primus/configs/platforms/) maps distributed environment variable names and logging defaults; if omitted, the parser injects platform_azure.yaml (see PrimusParser.parse_platform in primus/core/launcher/parser.py).
Experiment config structure#
work_group: ${PRIMUS_TEAM:amd}
user_name: ${PRIMUS_USER:root}
exp_name: ${PRIMUS_EXP_NAME:my_experiment}
workspace: ${PRIMUS_WORKSPACE:./output}
modules:
pre_trainer:
framework: megatron # backend name (megatron, torchtitan, maxtext, megatron_bridge, …)
config: pre_trainer.yaml # module preset file under primus/configs/modules/<framework>/
model: llama3_8B.yaml # model preset file under primus/configs/models/<framework>/
overrides: # training overrides (deep-merged last)
train_iters: 50
micro_batch_size: 4
Required top-level keys are validated in PrimusParser.parse_meta_info: work_group, user_name, exp_name, workspace.
Module presets#
Location:
primus/configs/modules/<framework>/(for exampleprimus/configs/modules/megatron/pre_trainer.yaml).Purpose: Default training behavior (iterations, batching, optimizer, logging, parallelism-related flags for that backend).
Inheritance: Use
extends:to compose files in the same directory (or relative paths). Multiple entries merge in order; the current file wins on conflicts (_apply_extendsinyaml_loader.py).
Example chain (excerpt): pre_trainer.yaml extends trainer_base.yaml, which extends ../module_base.yaml and other shared fragments (primus/configs/modules/megatron/trainer_base.yaml).
Model presets#
Location:
primus/configs/models/<framework>/(for exampleprimus/configs/models/megatron/llama3_8B.yaml).Purpose: Architecture dimensions, tokenizer identifiers, and other model metadata.
Inheritance: Same
extends:mechanism as modules (for examplellama3_8B.yaml→llama3_base.yaml→ …).
Platform presets#
Location:
primus/configs/platforms/(for exampleprimus/configs/platforms/platform_azure.yaml).Purpose: Names of environment variables used for distributed launch (
NNODES,NODE_RANK,MASTER_ADDR, …) and defaults such asmaster_sink_levelandworkspace.Default: If the experiment omits
platform, the parser setsconfig: platform_azure.yaml(primus/core/launcher/parser.py).
Environment variable substitution#
primus/core/config/yaml_loader.py expands:
Pattern |
Behavior |
|---|---|
|
Required. Raises if |
|
Uses |
After substitution, purely numeric strings may be converted to int or float.
extends: inheritance#
For each YAML file:
Each path in
extends:is resolved relative to the directory of the current file.Presets are loaded recursively (each may have its own
extends:).Merge order: earlier presets in the list are merged first; later presets override earlier ones; the current file overrides all (
_apply_extends).
PresetLoader.load (primus/core/config/preset_loader.py) resolves primus/configs/<config_type>/<framework>/<name>.yaml and runs the same parse_yaml pipeline.
CLI overrides (training)#
After the main arguments are parsed, unknown tokens are interpreted as key=value overrides and deep-merged into the active training module namespace (module_cfg.params). The core runtime applies them in PrimusRuntime._apply_overrides (primus/core/runtime/train_runtime.py) using parse_cli_overrides (primus/core/utils/arg_utils.py) followed by deep_merge. Both key=value and --key value forms are accepted. Unknown keys are merged in (not rejected) and forwarded to the backend; the stricter key-existence check in parse_args / _check_keys_exist (primus/core/launcher/parser.py) belongs to a legacy path that the train subcommand does not exercise.
Example (conceptual):
./runner/primus-cli direct -- train pretrain --config exp.yaml \
--train_iters 100 --micro_batch_size 2
Merge priority (training config)#
The effective ordering of training parameters is:
CLI overrides (key=value after the main
trainarguments)—highest. Applied last by the runtime (PrimusRuntime._apply_overrides), after preset and experiment merging.modules.pre_trainer.overridesin the experiment YAML (applied inPrimusParser.parse_trainer_module).Module preset with model preset additions: the module preset is loaded first, then the model preset is merged in with
allow_override=False, so duplicate top-level module keys are preserved while non-duplicate model keys are added (merge_namespaceinparse_trainer_module).Preset chains via
extends:inside those files—base layers first, specialized layers later, file body last.
A concise mental model:
CLI overrides > experiment overrides > module preset with model preset additions > each preset’s own extends: chain > shared bases such as module_base.yaml.
Config resolution walkthrough: llama2_7B-BF16-pretrain.yaml#
Example experiment: examples/megatron/configs/MI300X/llama2_7B-BF16-pretrain.yaml.
Load experiment—
parse_yamlreads the file;${PRIMUS_*:…}placeholders resolve.Meta—
work_group,user_name,exp_name,workspaceare checked.Platform—If not present, default
platform_azure.yamlloads fromprimus/configs/platforms/.Module preset—
PresetLoader.load("pre_trainer.yaml", "megatron", "modules")loadsprimus/configs/modules/megatron/pre_trainer.yamland applies itsextends:chain (for exampletrainer_base.yaml→ …).Model preset—
PresetLoader.load("llama2_7B.yaml", "megatron", "models")loadsprimus/configs/models/megatron/llama2_7B.yaml(which extendsllama2_base.yaml→llama_base.yaml→ …).Merge—Module and model namespaces are merged for
pre_trainer.Experiment overrides—Keys under
modules.pre_trainer.overridesin the example file (for examplemock_data: true, parallelism, LR) are applied on top.CLI overrides—Any key=value pairs from the command line are merged last.
How to write a new config for a new model#
Add or reuse a model preset under
primus/configs/models/<framework>/, usingextends:from the closest existing architecture (for example copyllama3_8B.yamland adjust hidden size, layers, tokenizer).Point an experiment YAML at it—set
modules.pre_trainer.framework,config: <module_preset>.yaml, andmodel: <your_model>.yaml.Set overrides in the experiment file for run-specific values (batch sizes, paths,
mock_data, parallelism). Prefer small experiment files that reference presets instead of duplicating hundreds of keys.Validate with
--dry-runand by tracing the referenced experiment, module, and model presets (see below).Optional: add an example under
examples/<backend>/configs/<platform>/for others to copy.
Debugging config issues#
Technique |
What it does |
|---|---|
|
Parsed by the training config parser, but the default core |
|
Shows the launcher command without executing (shell layer). |
|
Enables verbose logging for launcher and Python ( |
Inspect presets |
Open the resolved |
If ${VAR} substitution fails, set the variable or switch to ${VAR:default} in the YAML.
Cross-references#
Default launcher YAML:
runner/.primus.yamlYAML loader (env + extends):
primus/core/config/yaml_loader.pyParser and merge:
primus/core/launcher/parser.pyPreset paths:
primus/core/config/preset_loader.py