自从 10 月份以来 Thinking Machine Labs 的 On Poilcy Distillation 博客1 之后,OPD 引发了越来越多的关注。最近 MiMo-V2-Flash 在其技术报告2 中也提到他们使用了 Multi-Teacher On-Policy Distill 作为全新的 Post-Training 范式。

本文尝试回答几个问题:

  • 什么是 On Policy Distillation?
  • OPD 相对于 SFT 和 RL 的区别和联系是什么?有什么优势?
  • OPD 常见应用场景是什么,在 LLM 训练的哪个阶段?

Notation

符号表示 数学含义
$\mu_\theta$ he student sampling policy adopted in the inference engine
$\pi_\theta$ target student policy optimized in the training engine
$\pi_{\text{domain}_x}$ the teacher policy specialized for the domain of prompt $x$ sampled from distribution $\mathcal{D}$
$\text{sg}[\cdot]$ stop-gradient operator

On Policy Distillation 是什么

一句话总结:

On-Policy Distillation 在策略蒸馏是一类将策略蒸馏 Policy Distillationon-policy 强化学习相结合的方法,主要用于多策略融合、模型压缩、稳定训练或加速学习

Knowledge Distillation

Knowledge Distillation 是一种模型压缩知识迁移技术。

核心思想:

让一个较小的模型(称为 student)去模仿一个较大的、性能更强的模型(称为 teacher),从而在保持较高性能的同时显著减少模型复杂度。

传统训练中,student 直接学习真实标签 y,这叫做 hard target 但在蒸馏中,student 还要学习 teacher 的 soft target

  • teacher 不仅告诉你哪个类别是正确的 one-hot label
  • 还告诉你每个类别的置信度分布 soft probability

例如,真实标签是 cat

  • teacher 输出:[cat: 0.9, dog: 0.08, fox: 0.02]
  • student 不仅学到 猫是正确的,还学到 狗和猫有点相似

Forward KL vs Reverse KL

OPD in RL

