Skip to content

MILES with an OLMo-core trainer

Use the operating guide for MILES GRPO runs and the support matrix for supported boundaries. The adapter replaces the MILES Megatron trainer actor, while retaining MILES rollout actors, samples, advantages, PPO loss helpers and transport primitives. Open Instruct supplies configuration, data/verifiers, lifecycle coordination and run artifacts.

Trainer hookup

miles/backends/core_utils/actor.py implements the trainer actor contract. The models.py facade selects moe_models.py for the specialized OLMoDDP MoE path or standard_models.py for dense Core TransformerTrainModule/FSDP. MILES calls the actor for initialization, scoring, training, save/restore and weight export. The Core objective hook accepts MILES' token log-probability loss and performs backward, distributed gradient synchronization and optimizer stepping through Core. It does not select the MILES FSDP trainer or construct a Megatron model.

driver.py coordinates collection, optimizer completion, publication, evaluation and checkpoint boundaries. A policy version advances only after a successful optimizer step. The async producer attaches behavior versions to samples; the trainer checks their age again when consuming the batch.

The runtime uses the exact OLMo-core commit recorded in runtime.lock.json, including the optional trainable FP32-output head and production MoE support. Image builds fetch the full commit in the runtime lock without applying a Core patch. The port retains custom objectives, routing replay/count controls, bounded checkpoint planning and streaming HF interchange, including the inherited per-head attention and hybrid configuration export support.

Local checks cover model/configuration roundtrips, checkpoint planning, adapter contracts and a single-GPU hybrid-MoE scoring/backward/optimizer step. Validate other topologies and feature combinations before relying on them. Use the runtime lock and build procedure to reproduce the current source.

Samples, scoring and objectives

Core microbatch size is one. Optional packing combines complete samples in a document-isolated forward without crossing optimizer partitions. Global batch size must divide collections into whole optimizer steps and be divisible by trainer world size. Every rank executes the same number of forwards/backwards. Masks, response boundaries and next-token logits remain attached to their original sample.

A standalone scoring pass supplies an unchanged trainer-policy anchor when needed. With one optimizer step per collection, no reference KL and no dropout, the training forward can supply that anchor. The first update of each process and periodic checks compare the two forwards before permitting the skip. See scoring controls for forcing the pass and its tolerance. Async TIS corrects the behavior-versus-trainer ratio; it does not make stale data on-policy. Allowed lag is in optimizer steps, including multiple steps in a collection. Async requires positive lag and resident disaggregated engines.

Core's router auxiliary/z losses are independent of PPO clipping, advantage normalization and TIS. Replay fixes selected expert IDs; router probabilities and weights still participate in differentiable computation. Packing retains Core pretraining's local-batch auxiliary loss over each packed forward's tokens. It is not a sum of independently balanced response losses.

Router replay and parallelism

Enable both use_rollout_routing_replay=true and use_miles_router=true. The captured IDs travel with each sample through DP distribution and packing. The adapter aligns replay by document/token/layer and retains it across backward recomputation. Each sample's final unscored token has an explicit synthetic tail; that convention is not a claim of Megatron auxiliary-loss equivalence. Expert-parallel ranks receive the routing information needed by their local forward; trainer PP/TP/CP greater than one are rejected, not implicitly supported. A replay match verifies supplied assignments; it does not measure what the trainer would have selected without replay.

Checkpoints and publication

SGLang starts from HF config/tokenizer/weights. Core imports those weights into its native training representation. Updated policies are streamed directly as serving tensors; no HF directory or Megatron conversion is written per update. MoE export supports fused expert tensors; final HF exports retain standard per-expert slices. Dense export gathers parameters through its FSDP backend. The normal disaggregated transport broadcasts flattened NCCL buckets; colocation uses IPC. Current full-model starters use mixed-policy refresh; low-level barrier and independent engine drain remain distinct modes. Publication contracts explain recorded behavior probabilities, final-forward replay routes and oldest-token lag checks.

Native checkpoints include model/optimizer/scheduler and rank RNG state. Schema-2 manifests record world size, EP degree and the committed rollout cursor. Restore validates these before native loading collectives. The data cursor includes pristine pending prompts; partially generated responses are regenerated after restart. Serving RNG and exact future generations are not restored. Schema-1 multi-rank checkpoints require explicit migration, and topology changes on restore are not supported.

