小米、DeepSeek、NVIDIA都在用,TRL现已支持多教师蒸馏
MOPD(Multi-Teacher On-Policy Distillation,多教师同策略蒸馏)最近频繁出现在今年的技术报告中。小米在 1 月为 MiMo-V2-Flash 命名了这项技术,此后 DeepSeek、Moonshot、NVIDIA、Liquid AI 和 Mistral 等都用它来构建模型。
TRL 现在支持 MOPD。AsyncDistillationTrainer 会把每个 prompt 路由到它对应的专家教师,同步版 DistillationTrainer 的支持也将在 #7215 中到来。如果你已经了解 MOPD,只想看 TRL 示例,可直接跳到“MOPD in TRL”一节。
要让一个模型同时擅长数学、代码、工具使用或指令遵循等多个领域,并用一次 RL 训练完成,这很难。训练时各领域会把模型拉向不同方向,每个领域只分到每个 batch 的一小片,提升一个领域可能悄悄伤害另一个领域。借助 MOPD,实验室的解决办法是为每个领域训练一个专家,再把专家合并回一个模型。
我们在《Distillation in 2026(so far)》中介绍了实验室使用蒸馏的整体图景。
什么是 MOPD?
蒸馏训练一个模型(学生)去模仿另一个模型(教师)。在 MOPD 中有多个教师,每个领域一个,学生向所有教师学习。严格来说,MOPD 是三阶段后训练配方的最后一步,不过这个名字经常被用来指代整个配方:
- 通用 SFT:一个模型在混合数据上做常规监督微调,学会每个领域的基础。这是共享的起点。
- 领域专家:从这个 checkpoint 出发,为每个领域单独训练一个 RL 模型,例如一个数学、一个代码、一个指令遵循、一个 agentic 任务。每个专家只需要把一件事做到很好。
- 融合:学生(通常还是那个 SFT checkpoint)回答来自各个领域的 prompt。每个 prompt 所属领域的专家充当教师,逐 token 给答案打分,学生被训练得靠近该教师的分布。
MOPD 配方:一个 SFT checkpoint,每个领域一个 RL 专家,然后进入融合循环,每个 prompt 由它所属领域的专家打分。
MOPD 是多教师的同策略(on-policy)蒸馏。三个特性让它成立,前两个来自同策略蒸馏本身,第三个来自多教师:
- 学生从自己的样本中学习。教师给学生实际写出的内容打分。如果只用教师输出做普通 SFT,学生只在教师写的文本上训练,但推理时它必须续写自己的文本,早期一个错误就会把它带到训练中没见过的状态。用自己的样本训练可以避免这一点,这就是“同策略”的部分。
- 信号是稠密的。RL 对每个答案只给一个 reward,而这里每个 token 都得到教师的反馈,损失通常是学生 token 上学生与教师之间的反向 KL 散度,也就是教师对学生的每个 token 选择有多不同意。教师自己从不写任何东西,只读学生的答案。不同实验室在每个 token 上使用多少教师分布并不相同。Nemotron 3 Ultra 和 MiMo-V2-Flash 只使用学生写下那个 token 的教师概率。Open-MOPD 比较最可能的 16 个 token。DeepSeek-V4 使用词表上的完整分布,因为单 token 版本会带来高方差梯度和不稳定的训练。Mistral Large 4 也使用完整分布。
- 每个 prompt 只发给一个教师。数学 prompt 只由数学专家打分,代码 prompt 只由代码专家打分。
在这些配方里,教师通常和学生同样大小,并从同一个 checkpoint 开始。它们之所以是有用的教师,是因为每个都只在单一领域上训练过。
谁在用 MOPD?
Liquid AI 的配方最容易读。一条通用路线从 SFT 走到 MOPD,另一条专家路线(每个专家都经过 SFT 和 RL 训练)汇入其中。
LFM2.5-2.6B 训练配方。来源:Liquid AI。
MiMo-V2-Flash 是给这项技术命名的论文,它更详细地画出了融合步骤。学生做 rollout,每个领域教师返回 token 级 reward。
图 3,来自 MiMo-V2-Flash 技术报告。
NVIDIA 展示了 MOPD 在规模上的样子。对于 Nemotron 3 Ultra,他们使用了十多个教师,并运行了两轮 MOPD。第一轮之后,他们从合并后的模型出发训练新教师,再运行一次 MOPD。
图 10,来自 Nemotron 3 Ultra 技术报告。
NVIDIA 还在 Hub 上发布了其中五个教师,分别面向 STEM、竞赛编程、指令遵循、通用推理和聊天。大多数实验室只发布最终模型,所以专家 checkpoint 仍然很少,我们预计未来几个月会出现更多。
以下是其报告或模型卡明确描述 MOPD 的主要发布:
| 发布时间 | 实验室 | 模型 | 用法 |
|---|---|---|---|
| 2026 年 11 月 | Mistral AI | Mistral Large 4 | 按推理强度(高、中、低)而非按领域分三个教师 |
| 2026 年 10 月 | Liquid AI | LFM2.5-24B-A2B | 两个 MOPD 阶段,一个非 agentic,一个 agentic |
| 2026 年 9 月 | 小米 | MiMo-V2.6 | “MOPD2”,包含两个领域教师家族 |
| 2026 年 7 月 | Liquid AI | LFM2.5-2.6B | 从共享 SFT checkpoint 出发,每个领域一个专家 |
| 2026 年 7 月 | Moonshot AI | Kimi K3 | 九个专家,按领域和推理强度划分 |
| 2026 年 6 月 | NVIDIA | Nemotron 3 Ultra | 十多个教师,两轮 MOPD |
| 2026 年 4 月 | DeepSeek | DeepSeek-V4 | 十多个领域教师,替代 V3.2 的混合 RL 阶段 |
| 2026 年 2 月 | Zhipu AI | GLM-5 | 一种变体,教师是早期 RL 阶段的最终 checkpoint |
| 2026 年 1 月 | 小米 | MiMo-V2-Flash | 给这项技术命名 |
MOPD 建立在常规的单教师同策略蒸馏之上,Thinking Machines 在 2025 年末对此解释得很好。研究方面,MOPD 论文单独研究了该方法,Open-MOPD 发布了完整配方及其 checkpoint,下面的示例就使用它。
在 TRL 中使用 MOPD
在 TRL 中,MOPD 由 AsyncDistillationTrainer 支持,下面的示例使用的就是它。你用 vLLM 服务每个专家,给训练器每个教师一个 URL,并添加一个 teacher_id 列,把每个 prompt 路由到它的专家。生成、教师打分和训练异步运行,所以学生会在训练的同时继续生成。
我们构建了一个示例,用真实专家展示该功能,也就是 Open-MOPD 发布的专家。学生是它们的 SmolLM3-3B SFT checkpoint,教师是从它出发用 GRPO 训练的三个代表数学、代码和指令遵循的专家。发布的 prompt 混合数据已经为每个 prompt 标好了领域。
from datasets import interleave_datasets, load_dataset
from trl.experimental.async_distillation import AsyncDistillationConfig, AsyncDistillationTrainer
dataset = load_dataset("BytedTsinghua-SIA/Open-MOPD-Data", data_files="rl_prompt_mix/train.parquet", split="train")
dataset = dataset.select_columns(["prompt", "domain"]).rename_column("domain", "teacher_id").shuffle(seed=42)
# 约一半提示是指令遵循,所以按 40/40/20 采样数学、代码和 IF
dataset = interleave_datasets(
[dataset.filter(lambda row, d=domain: row["teacher_id"] == d) for domain in ("math", "code", "if")],
probabilities=[0.4, 0.4, 0.2],
seed=42,
)
config = AsyncDistillationConfig(
teacher_server_urls={
"math": "http://localhost:8001",
"code": "http://localhost:8002",
"if": "http://localhost:8003",
},
beta=1.0, # 对路由到的教师使用反向 KL
teacher_top_k=1, # beta=1.0 时只使用采样 token 的教师 logprob
max_completion_length=16384,
request_timeout=3600,
)
trainer = AsyncDistillationTrainer(
model="BytedTsinghua-SIA/Open-MOPD-SmolLM3-3B-MixSFT",
args=config,
train_dataset=dataset,
)
trainer.train()
使用反向 KL(beta=1.0)时,TRL 只使用学生采样到的那个 token 的教师概率,和 Nemotron 3 Ultra、MiMo-V2-Flash 一样,因此示例没有遵循 Open-MOPD 的 top-16 比较。teacher_top_k=1 可以让每个教师的响应保持很小。top-k 只在前向 KL(beta=0.0)下有意义,那时损失会比较教师最可能的 k 个 token,再加一个桶表示剩余概率质量。逐 token 比较教师和学生,也是每个教师都必须和学生共享 tokenizer 的原因。
完整脚本是 TRL examples 中的 async_distillation_mopd.py。
在 HF Jobs 上运行
MOPD 需要同时运行五个进程:一个学生的 vLLM 服务,它生成答案并在每一步后接收更新后的权重;每个教师一个 vLLM 服务(本例中有三个),它们只打分;以及训练进程。下面是我们如何用单机 4 张 H200 放下它们:
| GPU | 运行内容 |
|---|---|
| 0 | 学生的 vLLM 服务 |
| 1 | 数学和指令遵循教师,共享 GPU |
| 2 | 代码教师,单独占一张卡,因为代码 prompt 最长 |
| 3 | 训练 |
HF Jobs 上的一个 job 给你一个容器和一条命令,所以示例附带了 launcher.py,它会启动四个服务,等待它们响应,然后运行训练脚本。整个运行就是一条命令:
hf jobs uv run \
--flavor h200x4 \
--image huggingface/trl \
--secrets HF_TOKEN \
--timeout 6h \
https://raw.githubusercontent.com/huggingface/trl/main/examples/async_distillation_math/launcher.py
如果你在自己的机器上运行,从 launcher 中复制 vllm serve 命令。每个教师都会得到比学生更大的 --max-model-len,因为打分时会把学生的完整答案再加一个 token 发过去;共享一张 GPU 的两个教师会先后启动,因为 vLLM 会根据启动时空闲的显存来规划内存。
这个布局是我们测试过的,具体取决于你的硬件。例如有 8 张 GPU(h200x8)时,你可以给每个教师单独一张 GPU,用两张 GPU 跑学生的服务来加快生成,再用剩下的三张训练。
观察 token 不均衡
训练器会按教师记录指标,所以你能看到学生从每个教师那里学得如何。teacher_jsd/<id> 显示学生与每个教师的距离(越低越接近),teacher_token_frac/<id> 显示每个训练步中分给该教师的 token 占比。
teacher_token_frac 是最需要盯住的指标。损失是在 token 上平均的,所以每个领域的权重取决于它产生的 token 数,而不是它拥有的 prompt 数。数学或代码答案是一长串推理,有几千个 token。指令遵循答案,比如“写两段用星号分隔的文字”,只有几百个 token。因此指令遵循可以拥有 20% 的 prompt,却只拿到 1% 到 2% 的 token,学生几乎无法从该教师那里学到东西。Open-MOPD 作者发现了这一点,并在论文中深入解释,同时给出了修复方法。
我们用上面的设置做了一个短实验,检查 TRL 实现是否工作,以及这些指标是否能显示发生了什么。这是一次短运行,60 步,约为论文训练量的 1%。不均衡在最初几步就显现出来。指令遵循一开始有公平的 token 份额,但一旦数学和代码答案变长,它就掉到几个百分点。下图中,学生稳定地靠近数学和代码教师,而它与指令遵循教师的距离几乎不动。
TRL 在一次 60 步运行中记录的指标,使用 Open-MOPD 专家和 40/40/20 的 prompt 划分。上图:每个教师分到的训练 token 占比(teacher_token_frac/<id>),指令遵循有 20% 的 prompt,却只拿到 1% 到 3% 的 token。下图:与每个教师的散度(teacher_jsd/<id>,对原始值做 5 步移动平均),数学和代码在靠近它们的教师,指令遵循几乎不动。
这在评测中也能看出来。我们在 60 步后停止运行,用 Open-MOPD 的评测集和打分器评测它,并与起始 checkpoint 和论文最终模型(按完整配方训练,包括对这个不均衡的修复)放在一起比较:
| 模型 | AIME24 | AIME25 | IFEval |
|---|---|---|---|
| MixSFT(起点) | 17.5 | 19.2 | 67.5 |
| 本示例:用 TRL 做 MOPD,60 步 | 24.2 | 22.5 | 73.0 |
| Open-MOPD 最终模型(论文) | 19.2 | 25.0 | 75.8 |
AIME:每题 4 个样本;IFEval:严格的 prompt 级准确率。我们没有评测代码。
学生在 60 步内就在两个领域上都有提升,足以说明示例有效。数学上它达到了论文最终模型的水平(每题 4 个样本时,几个点的差异是噪声)。差距在指令遵循,也就是拿到 token 最少的领域。
checkpoint、包含本次运行所有指标的 Trackio dashboard,以及 Open-MOPD 的模型和数据都在这个 collection 里。
示例使用数学、代码和指令遵循,是因为这些是 Open-MOPD 发布的专家,但思路是你也可以接入自己的专家。如果你有自己关心领域的 RL 专家,并且它们从同一个基础模型训练而来、共享 tokenizer,你只需要用 vLLM 服务它们,并给每个 prompt 标上领域。之后你可以训练更久,或在数据中给指令遵循 prompt 更高权重,而按教师分的指标会告诉你是否有帮助。
要点
MOPD 让单个模型保留多个 RL 专家学到的东西,而不需要一次 RL 运行同时平衡所有领域。实验室已经在规模上使用它,借助一些实验室发布的专家、开放数据和 AsyncDistillationTrainer,你现在也可以自己尝试。如果想更进一步,AsyncDistillationTrainer 文档覆盖了其余选项和指标,DistillationTrainer 文档则覆盖同步版本。