Preference Variety (v0.40.0)
Five preference losses live behind one config knob. Pick a loss without renaming your task, anneal β over training, periodically refresh the frozen reference, and blend losses with a forward-looking multi-objective surface.
On a card that cannot hold the model: since v0.72.4,
dpo,orpo,simpoandktoalso run over a streamed base, where the frozen reference is that same stream with its adapters switched off rather than a second copy of the weights. Note the unifiedtask: preferencedispatcher below, andipoandbco, are not in the streaming allowlist: name the loss intaskdirectly. See Preference losses over streaming.
BCO (Binary Classifier Optimization)
Same input format as DPO; rows are split internally to TRL's BCO unpaired schema ({prompt, completion, label}).
task: bco
data:
train: ./data/preferences.jsonl
format: dpo
training:
bco_beta: 0.1
lora: { r: 64, alpha: 16 }
quantization: 4bitbco_beta defaults to 0.1 (gt=0). New soup init --template bco ships in the box.
Unified preference dispatcher
Use task: preference + training.preference_loss to swap losses without touching task. Hyperparameter sweeps over the loss type itself become trivial.
task: preference
data:
train: ./data/preferences.jsonl
format: dpo
training:
preference_loss: dpo # or simpo, orpo, ipo, bcoLegacy task: dpo / task: simpo / etc. remain first-class — the unified surface is additive.
KL-controlled DPO variants
Anneal β over training and periodically refresh the reference model.
task: dpo # or task: preference + preference_loss: dpo, or task: ipo
training:
dpo_beta: 0.1
dpo_beta_schedule: linear # linear | cosine | exponential
dpo_beta_end: 0.01
dpo_ref_regen_epochs: 2 # copy student → ref model every 2 epochsBoth controls are gated to DPO-family tasks (dpo, ipo, or preference with preference_loss in {dpo, ipo}). Transformers backend only.
The BetaScheduleCallback resolves total_steps lazily in on_train_begin so the schedule sees the real state.max_steps populated by HF Trainer. Epoch-0 regen is suppressed (avoids copying the untrained student).
Multi-objective preference loss (v0.40.1, blend added in v0.53.11)
task: preference
training:
preference_loss_weights: {dpo: 0.7, simpo: 0.3}The schema validates 2–5 entries summing to 1.0 (±1e-6). Single-entry rejected with an actionable message pointing at scalar preference_loss. Mutually exclusive with scalar preference_loss. Rejected on MLX backend.
bco cannot be combined with a paired loss, and the refusal arrives later than the others: the schema allowlist accepts the name, so the config loads clean and validate_weight_compat raises at trainer setup instead. BCO scores each completion on its own, the paired losses need a chosen-versus-rejected pair, and there is no shared batch shape. Use bco as a scalar preference_loss rather than as an ensemble member.
This surface shipped schema-only in v0.40.0, where training raised an actionable NotImplementedError (the same stub-then-live pattern as v0.27.0 MII / v0.37.0 multipack / v0.38.0 quant menu / v0.39.0 ReLoRA). v0.40.1 replaced that stub with a primary-loss approximation: the highest-weighted loss becomes the trainer and its term is scaled by its weight. v0.53.11 added a per-batch weighted blend on top, but the blend reads the policy log-probs from the batch the trainer receives and quietly falls back to that primary-loss scaling when they are missing. TRL 0.29's DPOTrainer, ORPOTrainer and CPOTrainer (the SimPO trainer) compute those log-probs inside their own loss and do not put them in the batch (read from the TRL 0.29.1 source, not run on a GPU), so on the current stack treat preference_loss_weights as the primary-loss behaviour until a run shows the blend. At v0.75.2 the NotImplementedError stub is gone.
Stats
- Net +118 tests (4538 → 4656 across 136 files)
- BCO trainer + dispatcher + β schedule math + ref-model regen TOCTOU + multi-objective schema bounds
See also
- DPO training guide — preference dataset format
- Trace-to-preference — harvest pairs from production logs
- Registry — track preference variants in the lineage DAG
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.