Training Guide
DantinoX uses a single Trainer class for all three paradigms (AR, Diffusion, Continuous Flow-Matching). This page explains every training option, what it does, and when to change it.
Quick start
=== “CLI”
```bash
# Autoregressive
dantinox train \
--config configs/default_config.yaml \
--data_path data/wiki.txt
# Diffusion
dantinox train \
--config configs/diffusion_base.yaml \
--data_path data/wiki.txt \
--use_bf16 true \
--n_devices 2
# Override any field inline
dantinox train \
--config configs/default_config.yaml \
--data_path data/wiki.txt \
--lr 1e-4 \
--batch_size 128 \
--optimizer muon
```
=== “Python”
```python
from dantinox import Trainer
from dantinox.core.config import Config
config = Config.from_yaml("configs/default_config.yaml")
run_dir = Trainer(config).fit("data/wiki.txt")
# run_dir is e.g. "runs/run_20260611_142301"
```
=== “One-liner”
```python
import dantinox as dx
run_dir = dx.fit(
"ar", # paradigm
"data/wiki.txt", # data
dim=512, n_heads=8, head_size=64,
num_blocks=12,
lr=3e-4, epochs=5,
)
```
Training configuration fields
Every field below can be set in a YAML config or overridden on the CLI with --field value.
Learning rate
Field |
Default |
Description |
|---|---|---|
|
|
Peak learning rate. The highest LR reached after warmup. Typical range: |
|
|
Schedule applied after warmup. See Schedules. |
|
|
Linear warmup from LR=0 to |
Batch size and gradient accumulation
Field |
Default |
Description |
|---|---|---|
|
|
Total number of sequences per optimiser update. This is the effective batch size: |
|
|
Number of gradient accumulation micro-steps. Allows simulating a large batch when GPU memory is limited. |
!!! note “Effective batch size”
Effective batch size = batch_size × n_devices.
`batch_size` is the total size summed across all accumulation steps. The micro-batch fed to each step is `batch_size / grad_accum`.
Example: `batch_size=256, grad_accum=4, n_devices=2` → micro-batch per step = 256/4 = 64, total effective batch = 256 × 2 = 512.
Optimisers
Set via optimizer: "...":
=== “AdamW (default)”
```yaml
optimizer: "adamw"
```
Adam with decoupled weight decay. The standard choice for most transformer training. Reliable across architectures and scales. Uses per-parameter adaptive learning rates and momentum.
**When to use:** default for everything. Start here.
=== “Lion”
```yaml
optimizer: "lion"
```
Sign-based gradient update. Uses less memory than AdamW (stores only momentum, not variance) and often trains faster. From the paper *"Symbolic Discovery of Optimization Algorithms"* (Chen et al., 2023).
**When to use:** when memory is tight, or when you want to experiment with faster convergence. May need a lower LR than AdamW (divide your AdamW LR by ~3–10).
=== “Muon”
```yaml
optimizer: "muon"
```
Momentum Orthogonalized by Newton-Schulz. Applies Newton-Schulz orthogonalization to 2D weight gradients, which makes the update geometry-aware. Falls back to Adam for biases and norms. From optax >= 0.2.6.
**When to use:** state-of-the-art for transformer pre-training. Often achieves lower loss than AdamW at equivalent compute. Recommended for research runs.
=== “Adafactor”
```yaml
optimizer: "adafactor"
```
Memory-efficient approximation of Adam. Factorises the second-moment matrix instead of storing it per-parameter, saving O(√(m×n)) vs O(m×n) memory per matrix.
**When to use:** when training very large models (billions of parameters) where AdamW's optimizer state would not fit in memory.
=== “Adam”
```yaml
optimizer: "adam"
```
Classic Adam without weight decay. Avoid for training from scratch (weight decay is important). Useful for final fine-tuning steps.
Schedules
Set via lr_schedule: "...". All schedules include a linear warmup from 0 to peak LR:
=== “cosine (default)”
```yaml
lr_schedule: "cosine"
```
After warmup, the LR follows a half-cosine decay from `lr` to `lr × 0.01`.
```
LR
▲
│ ╭───╮
│ ╭─╯ ╰─╮
│ ╭─╯ ╰───────────
└──────────────────────── step
warmup decay
```
Best default. Smooth decay avoids abrupt LR changes near the end of training.
=== “linear”
```yaml
lr_schedule: "linear"
```
After warmup, the LR decreases linearly from `lr` to `lr × 0.01`. Simpler than cosine.
=== “constant”
```yaml
lr_schedule: "constant"
```
After warmup, the LR stays at `lr` until training ends. Useful for fine-tuning on small datasets or as a baseline.
=== “wsd (warmup-stable-decay)”
```yaml
lr_schedule: "wsd"
```
Three phases: (1) linear warmup → (2) stable plateau at peak LR for 40% of budget → (3) cosine decay to `lr × 0.01`. Shown to work well for very long training runs (Hu et al., 2024).
```
LR
▲
│ ╭───────────╮
│ ╭─╯ ╰─╮
│ ╭─╯ ╰────
└──────────────────────── step
warmup stable decay
```
Gradient clipping
Field |
Default |
Description |
|---|---|---|
|
|
Maximum global gradient norm. Gradients are rescaled if their global L2 norm exceeds this value. Set to |
Gradient clipping prevents “exploding gradients” — rare but catastrophic events where a single bad batch causes the gradient to be huge, blowing up the weights. A value of 1.0 is safe for most cases.
Precision
Field |
Default |
Description |
|---|---|---|
|
|
If true, model parameters are cast to |
BFloat16 (bfloat16) has the same exponent range as float32 but fewer mantissa bits. Unlike float16, it rarely causes numerical overflow/underflow in transformer training.
Multi-GPU
Field |
Default |
Description |
|---|---|---|
|
|
Number of GPUs to use. |
DantinoX uses JAX SPMD data parallelism: the model is replicated on all devices, the batch is sharded (split) across devices, and gradients are reduced (averaged) automatically.
Regularisation
Field |
Default |
Description |
|---|---|---|
|
|
Dropout applied inside attention and FFN. |
|
|
Early stopping: stop training if validation loss has not improved for this many evaluation intervals (each 500 steps). |
Dataset
Field |
Default |
Description |
|---|---|---|
|
|
|
|
|
HF dataset identifier (e.g. |
|
|
HF dataset config (e.g. |
|
|
HF dataset split to use. |
|
|
Column name containing the text in a HF dataset. |
|
|
Cap the number of tokens used for training. Useful to run a fixed compute budget regardless of corpus size. Set to |
|
|
|
Checkpointing
Field |
Default |
Description |
|---|---|---|
|
|
Save a resumable checkpoint every N steps (in addition to the best-val checkpoint). |
|
|
Number of batches averaged for each validation loss estimate. |
|
|
Random seed for data sampling and model initialisation. Set for reproducibility. |
The training loop — what happens at every step
Sample a micro-batch of
batch_size / grad_accumsequences from the training corpusForward pass: feed the batch through the model, compute the loss
Backward pass: compute gradients with
nnx.value_and_gradAccumulate: add scaled gradients (
/ grad_accum) to the accumulatorRepeat steps 1–4
grad_accumtimesClip gradients (if
grad_clip > 0)Update parameters with the optimiser
Every 500 steps: evaluate on a validation subset, log to CSV, save best checkpoint
Run directory structure
Every training run saves its artifacts to an isolated directory:
runs/
└── run_20260611_142301/
├── config.yaml ← complete config snapshot (use to reproduce!)
├── tokenizer.json ← tokenizer vocabulary
├── best_model_weights.msgpack ← checkpoint with lowest validation loss
├── model_weights.msgpack ← latest resume checkpoint (deleted on completion)
├── training_cursor.json ← resume pointer (step number, deleted on completion)
├── model_summary.json ← parameter count and memory breakdown
└── training_log.csv ← step, train_loss, val_loss, ms/step
The model_weights.msgpack and training_cursor.json files exist only during training. When training completes normally, the cursor is deleted. This lets you distinguish a completed run from an interrupted one.
model_summary.json — memory breakdown
{
"total_params_M": 48.23,
"dtype": "bfloat16",
"weights_mem_MB": 96.47,
"optimizer_mem_MB": 96.47,
"est_activations_MB": 3276.8
}
Field |
Meaning |
|---|---|
|
Total trainable parameters in millions |
|
Floating-point type of stored weights |
|
Approximate VRAM for model weights |
|
VRAM for optimiser state (AdamW stores m+v → 2× weights) |
|
Estimated VRAM for activations during the backward pass |
Dataset tokenisation cache
The first training run for a given dataset tokenises the corpus and saves:
data/<dataset>_<config>_<tokenizer_type>.npy ← token ID array (int32)
data/<dataset>_<config>_<tokenizer_type>.json ← shared tokenizer vocab
All subsequent runs with the same (dataset_name, dataset_config, tokenizer_type) load directly from these files — no re-download, no re-tokenisation. This reduces per-run startup from ~60s to ~2s.
Find-LR — auto-detect the optimal learning rate {#find-lr}
Before committing to a full training run, use the LR range test to find a good starting LR:
dantinox find-lr \
--config configs/default_config.yaml \
--data_path data/wiki.txt \
--min_lr 1e-7 \
--max_lr 1.0 \
--num_steps 100 \
--plot # save lr_finder.png
How it works (Smith 2015):
Start with LR =
min_lrTrain for one step, measure loss
Multiply LR by a constant factor (exponential sweep)
Repeat for
num_stepsstepsPlot smoothed loss vs LR
Find the LR at the steepest downward slope — this is the suggested LR
If the loss diverges (> 4× best loss), stop early
Rule of thumb: use a LR that is 3–10× smaller than the LR where loss starts exploding.
Resuming training
If a run is interrupted, resume it from the last saved checkpoint:
dantinox train \
--config configs/default_config.yaml \
--data_path data/wiki.txt \
--run_dir runs/run_20260611_142301 \
--resume
The trainer will:
Read
training_cursor.jsonto find the last completed stepLoad
model_weights.msgpackinto the modelContinue training from
start_step + 1
!!! warning “Optimizer state is not restored” When resuming, the optimiser state (momentum, variance) is re-initialised from zero. This causes a brief spike in loss for the first few hundred steps until the optimiser re-warms.
W&B logging
Pass --wandb_project MyProject to log to Weights & Biases:
dantinox train \
--config configs/default_config.yaml \
--data_path data/wiki.txt \
--wandb_project DantinoX_experiments
Logged metrics: train_loss, val_loss, step.
Pages in this section
Page |
What it covers |
|---|---|
AR-specific details: causal mask, teacher-forcing, cross-entropy loss |
|
Masked diffusion: ELBO loss, noise schedules, continuous t, 1/t weighting |
|
Frozen T5 embedder, denoiser/decoder branch losses, CFG training, self-conditioning |
|
Deep dive into AdamW, Lion, Muon, Adafactor, WSD |
|
Bayesian W&B sweeps, sweep YAML format |
|
SPMD data parallelism, mesh sharding, batch divisibility |
|
Reproducing the benchmark results |