Training Stability & Auto-Tuning (v0.32.0)

Pre-flight tuning + in-training stability nets. All flags are opt-in. Not all of them do something at v0.75.2: warmup_auto and convergence_detection are accepted by the schema, but nothing in v0.75.2 reads warmup_auto or acts on convergence_detection, and the loss-spike hint and the VRAM advisory are read by the SFT trainer only. Each section below says which.

LR Range Finder

Run a fast.ai-style geometric LR sweep before the real training run. Soup writes a JSON report with the recommended LR, the loss curve, and the divergence point.

bash
soup train --config soup.yaml \
  --find-lr \
  --find-lr-start 1e-7 \
  --find-lr-end 1e-1 \
  --find-lr-steps 100 \
  --find-lr-output ./lr_finder.json

The report contains the geometric lrs[], raw + EMA-smoothed losses[], the recommended LR (steepest negative gradient before divergence), the LR with min loss, and the divergence point if any.

v0.33.0: --find-lr now runs an in-process LR-sweep training loop. NaN/Inf loss terminates the sweep early so diverged_at is honest.

Warmup (warmup_auto is accepted, not read)

yaml
training:
  warmup_ratio: 0.03   # 3% of total update steps (default)

warmup_ratio (0.0 to 0.5) sets warmup as a fraction of the total update steps: warmup_steps = int(total_steps * warmup_ratio), with no clamp. warmup_auto: true is accepted by the schema, but nothing in v0.75.2 reads it, so setting it changes nothing about a training run. A helper that clamps warmup to [10, 1000] steps exists as library code, but no training path and no command calls it, and soup autopilot does not write a warmup into the config it generates.

Auto mixed-precision

yaml
training:
  auto_mixed_precision: true

Picks bf16 on Ampere+, fp16 on Turing or known fp16-stable models (Qwen2 / Qwen2.5 / Phi-3 / Phi-3.5), no on pre-Pascal. Multi-version pairs match the longest substring deterministically.

Loss spike recovery hint

Builds on the loss watchdog. The watchdog itself stops the run when the loss stays above loss_watchdog_threshold (default 3.0) for loss_watchdog_patience (default 5) consecutive steps. loss_spike_recovery does not change that: it makes the watchdog also write a spike_recovery.json hint next to the run output, so that you (or a wrapper script) can relaunch with a lower learning rate.

yaml
training:
  loss_watchdog: true                   # required
  loss_spike_recovery: true
  loss_spike_recovery_max_attempts: 3
  loss_spike_recovery_lr_decay: 0.5

The hint records the loss at the spike, the previous learning rate, a recommended one (the previous rate times loss_spike_recovery_lr_decay), and an attempt counter against loss_spike_recovery_max_attempts. Soup does not decay the learning rate or resume the run by itself, and nothing in Soup reads spike_recovery.json back: relaunch with the recommended lr and --resume yourself. Because the run stops on the first firing, the attempt counter does not get past 1 within one run. Only the SFT trainer reads loss_spike_recovery. The watchdog itself runs on the SFT, pretrain, DPO, IPO, ORPO, SimPO, KTO, BCO, online DPO, GRPO, PPO, reward-model, embedding, classifier (which also serves reranker and cross_encoder), distill and ASR trainers, and so on task: preference, which hands off to the paired-loss trainers. task: prm, task: unlearn, task: moe_lora_routing, task: tts and the MLX backend accept loss_watchdog and never read it.

Convergence detector (accepted, not enforced)

yaml
training:
  convergence_detection: true
  convergence_window: 50
  convergence_rel_tol: 0.005

These keys are accepted by the schema, but nothing in v0.75.2 acts on them: the only reader is a startup check in soup train that prints a note when convergence_detection is set ("set but not enforced during training in this build"), and no advice is surfaced during a run. The plateau-detection logic that would produce continue / early_stop / lower_lr advice exists as library code that no training path calls.

VRAM pressure advisory

yaml
training:
  grad_accum_auto_tune: true
  grad_accum_pressure_threshold: 0.92

Records peak memory each step. When pressure crosses the threshold, recommends a new (batch, accum) pair preserving effective batch (capped at accum=1024). It is an advisory printed once per run on CUDA, not an automatic change (restart with the new pair to take effect), and only the SFT trainer reads grad_accum_auto_tune.

Soup is free and Apache-2.0. If it saved you a training run, starring the repo costs nothing and helps most. You can also fund the GPU time behind the work a 4 GB laptop cannot reach.