Models
Table with columns: Role, Model| Role | Model |
|---|
| Student | RockToken/qwen3_30b_a3b_to_4b_offpolicy_20k |
| Teacher | Qwen/Qwen3-30B-A3B-Instruct-2507 (MoE) |
enable_thinking=False throughout.
Training data
- Source:
open-thoughts/OpenThoughts3-1.2M, domain == "code" slice
- 5,000 single-user-turn prompts; 70 exceeding
prompt_max_len=2560 were filtered, leaving 4,930
- Only the prompts are used; on-policy KD never reads the dataset's reference answers
Training setup
Framework: KDFlow — FSDP2 + SGLang rollout, Ray-orchestrated GPU co-location with sleep/wakeup. Same pipeline revision as the math-domain onpolicy_5k_src* runs.
Hardware: 1× node, 4× H100 (94 GB), 33 h 09 min wall-clock (~133 GPU-hours).
Key hyperparameters
Table with columns: Group, Value| Group | Value |
|---|
| Backend | fsdp2, bf16, gradient ckpt on |
| Epochs | 1 (2,465 rollout iterations) |
| Train batch | 4 (micro 1) |
| Learning rate | 2e-6, cosine, warmup 5% |
| KD ratio | 1.0 |
| KD loss | reverse KL (rkl) |
| KD algorithm | vanilla_kd |
| Rollout engine |
prompt_max_len is 2560 instead of the math runs' 800: code prompts carry problem statements and starter code (p99 ≈ 2,356 tokens).
Note on the LR schedule: as in the earlier runs of this series, the scheduler's horizon is sized to 4× the actual number of updates, so the cosine decay is only partially traversed — the LR moves from 2.00e-6 to 1.79e-6 over the run rather than reaching zero. Kept as is for comparability within the series.
Training dynamics
Means over 500-step blocks (per-step values are noisy at batch 4):
Table with columns: steps, loss (reverse KL), mean gen length| steps | loss (reverse KL) | mean gen length |
|---|
| 1–500 | 0.190 | 6,814 |
| 501–1000 | 0.178 | 6,611 |
| 1001–1500 | 0.175 | 6,471 |
| 1501–2000 | 0.166 | 6,647 |
| 2001–2465 | 0.166 | 6,378 |
The loss starts near 0.19 rather than the ~3 seen when distilling from a raw instruct model — the student has already been through off-policy KD against the same teacher, so on-policy training starts close and grinds out the remaining distribution gap.
⚠ Truncation caveat
Code responses run long, and a substantial share of rollouts hit the 8,000-token generation cap: per-step mean lengths sit at p50 = 7,069 against the cap, and in 20% of steps the whole batch was truncated (step-mean ≥ 7,990). Truncated rollouts contribute KD signal only for their first 8,000 tokens, and the student receives no supervision on how the teacher would have ended those responses. Treat comparisons against the science and math checkpoints (which trained essentially truncation-free) with this in mind.
Intended use
Research on distillation dynamics, in particular whether on-policy KD gains transfer across domains (math-trained off-policy base → code on-policy round). Domain: code (OpenThoughts-3 code split).
Limitations
- The on-policy round is code-only; not tuned for chat or safety.
enable_thinking=False — this student does not emit thinking traces.
- Heavy generation-length truncation during training; see the caveat above.
- Single checkpoint at the end of one epoch; no intermediate checkpoints were kept.