完整答案蒸馏实战:Qwen3.8-Whittle-MoE-27B-A17.8B 的 teacher32 数据集如何教会大模型"何时该停笔"
Qwen3.8-Whittle-MoE-27B-A17.8B 是一个把 27B 稠密模型改造成混合专家(MoE)架构的开源模型,压缩之后它会陷入一种怪病:列表说到一半就开始"车轱辘话",反复复读同一个模板。这篇文章拆解它的完整答案蒸馏实战——用一份名为 teacher32 的数据集(245 条"写完了就停笔"的完整答案),把"何时该停"这个缺失的信号,通过 top-32 概率蒸馏灌回模型,最终把循环率从 69% 打到 8%,而且没有让模型"变哑"。
一、先认识怪病:MoE 压缩后为什么会"说个不停"
Whittle 的架构是一次"切割",而不是重建:父模型 Qwen3.8-27B 每一层宽 17408 的稠密 FFN,被切成 64 个宽 192 的 routed 专家薄片,加 1 个宽 5120 的常驻 shared 专家。算式是精确的——64×192 + 5120 = 17408,一个神经元都不新造。每个 token 只激活 64 选 16 的专家,于是 27B 总参数里只有 17.8B 真正在跑,量化后 24GB 显存就能推理。
代价是模型学会了重复。评测基线里,144 条生成有 93 条退化成列表尾部复读,循环率高达 65%(后固定为 69%)。而且它不是复读整句,而是复读模板,比如:
- Helping with financial planning
- Helping with health and wellness
- Helping with travel and tourism
- ……一直换尾巴词,前两个词永远一样
早期的 rep-4gram 指标对这种"换尾巴"的重复完全失明(直接打 0.000),这正是它反复骗过每一版模型的元凶:仪器根本没看见缺陷。诊断细节见 WHITTLE_FINDINGS.md。
二、诊断:如何看懂"重复与停止是同一个旋钮"
团队连跑了 5 轮训练,得到一个反直觉、但近乎同义反复的结论:重复,就是"不会停"。
看这张对照表(同一评测台、同一批种子):
| 轮次 | on-policy 数据 | EOS 是否保留 | 单轮循环率 |
|---|---|---|---|
| baseline | 无 | 保留 | 69% |
| B | 8× | 保留 | ~0%,但 6/16 被截断 |
| C | 2× | 全部屏蔽 | 90% |
| E | 接 B + 长文档 | 保留 | 2%,但答案被压到 7 个词 |
问题不在"要不要停",而在"何时停"。B 轮证明:教师模型在学生开始复读的那个位置,意见几乎都是"停",这个梯度最猛、最能治循环——可它同时把模型教成了"哪儿都早停"。反过来,把 EOS 全局屏蔽(C 轮),模型又彻底不会停,直接弹回 90%。
更关键的证据在推理端:直接给 EOS logit 加偏置,剂量-反应曲线显示,从"全循环"一路滑到"全沉默",中间根本不存在一个健康工作点。这说明"答案何时算写完"这个信息,压根不在权重里——缺的不是压力,是数据。完整推导见 WHITTLE_FINDINGS.md。
三、teacher32 数据集:245 条完整答案如何埋下停止信号
于是下一轮蒸馏的目标被钉死了:恰好蒸馏"因为写完而停止"这件事。这就是 teacher32 数据集(logic65/whittle-teacher32-complete-answers)的由来。
它由父模型(teacher)对同一批枚举提示词写出完整、正确的答案,并在每个 token 位置记录 top-32 概率,共 245 条,覆盖:
- 短到 7 个 token 的事实性答案,一句话就收
- 中长度解释
- 长到 4000 token 的结构化文档
- 带代码块的回答
- 多轮对话——因为实测的失败点就在第 5 轮之后
💡 设计上有个关键讲究:长度多样性不是装饰,而是解药。如果数据集里全是长答案,模型学到的会是"大概 300 词时停"这种长度先验,而不是"内容写完时停"。所以 teacher32 故意在每一个尺度上都埋了停止信号。
另有一个 r2-structured 子集,放 34 条最长 4.9k 的结构化范例,专门补 SQL / HTML / 表格这类重灾区。
数据集还刻意与评测 gate 完全不相交。早期版本里 12 条 gate 提示有 11 条混进了训练集,等于把考试卷塞进了教材。规则很朴素:在生成数据之前,先审计 train/test 重叠。设计全过程见 WHITTLE_FINDINGS.md。
四、蒸馏实战:把 top-32 概率灌回模型的 3 个工程坑
拿到数据后,真正的坑在"怎么算损失"上。
坑一:显存爆炸。248320 的词表,8k 序列的一次全宽 fp32 logits 就是多 GB 的张量,教师模型直接 OOM。解法是windowed pass:分块 prefill、把past_key_values带下去,边算边取 top-64。它之所以在这台混合 GDN 架构上成立,是因为线性注意力层只维持一个固定大小的循环状态,完整上下文能用一个窗口的激活代价保留。落地前先用单次完整前向对齐验证——top-1 一致率 1.0000、最大 log-prob 差 0.0000,才敢花一小时 A100。
坑二:损失函数不能是朴素的 KL。top-k 截断的 logit 需要一个解耦目标,拆成三项:
- 对"top-32 集合内总概率质量 vs 集合外"做 binary KL
- 对集合内部形状做 conditional KL
- 再用真实下一个 token 做 CE 锚定
三项若合并成一个 KL,会悄悄把模型教成"形状对了、但概率量放错了地方"。
坑三:别在循环位置保留 EOS 目标。on-policy 行的"停"是病灶的症状,不是要学的东西;可对干净长文档,EOS 又是唯一告诉"段落到此结束"的信号。所以掩码必须逐行选择:只在 on-policy 行屏蔽,在干净文档上保留。一刀切全局屏蔽,代价是一整轮训练才发现自己把停止能力全删了。三处细节见 WHITTLE_FINDINGS.md。
蒸馏完成后,学生侧的训练适配器落在 v2-adapter/,完整权重索引见 v2/model.safetensors.index.json。
五、蒸馏成果:循环率从 69% 降到 8%,且不"变哑"
固定同一台评测台、同一批提示和种子,历代版本对比如下(完整历史见 README.md):
| 指标 | 上一版 | v2 | v2.1 |
|---|---|---|---|
| 单轮循环率(12 提示×3 种子) | 69% | 11% | 8% |
| 多轮循环率 | 64% | 7% | 7% |
| 后期轮次(第 5 轮起) | 56% | 17% | 8% |
| 结构化输出循环率 | ~75% | 39% | 22% |
| 中位答案长度 | 268 词 | 386 词 | 388 词 |
| 静默 / 截断答案 | 未测 | 0 | 0 |
| 知识测试 | 28/39 | 27/39 | 28/39 |
三个数字值得圈出来:
- 📊中位长度没掉,反升到 388 词——说明模型学会了"该长就长",而不是靠早停来假装不循环
- 静默 / 截断为 0——这是上一轮反复踩的坑,现在被守住了
- 知识 28/39 打平基线——修复停止没有伤害既有知识
诚实地说,它没变完美:结构化输出(SQL / HTML / 表格)仍有约 1/5 会退化,45+ 项的长列表精确计数仍是架构层面的深度短板。这些限制在 README.md 里都白纸黑字写明了。
六、可复现的评测门槛:别只测你要修的那个缺陷
每个版本的发布都要过 loop_test.py——它就是模型卡上所有循环率的生成器,任何人可复现或质疑。一条生成被判 FAILED,只要触发以下任一:
- 4-gram 重复 > 0.15
- 重复整行 > 0.20
- 重复行首 > 0.40
- 或答案低于字数底线
最后那条"字数底线"是全篇最容易漏的一课:只测重复率的 gate,会被一个只回"好的。"的模型轻松通过——所有重复指标对一句空话都打 0.000。所以每个 gate 至少要有一个"过度修复反而会变差"的指标(这里就是长度底线),否则优化器(无论人或机器)总会找到退化解。12 条单轮、6 条结构化、2 段共 14 轮对话的完整判定逻辑见 loop_test.py。
七、复刻指南:6 条把"何时停笔"教给大模型的经验清单
- 数据先于算力:先用小窗口对齐验证教师采集是否正确(top-1 一致率、log-prob 差),再烧 A100。
- 生成数据前先审计 train/test 重叠,gate 冻结,训练集与之完全不相交。
- 数据集要覆盖"每个尺度都有停止信号",避免只教出长度先验。
- 每个 gate 配一个防过度修复的指标(长度底线),并手工抽查,别信单一汇总数。
- EOS 掩码要逐行条件化,不是一刀切删除。
- 完整的方法、失败日志与脚本都公开在 WHITTLE_FINDINGS.md 与 ROADMAP.md,训练计划见 ROADMAP.md。
结语
teacher32 做的事情可以浓缩成一句话:用 245 条"写完了就停笔"的完整答案,把"何时该停"这个缺失的信号,从教师模型的 top-32 概率里蒸馏回学生。它证明了:对压缩后的 MoE,缺失的往往不是知识、也不是算力,而是"答案何时算完整"这最后一点信息。
相关权重与配置,方便你按图索骥:
- 根目录当前发布权重:model.safetensors.index.json
- v2.2 停止门(64 个
shared_expert_gate张量):v2.2/shared_expert_gate.safetensors - 架构定义(64 专家 / 每 token 激活 16 / 中间维 17408):config.json
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考