docs: M3 — DPO results (infra correct, held-out correctness flat, over-optimization collapse)
Implementation log (docs/18) + Phase-3 row (evolution.md): the two ops + gates, pair-gen (gold chosen / sampled-wrong rejected), reference-logprob caching, the training loop, and the honest finding — reward margin + pref-acc rise but held-out arithmetic correctness stays ~5-8% (flat within std-error) and over-optimizes to collapse (margin +34 → 0% format). DPO reweights, it does not install the capability; motivates M4 GRPO (optimize the verifiable reward online). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -410,3 +410,59 @@ short arithmetic-eval lengths the cache is overhead-bound and gives ~nothing —
|
||||
per-layer host round-trip is part of why short-seq is overhead-bound; M2b's device-side cache
|
||||
targets it.) This is the same measure-first lesson as T17 (process-per-GPU throughput-neutral):
|
||||
the win is real but only in the regime that actually stresses the bottleneck.
|
||||
|
||||
### M3 — DPO (offline preference optimization, landed; honest negative result)
|
||||
|
||||
The first real alignment method. Infra landed and gated; the empirical finding is that DPO
|
||||
**does not improve held-out arithmetic correctness on this task** — a genuine, on-theme negative
|
||||
result (the design doc's "RL is finicky" risk, made concrete).
|
||||
|
||||
**Two new autograd ops (`xtrain-autodiff`, both reuse the CE kernel — no new CUDA):**
|
||||
- `seq_logprob(logits, target)` = `Σ log πθ(target)` over non-ignored positions (the per-
|
||||
sequence logprob DPO compares). `= −Σ per_row` of cross_entropy (ignored rows already 0, like
|
||||
SFT masking); backward = `cross_entropy_backward(probs, target, −upstream)` (SUM, no mean).
|
||||
**Gate:** finite-diff grad-check with a `-100` completion mask.
|
||||
- `dpo_loss(lpθ_chosen, lpθ_rejected, lpref_chosen, lpref_rejected, β)` = `−log σ(Δ)` with the
|
||||
two policy logprobs as parents (ref logprobs constant). **Gate:** grad-check both parents +
|
||||
degenerate points (policy==ref ⇒ Δ=0, L=log2, grads ∓β/2; β=0 ⇒ grads 0).
|
||||
|
||||
**Pair construction (`gen_dpo_pairs`, aligned decision):** chosen = gold answer; rejected = the
|
||||
SFT model's own **greedy** (KV-cache engine, M2a) completion when it's a format-valid WRONG
|
||||
boxed answer — a hard negative in the model's distribution. Since SFT is ~8% correct (M1),
|
||||
greedy is wrong ~92% of the time, so this is fast and deterministic; ~8% of prompts are skipped
|
||||
(greedy correct). 1500 pairs generated (158 skipped) in ~8 min.
|
||||
|
||||
**Training (`train_dpo`):** loads the SFT ckpt as policy AND frozen reference; **precomputes the
|
||||
reference logprobs once** (while policy == reference) and caches them — one resident model. Each
|
||||
step forwards the policy on chosen + rejected, `seq_logprob` each, minimises `dpo_loss`; the two
|
||||
forwards share params so backward accumulates both branches. Loss **starts at exactly log2**
|
||||
(Δ=0 at init) — a built-in correctness check that fired correctly. Tracks reward margin +
|
||||
preference accuracy.
|
||||
|
||||
**Result (v12 1.05B, 1500 pairs, β=0.1; 100 held-out prompts, vs the SFT baseline format
|
||||
100/100, correct 8/100):**
|
||||
|
||||
| run | reward margin | pref-acc | format | correct |
|
||||
|---------------------------|---------------|----------|--------|---------|
|
||||
| SFT (baseline) | — | — | 100/100 | 8/100 |
|
||||
| DPO lr 5e-7 × 300 | +0.78 | ~82% | 100/100 | 7/100 |
|
||||
| DPO lr 5e-7 × 800 | +1.25 | ~82% | 100/100 | 5/100 |
|
||||
| DPO lr 1e-6 × 2000 | **+34.2** | ~76% | **0/100** | 0/100 |
|
||||
|
||||
The reward margin and preference accuracy rise cleanly (the loss IS being optimized — the infra
|
||||
is correct), but the implicit reward **does not transfer to held-out correctness**: it stays
|
||||
~5–8% (all within the ~2.7% std-error of 100 prompts — statistically flat), and pushing harder
|
||||
**over-optimizes to collapse** (margin +34 = huge KL from the reference → the model emits
|
||||
garbage, `46 * 80 = CRAFTIE SERIES SERIES…`, format 0%).
|
||||
|
||||
**The lesson (why):** chosen and rejected differ only in the final number tokens, so DPO raises
|
||||
`log p(correct) − log p(wrong)` for the *specific* training pairs — it **reweights the existing
|
||||
distribution, it does not install the capability**. The base model has no arithmetic algorithm,
|
||||
so preferring correct-vs-wrong final answers on seen pairs cannot generalize to unseen problems;
|
||||
and the only way to drive the margin far is to globally distort the distribution → incoherence.
|
||||
**DPO works when the chosen is already plausible under the policy; it cannot manufacture
|
||||
knowledge the model lacks.** This is the precise motivation for **M4 GRPO**: optimize the *actual
|
||||
verifiable reward* online (sample → check → reinforce what is genuinely correct), rather than a
|
||||
fixed-pair proxy — though GRPO faces the same 8%-correct sparsity, so whether it moves the metric
|
||||
is M4's open question. Gate met for M3 = the infra is correct (op grad-checks, log2-at-init,
|
||||
margin/acc rise); the correctness flatness is the reported finding, not a bug.
|
||||
|
||||
Reference in New Issue
Block a user