Online DPO (v0.71.31)

soup train with 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

yaml
base: HuggingFaceTB/SmolLM2-135M-Instruct
task: online_dpo
data:
  train: ./data/prompts.jsonl      # prompt-only rows; see the note on row shape below
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 }
bash
soup train --config online_dpo.yaml
# or start from the ready-made recipe:
soup recipes use online-dpo-smollm2-135m

Row shape. The data goes through the normal format detection first, so a row has to be one the loader recognises. A chat row with no assistant turn, {"messages": [{"role": "user", "content": "Say hi"}]}, passes soup train --dry-run as chatml; a bare {"prompt": "Say hi"} row does not (Cannot detect format. Keys found: {'prompt'}, exit 1) unless you wrap it in a recognised shape.

Config fields

FieldDefaultMeaning
online_dpo_judge(none)Judge URL (ollama://model, https://..., or http://localhost / http://127.0.0.1). Mutually exclusive with reward_model. Since v0.75.2 a URL naming a private, link-local or reserved IP address is refused when the config loads, not when the trainer starts, so soup train --dry-run catches it; use a hostname (private addresses refused).
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_typesigmoidsigmoid (DPO) or ipo.
online_dpo_max_new_tokens64Tokens to sample per completion (1..4096).
betavia dpo_betaThe 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.

The judge is chosen by capability, not by version: Soup asks the installed trl OnlineDPOTrainer whether it accepts a pairwise judge=.

  • On the supported range (trl>=0.29.0,<1.0.0, which is what [train] installs) the swap-debiased pairwise judge is used (judge=).
  • On a trl that has dropped judge= (trl 1.x removed pairwise judges, and is outside the declared range) the same JudgeEvaluator is adapted to a pointwise reward_funcs= scorer.

Same judge model either way; the comparison shape differs with what the installed trl accepts. The upper bound sits below trl 1 because that migration is separate work, so the pointwise branch is there for a mismatched install, not the normal path.

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

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.