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

yaml
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 }
bash
soup train --config online_dpo.yaml
# or start from the ready-made recipe:
soup recipes use online-dpo-smollm2-135m

Config fields

FieldDefaultMeaning
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_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.

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 JudgeEvaluator as a pointwise reward_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