feat: add paired DeepSeek routing length control

This commit is contained in:
wuyang
2026-07-29 16:17:18 +08:00
parent 059458f8e3
commit 9ca08501a8
15 changed files with 318874 additions and 69 deletions
@@ -0,0 +1,309 @@
# DeepSeek-V2-Lite 路由长度控制审计
> 状态:第三轮真实权重执行 / 同 prompt 嵌套前缀 / paired bootstrap
> 捕获时间:2026-07-29T07:41:00+00:00 至 07:43:00+00:00
> 证据身份:X(两组真实 forward)+ S(配对统计)
> 前置账本:`DEEPSEEK_ROUTING_CORPUS_AUDIT.md`
## 1. 为什么必须补这轮
第一版四域公开语料探针有意保留各来源的自然长度:
| 域 | 32 条 prompt 的有效 token |
| --- | ---: |
| 英文百科 | 2,882 |
| 中文新闻 | 573 |
| Python 代码 | 2,983 |
| 小学数学 | 2,022 |
虽然默认的 `prompt_balanced` 口径会先归一每条 prompt,再让每条 prompt 等权,
它仍不能消除以下混杂:
- 短 prompt 主要覆盖序列起点;
- 代码前缀常集中出现 `def`、函数名、类型和 docstring 开头;
- 长 prompt 让后续自然语言、变量与推理结构进入 router;
- position、共享前缀和内容范围会一起变化。
因此上一轮的“Layer 4 中文更集中”“Layer 5/6 数学更集中”只能先当描述事实,不能
直接解释成 domain semantics。
## 2. 为什么没有选择 32-token 对照
对四域全部候选用官方 DeepSeek-V2-Lite tokenizer 计算未截断长度:
| 域 | 候选 | ≥32 tokens | ≥48 tokens |
| --- | ---: | ---: | ---: |
| 英文百科 | 1,841 | 1,623 | 1,525 |
| 中文新闻 | 10,000 | **105** | **8** |
| Python 代码 | 164 | 164 | 162 |
| 小学数学 | 1,319 | 1,279 | 940 |
如果强行要求 32 tokens,中文域只能从 TNEWS 最长约 1% 的尾部取样。长度虽然相同,
“中文新闻”本身却会变成异常长标题/句子的特殊子群。
本轮选择 24 tokens 作为 eligibility threshold。TNEWS 仍有 1,609 条合格候选,
可以固定选出 32 条,同时保留足够的共同上下文。
## 3. 对照合同
### 3.1 同一批源 prompt
固定 salt:
```text
llm-atlas-deepseek-routing-length-control-v1
```
四域都先筛选 tokenizer 长度至少 24 的候选,再按:
```text
SHA256(salt | domain | source_id), then source_id
```
取前 32 条。
两档实验的 source ID、selection rank、原文 SHA-256、字符数和未截断 token 数完全一致。
唯一实验变化是模型实际看到的嵌套前缀:
```text
short: tokens [0:16]
long: tokens [0:24]
```
所以 16-token 输入严格是同一条 24-token 输入的前缀,而不是另选一批样本。
### 3.2 样本池
| 域 | 文本过滤后候选 | ≥24 tokens | 选中 | 选中原始长度 min / mean / max |
| --- | ---: | ---: | ---: | ---: |
| 英文百科 | 1,841 | 1,655 | 32 | 26 / 152.0 / 423 |
| 中文新闻 | 10,000 | 1,609 | 32 | 24 / 26.7 / 48 |
| Python 代码 | 164 | 164 | 32 | 43 / 152.9 / 325 |
| 小学数学 | 1,319 | 1,319 | 32 | 35 / 62.0 / 139 |
这仍不是四个来源的无偏随机样本。特别是中文只代表“至少 24 tokens 的 TNEWS 子群”。
它是长度控制 cohort,不应取代自然长度 cohort。
## 4. 真实执行量
模型、revision、第一 checkpoint shard、BF16、layer 0–6、batch size 16 与上一轮相同。
| cohort | prompt | tokens / prompt | 有效 token | routes / MoE layer | 6 层 routes |
| --- | ---: | ---: | ---: | ---: | ---: |
| matched-16 | 128 | 16 | 2,048 | 12,288 | 73,728 |
| matched-24 | 128 | 24 | 3,072 | 18,432 | 110,592 |
| 合计 | 256 次输入 | — | 5,120 | — | **184,320** |
加上自然长度 cohort 的 304,560 次,本专题目前累计保存 **488,880 次**真实
top-6 routed-expert 选择。
每条 prompt、每层继续满足:
```text
routes = valid_tokens × 6
```
padding positions 没有进入统计。
## 5. 为什么要做 paired bootstrap
分别看两档 95% 区间并不等于直接估计变化。因为两档使用相同 source prompts,最有效的
比较方式是:
1. 每个 domain 内生成一组 32 个有放回 prompt indices;
2. short 与 long 同时使用这组 indices;
3. 分别计算 metric;
4. 保存 `long - short`;
5. 重复 2,000 次,取 delta 的 2.5% 与 97.5% 分位点。
固定:
```text
replicates = 2000
seed = 20260729
resampling unit = source prompt
same sampled indices for short and long = true
```
这样 prompt 本身的难度/格式差异会在配对差中部分抵消。它仍不是随机分配实验,不能
外推到 cohort 之外。
## 6. 主要结果:延长前缀通常让路由更平
以下使用 `prompt_balanced`。表中是:
```text
CV(16 tokens) → CV(24 tokens), Δ = long - short [paired 95% CI]
```
### Layer 1
| 域 | CV 变化 |
| --- | ---: |
| 英文百科 | 0.841 → 0.699, **−0.142** [−0.176, −0.113] |
| 中文新闻 | 0.882 → 0.801, **−0.081** [−0.114, −0.050] |
| Python 代码 | 1.048 → 0.934, **−0.114** [−0.138, −0.092] |
| 小学数学 | 0.929 → 0.800, **−0.129** [−0.160, −0.100] |
### Layer 2
| 域 | CV 变化 |
| --- | ---: |
| 英文百科 | 0.610 → 0.527, **−0.084** [−0.116, −0.059] |
| 中文新闻 | 0.499 → 0.390, **−0.109** [−0.135, −0.081] |
| Python 代码 | 0.969 → 0.718, **−0.251** [−0.283, −0.215] |
| 小学数学 | 0.552 → 0.480, **−0.072** [−0.102, −0.051] |
### Layer 3
| 域 | CV 变化 |
| --- | ---: |
| 英文百科 | 0.542 → 0.513, −0.030 [−0.064, −0.005] |
| 中文新闻 | 0.520 → 0.462, **−0.059** [−0.092, −0.029] |
| Python 代码 | 0.989 → 0.862, **−0.127** [−0.164, −0.089] |
| 小学数学 | 0.593 → 0.536, **−0.057** [−0.097, −0.025] |
### Layer 4
| 域 | CV 变化 |
| --- | ---: |
| 英文百科 | 0.672 → 0.609, **−0.063** [−0.098, −0.033] |
| 中文新闻 | 0.995 → 0.898, **−0.097** [−0.124, −0.069] |
| Python 代码 | 1.135 → 0.979, **−0.156** [−0.201, −0.111] |
| 小学数学 | 0.663 → 0.594, **−0.070** [−0.108, −0.036] |
### Layer 5
| 域 | CV 变化 |
| --- | ---: |
| 英文百科 | 0.597 → 0.547, −0.050 [−0.085, −0.023] |
| 中文新闻 | 0.613 → 0.510, **−0.103** [−0.137, −0.068] |
| Python 代码 | 0.934 → 0.778, **−0.156** [−0.194, −0.119] |
| 小学数学 | 0.651 → 0.686, +0.035 [−0.016, +0.072] |
### Layer 6
| 域 | CV 变化 |
| --- | ---: |
| 英文百科 | 0.661 → 0.632, −0.028 [−0.059, −0.002] |
| 中文新闻 | 0.679 → 0.582, **−0.096** [−0.118, −0.072] |
| Python 代码 | 0.908 → 0.810, **−0.099** [−0.127, −0.071] |
| 小学数学 | 0.676 → 0.687, +0.011 [−0.038, +0.052] |
24 个 layer×domain 比较中:
- 22 个点估计为负;
- 20 个 paired 95% interval 完全低于 0;
- 只有 Layer 5/6 数学的点估计略为正,区间都跨 0。
最强变化是 Layer 2 代码:增加 8 个后续 tokens 后,CV 下降 0.251。一个合理但尚未
被因果证明的解释是,16-token 代码前缀共享更多 Python 函数签名/样板结构;继续读到
docstring 和任务内容后,路由分散到更多 experts。
正确语气是“固定 cohort 的短代码前缀更集中”,不是“代码越长一定越均衡”。
## 7. 中文↔代码距离没有消失,但随长度下降
在两档 matched cohort 中,六层最大的 JSD pair 都是中文新闻↔代码。
| layer | JSD@16 | JSD@24 | paired Δ | 95% CI |
| ---: | ---: | ---: | ---: | ---: |
| 1 | 0.0946 | 0.0787 | **−0.0158** | [−0.0259, −0.0088] |
| 2 | 0.0906 | 0.0650 | **−0.0256** | [−0.0359, −0.0182] |
| 3 | 0.1287 | 0.1106 | **−0.0182** | [−0.0289, −0.0093] |
| 4 | 0.1862 | 0.1584 | **−0.0278** | [−0.0390, −0.0195] |
| 5 | 0.1290 | 0.1118 | **−0.0172** | [−0.0279, −0.0090] |
| 6 | 0.1487 | 0.1363 | **−0.0124** | [−0.0240, −0.0040] |
这给出两个同时成立的事实:
1. 长度/前缀范围确实影响域间距离;从 16 延长到 24 后,六层距离都下降;
2. 长度控制没有抹掉中文↔代码差异;24-token 下六层仍为 0.065–0.158。
所以不能把上一轮差异全部归因于长度,也不能把剩余差异全部归因于语义。tokenizer、
字符集、代码格式、共享样板和内容都仍在一起变化。
## 8. 自然长度 cohort 应怎样重新解读
### Layer 4 中文集中仍然存在
自然长度中文 Layer 4 CV 为 0.910;matched-24 为 0.898。两个 cohort 的点估计接近,
说明“Layer 4 中文较集中”不是只在极短标题上才出现。
但两组 source prompts 不同,因此这个接近不能写成配对因果结论。
### Layer 5/6 数学集中对 cohort 很敏感
| layer | 自然长度数学 CV | matched-24 数学 CV |
| ---: | ---: | ---: |
| 5 | 0.848 | 0.686 |
| 6 | 0.770 | 0.687 |
自然长度与 matched cohort 同时改变了样本身份和截断位置,所以不能说“差值全部由长度
造成”。它足以发出一个敏感性警报:
> Layer 5/6 数学集中现象不应在没有更多长度分层和同样本长上下文实验前被当成稳定
> domain signature。
## 9. Total variation:新增 8 tokens 真的改变了分布
每域同层的 16/24 aggregate distributions 还计算:
```text
TV(P16, P24) = 1/2 Σ_e |P16(e) - P24(e)|
```
prompt-balanced 点估计范围约 0.049–0.116。代码域通常最大:
- Layer 2 code TV = 0.116;
- Layer 4 code TV = 0.114;
- Layer 6 code TV = 0.114。
这说明变化不只是 CV 公式的小幅抖动;约 10% 以上的 aggregate probability mass
需要在 expert IDs 之间重新分配,才能把短前缀分布变成长前缀分布。
TV 仍然不命名 expert,也不告诉我们输出质量。
## 10. 可复现性
真实 trace:
| 输出 | 完整 JSON SHA-256 | 独立重跑 |
| --- | --- | --- |
| matched-16 | `f8d437d5379ffb41ac8dca5a8e97c0f44ba10ce7b63f95d7be0b7c88ac0baebd` | byte-exact |
| matched-24 | `bed54835ad243ca2ab46bf9574e53137e6c2c0e19267f581719b5f2f65546436` | byte-exact |
配对比较:
```text
00bdc7fe3bffba564516d4cc76567b1144e0fcaa3b304eb80e7395be3dcf61a1
```
比较脚本独立执行两次,结果 byte-exact。它验证 short/long 的 source identity、
模型/语料 provenance、layer 顺序和 exact token contract 后才生成 delta。
入口:
- `experiments/deepseek/v2_lite_routing_corpus.py`
- `experiments/deepseek/compare_routing_length_control.py`
- `src/data/deepseek-v2-lite-routing-matched16.json`
- `src/data/deepseek-v2-lite-routing-matched24.json`
- `src/data/deepseek-v2-lite-routing-length-sensitivity.json`
## 11. 仍然不能说什么
- 不能把至少 24 tokens 的 TNEWS cohort 写成所有中文新闻;
- 不能把 matched-16/24 写成完整上下文行为;
- 不能把前缀长度的影响写成 position 的单独因果效应;
- 不能把中文↔代码 JSD 写成 expert specialization 的直接证明;
- 不能用 paired interval 冒充随机实验或线上总体区间;
- 不能把 CV 下降自动解释成模型“更好”;
- 不能把早期六个 MoE 层外推到完整 27 层。
## 12. 下一步
1. 下载并执行完整 layer 0–26,观察长度敏感性是否在中后层改变;
2. 在同一批长源文本上增加 32/48/64 token 嵌套前缀,但中文需要换成更适合长文本的公开语料;
3. 加入 tokenizer fragmentation、字符数和 unique-token ratio 协变量;
4. 对代码拆开 signature、docstring、body,不把格式位置与内容混为一谈;
5. 若要做总体推断,预注册 sample frame、主要指标和 permutation/null procedure。