Configuration
Soup uses a single YAML config file for all settings. Run soup init to generate one.
Reproducibility and full fine-tuning (v0.73.0)
Two training keys landed in v0.73.0. Both are config keys, not CLI flags.
training:
seed: 1234 # weight init of new params, data order, dropout
data_seed: 7 # optional: vary data order while holding init fixed
quantization: none # required with r: 0, because the default (4bit) is refused
lora:
r: 0 # 0 means no adapter: full fine-tuning, dense checkpointseed and data_seed are the first seed knobs in the project's history: before this every run trained at seed 42 with no way to change it, so "run this twice with a different seed" was impossible. Both default to unset rather than to 42, deliberately, because an unset seed has to keep reproducing two different historical defaults (the trainer's 42 and the multipack sampler's 0) and a plain 42 would have silently re-ordered every existing multipack run. A boolean is refused by name, since seed: true would otherwise become seed 1.
The honest scope, and it widened in v0.73.1: the seed reaches the trainer arguments in every wrapper now, applied before the model loads, so setting it on a DPO run is real. It reached one wrapper of eighteen when it shipped in v0.73.0, which is what the original note here described. On a streamed run it additionally seeds the adapter initialisation for all five streaming tasks, which is why a streamed run is bit-reproducible from a seed while a resident 4-bit one still is not.
lora.r: 0 selects full fine-tuning on task: sft and, since v0.75.0, task: embedding: no adapter is built, and the run writes a dense checkpoint rather than a LoRA. On any other task the gate does not apply at all, and that is worth knowing before you rely on it: classifier, reranker, cross_encoder and asr gate LoRA behind their own flag and ignore the rank entirely, while the remaining tasks hand the 0 straight to PEFT, which rejects it with its own message about a positive integer rather than Soup's named one. Rank 0 was chosen because three parts of the codebase already read it as "no adapter" and because r: 0 used to crash, so no config that worked before changes meaning. It is refused with a named message alongside a non-transformers backend, a non-text modality, any quantisation (the default counts: quantization is 4bit unless you set it, which is why the block above sets none), Spectrum, LISA, layer streaming, or any LoRA-shaped option, and it refuses rather than running a no-op if your freeze settings leave nothing trainable.
Config Structure
base: meta-llama/Llama-3.1-8B-Instruct # HuggingFace model ID (required)
task: sft # Training task
# backend: unsloth # 2-5x faster (pip install "soup-cli[fast]")
# modality: text # text, vision, or audio
data:
train: ./data/train.jsonl # Path to training data
format: alpaca # Data format (auto-detected if omitted)
val_split: 0.1 # Validation split ratio (evaluated each epoch since v0.76.0, except on grpo, ppo and online_dpo)
max_length: 2048 # Max sequence length (64-1048576)
# image_dir: ./data/images # For vision modality
# audio_dir: ./data/audio # For audio modality
training:
epochs: 3
lr: 2e-5
batch_size: auto # auto or integer
quantization: 4bit # the default; also none, 8bit, gptq, awq, hqq:Nbit, ...
# weight_decay: 0.01 # default 0.01
# max_grad_norm: 1.0 # gradient clipping, default 1.0
# logging_steps: 10 # log metrics every N steps
# save_steps: 100 # checkpoint every N steps
# warmup_ratio: 0.03 # 0.0-0.5, default 0.03
# scheduler: cosine # LR scheduler
# quantization_aware: fp8 # fp8 or quest; true (int8 QAT) is refused since v0.76.0
# optimizer: adamw_8bit
# gradient_checkpointing: true
# stream_layers: false # Train or align a model bigger than VRAM (v0.72, BETA)
# stream_source: auto # auto | ram | disk
# stream_buffers: 2 # 2-8
# stream_pin: false # v0.74.0: force the pageable store
# stream_read_ahead: 2 # v0.76.0, disk tier only: 1-8
lora:
r: 64
alpha: 16
dropout: 0.05
# target_modules: auto # Auto-detected per model
# use_dora: false # Weight-decomposed LoRA
output: ./outputDefaults worth knowing
These are the values a key takes when you leave it out. The quantization default is the one that surprises people: quantization is 4bit unless you set it, so a config that does not mention it trains a QLoRA. The exception is eight tasks whose trainer never quantizes the base: on those an unset value resolves to none (see Keys a task ignores).
| Key | Default | Bound or note |
|---|---|---|
epochs | 3 | at least 1 |
lr | 2e-5 | |
batch_size | auto | auto or an integer |
gradient_accumulation_steps | 4 | at least 1 |
quantization | 4bit | lora.r: 0 (full fine-tuning) refuses it, so set none. Unset resolves to none on distill, classifier, reranker, cross_encoder, prm, moe_lora_routing, unlearn and asr |
optimizer | adamw_torch | |
scheduler | cosine | a free string: the config does not check the name, it is passed to the trainer |
weight_decay | 0.01 | 0 or more |
max_grad_norm | 1.0 | greater than 0 |
warmup_ratio | 0.03 | 0.0 to 0.5 |
logging_steps | 10 | |
save_steps | 100 |
What batch_size: auto does
auto starts from a static estimate built from the model size, sequence length, quantization and LoRA rank. On a CUDA card the SFT trainer alone then refines it with a real probe, one forward and backward at each candidate size, starting at the estimate, halving when it runs out of memory and doubling while it fits, never above four times the estimate (training.auto_batch_size_strategy chooses auto, the default, probe or static; see OOM-probe auto batch size). The answer is cached per base model, sequence length, quantization, LoRA rank and GPU. Every other task, every CPU run and static use the static estimate unchanged. task: kto floors the estimate at 2, because a KTO config with batch_size: 1 is refused (below).
It errs high when the whole model trains. The estimate charges trainable-parameter memory as a small share of the model, at most 5% and derived from the LoRA rank, and charges none for lora.r: 0. The probe never takes an optimizer step, so it does not see the optimizer state either, which for AdamW is two extra values for every trainable parameter. With lora.r: 0 or with unfrozen_parameters (Spectrum), set batch_size explicitly, or start low and raise it. LISA (lisa_enabled) is a separate case: the probe also runs while every layer is still trainable, so its gradient figure is not LISA's either, and which way it errs was not measured. Set batch_size explicitly there as well.
Layer streaming keys
These turn on layer streaming, which trains a model larger than your VRAM by keeping the frozen base out of the card entirely. They are config keys, not CLI flags: there is deliberately no --stream-layers.
| Key | Values | Default | Notes |
|---|---|---|---|
stream_layers | true / false | false | BETA. Only enable it if the model does not fit resident; streaming trades time for memory |
stream_source | auto / ram / disk | auto | auto takes RAM when the base fits and falls back to an NVMe tier; ram refuses instead of falling back; disk forces NVMe |
stream_buffers | 2 to 8 | 2 | VRAM buffers in the pool. 2 is double-buffering; 1 cannot overlap load with compute, so it is refused |
stream_read_ahead | 1 to 8 | 2 | v0.76.0. Disk tier only: how many layers the background reader stages. One slot is always the layer in use, so N stages N-1 ahead. Each level costs one more layer of host staging memory. A non-default value beside stream_source: ram is refused, because the RAM tier reads nothing ahead. See The disk tier |
stream_vram_probe | true / false | false | v0.73.1. Decide the fit by measuring one real forward and backward at your shape, instead of predicting it. task: sft only. Costs 1 to 5 seconds, and cannot overrule a prediction more than 4x over budget |
stream_disk_kind | nvme / ssd / hdd | (unset) | v0.73.3. Override the detected media type behind the disk tier. nvme forces the tier on, ssd and hdd force it off. The override prints beside what was actually detected, and deliberately carries no measured rate, so a later refusal can never cite a reading you overrode |
stream_vram_override | bytes | (unset) | v0.73.1. Replaces the free-VRAM figure the pre-flight checks against, in either direction. It changes the yardstick, not the check: an override below real free VRAM still refuses a config that would otherwise fit |
stream_pin | true / false | (unset) | v0.74.0. Force the RAM store pageable or page-locked instead of letting Soup decide. false prints the throughput it costs rather than absorbing it silently; true refuses on a CUDA box that cannot page-lock, naming the size rather than a ceiling nobody probed: the RAM store on the RAM tier and, since v0.76.0, the background reader's host staging on the disk tier (it was announced-and-proceeds there before). With no CUDA device there is nothing to page-lock, and it is announced and the run proceeds on a pageable CPU source |
stream_ngram_source | auto / ram / disk | auto | v0.74.0. Where Qwen4-Exp's external N-gram table is read from. Read-only, and only meaningful for that family |
Setting any of these while stream_layers is false is refused, because the knobs would silently do nothing. Streaming also reads one environment variable for the disk tier, SOUP_LAYER_STREAM_STRIPE_DIRS (see Environment variables).
A key the schema does not declare is no longer silently dropped (v0.74.0). Until then none of the config models overrode the library default of ignoring undeclared keys, so a typo validated clean and was discarded:
training.quantizaton: nonetrained 4-bit,training.gradient_checkpoint: truedid no checkpointing,data.max_len: 512truncated at 2048, andsoup train --dry-runprinted "Config valid. Ready to train!" Loading a config now walks the whole model tree and reports every key it cannot place in one report, naming the field you probably meant. Since v0.75.0 the load is refused.soup trainexits 1 before the training stack is imported, and the API and Web UI loader raisesValueErrorwith the same text. Nothing is defaulted and nothing is substituted; the message saysRefused.rather thanNot applied., which would have read as if the run went ahead without the key, and the scan stops at 100 findings and says so. Two things are worth knowing. A config that must stay loadable on v0.74 as well needs the key removed, not renamed, because v0.74 warns and ignores it while v0.75 refuses it, and neither applies it. Andsoup planandsoup applyread the YAML as a plain mapping, so they do not run this check at all.soup sweepis stricter, because a swept parameter that matches nothing produces a grid of identical arms and a meaningless winner: it exits 1 before the first arm.
That refusal covers keys the schema does not know. A key the schema declares and no code reads is a different case, and v0.76.0 split it three ways.
- Refused at load (new in v0.76.0). Dozens of combinations that loaded on v0.75 are now refused with a message that names the field and what to change. On v0.75 some of them were ignored and some failed later. Examples:
use_ligeroruse_flash_attnon a task that is notsftortts,rope_scaling_typeon a task that does not rescale RoPE,freeze_layersondpo,quantization_aware: true,optimizer: muonon the transformers backend, and so on. They are listed in Settings refused at load. A config that loaded on v0.75.2 can stop loading, so runsoup doctor --config soup.yamlfirst: it exits 2 with the error andConfig could not be loaded (see above).. Unknown keys are reported together, but a cross-field refusal prints only the first one it reaches, so fix that setting and run it again until it prints no error. - Warned at load, refused from v0.77 (upstream's stated deadline). Twenty-nine fields are accepted by the schema but read by nothing. Set to anything other than the schema default, each prints
Warning: <section>.<name> is accepted but read by nothing; v0.77 will refuse it, and the load continues with exit 0. The 18 undertrainingarelong_context_grpo,vision_grpo,quantize_ref_model,grace_codebook,grace_codebook_size,grace_codebook_dim,lr_groups,early_stop_patience,citation_recall_threshold,forgetting_eval_steps,forgetting_benchmark,forgetting_stop,checkpoint_eval_steps,checkpoint_eval_metric,checkpoint_eval_tasks,checkpoint_keep_top,convergence_windowandconvergence_rel_tol; the 11 underdataarevideo_dir,video_fps,video_maxlen,image_min_pixels,image_max_pixels,image_resize_algorithm,split_thinking,eval_on_each_dataset,resize_vocab,extend_conversationandskip_prepare_dataset. Delete the key to keep the config loading after that. Three deprecated values also warn and are ignored:data.remove_unused_columns: true, an explicitquantization: 4bitor8biton one of the eight tasks below, andsoup ab --beta. - Still accepted in silence. A few keys are inert and carry no load warning and no announced deadline: the four parent switches
forgetting_detection,checkpoint_intelligence,early_stop_on_regressionandconvergence_detection, plusforgetting_threshold(soup trainprints a yellowNote:that they are set but not enforced) andwarmup_auto. The pages that document such a key say so, as "accepted by the schema, but nothing in v0.76.0 reads it". An unread key still takes part in the config hash thatsoup ship --configcompares, so editing one makes earlier--evidenceread as stale.
soup doctor --config also prints a small backend-support table: 18 settings known to be unread on task: sft with backend: mlx (that table), 3 on backend: unsloth (quantization_aware, fp8_attention, nvfp4, all rejected), and 2 each for vision and audio SFT on the transformers backend (a few of the MLX entries are refused at load before the table is reached: see the MLX page). For every other task and backend it has no entry, so it prints None of the N setting(s) known to be unread on task=<t> backend=<b> is switched on in this config. whether or not the config has a problem. Read that line as "not reviewed", never as an all-clear.
stream_vram_probe and stream_vram_override are not interchangeable, and the difference is the point. stream_vram_probe is a measurement: it runs the step and reads the peak. stream_vram_override is an assertion you are making about how much VRAM is really available, which is what you need when the pre-flight cannot see the truth, as under a per-process memory cap in a hosted notebook.
Streaming also constrains keys you already set: quantization must be none or 4bit, batch_size must be a concrete number rather than auto, and task must be one of sft, dpo, orpo, simpo and kto. Streaming also refuses use_liger, use_flash_attn, quantization_aware, fp8_attention, nvfp4, rope_scaling_type, freeze_layers, freeze_ratio, relora_steps and a LoRA target on lm_head or embed_tokens; the full table is on Layer streaming. (kto needs batch_size of 2 or more; since v0.76.0 that holds for every KTO run, not only streamed ones.) Scaling a streaming run covers sizing, the VRAM pre-flight and the disk tier; Preference losses over streaming covers the four alignment tasks.
Keys a task ignores
Eight tasks load the base unquantized because their trainers never quantize it: distill, classifier, reranker, cross_encoder, prm, moe_lora_routing, unlearn and asr. On them:
- An unset
training.quantizationresolves tonone(it is4biteverywhere else). - An explicit
4bitor8bit(orload_in_8bit: true) loads withWarning: training.quantization: 4bit has no effect on task='distill' and is ignored: its trainer never quantises the base, so the run trains unquantised. Set quantization: none. Soup v0.77 will refuse it.and is treated asnone. - Any Quant Menu value such as
gptq, andbnb_4bit_quant_storage, is refused at load. task: prmalso refuses a non-defaulttraining.lorablock, because it fine-tunes every base parameter (lora.r: 0loads).
expand_layers is refused unless the resolved quantization is none.
How target_modules: auto is resolved
lora.target_modules: auto (the default) resolves in this order:
- Architectures that PEFT maps itself (
llama,mistral,qwen2and so on) use PEFT's own default. - Architectures in Soup's table: the Qwen3.5 family and a set of Mixture-of-Experts models (
qwen3_moe,deepseek_v3,deepseek_v4,glm4_moe,glm_moe_dsa,granitemoehybrid,kimi_k2,kimi_k25,gpt_oss,minimax_m2,minimax_m3_vl,mistral3). These target the attention projections; MiniMax-M3 andmistral3use language-tower patterns, so the vision tower and projector stay unadapted. - Anything else is refused with
training.lora.target_modules='auto' has no mapping for model_type=..., which asks for an explicittraining.lora.target_moduleslist or, for a Mixture-of-Experts model,training.moe_lora: true.training.lora.target_parametersalone also suffices.
On granitemoehybrid only a few layers carry attention (4 of 40 on granite-4.0-h-tiny-base), so training prints a yellow Partial LoRA coverage: line. The notice ends by telling you to set training.lora.target_modules explicitly to include the other layers; Soup has not measured whether adapting a state-space projection trains well.
Templates
Soup includes 21 built-in templates:
soup init --template chat # Conversational fine-tune
soup init --template code # Code generation
soup init --template medical # Domain expert
soup init --template reasoning # GRPO reasoning (DeepSeek-R1 style)
soup init --template vision # Vision/multimodal fine-tune
soup init --template audio # Audio/speech fine-tune
soup init --template kto # KTO unpaired preference
soup init --template orpo # ORPO (no reference model)
soup init --template simpo # SimPO length-normalized preference
soup init --template ipo # IPO regularized preference
soup init --template bco # BCO binary classifier preference (v0.40)
soup init --template rlhf # Full RLHF pipeline (SFT -> RM -> PPO)
soup init --template pretrain # Continued pre-training on raw text
soup init --template moe # MoE fine-tuning (ScatterMoE LoRA)
soup init --template longcontext # 128k+ context fine-tuning
soup init --template embedding # Sentence embedding fine-tuning
soup init --template tool-calling # Function / tool-calling fine-tune (v0.25)Four more are regulation-shaped (compliance pack, v0.71.35). Each is a valid training config on a license-clean Apache-2.0 base plus header comments naming that regime's exact commands, because Soup's compliance controls are CLI flags and commands rather than config keys:
soup init --template hipaa # Protected Health Information
soup init --template soc2 # SOC 2 Trust Services Criteria
soup init --template eu-ai-act # EU AI Act Annex XI/XII
soup init --template sr-11-7 # SR 11-7 Model Risk ManagementTask-Specific Config Keys
| Key | Tasks | Description |
|---|---|---|
dpo_beta | DPO | DPO beta parameter |
kto_beta | KTO | KTO beta parameter |
orpo_beta | ORPO | ORPO beta parameter |
simpo_gamma | SimPO | SimPO gamma parameter |
cpo_alpha | SimPO | CPO alpha parameter |
ipo_tau | IPO | IPO tau parameter |
grpo_beta | GRPO and its variants | KL coefficient, default 0.1. Since v0.76.0 gspo, dapo, dr_grpo, bnpo, two_sided and rft apply it too. 0 turns the KL penalty off (KL-free recipes) and is refused together with reward_hack_mitigation kl_control or pid_lagrangian |
num_generations | GRPO | Number of generations per prompt |
reward_fn | GRPO, PPO | Reward function (accuracy/format/path.py) |
reward_model | PPO | Path to reward model |
ppo_epochs | PPO | PPO training epochs |
ppo_clip_ratio | PPO | PPO clip ratio |
ppo_kl_penalty | PPO | PPO KL penalty |
loraplus_lr_ratio | Every LoRA task | LoRA+ learning rate ratio. Applied since v0.76.0 on sft, pretrain, embedding, dpo, kto, orpo, simpo, ipo, bco, grpo, ppo, online_dpo, reward_model, distill, and on classifier, reranker, cross_encoder and asr with their LoRA flag; through v0.75.2 only the first three read it. Refused on prm, moe_lora_routing, unlearn, backend: mlx, lora.use_vera, use_lorafa, use_galore and optimizer apollo_adamw, lomo, adalomo |
use_galore | SFT, Pretrain | Enable GaLore optimizer |
moe_lora | Every LoRA task but a few | Target MoE expert layers. Read by sft, tts, pretrain, dpo, kto, orpo, simpo, ipo, bco, grpo, ppo, online_dpo, reward_model, embedding, distill, unlearn and, with classifier_lora: true, the classifier family. Refused on asr, prm, moe_lora_routing, SFT with vision or audio, and backend: unsloth. See Backends |
moe_aux_loss_coeff | SFT (text), TTS, Pretrain | Router load-balancing loss. A non-default value is refused on every other task, and on SFT with vision or audio |
use_liger | SFT, TTS | Liger Kernel fused ops. Refused at load on any other task |
use_flash_attn | SFT, TTS | FlashAttention v2/v3. Refused at load on any other task |
use_ring_attention | none | Ring FlashAttention. Accepted, and checked before training (CUDA, two or more GPUs, ring-flash-attn installed, max_length of 8192 or more), but nothing in v0.76.0 applies it to the model |
rope_scaling_type | SFT, TTS, Pretrain | RoPE scaling (linear, dynamic, yarn, llama3; longrope is refused). Applied before the model is built, on backend: transformers only (on SFT, the text path without stream_layers); refused at load on every other task, backend or path. See Long context |
neftune_alpha | SFT, DPO, KTO, ORPO, SimPO, IPO, BCO | NEFTune noisy embeddings (0-50) |
packing | SFT, Pretrain | Sample packing for efficiency |
curriculum | SFT | Sort the training rows from short to long before training. The Trainer's default sampler is random, so the model does not see them in that order |
curriculum_metric | SFT; 13 tasks with curriculum_dynamic | Sort metric. The static sort always uses length: perplexity and loss are accepted, print a notice and fall back to length, and only the curriculum_dynamic callback reads them |
curriculum_buckets | SFT; 13 tasks with curriculum_dynamic | Number of difficulty buckets (1-20, default 4). The static sort only prints it; the curriculum_dynamic callback reads it |
loss_watchdog | Every trainer that attaches the live callback | Enable loss watchdog. Refused at load on prm, unlearn, moe_lora_routing and backend: mlx |
loss_watchdog_threshold | Same as loss_watchdog | Loss spike threshold (≤100) |
loss_watchdog_patience | Same as loss_watchdog | Patience before stopping (≤1000) |
freeze_layers | SFT, TTS (text, transformers, no streaming) | Freeze bottom N layers (≤1000). Refused at load elsewhere |
freeze_ratio | SFT, TTS (text, transformers, no streaming) | Freeze ratio of layers. Refused at load elsewhere |
auto_mixed_precision | SFT, TTS | Pick bf16 or fp16 from the model and GPU. Setting it to true is refused at load on any other task |
embedding_loss | Embedding | Loss function |
embedding_pooling | Embedding | Pooling strategy |
Since v0.76.0 a key set on a task, backend or path that never reads it is, for many keys, refused when the config loads rather than ignored. The refusal names the key, the task or backend, and what to do (Use task: sft, or remove the key); soup train, soup train --dry-run, soup sweep and soup doctor --config all refuse it, and deleting the key is the fix. For most of these keys a run that finished on v0.75 ignored the key and trained as if it were not there, and some of the rest stopped after the model had loaded. Three are different: for use_longlora, ebft_variant and quantization_aware: true the key was applied, wrongly, so a run that finished on v0.75 did not do what its config said (see Re-run this). The rows above say which keys: use_liger, use_flash_attn, auto_mixed_precision, freeze_layers, freeze_ratio, rope_scaling_type, moe_aux_loss_coeff, loss_watchdog and its two siblings, loraplus_lr_ratio, moe_lora, plus data.chat_template (below), expand_layers, backend: unsloth on the ten tasks with no unsloth setup, and data.add_new_tokens / new_special_tokens outside the eleven tasks that add tokens. A key not named there is still accepted and ignored by a task that does not read it, so check this column. use_ring_attention and use_galore still go through their pre-flight check first, on any task. That check can refuse a machine that lacks the package or, for use_galore, a config with quantization: 4bit or 8bit (the default is 4bit) or backend: unsloth, so use_galore: true on a DPO run with the default quantization stops the run before it starts. The curriculum_metric and curriculum_buckets rows are the other exception: with curriculum_dynamic: true (which requires curriculum: true) the dynamic-curriculum callback reads them on the 13 tasks that allow it (sft, pretrain, dpo, grpo, kto, orpo, simpo, ipo, bco, reward_model, embedding, ppo, preference). Check this column before assuming a key took effect on a DPO or GRPO run.
data.chat_template is applied since v0.76.0 by SFT and by the DPO, ORPO, SimPO, KTO, BCO, IPO, PPO, reward-model, GRPO and Online DPO trainers, for conversational data; through v0.75.2 only SFT applied it, so on the others the tokenizer's own template rendered the prompts. Tasks that never render chat (pretrain, embedding, classifier, reranker, cross_encoder, prm, asr, moe_lora_routing, unlearn) refuse the key at load.
More keys, and where each is documented
These keys are all read by the code, and the defaults and refusals in this table are what the config loader does, checked against the schema at v0.76.0.
| Key | Default | What it does |
|---|---|---|
training.gptq_disable_exllama | true | Load a GPTQ base without the exllama kernel, which silently breaks adapter training. Read only with quantization: gptq, so leave it on. See Quant menu |
training.fp8_recipe | tensorwise | torchao scaling recipe for FP8 training: tensorwise, rowwise or rowwise_with_gw_hp. Refused unless quantization_aware: fp8. See Speed and memory |
training.reward_hack_halt | false | Stop a GRPO run on a HACK verdict from the reward-hack detector. Needs reward_hack_detector, which task: ppo refuses when the trainer is built. The config form of --reward-hack-halt |
training.echo_trap_tokenizer_aware | false | Score echo traps on tokenizer ids instead of whitespace tokens. Needs echo_trap_enabled: true. The config form of --echo-trap-tokenizer-aware |
training.minillm_on_policy | false | Use the on-policy MiniLLM rollout instead of the offline blend. Needs task: distill and minillm_enabled: true. The config form of --minillm-on-policy |
training.reward_hack_* | see the page | Twenty-two tunables for the mitigation controller, each refused while reward_hack_mitigation is off. Defaults and bounds: Reward-hack mitigation |
training.curriculum_dynamic_recompute_steps, _floor, _temperature | 50, 0.05, 1.0 | Tune the dynamic-curriculum policy. See Data mixing |
training.eval_steps | unset | Evaluate the validation split every N optimizer steps; unset evaluates at the end of each epoch. Refused on backend: mlx, ppo, online_dpo, unlearn, and when there is no validation split. See Training methods |
training.rewind_log | true | Write <output>/rewind.jsonl, the per-row loss record soup rewind reads. SFT only. See soup rewind |
training.use_lorafa | false | LoRA-FA: freeze the LoRA A matrices and train B. See LoRA quality |
training.distill_chunk_size, training.distill_checkpoint | unset, false | Chunked and checkpointed evaluation of the distillation divergence, to lower peak memory. task: distill only. See Modality II |
data.raft_epoch_shuffle | false | Re-permute RAFT golden and distractor documents every epoch. See RAG and RAFT |
data.replay, data.replay_ratio, data.replay_seed | unset, 0.1, unset | Continual-learning rehearsal on sft and pretrain. See Running training |
Two declared settings are the opposite case. data.remove_unused_columns now defaults to false; an explicit true loads with a warning and is ignored, and upstream says v0.77 will refuse it. The advise: block is accepted by the schema, but nothing in v0.76.0 reads it: its three keys goal, probe and record are used by nothing (soup advise takes them as flags only, see soup advise).
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.