A deliberate debug_exit_after_rollout stop preserves a resumable workflow. Final HF export is deferred until the configured collection horizon completes; the first process must not occupy the final export directory prematurely. See model/checkpoint operations.

Training contract checks

Every real training step records training_contract_rankN.jsonl beneath miles.save, when supplied, and emits the same records to logs. Records include:

  • Actual global sample, active-token and model-token counts; policy and auxiliary denominators; local accumulation count; response-versus-token reduction mode.
  • Local normalized policy objective and weighted auxiliary terms separately. Averaging these local objectives across ranks gives the corresponding global objective; they are not already global metrics.
  • Consumed/published policy versions, LR used/next, completed step and elapsed time.
  • Globally reduced probability-error histograms, exact maximum, upper-bin estimates of p50/p95/p99, response-position thirds and response-length buckets. A null quantile upper bound means the overflow bin (>1.0), not missing observations.

core.diagnostic_interval=N additionally measures local gradient norms before optimizer intake and sampled model updates every N optimizer steps. These are explicitly not global optimizer norms: expert gradients may still need Core's EP-MP rescaling, and FP8 stores outside named_parameters are outside coverage. Update samples retain at most 256 values per named parameter, rather than cloning the model. With check_weight_update_equal=true, the driver also checks serving weights at publication boundaries whose rollout count is divisible by N (and on initial publication). A fresh run compares its initial publication against SGLang's original HF snapshot. Periodic and resumed checks snapshot the current serving state, reset tensors, republish the same trainer version, and compare exactly when quantization tolerance is disabled, over the non-skipped tensors. This catches missing or inconsistent transfers; it is not an independent proof of the export mapping for changed weights. Logprob checks and the initial HF comparison are separate checks. The round trip adds a second full transfer, with repeated_version=true in the publication log; include both transfers when measuring diagnostic overhead. The async producer remains paused until the check completes. The interval defaults to zero, leaving these periodic probes disabled. The maintained examples inherit that default. The dev mechanics example enables check_weight_update_equal=true: the full weight audit runs at startup, including resume, and does not run after ordinary training updates. The node and three-node learning examples disable this optional audit. Reserve a positive interval for investigating publication correctness. This interval also controls the extra gradient-norm and sampled-parameter-update diagnostics; setting it to zero does not disable the separate policy-version, logprob, replay, or scoring-pass checks. Upstream MILES supplies the optional startup check; the periodic same-version round trip is implemented by the MILES Core driver.

Runtime failures include non-finite active inputs/rewards, empty effective batches, inconsistent rank schedules, stale policy versions, non-finite losses, scheduler/clock disagreement and skipped optimizer steps. All ranks agree on skip status before any policy clock advances. The mean score-drift guard is configurable; tail distributions are recorded but have no fixed failure cutoff. A skip aborts the run; this is not transactional rollback of ranks that already performed an optimizer update.

Development checks

The independent fixed-batch reference checks next-token slicing, masks, unequal lengths, PPO clipping, entropy, KL and loss reduction without reusing the loss helpers it is testing. Tiny native EP1/EP2 comparisons cover policy-only, auxiliary-only and combined gradients/Adam state, with recomputation on/off. These are native consistency checks, not full-model Megatron equality.

Run the current packaged regression suite inside the pinned application image:

bash scripts/miles/test_runtime.sh -q

The packaged suite does not run distributed experiments; use the structured examples for end-to-end checks.

Router auxiliary objectives

These optional controls change the MoE router's auxiliary losses. They are independent of the RL policy loss's token-versus-response normalization and of whether routing replay is enabled.

Field under [core] Default Alternative and meaning
router_aux_loss_grouping "pack" "sequence": compute balancing statistics separately for each original prompt-plus-response document.
router_aux_loss_reduction "token" "response": give each document equal weight instead of weighting by model-token count.
router_z_loss_reduction "token" "response": independently give each document equal weight for z-loss.
router_aux_count_source "executed" "router_selected": use the current forward's router top-k choices to count expert selections for balancing.
router_aux_loss_weight 0.01 Balancing coefficient; 0.0 disables its gradient contribution.
router_z_loss_weight 1e-5 Z-loss coefficient; 0.0 disables its gradient contribution.

Grouping, then averaging, then the coefficient

Grouping decides which tokens share an expert-usage histogram. "pack" shares one histogram across the physical forward; "sequence" makes a separate histogram for each original document even when several documents occupy one pack. Neither choice changes attention boundaries or physical packing.