$$ \mathcal{D}*{\text{reverse-KL}}(\theta) = \mathbb{E}*{x \sim \mathcal{D}, y_{Technical Formulation of MOPD

在通过 SFT 奠定基础,并通过领域特定的 RL 训练出专业化教师模型之后,现在将形式化multi-teacher on-policy distillation——该机制可将这些专业化能力整合到统一的学生模型中。

学生与教师之间的reverse KL divergence loss定义为:

$$ \mathcal{L}*{\text{reverse-KL}}(\theta) = -\mathbb{E}*{x \sim \mathcal{D}, y_{ 梯度为:

$$ \nabla_\theta \mathcal{L}*{\text{reverse-KL}}(\theta) = -\mathbb{E}*{x \sim \mathcal{D}, y_{ 参照 IcePop 中的方法3,采用训练-推理重要性采样,并丢弃差异较大的 token。随后定义 MOPD 的 the surrogate loss 为:

$$ \mathcal{L}*{\text{MOPD}}(\theta) = -\mathbb{E}*{x \sim \mathcal{D}, y \sim \mu_\theta(\cdot|x)} \left[ \frac{1}{|y|} \sum_{t=1}^{|y|} w_t \hat{A}*{\text{MOPD},t} \log \pi*\theta(y_t|x, y_{ 其中

$$ w_t(\theta) = \begin{cases} \text{sg}\left[ \frac{\pi_\theta(y_t|x,y_{默认情况下,我们将 MOPD 的优势函数与其他类型的优势函数结合(例如基于结果奖励模型(ORM)计算的优势,包括 GRPO。设 $\hat{A}*{\text{ORM}}$ 为 ORM 计算的优势函数,则最终优势函数为:

$$ \hat{A}*{\text{MOPD}, t} = \text{sg}\left[ \log \frac{\pi_{\text{domain}*x}(y_t|x, y*{图6展示了 MOPD 相对于传统后训练方法的有效性:在数学推理(AIME 2025)和代码(LiveCodeBench)基准测试中,MOPD 成功保留并融合了多教师的专业化能力,在多数领域中达到或超过了最强教师的性能。

代码实现

1
2
3
4
5
6
7
teacher_logits = teacher(seq)[:-1].detach() # [seq_len, vocab_size] 左移一位
student_logits = student(seq)[:-1]  # [seq_len, vocab_size]
teacher_logprob = logsoftmax(teacher_logits)
student_logprob = logsoftmax(student_logits)

kl_loss = teacher_logprob.exp() * (teacher_logprob - student_logprob) # [seq_len, vocab_size]
kl_loss_token = kl_loss.sum(-1) # [seq_len,]

TML

TML 根本就没有想词表的事情,kl compute 全程只使用被选中的 token

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
# Initialize teacher client (main):
teacher_client = service_client.create_sampling_client(
    base_model=teacher_config.base_model,
    model_path=teacher_config.load_checkpoint_path,
)

# Sample trajectories (main):
trajectories = do_group_rollout(student_client, env_group_builder)
sampled_logprobs = trajectories.loss_fn_inputs["logprobs"]

# Compute reward (compute_teacher_reverse_kl):
teacher_logprobs = teacher_client.compute_logprobs(trajectories)
reverse_kl = sampled_logprobs - teacher_logprobs
trajectories["advantages"] = -reverse_kl

# Train with RL (train_step):
training_client.forward_backward(trajectories, loss_fn="importance_sampling")

其实这里相当于对完整的 kl 做了一次蒙特卡洛模拟。因为直接使用 student 做 rollout 时,选中的每个 token 的概率正比于 student_prob,那么在这个 token 上估计一次 kl,它的期望和全词表估计是一样的。也正是由于选中概率和 student 一样,所以期望和正版 reverse_kl loss 一致,所以即使根本没有加权这个过程,作者仍然把这个 loss 叫做 reverse_kl loss。

GLM-5 / slime 中的 OPD 实现剖析

GLM-5 技术报告4 中明确提到,post-training 主线是 Reasoning RL → Agentic RL → General RL 的串行 RL pipeline,并贯穿使用 On-Policy Cross-Stage Distillation 来对抗"后阶段灾难性遗忘前阶段能力"的问题——即每跑完一个 RL 阶段后,用前一阶段的 checkpoint 作为 teacher,把丢掉的能力以 OPD 的方式拉回来。报告原话:

“we implemented a sequential Reinforcement Learning pipeline—starting with Reasoning RL, followed by Agentic RL, and finishing with General RL. Crucially, we utilized On-Policy Cross-Stage Distillation throughout this process to prevent catastrophic forgetting, ensuring the model retains its sharp reasoning edge while becoming a robust generalist.”

这套 cross-stage OPD 的工程载体就是 zai-org/slime(GLM-5 报告里也直接点名"on the slime framework")。下面拆解 slime 的具体实现。

设计哲学:OPD 与 advantage estimator 正交

slime 在 OPD 上的最关键决定是:不把 OPD 实现成一个新的 estimator,而是作为任意 advantage estimator 之上叠加的 KL 罚项5

$$ \hat{A}*t = A_t - \lambda*{\text{opd}} \cdot \big(\log \pi_\theta(y_t|x, y_{其中 $A_t$ 来自 base estimator(GRPO / GSPO / PPO / REINFORCE++),第二项是 sampled-token 级别的 reverse KL(K1 估计器)。这个写法在 slime/backends/megatron_utils/loss.py:apply_opd_kl_to_advantages 中只用十几行就实现了:

1
2
3
4
5
def apply_opd_kl_to_advantages(args, rollout_data, advantages, student_log_probs):
    teacher_log_probs = rollout_data.get("teacher_log_probs")
    for i, adv in enumerate(advantages):
        reverse_kl = student_log_probs[i] - teacher_log_probs[i]
        advantages[i] = adv - args.opd_kl_coef * reverse_kl

这意味着:

  • 任意 RL estimator 都能直接套上 OPD:在 compute_advantages_and_returns 跑完后,最后一步统一注入 KL 罚项;
  • 没有"OPD trainer"这个独立概念,OPD 只是 RL trainer 的一个开关 (--use-opd);
  • 可以"纯蒸馏"也可以"RL+蒸馏混合":当 task reward 全部置零时,advantage 就退化为 $-\lambda_{\text{opd}} \cdot \text{KL}$,等价于 TML blog 里的 “RL importance-sampling loss + 负 reverse KL 当 advantage” 的范式(见 slime/rollout/on_policy_distillation.py:post_process_rewardsscalar_rewards = [0.0] * len(samples))。

两种 teacher 部署模式:sglang vs megatron

slime 用 --opd-type 把 teacher 服务模式抽象成两条互斥路径,对应"教师远大于学生"和"教师与学生同架构"两种主流场景:

维度 --opd-type sglang --opd-type megatron
Teacher 位置 独立 SGLang server,单独占 GPU 与训练同集群,作为额外 Megatron model 加载
数据获取时机 Rollout 阶段:每条样本回填 logprob 训练前向阶段:每个 microbatch 重算
通信媒介 HTTP (aiohttp POST /generate) Megatron 内部 forward,无跨进程通信
Teacher 架构限制 任意(只要能跑 sglang),通常用于 Qwen3-32B → Qwen3-8B、Kimi → 小模型 必须与 student/ref 完全同架构
显存占用 学生集群完全不占 teacher 显存 学生集群额外存一份 teacher 权重
跨 stage cross-stage 蒸馏 ✗ 通常不用,需要起 server GLM-5 的天然选择:上一阶段 ckpt 直接 --opd-teacher-load
通信成本 高:response 每个 token 一次 logprob 回传 低:teacher 与 student 在同一 forward pipeline

SGLang 模式:把 teacher 包装成 reward server

slime 用了一个非常巧妙的复用:把 teacher 当成一个特殊的 reward model——通过既有的 custom RM 接口接入,避免引入第二条数据通路。slime/rollout/on_policy_distillation.py:reward_func

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
async def reward_func(args, sample, **kwargs):
    payload = {
        "input_ids": sample.tokens,
        "sampling_params": {"temperature": 0, "max_new_tokens": 0, ...},
        "return_logprob": True,        # 关键:让 sglang 只返回 logprob,不生成
        "logprob_start_len": 0,
    }
    async with aiohttp.ClientSession() as session:
        async with session.post(args.rm_url, json=payload) as resp:
            return await resp.json()

要点:

  1. **max_new_tokens=0 + return_logprob=True**:sglang server 只做一次 prefill forward,返回每个位置的 logprob(标量),不真的采样。这就是工程上获取 teacher 监督信号最便宜的方式——不需要 KV cache 增长,不需要 decode loop。
  2. logprob 是 sampled-token level 而非 full vocab:和 TML、verl 的选择一致——传完整词表 (~150k floats × T tokens) 不可行,每位置回传一个标量 logprob 就够 K1/K2 估计了。
  3. 复用 reward 通道--custom-rm-path + --custom-reward-post-process-path,没碰训练 loss 路径。

后处理把 logprob 截到 response 段并塞回每个 sample:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
def post_process_rewards(args, samples, **kwargs):
    teacher_log_probs = [
        torch.tensor([item[0] for item in reward["meta_info"]["input_token_logprobs"][1:]],
                     dtype=torch.float32)
        for reward in raw_rewards
    ]
    teacher_log_probs = [t[-response_length:] for t, response_length in zip(...)]
    for sample, t in zip(samples, teacher_log_probs):
        sample.teacher_log_probs = t          # 写回 Sample
    return [0.0]*len(samples), [0.0]*len(samples)   # 任务 reward 留空

Sample 数据类直接长出一个字段:

1
2
3
4
# slime/utils/types.py
class Sample:
    rollout_log_probs: list[float] | None = None
    teacher_log_probs: list[float] | None = None  # 教师 log-prob, OPD 专用

这一字段会在 slime/ray/rollout.py 里随 batch 一起序列化送到 train actor,再在 slime/backends/megatron_utils/data.py 里和 rollout_log_probs 同样的代码路径处理(CP slicing、padding 等):

1
2
3
4
5
6
# slime/backends/megatron_utils/data.py
for key in ["rollout_log_probs", "teacher_log_probs"]:
    rollout_data[key] = [
        torch.tensor(slice_log_prob_with_cp(log_prob, total_length, response_length, ...))
        ...
    ]

Megatron 模式:teacher 当成第二个 ref model

当 teacher 与 student 同架构(典型情况:cross-stage 蒸馏,teacher 就是上一阶段 ckpt),slime 走第二条路径——复用 ref_model 的"额外模型加载 + 权重切换"机制slime/ray/placement_group.py

1
2
3
4
5
return self.async_init(
    args, role="actor",
    with_ref=args.kl_coef != 0 or args.use_kl_loss,
    with_opd_teacher=args.use_opd and args.opd_type == "megatron",
)

slime/backends/megatron_utils/actor.py 里:

1
2
3
# 初始化时多加载一份 teacher 权重
if with_opd_teacher:
    self.load_other_checkpoint("teacher", args.opd_teacher_load)

训练每步通过 _switch_model("teacher") 把当前活跃权重切到 teacher,跑一次 forward-only:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
# slime/backends/megatron_utils/actor.py:train_actor
if "ref" in self.weights_backuper.backup_tags:
    self._switch_model("ref")
    rollout_data.update(self.compute_log_prob(..., store_prefix="ref_"))

if "teacher" in self.weights_backuper.backup_tags:        # ← OPD teacher
    self._switch_model("teacher")
    rollout_data.update(self.compute_log_prob(..., store_prefix="teacher_"))

self._switch_model("old_actor" if self.args.keep_old_actor else "actor")
...
compute_advantages_and_returns(self.args, rollout_data)   # 内部调 apply_opd_kl_to_advantages

这里有几个工程细节值得拉出来讲:

  1. **weights_backuper + _switch_model**:slime 用一个 weight 备份机制实现"一份 GPU 显存承载多套权重"。teacher 与 ref/old_actor 共享同一份计算图骨架,切换的只是权重(CPU↔GPU offload 或者 CPU pinned memory hot-swap)。代价:每步多一次 forward,但训练用 compute_log_prob 是纯前向,已经比一次 RL update 便宜。
  2. routing replay:MoE 模型上,teacher forward 时设置 ROUTING_REPLAY_STAGE = "fallthrough"——不复现 student 的路由,让 teacher 走自己的 expert 选择。这跟 ref model forward 的处理一致,避免 routing replay 把 teacher 的 logprob 拉偏。
  3. **opd_teacher_ckpt_step**:可以指定 teacher 的具体 ckpt step 而不是 latest,cross-stage 时直接指 “Reasoning-RL 结束的那个 step”。

跑一下:从命令行参数还原工作流

examples/on_policy_distillation/run-qwen3-8B-opd.sh 是教科书级别的 SGLang 模式样例:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
# 1. 启动 teacher server(占一张 GPU)
CUDA_VISIBLE_DEVICES=7 python3 -m sglang.launch_server \
    --model-path /root/Qwen3-32B \
    --port $TEACHER_PORT \
    --tp 1 \
    --mem-fraction-static 0.6 &

# 2. 等 health check 通过
until curl -sf http://$TEACHER_IP:$TEACHER_PORT/health_generate; do sleep 5; done

# 3. 启训练(占剩下 7 张),把 teacher server URL 当 reward URL 接入
python3 train.py \
   --advantage-estimator grpo \
   --use-opd --opd-type sglang --opd-kl-coef 1.0 \
   --use-kl-loss --kl-loss-coef 0.00 \                          # ref-model KL 关掉
   --custom-rm-path slime.rollout.on_policy_distillation.reward_func \
   --custom-reward-post-process-path slime.rollout.on_policy_distillation.post_process_rewards \
   --rm-url http://$TEACHER_IP:$TEACHER_PORT/generate

看这两条参数组合即可还原 OPD 的语义:

  • --advantage-estimator grpo + --use-opd --opd-kl-coef 1.0:GRPO 计算 group-relative advantage,再叠加 token-level reverse KL;
  • --use-kl-loss --kl-loss-coef 0.00:保留 ref model 计算路径但 coef 设 0,相当于把 ref-vs-teacher 的角色完全交给 teacher 一方;
  • 8 GPU 配置里 1 张给 teacher、2 张给 actor、4 张给 rollout、剩下做编排——典型的 disaggregated layout。

Megatron 模式更简洁,连 server 都不需要:

1
2
3
4
python3 train.py \
   --advantage-estimator grpo \
   --use-opd --opd-type megatron --opd-kl-coef 1.0 \
   --opd-teacher-load /root/PrevStage_Checkpoint_torch_dist  # ← cross-stage 蒸馏的精髓在这里

--opd-teacher-load 指向上一阶段的 RL ckpt,就完成了 GLM-5 那套 “Reasoning-RL → 用 Reasoning-RL 当 teacher 蒸到 Agentic-RL 阶段” 的级联。

关键设计决策与 trade-off 总结

决策点 slime 的选择 等价/对比方案 取舍
Loss vs Advantage Advantage 减项(K1 estimator,保留正负号) verl PR #4897 提供 loss/advantage 双形态;TML 也用 advantage Advantage 形式不需要 β coef tuning,与 PG/GRPO 自动同尺度
Sampled-token vs Top-k Sampled-token logprob (k=1) verl GKD recipe 支持 top-k forward KL 通信简单(标量)+ 稳定(top-k reverse KL 易导致 student 推平 top-k mass)
Teacher 服务方式 sglang serverMegatron 内联 二选一 verl 用 vLLM + ZeroMQ;TML 走 Tinker API 二元设计覆盖了"超大教师"和"同架构 cross-stage"两种主流场景
Teacher 与 ref 关系 正交 + 互斥:可以同时存在,可以单独存在 verl 早期把 teacher 当 ref 替换 OPD 与 ref-KL(防 actor 漂移)不冲突,可叠加
KL 估计器 K1student_logp - teacher_logp)+ low_var_kl DeepMind GKD 用 JSD;DistiLLM 用 SKL K1 + advantage 形式天然兼容 PPO clip + 负数 advantage
MoE routing Teacher forward 走 fallthrough,不复现 student routing 避免 routing replay 把 teacher 拉到 student 的子分布上
参数命名空间隔离 --opd-* 前缀,配合 --use-opd 守卫 启用 OPD 必须显式选 type;类型与 teacher-load 互斥校验

实测效果

slime 在 README 里给了一个简洁但有力的对照实验5

设置 Math500 Pass@1
Qwen3-8B-Base + SFT (OpenThoughts3-1.2M 子集) 76%
上述 + On-Policy Distillation (Qwen3-32B teacher,剩余数据) 94%

也就是同样的数据预算下,把后半段从 SFT 换成 OPD,pass rate 从 76% 跳到 94%。这与 TML 报告的 7-10× gradient step 提速、Qwen3 报告的 17920 → 1800 GPU-hours(10× compute 节省)是同一个量级的收益。

与 GLM-5 cross-stage 蒸馏的对应

把 slime 的实现和 GLM-5 报告里的 cross-stage 训练流程对应起来:

GLM-5 训练流水(来自 GLM-5 paper Fig.5 + §3):

  SFT
   │
   ▼
  Reasoning RL                ← 第 1 阶段,结束时存 ckpt_R
   │  ┌─────────────────────┐
   │  │  OPD: teacher = ckpt_R
   │  │  └──> 防止后续阶段忘掉 reasoning 能力
   │  └─────────────────────┘
   ▼
  Agentic RL                  ← 第 2 阶段,结束时存 ckpt_A
   │  ┌─────────────────────┐
   │  │  OPD: teacher 可以是 ckpt_R 或 ckpt_A 的某种组合
   │  └─────────────────────┘
   ▼
  General RL                  ← 第 3 阶段,最终模型
   ▲
   │  此处的 OPD 用前阶段 teacher 防止 General RL 把 reasoning/agentic 能力磨平

在 slime 上落地,这就是连续跑三轮训练,每轮都开 --use-opd --opd-type megatron --opd-teacher-load <prev_stage_ckpt>——前一阶段的产物直接成为下一阶段的 teacher。这种 cross-stage 复用让 OPD 不再是 “static teacher → student” 的 strong-to-weak 蒸馏,而是 “self-historical-teacher → self” 的 anti-forgetting 机制,这一点和 MOPD 的 “multiple specialized teachers → unified student” 思路是互补的。

📌 Resume 钩子:这一节天然适合在简历里以 “Built cross-stage on-policy distillation infra (used by GLM-5 paradigm) on top of slime, where each RL stage’s checkpoint serves as teacher for the next” 这样的形式出现,能引出几个深度问题——为什么不用 ref-KL 直接代替?sglang vs megatron 模式怎么选?logprob shape mismatch 怎么处理?MoE routing 复现策略?这些 slime 代码里都给了答案。

MiMo-V2-Flash 中的 MOPD 实现剖析

如果说 GLM-5 / slime 把 OPD 用成了**「时序型」cross-stage anti-forgetting** 工具(一阶段 teacher → 下一阶段 student),那 Xiaomi MiMo-V2-Flash2 走的是另一条互补的路线:「并行型」multi-teacher specialty fusion——同时存在多个 domain-specialized RL teacher,让一个统一的 MoE student 同时拿到所有领域的 dense token-level 监督。这一节拆解 MiMo 在 OPD 上从算法到 infra 的端到端设计。

设计动机:为什么需要 multi-teacher

MiMo 的报告把传统 post-training 的两个本质问题点出来:

  1. “See-saw” effect (能力跷跷板):在一个统一的 RL pipeline 里依次堆 math RL、code RL、agent RL,会出现"提升 A 牺牲 B"的现象——多 stage sequential RL 难以避免。
  2. Learning inefficiency:当你想"合并"多个 specialized model 的能力时(比如有一个 math RL teacher、一个 code RL teacher、一个 search-agent RL teacher),传统做法只有两条:
    • Parameter merging(model soup / averaging):损失峰值能力;
    • Sequential off-policy distillation:在 static dataset 上 SFT,碰到 exposure bias + sparse 监督。

MOPD 的回答是:把 multi-teacher 知识融合本身重新公式化为一个 RL 问题——每个 prompt 由它所属 domain 的 specialized teacher 提供 dense token-level 监督,student 自己 on-policy rollout,在共享一份 MoE 参数的前提下"学会用不同 expert 子集服务不同 domain"。这个目标天然契合 MoE 架构(309B 总参 / 15B active,256 expert / 8 active per token),不同 domain 的知识可以路由到不同 expert 上去。

三阶段 pipeline:teacher 的产生与使用

MiMo 把整个 post-training 切成三个阶段(图 3 对应 §4.1):

                  ┌────────────────────────────────────────────────┐
Stage 1: SFT      │  在百万级混合 instruction 数据上做 SFT          │
                  │  (覆盖 thinking / non-thinking / agent 三种模式) │
                  └─────────────────────┬──────────────────────────┘
                                        │
                                        ▼
                  ┌────────────────────────────────────────────────┐
Stage 2:          │  在 SFT 模型基础上独立训练多个 domain teacher:  │
Domain-Special.   │  ── Agentic teachers ──                         │
RL/SFT Teachers   │     • Code Agent (90k real + 30k synth tasks)   │
                  │     • Search Agent (150k synth tasks)            │
                  │     • Function-Calling / General Agent (50k)     │
                  │  ── Non-Agentic teachers ──                      │
                  │     • Math reasoning (verifiable RL)             │
                  │     • General reasoning (rubric-based RL)        │
                  │     • Safety alignment (rubric RL)               │
                  │  注:teacher 也可以是 SFT 或 student 自己          │
                  └─────────────────────┬──────────────────────────┘
                                        │
                                        ▼
                  ┌────────────────────────────────────────────────┐
Stage 3: MOPD     │  Student 从自己的 evolving distribution 采样,    │
                  │  对每个 prompt x 只激活其 domain 对应的 teacher │
                  │  π_{domain_x}, 同时拿到 ORM 的 outcome reward    │
                  └────────────────────────────────────────────────┘

这个流程的精妙之处:

  • 每个 prompt 只跟 1 个 teacher 算 reverse KL——不是「同时 query N 个 teacher 取平均」。MOPD 是 “domain-routed teaching”,避免了多 teacher 平均带来的 mode collapse。
  • Teacher 不必是大模型——可以是同尺寸 SFT 后用 RL 提升过的 specialized checkpoint,甚至可以是 student 自己(表 7 中 MMLU-Pro / GPQA / Arena-Hard 等任务的 best teacher 标注为 “Self”)。这与 slime/GLM-5 的 cross-stage 用 historical self 当 teacher 的思路在精神上一致。
  • 支持 iterative co-evolution:MOPD 输出的 student 可以再回到 Stage 2 训练新一轮 specialized teacher,形成自循环。

这一点和我们前面讲的 GLM-5 cross-stage OPD 形成了清晰的二元对比:

  • GLM-5/slime:1 teacher × N stages(时序)
  • MiMo MOPD:N teachers × 1 stage(并行)

两者在工程上完全可以叠加——slime 已经具备多 teacher 抽象(虽然代码里默认一个 --opd-teacher-load,但 _switch_model("teacher") 完全可以扩展到 N 个)。

MOPD 的 advantage 设计:双信号融合

MOPD 的核心 surrogate loss 在前一节"Technical Formulation of MOPD"里已经写过完整数学。这里只强调一个最容易被忽略但工程上至关重要的点——advantage 的"双信号"组合

$$ \hat{A}_{\text{MOPD}, t} = \underbrace{\text{sg}\!\left[\log \frac{\pi_{\text{domain}_x}(y_t|x, y_{这个结构意味着 MOPD 不是"OPD 替换 RL",而是"OPD 加在 RL 之上":teacher KL 给每个 token 提供 dense 的 process-level 信号(“这一步走得准不准”),ORM 给整条轨迹提供 sequence-level 的 outcome 信号(“最后答对了没”)。

把这一点跟 slime 的实现对比就很清楚——它们在框架层是同一个抽象:

  • slime: advantages[i] = adv_grpo[i] - opd_kl_coef * (student_logp - teacher_logp)
  • MiMo: Â_MOPD = α * Â_ORM + sg[log π_T - log π_θ]

但 MiMo 在 batch 内的 teacher 路由(每条 sample 根据 prompt 的 domain 选不同的 teacher)和 student rollout 已经偏离 teacher 时的 train-inference IS 重加权(参照 IcePop3 截断 ratio 越界的 token 不更新)这两点上做了 slime 暂时没做的扩展。

MOPD 实验结果解读:超越 best teacher

报告 Table 7 给了一组比较彻底的数据,我把"具有特殊意义"的几行抽出来:

Benchmark Student (Before MOPD) Best Teacher Student (After MOPD) Δ(Student-Teacher)
AIME 2025 89.3 93.9 (Math RL teacher) 94.1 +0.2 ✓ 超过 teacher
HMMT Feb. 2025 76.9 82.6 (Math RL teacher) 84.4 +1.8 ✓ 超过 teacher
LiveCodeBench 77.5 82.6 (Code RL teacher) 83.2 +0.6 ✓ 超过 teacher
Arena-Hard (Hard Prompt) 50.0 50.0 (Self) 54.1 +4.1 ✓ 超过 self
Tau2-Bench (Telecom) 92.7 95.0 (Search RL teacher) 95.3 +0.3 ✓ 超过 teacher
GPQA-Diamond 84.9 84.9 (Self) 84.3 -0.6
BrowseComp 42.5 51.7 (SFT teacher) 45.4 -6.3

要点:

  1. Student 在多个 benchmark 上反超了"该 domain 最强的 teacher"——这跟传统蒸馏"student 性能 ≤ teacher" 的直觉相反。MOPD paper 把这个现象归功于 multi-teacher 之间的"知识互补"——一个 prompt 在 math 域归 math teacher 管,但 student 跨域学到的 generalization(特别是来自 self / SFT teacher 的 instruction-following 信号)会反过来加强 math 域上的具体推理能力。
  2. 失败的两个 case 都很有趣
    • GPQA-Diamond 退步是因为 best teacher 是 student 自己(即没有 specialized teacher 提供新信号),MOPD 的 reverse KL 在 self-teaching 上等于 self-distill,会有轻微 mode collapse;
    • BrowseComp 大幅退步(-6.3)说明 SFT teacher 在 search 这种长链条 agent 任务上的监督质量本身就不够稳,dense token-level reverse KL 把 SFT teacher 的"风格"学得太彻底反而拖累了下游能力。

这两个 case 是对面试官非常好的"诚实回答素材"——“我们 MOPD 的 wins/losses 边界很清晰:当 best teacher 比 student 强、且监督信号的质量稳定时收益最大;当 best teacher 是 student 自己或是低质 SFT 时,MOPD 反而可能伤害”

MOPD 训练的 RL Infra:四大支柱

MOPD 的算法本身要落地,离不开 MiMo 在 SGLang + Megatron-LM 之上做的四个 infra 优化(报告 §4.6)。这四个组件加起来才让 309B/15B 的 MoE student 能在 10k+ 并发 K8s pod 的 agentic 环境下稳定跑 OPD:

(1) Rollout Routing Replay (R3) — MoE on-policy 的"原子级一致性"修复

问题:MoE 模型里,router 给每个 token 决定送进哪 8 个 expert。由于推理引擎(SGLang,FP8/BF16,特定 kernel)和训练引擎(Megatron,BF16,不同 kernel)在数值精度、累加顺序、attention backend 上完全不同,同一 token 在 inference 时可能路由到 expert {3, 17, 88, …},在 training forward 时却路由到 {3, 19, 88, …}——这一个 expert 之差就让 logits 出现明显偏差,直接破坏 on-policy RL 的核心假设(即 student 在训练时看到的 logprob 与采样时是同一分布)。这个问题在 OPD 里更严重,因为我们要算的就是 student 自己的 logprob 和 teacher 的 logprob 之差,路由不一致会让这个差值的方差爆炸。

R3 解法

Inference (SGLang)                     Training (Megatron)
┌──────────────────────┐               ┌──────────────────────────┐
│ Router 决策:          │               │ 用 inference 时记录的     │
│   token i → expert   │  ─ record ─►  │   expert 选择直接 replay,│
│   {e_a, e_b, ..., e_h}│               │   跳过 router 重计算       │
└──────────────────────┘               └──────────────────────────┘
       ▲                                            │
       │     训练 KL ↓ ~10×                          │
       └──────── 等价于"训练分布 = 推理分布" ────────┘

工程实现是:rollout 阶段把每个 token 在每层 MoE 的 top-k expert id 序列化下来(典型形态 [seq_len, num_layers, top_k] int32),跟着 sample 一起送进 train batch;training forward 时拦住 router 输出,强制用 replay 的 expert assignment。这套机制在 slime 代码里能直接看到对应物——slime/utils/routing_replay.py:RoutingReplayuse_rollout_routing_replay、环境变量 ROUTING_REPLAY_STAGE 三态(record / replay_forward / replay_backward / fallthrough)。所以前面讲 slime OPD 时提到的 teacher forward 走 fallthrough,正是为了让 teacher 走自己的 router、不被 student rollout 时的 routing 拖偏——这是 R3 的反向用例。

R3 的出处可以追溯到 OpenReview 上的同名论文(Xiaomi 团队作品);同时在 vLLM/veRL 上也有第三方落地,可让 token 级 KL 差异降低约一个数量级6

(2) Request-Level Prefix Cache — 多轮 agent 的 KV + routing 双缓存

问题:Agentic RL 里一条 trajectory 通常是 <prompt, reasoning_1, tool_call_1, tool_result_1, reasoning_2, ...> 这样的多轮结构。每一轮新 reasoning 都会带上前面所有轮次作为 context;如果不缓存,rollout 就要在每轮重新前向整个长 context。

Prefix Cache 解法:在 SGLang 引擎里同时缓存两套东西:

  • KV state:标准 prefix cache 已有;
  • Routed expert 选择:和 R3 配合,确保前几轮的 KV cache 在重用时所走的 expert 还和上次一致。如果只缓存 KV 不缓存 expert 选择,那么 R3 的一致性会在多轮间断掉。

这个设计专门服务于 agentic OPD/RL 场景——大量 prompt 是 long-horizon 的,每轮重算 prefill 是 GPU 算力的最大浪费源

(3) Fine-Grained Data Scheduler — 把 batch-level 调度降到 sequence-level + partial rollout

问题:传统 RL rollout 是 batch-level 的——一个 batch 的 N 条 sample 全部跑完才能进 train step。但 agentic task 的 rollout 长度方差极大:一个简单 SWE 任务可能 2k token 收尾,一个复杂的 100k context 任务可能要跑 1 小时。straggler 拖整个 batch,长尾可能让 GPU 闲置 50% 以上。

MiMo 解法(与 GLM-5 的 C3PO++ 思路一致):

  • Sequence-level scheduling:调度单元从 batch 降到 sequence;
  • Partial rollout:rollout 没跑完的 sample 也可以送进 trainer(带上 done=False 标记),等下一轮再续接;
  • Dynamic batch packing:trainer 端按到达顺序攒 batch。

效果是 GPU idle time 下降 + on-policy 性质保持——partial sample 在被续接前不会发生策略漂移(reward / advantage 的归因正确性需要在续接时仔细处理)。

(4) Toolbox & Tool Manager — 10k+ 并发 K8s pod 的工具执行层

问题:Agentic RL 涉及大量 tool call(bash / web search / code execution)。每个 tool call 如果都临时拉一个新 docker / pod,冷启动延迟会 dominate trajectory 生成时间。MiMo 的训练规模是 10000+ 并发 pod、覆盖 8 种编程语言。

两层架构

  1. Lower layer (Tool Manager):Ray actor pool,预热 N 个 actor,每个 actor 持有一组 K8s pod,按需分发;失败 pod 自动回收;资源限额 + 优先级队列。
  2. Upper layer (Toolbox):暴露给 student rollout 的同步接口(bashstr_replacefinish 三个原子工具),把任务逻辑和系统策略隔离。

70% 的 K8s pod setup 成功率 + 大规模 actor pool 的 graceful degradation 是 MOPD 之外、agentic RL 阶段才用得满的 infra,但 MOPD 的 search/code agent teacher 训练阶段也会用到同一套。

MTP:让 small-batch on-policy rollout 真正可行

MOPD 是天然的 on-policy + small batch 训练形态——on-policy 一定要用当前 student 的样本,所以 batch 不能开很大;但 small batch 又会让 GPU 算力浪费在 attention 这种 memory-bound 算子上。

MiMo 在 MTP 上的关键决定是:MTP 不只是推理时的 speculative decoding 加速器,更是 RL/OPD rollout 阶段的 throughput 提升器2。具体两条收益:

  1. Lifts arithmetic intensity for both FFN and attention:MTP 一次 forward 出 K 个 draft token,main model 并行 verify。这个 K 倍的 token-level parallelism 直接抬升了 attention 的 arithmetic intensity(不再是每次 1 个 token 的 batch=1 算 attention),FFN 也跟着受益。
  2. Mitigates long-tail straggler GPU idleness:rollout 进入长尾阶段后(少数 sample 还在跑、大部分已完成),active batch size 可能逼近 1。这种状态下的 vanilla decoding 对 GPU 极其不友好;MTP 通过 token-level 并行救场。

MiMo-V2-Flash 设计了一个轻量化 MTP block,专门服务这两个用例:

  • dense FFN 而非 MoE(避免 MTP 自身又引入 MoE routing 不一致);
  • SWA 而非 GA(KV cache 占用极小);
  • 单 block 仅 0.33B 参数;
  • pre-training 阶段挂 1 个 head;post-training 阶段把 head 复制 K 次(K=3 时 3.6 acceptance length, 2.6× decoding speedup)。

📌 这一点对你简历里"通过 MTP 蒸馏的优化 rollout 加速"那个 bullet 是非常硬的支撑:MiMo-V2-Flash 的报告把 MTP-for-RL 单独立小节论证了它和 small-batch on-policy 的天然契合,可以直接引用。

MOPD 与 GLM-5 cross-stage / slime OPD 的设计差异

把上面剖析整合成一张总对比表:

维度 slime / GLM-5 cross-stage OPD MiMo MOPD
Teacher 数量 1 (上一阶段 self ckpt) N (并行多个 specialized teacher)
Teacher 与 prompt 关系 全 batch 共享 按 prompt 的 domain 路由
主要解决的问题 Sequential RL 的 catastrophic forgetting Multi-skill fusion 的 see-saw effect
Advantage 形式 $\hat{A} - \lambda \cdot \text{KL}$(OPD 罚项加在 RL adv 上) $\text{KL} + \alpha \cdot \hat{A}_{\text{ORM}}$(KL 是主,ORM 是辅)
Teacher 服务模式 sglang server / megatron 同集群(二选一) 多 teacher 同时存在,需要更复杂的多服务编排
Train-inference IS reweight 不内建(依赖外部 ref-KL) 内建 IcePop-style ratio clipping
MoE routing 一致性 RoutingReplay 三态(record/replay/fallthrough) R3 + per-layer expert id 序列化
Rollout 优化 partial rollout(slime 也支持) partial rollout + Fine-Grained Scheduler + MTP
工具执行 通过 --custom-rm-path 接入 Toolbox + Tool Manager(Ray actor pool, 10k+ K8s pod)
落地代表 GLM-5 (744B MoE), Qwen3 OPD MiMo-V2-Flash (309B/15B MoE), 后续 MiMo 系列

两者并不互斥:一个完整的 OPD pipeline 完全可以是「在 stage 内用 MOPD 多 teacher 并行融合,stage 之间再用 cross-stage OPD 防遗忘」——这正是 MiMo-V2-Flash 在 Stage 3 后接续 Agentic RL 时实际做的(Agentic RL 阶段自然会偏向 code agent,那时再回头用 MOPD 后的 ckpt 当 anti-forgetting teacher)。

关键数字 & 简历素材

把 MiMo 这一节里能够直接进简历当锚点的硬数字汇总:

  • 309B 总参 / 15B active MoE student(256 experts / 8 active per token)
  • 27T tokens 预训练 + 256K context
  • 多个 trillion-class teacher(与 Kimi-K2 1T、DeepSeek-V3.2 671B 同档)
  • R3 让 train-inference logits KL 降低约 1 个数量级
  • MTP K=3 时 3.6 acceptance length, 2.6× decoding speedup
  • 10k+ 并发 K8s pod,70% 环境 setup 成功率
  • MOPD 让 student 在 5/8 reasoning benchmark 上反超 best specialized teacher
  • MOPD 之后的 MiMo-V2-Flash 用 1/2~1/3 参数追平 DeepSeek-V3.2 / Kimi-K2

📌 Resume 钩子:这一节可以让你在简历里写 “Built MOPD-style multi-teacher on-policy distillation infra for trillion-scale MoE training, with R3-based MoE routing replay, MTP-accelerated rollout, and disaggregated multi-teacher serving”——能引出"R3 怎么实现的?““multi-teacher 路由怎么编排?““MTP 在 RL rollout 怎么 verify?““partial rollout 时 advantage 怎么续接?“等几乎一整套面试技术问题,这些问题你在 ByteDance Seed 上都做过对应的工作

DeepSeek-V4 中的 Full-Vocabulary OPD 实现剖析

DeepSeek-V47 在 OPD 上做出了一个比 slime/GLM-5 cross-stage 和 MiMo MOPD 都更激进的工程决定:把整个 post-training 中的 mixed RL 阶段完全替换成 On-Policy Distillation,并采用 full-vocabulary logit 蒸馏而非业界主流的 sampled-token 估计。这一节剖析他们为什么这么做、怎么做的,以及这套设计与前面两套(slime / MiMo)的根本差异。

设计决定:mixed RL 整段被 OPD 替换

DeepSeek-V4 报告 §5.1 的原文(line 1536-1539)非常直白:

“Following pre-training, we conducted a post-training phase to yield the final models of DeepSeek-V4 series. Although the training pipeline largely mirrored that of DeepSeek-V3.2, a critical methodological substitution was made: the mixed Reinforcement Learning (RL) stage was entirely replaced by On-Policy Distillation (OPD).

这跟前面两个案例的对比非常鲜明:

系统 OPD 在 pipeline 中的地位
slime / GLM-5 RL 阶段之间的 cross-stage anti-forgetting 工具(每个 stage 还是真的在做 RL)
MiMo MOPD RL 之上叠加的 dense reward 信号(Â = α·Â_ORM + KL
DeepSeek-V4 直接顶替 mixed-RL 整个阶段(specialist 们在前面 RL 出来,最后合并完全靠 OPD)

DeepSeek-V4 团队把"模型合并"这一步看作 OPD 的 sole job——不再让 student 同时做 RL 探索 + KL 蒸馏,而是把 RL 的探索全部前置到每个 specialist 的训练阶段,最后用 OPD 把多个 specialist 的能力logits-level 合并到一个 unified student 里。报告里把这个判断说得很明确:

“the knowledge from physically distinct expert weights is consolidated into a unified parameter space via logits-level alignment, practically circumventing the performance degradation often encountered in traditional weight-merging or mixed RL techniques.”

也就是说他们认为 mixed RL(一个统一 RL pipeline 同时学多个 domain)的"see-saw effect"问题——这个问题在 MiMo 报告里也被点名——可以通过把 RL 拆成单领域 specialist + OPD 合并来彻底回避。

Specialist Training:teacher 的产生(含 GRM)

DeepSeek-V4 的 teacher 不是"训好的别人家模型”,而是基于 V3.2 训练 pipeline 自己跑出来的 domain specialist。每个 specialist 走的是 SFT → GRPO RL 的标准路径,但有几个值得抽出来讲的设计点:

  1. 三档 reasoning effort(Non-think / Think High / Think Max):每档配不同的 length penalty 和 context window,实际上是用同一个 specialist 训出三个变体——这就让最终 OPD 的 teacher 池可以同时覆盖"快/中/深思考"三档,student 学完之后也支持三种模式切换。
  2. Generative Reward Model (GRM):处理"难以 rule-based verify"的任务时,DeepSeek-V4 没用传统的 scalar reward model,而是让 actor 自己同时充当 GRM——同一份权重既出 response 又出 evaluation。RL 优化时联合优化生成和 judging 两个能力。这套思路使得最后 teacher 池里既有 verifier 训出来的,也有 GRM-judge 训出来的。
  3. Tool-Call Schema 用 XML(<|DSML|...|>:避免 JSON-based tool call 的 escape 问题;这点是为后续 OPD 阶段保持 student 与各 teacher tool-call 格式一致服务的。
  4. Interleaved Thinking:reasoning trace 在 tool-result 轮次间完全保留(V3.2 是丢弃),充分利用 1M-token context。这意味着 OPD 时 teacher logits 是在"完整 reasoning history"上计算的,dense token 信号包含跨轮 reasoning 的连续性。

最终 OPD 阶段 超过 10 个 teacher(“more than ten teacher models covering various domains are employed”),每个 teacher 都可能是 trillion-class 模型——这是 V4-Pro 自身就是 1.6T/49B 的规模,所以 teacher 跟 student 是同一档数量级。

算法形态:multi-teacher full-vocabulary reverse KL

OPD 目标函数(报告 Eq. 29):

$$ \mathcal{L}_{\text{OPD}}(\theta) = \sum_{i=1}^{N} w_i \cdot D_{\text{KL}}\!\left( \pi_\theta \,\|\, \pi_{E_i} \right) $$

其中:

  • $\pi_{E_1}, \ldots, \pi_{E_N}$ 是 N 个 specialist teacher(N>10);
  • $w_i$ 是各 expert 的权重,按 importance 分配;
  • 整体仍然是 reverse KL(student 在前),所以 mode-seeking 的属性保留;
  • trajectory 由 student $\pi_\theta$ 采样——保持 on-policy;
  • “the unified policy 𝜋𝜃 selectively learns from the specialized expert relevant to the current task context” — 即 teacher 之间通过 prompt domain 分流(和 MiMo MOPD 的 domain-routing 同理)。

与业界主流的根本差异:full-vocabulary 而非 sampled-token

这是 DeepSeek-V4 OPD 与前面 slime / MiMo / TML 全都不同的一点。报告 §5.1.2 末尾(line 1750-1760)单独写了一段对比:

“In handling the above OPD objective, prior works usually simplify the full-vocabulary KL loss into a token-level KL estimate at each token position, and reuse RL framework by replacing $\text{sg}\!\left[\log \frac{\pi_{E_i}(y_t|x,y_{it leads to high variance in gradient estimation and often causes training instability. Therefore, we adopt full-vocabulary logit distillation in our OPD. Preserving the complete logit distribution in calculating reverse KL loss yields more stable gradient estimates and ensures faithful distillation of the teachers’ knowledge.”

把这段对比成表:

方案 监督形态 通信成本 显存成本 梯度方差 稳定性 代表
Sampled-token K1/K2 每位置 1 个标量 logprob 极低 极低 高(蒙特卡洛) 中(需 IS clipping / IcePop) TML, slime, MiMo, verl
Top-k logit 每位置 K 个 logit 中(缺 tail) 不稳(top-k reverse KL 易诱导 student 推平 top-k) verl GKD recipe
Full vocab logit (V4) 每位置 |V|≈100k+ 个 logit 高(但被消除) 高(被消除) DeepSeek-V4

V4 团队认为对于 trillion-class teacher × 10+ teacher × 1M-context 这种规模,sampled-token 的方差代价已经超过 full-vocab 的存储代价——但前提是要把 “full-vocab logit 怎么便宜地拿到训练 loop 里” 这个工程问题解掉。下一节就是他们的解法。

让 Full-Vocabulary OPD 可行的四件事

DeepSeek-V4 §5.2 列了四个 RL/OPD 共用的基础设施优化,其中两个对 OPD 是 enabler 级的关键。

(1) FP4 Quantization Integration — 让 teacher inference 便宜

报告 §5.2.1:

  • MXFP4 量化用在所有 rollout 和所有 inference-only forward——包括 teacher 和 reference model 的 forward;
  • Rollout/inference 阶段直接用 native FP4 权重;
  • Training step 用 lossless FP4→FP8 dequantization simulate,复用既有的 FP8 mixed-precision 框架(FP32 master weights),backward pipeline 完全不动。

这里关键是把 teacher 的 forward(OPD 里最频繁的算子之一)整体降到 FP4 推理路径——10+ 个 trillion-class teacher 同时存在的时候,光 KV cache + activation 就可能成倍于 student,FP4 几乎是必需的。

(2) Efficient Teacher Scheduling for Full-Vocabulary OPD — 这一节是核心

报告 §5.2.2 是整个 V4 OPD 设计最浓缩的工程章节,逐条拆开:

问题 1:N>10 个 trillion-class teacher 的权重不可能同时驻留 GPU。

解法 1:所有 teacher weights offload 到 centralized distributed storage,ZeRO-like sharding 按需拉取——OPD forward 时才加载某个 teacher 的当前 layer。这就把 GPU DRAM 压力 → 网络 I/O 压力(V4 的 3FS 集群存储就是为这个服务的)。

问题 2:vocab size > 100k,把所有 teacher 的 full logits 拉出来 materialize 即使写到磁盘也吃不消。具体感受一下:100k vocab × 1M context × 10 teacher × FP16 = 2 TB / 一条 sample,完全不可行。

解法 2(最关键的工程 trick):只缓存每个 teacher 最后一层的 hidden state,logits 在 training step 用 student 自己的训练前向重新过 teacher 的 prediction head 算出来。

Teacher forward (offline-ish, FP4):
  prompt + student rollout
        │
        ▼
   ── teacher backbone ──▶ last-layer hidden state h^T_t  ── cache
                                                              │
                                                              ▼
                                                       centralized buffer
                                                              │
Training step (later, in main loop):                          │
  cached h^T_t  ──▶  teacher prediction head W_T  ──▶  full vocab logits
                                                              │
                                                              ▼
                                                  TileLang KL kernel
                                                  (exact full-vocab D_KL)

收益:

  • 存储:从 [T tokens × |V|] floats → [T × hidden_dim] floats,节省一个 vocab/hidden 比例(~10×–20×);
  • 重算成本:只有 prediction head 一次矩阵乘(hidden→vocab),相比 backbone 是几乎可以忽略的;
  • 完整性:拿到的还是 exact full-vocab logits,不是 top-k 近似。

问题 3:多 teacher 时即使只放 prediction head,10+ 个 head(每个都是 hidden→100k 的大矩阵)同时驻留 GPU 还是吃不消。

解法 3按 teacher index 排序训练样本,让一个 mini-batch 里的所有样本走同一个 teacher。这样:

  • 每个 distinct teacher head 只在一个 mini-batch 里加载一次
  • 任何时刻 GPU 上至多有 1 个 teacher head
  • 所有参数 / hidden state 的 load/offload 都 异步在后台进行,不阻塞计算 critical path。

问题 4:full-vocab KL 计算本身在 100k+ vocab 上很贵。

解法 4:用 TileLang 写专用 KL kernel——把 logsoftmax + KL 融成一个 fused kernel,避免动态显存分配,加速明显。这一点关联到 V4 §3.2(TileLang 训练框架)和 §3.3(高性能 batch-invariant deterministic kernel libraries)的整套基础设施。

(3) Preemptible & Fault-Tolerant Rollout — token-granular WAL

报告 §5.2.3 引入了一个 OPD 之外但 OPD 同样受益的组件——token-granular Write-Ahead Log

  • 每个 generation request 一个 WAL;
  • 每生成 1 个 token 立即 append 到 WAL
  • preempt 时暂停推理引擎、保存未完成 request 的 KV cache;
  • resume 时按 WAL + KV cache 续接 decode;
  • 即使硬件故障:用 WAL 里的 token 重 prefill 重建 KV cache。

报告里最有意思的是这一段(line 1815-1818)的"为什么不能直接重生"的分析:

“it is mathematically incorrect to regenerate unfinished requests from scratch, as this introduces length bias. Because shorter responses are more likely to survive interruption, regenerating from scratch makes the model more prone to producing shorter sequences whenever an interruption occurs.”

也就是说"被打断的多是长 sample”,如果直接丢掉重生,那训练数据就被人为偏向短样本——这会让 student 的输出分布漂移到偏短,伤害 reasoning quality。WAL 是一个比"记 RNG seed 重 decode"更高效的 length-bias-free 解法。

这点对 OPD 尤其重要,因为 OPD 的 teacher 监督是 token-level 的,每个被丢弃 / 重生的 token 都意味着一份对应的 teacher logit 监督被浪费或被错配。

(4) Million-Token Context Scaling for RL/OPD

§5.2.4 的核心是rollout 数据格式分层

  • 把 rollout data 拆成 lightweight metadata(用于 global shuffle、packing layout 计算)+ heavy per-token fields(cached teacher hidden states, logprobs 等);
  • per-token fields 走 shared-memory data loader——一个 node 内多个进程共享同一份内存,消除 intra-node 冗余;
  • mini-batch granularity 释放,CPU+GPU 内存压力可控;
  • 单设备 mini-batch 数动态调整,平衡 compute throughput 与 I/O overlap。

(5) DSec — 沙盒基础设施

§5.2.5 的 DSec 是面向 agentic 场景的 sandbox 平台(Rust 写、3FS 上、单集群百万级并发 sandbox)。和 OPD 直接相关的有:

  • Trajectory logging + preemption-safe resumption:当 RL/OPD 训练任务被抢占,sandbox 资源保留;resume 时 DSec replay 已完成的 command 的缓存结果,不重新执行非幂等操作(比如已经 commit 的 git 操作、已经发送的 HTTP)。
  • 4 种执行 substrate 共享同一个 Python SDK 接口(Function Call / Container / microVM via Firecracker / fullVM via QEMU),从 lightweight tool 到 full SWE pipeline 全覆盖。
  • 与 MiMo Toolbox + Tool Manager 思路类似,但 DSec 是有完整 trajectory 重放语义的设计,对长 horizon agent OPD 更友好。

跟 slime/GLM-5/MiMo 的总对比表(更新版)

把 DeepSeek-V4 的设计纳入前面两节的对比框架:

维度 slime / GLM-5 cross-stage MiMo MOPD DeepSeek-V4 OPD
OPD 在 pipeline 中的地位 RL 阶段之间的 anti-forgetting 工具 RL 阶段叠加的 dense reward 直接顶替 mixed RL 整段
Teacher 数量 1(上一阶段 self ckpt) N(domain-specialized) N>10(domain-specialized + 三档 reasoning)
Teacher 规模 与 student 同档 多 trillion-class 多 trillion-class(V4-Pro 1.6T 自蒸自)
Loss 形态 $\hat{A} - \lambda \cdot \text{KL}_{\text{token}}$ $\hat{A}_{\text{ORM}} \cdot \alpha + \text{KL}_{\text{token}}$ $\sum_i w_i \cdot D_{\text{KL}}^{\text{full vocab}}(\pi_\theta \| \pi_{E_i})$
KL 估计形式 Sampled-token K1 (logprob 标量) Sampled-token + IcePop IS reweight Full-vocabulary logit
Teacher 显存压力 小(同架构、可共享 GPU) 中(多 teacher,但有 R3) 极大 → ZeRO-like teacher offload + hidden-state cache
Logits 处理 不存(只存 logprob) 不存(只存 logprob) + R3 expert id 缓存 last-layer hidden state,训练时重算
Teacher head 调度 每步加载 ref/teacher 二选一 per-prompt domain routing mini-batch 级别按 teacher index 排序
KL 计算 PyTorch 标量减法 PyTorch 标量减法 + IS clip TileLang fused full-vocab KL kernel
容错与 preempt 标准 ckpt + Megatron resilience 同左 token-granular WAL, length-bias-free
量化 BF16/FP8 训练,BF16 推理 FP8 mixed precision FP4 (MXFP4) for all teacher/ref inference
Sandbox 通过 --custom-rm-path 接入 Toolbox + Ray actor pool DSec (Rust + 3FS, hundreds of thousands sandboxes)
落地代表 GLM-5 (744B), Qwen3 OPD MiMo-V2-Flash (309B/15B) DeepSeek-V4-Pro (1.6T/49B), V4-Flash (284B/13B)
Context 上限 通常 32K-128K 256K 1M tokens

核心设计取向的差异可以一句话概括:

  • slime / GLM-5:minimal-invasive,OPD 作为 RL 的扩展点;
  • MiMo MOPD:multi-teacher knowledge fusion,OPD 是 RL 的主要 reward source;
  • DeepSeek-V4:以"具备完整 logit 信号的 SFT-on-self-rollout"取代 mixed RL,把 RL 的探索完全留给上游 specialist

关键数字 & 简历素材

DeepSeek-V4 OPD 这一节里能直接进简历当锚点的硬数字:

  • DeepSeek-V4-Pro 1.6T 总参 / 49B activated;V4-Flash 284B / 13B
  • 1M-token context 训练与 OPD(业界第一档)
  • N > 10 个 trillion-class teacher,full-vocabulary OPD
  • Vocab > 100k,靠 last-layer hidden state cache 把 logits 物化代价完全消除
  • 每 mini-batch 至多 1 个 teacher prediction head 在 GPU 上(teacher index 排序调度)
  • MXFP4 量化所有 teacher/ref forward
  • TileLang fused KL kernel
  • Token-granular WAL 解决长样本被抢占时的 length bias
  • DSec:单集群数十万并发 sandbox

📌 Resume 钩子:DeepSeek-V4 这一节是简历里"为大规模 OPD 做了系统级 infra 工作"最有说服力的对照。可以写成 “Designed full-vocabulary OPD infrastructure for trillion-scale multi-teacher distillation: teacher hidden-state caching with on-the-fly logits reconstruction, teacher-index aware mini-batch scheduling, FP4 teacher inference, and token-granular WAL for length-bias-free preemption recovery”——能引出"为什么 full-vocab 不爆?““teacher head 怎么轮换?““为什么不能直接重生 unfinished rollout?““你怎么写 fused KL kernel?““1M context 下 rollout 数据怎么分层?” 这样一连串系统设计问题,全部都是你在 ByteDance Seed 的训练系统里直接对应的工作。

应用场景

参考资料


  1. https://thinkingmachines.ai/blog/on-policy-distillation/ ↩︎

  2. MiMo-V2-Flash Technical Report, https://github.com/XiaomiMiMo/MiMo-V2-Flash/blob/main/paper.pdf ↩︎ ↩︎ ↩︎

  3. Small leak can sink a great ship–boost rl training on moe with icepop!, Sep 2025. URL https://ringtech.notion.site/icepop ↩︎ ↩︎

  4. GLM-5: from Vibe Coding to Agentic Engineering, Zhipu AI & Tsinghua University, Feb 2026, https://arxiv.org/abs/2602.15763 ↩︎

  5. slime: Unified RL post-training framework, THUDM/zai-org, https://github.com/THUDM/slime, see slime/rollout/on_policy_distillation.py and slime/backends/megatron_utils/loss.py:apply_opd_kl_to_advantages ↩︎ ↩︎

  6. Rollout Routing Replay (R3): Stabilizing RL for Mixture-of-Experts LLMs, OpenReview, https://openreview.net/pdf/3625c3d087d60bb2438fa25e109d6b8fce3965ab.pdf; see also DeepWiki XiaomiMiMo/MiMo-V2-Flash §3.4 RL Infrastructure ↩︎

  7. DeepSeek V4 Paper, https://huggingface.co/deepseek-ai/DeepSeek-V4-Flash/blob/main/DeepSeek_V4.pdf ↩︎