Online DPO (v0.71.31)
soup train --task online_dpo puts an LLM judge (or a reward model) in the training loop. Each step samples two on-policy completions per prompt, a pairwise judge names the winner chosen and the loser rejected, and the model takes a DPO step on that fresh, self-generated pair. It wraps TRL's OnlineDPOTrainer, and it is transformers + text only (prompt-only data, like GRPO).
This is the training face of the v0.71.31 judge-in-the-loop suite: the same swap-debiased judge also mines data with best-of-N, grows it with Evol-Instruct, and decides SHIP with a pairwise win-rate in `soup ship`.
Config
base: HuggingFaceTB/SmolLM2-135M-Instruct
task: online_dpo
data:
train: ./data/prompts.jsonl # prompt-only (any format works; prompts are extracted)
training:
online_dpo_judge: "ollama://llama3.1" # a pairwise judge (ollama:// | https:// | http://localhost)
# OR set a reward model instead of a judge (exactly one of the two):
# reward_model: ./my-reward-model
online_dpo_loss_type: sigmoid # sigmoid | ipo
online_dpo_max_new_tokens: 64
dpo_beta: 0.1
lora: { r: 8, alpha: 16, target_modules: auto }soup train --config online_dpo.yaml
# or start from the ready-made recipe:
soup recipes use online-dpo-smollm2-135mConfig fields
| Field | Default | Meaning |
|---|---|---|
online_dpo_judge | (none) | Judge URL (ollama://model, https://..., or http://localhost). Mutually exclusive with reward_model. |
reward_model | (none) | A reward model to score completions instead of a judge. Exactly one of judge / reward_model must be set. |
online_dpo_loss_type | sigmoid | sigmoid (DPO) or ipo. |
online_dpo_max_new_tokens | 64 | Tokens to sample per completion (1..4096). |
beta | via dpo_beta | The DPO temperature; reuses the existing dpo_beta. |
The cross-validator requires backend: transformers and modality: text, and rejects both-set or neither-set judge / reward_model, plus any online_dpo_* field left non-default when the task is not online_dpo.
How the judge is used (and a per-version note)
The judge is Soup's JudgeEvaluator adapted to TRL, swap-debiased: it compares the two completions in both orders and only records a winner when (A,B) and (B,A) agree, so position bias cannot leak a preference.
Because CI resolves trl 1.x (which removed pairwise judges and moved the trainer to trl.experimental), Soup ships a runtime trl-version adapter:
- trl 0.19.x uses the swap-debiased pairwise judge (
judge=). - trl 1.x uses the same
JudgeEvaluatoras a pointwisereward_funcs=scorer.
Same judge model either way; the comparison shape differs by installed trl version. This is a documented per-version behaviour difference, not a bug.
Honesty
Proof-of-mechanism only. Online DPO was validated on SmolLM2-135M with a synthetic length-preferring judge on CPU (rewards/* and objective/kl logged), not a production RLHF claim. The 4-bit path is code-correct but hardware-gated (validated at quantization: none on CPU; real QLoRA online-DPO needs a bigger GPU). Scale validation is an open community ask (issue #286).
See also
- Best-of-N & Evol-Instruct — the data side of the judge-in-the-loop suite.
- soup ship — decide SHIP with a pairwise judge win-rate (
--task-mode pairwise). - Preference variety — the offline DPO / KTO / ORPO / SimPO / IPO / BCO dispatcher.
- GRPO Plus and PRM-guided GRPO — the RL alternatives.