Averaging decides how each document contributes to the update. With sequence grouping, suppose two documents have 2 and 6 model tokens and their balancing penalties are 1 and 3. Token averaging gives (2*1 + 6*3) / 8 = 2.5; response averaging gives (1 + 3) / 2 = 2. A balancing coefficient of 0.01 makes their contributions to the training objective 0.025 and 0.02, respectively. The same weights and coefficient scale their gradients.

With pack grouping and response averaging, documents share the pack's expert histogram, but each document's mean router probabilities has equal weight. Response averaging does not implicitly select sequence grouping. Z-loss has no expert histogram; its averaging is selected independently.

Here a document is the prompt plus its response, including the final forwarded token and its synthetic replay assignment. These are model tokens, not only policy-loss tokens. Padding is excluded. The token and document denominators span the optimizer update and data-parallel ranks, accounting for gradient averaging; this is not an average of microbatch means.

Executed versus router-selected counts

"executed" counts the actual selected experts. With replay active, those are the replayed assignments. "router_selected" instead derives a detached top-k histogram from this forward's router scores. It changes the balancing statistics only: replayed expert dispatch, selected expert weights, load metrics and z-loss keep their existing meanings. Gradients still flow through router probabilities; the discrete expert counts themselves are not differentiable.

Count-source selection works with both grouping choices and both averaging choices. It does not change rollout publication, discard behavior, or inference routing. Matching this setting alone does not establish equivalence with Megatron.

Configuration examples

The following explicitly spells out the defaults:

[core]
router_aux_loss_grouping = "pack"
router_aux_loss_reduction = "token"
router_z_loss_reduction = "token"
router_aux_count_source = "executed"
router_aux_loss_weight = 0.01
router_z_loss_weight = 1e-5

For equal document weighting and router-selected balancing counts, change the following fields in a copied run configuration:

[core]
compile_model = false
router_aux_loss_grouping = "sequence"
router_aux_loss_reduction = "response"
router_aux_count_source = "router_selected"
# Z-loss stays token-weighted unless router_z_loss_reduction is also changed.

Set either coefficient to 0.0 to disable that auxiliary loss; set both to zero to disable both. These are experimental objective choices; see development defaults for the example settings.

Supported scope and runtime

The all-default pack/token/token objective uses Core's native router methods; router-selected counts with that objective use Core's native count-source option. Other grouping/averaging combinations use document metadata preserved across backward recomputation. They require one unpadded instance per forward (which can contain multiple packed documents), trainer TP=CP=1, compile_model=false, and no global balancing or router orthogonal loss. Packed and unpacked execution are supported.

Router-selected counts additionally require plain softmax, local balancing, and no routing biases, expert groups, or uniform/random assignment overrides. EMO routing with router-selected balancing counts is not yet supported. Unsupported native routing combinations fail during model construction. Router objective controls require the Core MoE backend.

The Core commit pinned in runtime/miles/runtime.lock.json includes these controls; images built from an older lock do not. Selecting router-selected counts with an older Core dependency fails explicitly.

tests/miles/test_adapter_router_objective.py checks losses and gradients against an independent reference for every grouping/averaging/count-source combination, with and without activation recomputation. It also checks unchanged replay outputs and policy gradients. The pinned Core source includes native count-source regressions. tests/miles/router_objective_contract.py supplies GPU training and repacking checks; its --count-source option selects either count source. CPU checks do not cover distributed GPU execution of every combination.

FP32-output vocabulary head

Opt in with trainer.fp32_lm_head=true in a structured run, or core.fp32_lm_head=true in the low-level configuration. This sets Core's LMHeadConfig.fp32_output and SGLang's enable_fp32_lm_head together. An explicit conflicting serving false value is rejected. Default is false. Images built from an older runtime lock do not include this option.

CUDA BF16/FP16 projections retain FP32 output instead of rounding logits to the operand dtype. Weights remain in their original storage dtype. A custom backward uses ordinary low-precision gradient GEMMs, including rounding the incoming logit gradient to the operand dtype; this is not full-FP32 training. Autocast continues to select operand precision. Checkpoint parameter names are unchanged. The native Core option currently supports the default head and default loss, without tensor-parallel wrapping. Its low-precision CUDA path supports first-order gradients; higher-order derivatives and fused-linear cross entropy are excluded.

The option targets training-versus-serving probability mismatch; its effect on learning is not established. FP32 logits double that output tensor's storage; measure training memory and step cost for the chosen token/vocabulary sizes. See development defaults.