Files
llm-atlas/research/DEEPSEEK_ROUTING_HISTORY_DISTANCE_CONTROL_AUDIT.md
T

679 lines
19 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# DeepSeek-V2-Lite 消息历史距离控制审计
> 状态:真实官方权重执行(X)<br />
> 模型:`deepseek-ai/DeepSeek-V2-Lite`<br />
> revision:`604d5664dddd88a0433dbae533b7fe9472482de0`<br />
> 执行边界:layer 0–6;观测 MoE layer 1–6<br />
> 样本:WikiText-2 / TNEWS / HumanEval / GSM8K 各 32 条<br />
> 正式运行与独立复跑:byte-exact<br />
> 完整 JSON SHA-256:`423a095d92738d4bc6c2ace2afa9b35627e61811458c7883dca7b44aee4e648e`
## 0. 一句话先说结论
上一轮发现:
> system 后面先经过一轮 one-shot 历史,再到目标 user 时,<br />
> system 对目标 token 专家路由的影响明显变小。
但那轮把五件事绑在一起:
1. system 离目标更远;
2. 中间多了一段文本;
3. 多了一次 user → assistant 角色转换;
4. 多了 assistant EOS;
5. 中间文本恰好是一个可读示例。
本轮加入一个**重复词元 filler 历史**:
```text
User: x x x x x x x x x
Assistant: x + EOS
```
它与原 one-shot 在官方模板中都精确增加 17 tokens,并保持完全相同的:
- user / assistant 角色;
- assistant EOS;
- 目标 user 的绝对 token 位置;
- generation prompt;
- padded batch 形状。
目标内容上的 system-edge TV 均值变为:
```text
无历史 filler 历史 原 one-shot
0.0738 → 0.0378 → 0.0188
```
而且两个台阶都在 **24 / 24 个 layer × domain** 中下降,
各自的 source-paired 95% 区间也都是 **24 / 24 完全低于零**。
最稳妥的解释是:
> 在这组固定协议中,不需要一个可读的正确示例,
> 仅加入等长的重复词元历史就能复现约一半的 system-edge 缓冲;
> 换回原 one-shot 文本后还会再下降约一半。
这仍然不是“纯距离因果效应”:
- filler token 本身不是空气;
- filler 仍然改变了历史长度与隐藏状态;
- 原 one-shot 与 filler 的词元身份不同;
- 本轮没有生成答案,也没有测能力。
## 1. 为什么不是直接说“few-shot 让路由稳定”
“few-shot 让路由稳定”至少混合了三个问题:
1. **结构问题**:前面是否已有一个完成的 user / assistant turn?
2. **位置问题**:system 离目标有多远?
3. **内容问题**:中间那轮到底说了什么?
如果只比较:
```text
system → target
system → demo → target
```
看到差异后无法知道是哪一项造成的。
本轮不是一步解决所有问题,而是插入一个中间台阶:
```text
无历史 → 等长 filler → 原 one-shot
```
这样至少可以问:
- 没有可读示例时,历史结构是否已经足以产生缓冲?
- 在长度、角色、EOS 与位置相同时,替换具体文本还有多少额外变化?
## 2. 六格实验是什么
两个因子:
- `S`:system message 是否存在;
- `H`:历史为 none / filler / demo。
| 条件 | system | 历史 | 官方模板结构 |
|---|---:|---|---|
| `S0 / NONE` | 0 | none | target user → `Assistant:` |
| `S1 / NONE` | 1 | none | system → target user → `Assistant:` |
| `S0 / FILLER` | 0 | filler | repeated-token user → assistant + EOS → target |
| `S1 / FILLER` | 1 | filler | system → repeated-token turn → target |
| `S0 / DEMO` | 0 | demo | fixed demo user → assistant + EOS → target |
| `S1 / DEMO` | 1 | demo | system → fixed demo turn → target |
固定文本:
```text
system
Answer accurately and concisely. 请准确、简洁地回答。
demo user
Reply with OK. 只回复 OK。
demo assistant
OK
filler user
x x x x x x x x x
filler assistant
x
```
六格全部使用:
```python
tokenizer.apply_chat_template(
messages,
tokenize=True,
add_generation_prompt=True,
)
```
没有手写一个“看起来像官方”的模板。
## 3. “等长”到底等在哪里
128 条 source 上,逐条验证:
| 对比 | 每条 token 增量 | min | max | 是否全部相等 |
|---|---:|---:|---:|---|
| S0 filler − S0 none | +17 | 17 | 17 | 是 |
| S0 demo − S0 none | +17 | 17 | 17 | 是 |
| S1 filler − S1 none | +17 | 17 | 17 | 是 |
| S1 demo − S1 none | +17 | 17 | 17 | 是 |
system 也继续保持上一轮的正交增量:
```text
S1 − S0 = 每条 +16 tokens
```
因此:
- filler 与 demo 的目标位置相同;
- filler 与 demo 的角色前缀数量相同;
- filler 与 demo 都有一个 assistant EOS;
- 两者差别集中在 history content token identity。
### 3.1 为什么不叫“无语义 filler”
`x` 是一个真实、经过训练的 token。
九个 `x` 也可能触发:
- 重复模式检测;
- induction-like matching;
- 特定 token embedding;
- 特定 attention / MoE 路由。
所以这里使用:
> **低信息重复词元 filler**
而不使用:
> “无语义”“空白上下文”“纯距离”
## 4. 样本与上一轮完全一致
继续复用:
| 领域 | 数据 | 条数 | 输入字段 |
|---|---|---:|---|
| 英文百科 | WikiText-2 raw validation | 32 | `text` |
| 中文新闻 | CLUE TNEWS public test | 32 | `sentence` |
| Python 代码 | OpenAI HumanEval | 32 | `prompt` |
| 小学数学 | OpenAI GSM8K test | 32 | `question` |
固定:
- 相同 source IDs;
- 相同 source text SHA-256;
- 相同 canonical content SHA-256;
- 相同 23-token canonical prefix;
- 相同 sample salt;
- 答案不输入;
- 代码不执行。
本轮 128 个 `(source ID, content SHA-256)` 与模板实验、2×2 历史实验
逐项一致。
## 5. 执行账本
| 项目 | 数值 |
|---|---:|
| source prompts | 128 |
| 六格输入变体 | 768 |
| 输入 tokens | 38,236 |
| 六格共同目标交集 | 每格 2,874 |
| 执行层 | layer 0–6 |
| 观测 MoE 层 | layer 1–6 |
| 每 token routed experts | 6 |
| 新增真实 top-6 路由 | 1,376,496 |
| 公开语料累计真实路由 | 3,112,848 |
| bootstrap | 每域 2,000 次 |
分条件:
| 条件 | 输入 tokens | 六层真实路由 |
|---|---:|---:|
| S0 none | 3,898 | 140,328 |
| S1 none | 5,946 | 214,056 |
| S0 filler | 6,074 | 218,664 |
| S1 filler | 8,122 | 292,392 |
| S0 demo | 6,074 | 218,664 |
| S1 demo | 8,122 | 292,392 |
注意:路由次数等于真实输入 tokens × 6 experts × 6 MoE layers,
不是模型参数量,也不是训练 token 数。
## 6. 为什么仍然要精确对齐目标 token
不同历史会改变目标前面的文本,进而可能改变:
- 目标第一个 token 的边界切分;
- wrapper token 数量;
- token 的绝对位置。
本轮继续用三元组:
```text
(相对目标字符跨度 start, end, token ID)
```
只有六个条件都存在的三元组才进入 `target_content`。
结果:
```text
S0 none 2,874
S1 none 2,874
S0 filler 2,874
S1 filler 2,874
S0 demo 2,874
S1 demo 2,874
```
因此目标内容比较没有混入:
- `User:`;
- `Assistant:`;
- system;
- filler / demo;
- EOS;
- 边界重切分 token。
## 7. 统计单位与三个 system edges
对每个历史水平 \(h\),定义:
```text
p(0,h) = system 关闭时的 64-expert route-share
p(1,h) = system 开启时的 64-expert route-share
```
system edge 的标准 Total Variation:
\[
TV_h = \frac{1}{2}\lVert p(1,h)-p(0,h)\rVert_1
\]
三个真实边:
```text
TV_none
TV_filler
TV_demo
```
再比较:
```text
filler − none
demo − none
demo − filler
```
每个 domain / layer / scope / aggregation 内:
1. 以 source prompt 为单位有放回重采样;
2. 2,000 次;
3. 六格共用同一组 sampled source indices;
4. 先同时重建六格分布;
5. 再计算三条 system edge 与 edge 差。
因此 token 没有被伪装成独立样本。
## 8. 主结果:两个台阶都是 24 / 24
以下均为:
```text
target_content / prompt_balanced
```
| 层 | 域 | none TV | filler TV | demo TV | filler−none 95% CI | demo−filler 95% CI |
|---:|---|---:|---:|---:|---|---|
| 1 | 英文 | .1055 | .0559 | .0236 | -.0496 [-.0565,-.0406] | -.0323 [-.0402,-.0274] |
| 1 | 中文 | .0778 | .0276 | .0166 | -.0501 [-.0600,-.0410] | -.0111 [-.0161,-.0063] |
| 1 | 代码 | .1123 | .0571 | .0243 | -.0552 [-.0623,-.0480] | -.0328 [-.0397,-.0272] |
| 1 | 数学 | .1328 | .0791 | .0250 | -.0537 [-.0632,-.0457] | -.0541 [-.0638,-.0428] |
| 2 | 英文 | .0621 | .0300 | .0153 | -.0321 [-.0395,-.0244] | -.0147 [-.0211,-.0087] |
| 2 | 中文 | .0420 | .0204 | .0145 | -.0216 [-.0286,-.0172] | -.0059 [-.0104,-.0026] |
| 2 | 代码 | .0586 | .0329 | .0166 | -.0257 [-.0322,-.0197] | -.0163 [-.0209,-.0099] |
| 2 | 数学 | .0734 | .0399 | .0195 | -.0335 [-.0420,-.0246] | -.0204 [-.0276,-.0152] |
| 3 | 英文 | .0574 | .0317 | .0184 | -.0257 [-.0342,-.0191] | -.0133 [-.0204,-.0080] |
| 3 | 中文 | .0351 | .0220 | .0131 | -.0131 [-.0212,-.0079] | -.0089 [-.0143,-.0053] |
| 3 | 代码 | .0654 | .0398 | .0130 | -.0256 [-.0331,-.0187] | -.0267 [-.0315,-.0220] |
| 3 | 数学 | .0485 | .0345 | .0164 | -.0140 [-.0233,-.0094] | -.0181 [-.0225,-.0133] |
| 4 | 英文 | .0834 | .0338 | .0198 | -.0496 [-.0591,-.0432] | -.0139 [-.0211,-.0073] |
| 4 | 中文 | .0714 | .0286 | .0150 | -.0428 [-.0539,-.0353] | -.0136 [-.0186,-.0082] |
| 4 | 代码 | .0750 | .0445 | .0148 | -.0305 [-.0381,-.0242] | -.0297 [-.0349,-.0241] |
| 4 | 数学 | .1079 | .0511 | .0232 | -.0569 [-.0672,-.0473] | -.0279 [-.0345,-.0229] |
| 5 | 英文 | .0666 | .0338 | .0222 | -.0328 [-.0420,-.0220] | -.0116 [-.0218,-.0062] |
| 5 | 中文 | .0520 | .0269 | .0161 | -.0250 [-.0364,-.0182] | -.0108 [-.0156,-.0061] |
| 5 | 代码 | .0549 | .0386 | .0184 | -.0163 [-.0233,-.0104] | -.0202 [-.0249,-.0161] |
| 5 | 数学 | .0728 | .0449 | .0229 | -.0279 [-.0376,-.0192] | -.0221 [-.0313,-.0162] |
| 6 | 英文 | .0761 | .0312 | .0208 | -.0449 [-.0542,-.0373] | -.0104 [-.0160,-.0036] |
| 6 | 中文 | .0578 | .0256 | .0181 | -.0322 [-.0432,-.0247] | -.0074 [-.0131,-.0038] |
| 6 | 代码 | .0731 | .0343 | .0164 | -.0388 [-.0489,-.0292] | -.0179 [-.0244,-.0131] |
| 6 | 数学 | .1093 | .0422 | .0270 | -.0671 [-.0768,-.0562] | -.0153 [-.0227,-.0083] |
汇总:
| 问题 | 点估计下降 | 95% 区间完全低于零 |
|---|---:|---:|
| filler 是否小于 none | 24 / 24 | 24 / 24 |
| demo 是否小于 filler | 24 / 24 | 24 / 24 |
均值:
```text
none .0738
filler .0378 相对 none 约下降 49%
demo .0188 相对 filler 约再下降 50%
相对 none 约下降 75%
```
这不是 24 个独立总体显著性检验,也没有多重比较校正。
它是固定 cohort 上 24 个分层描述区间。
## 9. 六层都出现相同阶梯
四域平均:
| 层 | none | filler | demo |
|---:|---:|---:|---:|
| 1 | .1071 | .0549 | .0224 |
| 2 | .0590 | .0308 | .0165 |
| 3 | .0516 | .0320 | .0152 |
| 4 | .0844 | .0395 | .0182 |
| 5 | .0616 | .0361 | .0199 |
| 6 | .0791 | .0333 | .0206 |
四域分别跨层平均:
| 域 | none | filler | demo |
|---|---:|---:|---:|
| 英文 | .0752 | .0361 | .0200 |
| 中文 | .0560 | .0252 | .0156 |
| 代码 | .0732 | .0412 | .0173 |
| 数学 | .0908 | .0486 | .0223 |
不能据此给 expert 命名,也不能推出数学“更依赖”某个专家。
## 10. 逐 token 路由集合也同向
下表把 128 条 prompt 的精确对齐目标 token 汇总。
每格:
```text
top-6 set exact / mean Jaccard
```
| 层 | system / none | system / filler | system / demo |
|---:|---|---|---|
| 1 | .316 / .756 | .565 / .864 | .790 / .939 |
| 2 | .459 / .820 | .693 / .904 | .815 / .946 |
| 3 | .479 / .831 | .683 / .901 | .826 / .950 |
| 4 | .390 / .784 | .674 / .894 | .800 / .942 |
| 5 | .438 / .799 | .657 / .887 | .789 / .939 |
| 6 | .387 / .770 | .645 / .886 | .769 / .932 |
也就是说,aggregate route-share TV 的下降不是只有汇总分布看得到;
同一个目标 token 的 top-6 expert 集合也逐级更相似。
但“路由集合更相似”仍不等于“答案更好”。
## 11. 固定长度后,具体文本仍然重要
filler → demo 只替换 history content,角色、EOS、长度和目标位置不变。
目标内容上的平均 filler↔demo TV:
```text
system 关闭:.0357
system 开启:.0145
```
在 24 / 24 个 layer × domain 中:
```text
system 开启时的 filler↔demo TV < system 关闭时
```
这显示的是一个双向交互模式:
- history 类型改变 system edge;
- system 的存在也改变 filler / demo 之间的距离。
它不证明:
- 正确示例比错误示例好;
- model 理解了 `Reply with OK`;
- system 与 demo 在功能上互相替代;
- 路由距离与任务性能单调相关。
## 12. 为什么 CV 没有 24 / 24
TV 衡量整个 64-expert 分布的距离。
CV 只把分布压成一个“负载离散程度”标量:
- 分布可以大幅重排,但 CV 几乎不变;
- 分布可以朝不同 expert 移动,CV 方向相反;
- 两个分布 TV 很小,也可能跨过 CV 的局部斜率。
绝对 system-edge CV 变化:
| 对比 | \|CV edge\| 下降 |
|---|---:|
| none → filler | 18 / 24 |
| filler → demo | 19 / 24 |
CV edge contrast 的区间方向也不统一:
| 对比 | 完全负 | 完全正 | 跨零 |
|---|---:|---:|---:|
| filler − none | 4 | 9 | 11 |
| demo − filler | 8 | 4 | 12 |
所以本轮主结论严格写成:
> **system-edge route-distribution TV 下降**
而不是:
> “专家负载一定更均衡”
## 13. 完整输入与目标内容必须分开
目标内容:
```text
none .0738 → filler .0378 → demo .0188
24/24 → 24/24
```
完整输入:
```text
none .1582 → filler .1390 → demo .1131
20/24 → 23/24
```
完整输入还把以下 token 计入:
- system;
- filler / demo;
- `User:`;
- `Assistant:`;
- EOS;
- generation prompt。
它回答的是:
> 整个协议流量的 route-share 如何变化?
目标内容回答的是:
> 同一段目标文本在不同历史下如何被条件化?
两者不能互相替代。
## 14. BF16 batch shape 是一个真实边界
新六格中,旧四格的输入合同仍可与上一轮逐项核对:
```text
512 / 512 token-ID SHA-256 exact
```
但上一轮每批:
```text
8 sources × 4 variants = 32 rows
```
本轮每批:
```text
5 sources × 6 variants = 30 rows
```
虽然相同条件的 token IDs 完全一致,BF16 layer forward 的矩阵形状不同。
跨两次实验比较:
```text
1,062 / 3,072 prompt-layer-condition route hashes exact
1,414 / 3,072 integer load-vector pairs exact
```
Layer 1 仍有:
```text
481 / 512 route hashes exact
```
但细小 BF16 差异向深层传播后,整段 hash 很容易不再相同。
这意味着:
1. 相同 token IDs 不保证不同 batch shape 下所有临界 top-k gate 完全相同;
2. 本轮不能把旧实验与新实验的点估计差异全部解释为文本处理;
3. 本轮正式对比只使用**同一次六格运行内部**的条件;
4. 六格在每个 source 内进入同一 padded batch;
5. 正式运行自身的独立复跑仍然 byte-exact。
这是为什么“可复现”不仅要固定 seed,还要记录 batch contract。
## 15. 与已有论文的关系
### 15.1 demonstration 的作用不只是真实标签
[Min et al., EMNLP 2022](https://aclanthology.org/2022.emnlp-main.759/)
在一组分类与多选 ICL 实验中发现,label correctness 并非所有收益的唯一来源,
输入分布、label space 与 sequence format 也会贡献表现。
本轮与其问题意识相近:
> 把“示例内容”与“示例格式 / 历史结构”分开。
但本轮只测 DeepSeek-V2-Lite 的局部 MoE 路由,不复现其任务性能结论。
### 15.2 重复结构可能被模型机制利用
[Olsson et al., 2022](https://arxiv.org/abs/2209.11895)
讨论 induction heads 与序列内重复模式的关系;其在小型 attention-only 模型中提供
强因果证据,在更大含 MLP 模型中主要是相关证据。
因此九个重复 `x` 不能被当作“什么都没有”。
它恰好可能是一种很强的结构信号。
### 15.3 位置会影响模型如何使用上下文
[Liu et al., TACL 2024](https://aclanthology.org/2024.tacl-1.9/)
展示了长上下文任务中的位置敏感性。
本轮只移动 17 个模板 tokens,且没有任务输出,
不能直接套用“lost in the middle”结论;它只说明位置 / 历史距离值得单独控制。
### 15.4 irrelevant context 可能改变行为
[Shi et al., ICML 2023](https://proceedings.mlr.press/v202/shi23a.html)
研究了无关上下文对任务表现的干扰。
本轮没有测答案,因此 filler 导致路由变化不等于 distractor 导致能力下降。
## 16. 独立复跑
正式结果:
```text
src/data/deepseek-v2-lite-routing-history-distance-control.json
```
独立复跑:
```text
src/data/deepseek-v2-lite-routing-history-distance-control-repro.json
```
两者:
```text
42,885,795 bytes
SHA-256
423a095d92738d4bc6c2ace2afa9b35627e61811458c7883dca7b44aee4e648e
```
脚本:
```text
experiments/deepseek/v2_lite_routing_history_distance_control.py
```
关键执行参数:
```bash
python -B experiments/deepseek/v2_lite_routing_history_distance_control.py \
--artifact-dir /path/to/deepseek-v2-lite \
--human-eval /path/to/HumanEval.jsonl.gz \
--gsm8k /path/to/gsm8k/test.jsonl \
--tnews /path/to/tnews/test.json \
--tnews-archive /path/to/tnews_public.zip \
--wikitext /path/to/wikitext-validation.parquet \
--output src/data/deepseek-v2-lite-routing-history-distance-control.json \
--per-domain 32 \
--content-tokens 23 \
--batch-prompts 5 \
--layers 7 \
--bootstrap 2000 \
--seed 20260729 \
--captured-at 2026-07-29T10:17:00+00:00
```
## 17. 现在能说什么
- filler 与 demo 在官方模板下精确等长;
- 两者拥有相同角色、EOS 与目标位置;
- 重复词元 filler 已复现明显的 system-edge TV 缓冲;
- 从 filler 换为原 one-shot 后,system-edge TV 还会继续下降;
- 两个下降在 24 / 24 个 layer × domain 中同向;
- 逐 token top-6 set / Jaccard 与 aggregate TV 同向;
- 六格正式运行可以独立 byte-exact 复跑;
- batch shape 会影响深层临界 gate identity,必须记录。
## 18. 现在不能说什么
- filler 是无语义的;
- 本轮已经隔离纯距离效应;
- 原 one-shot 的“正确性”造成额外下降;
- 更小的 route TV 代表更好的答案;
- 更稳定的 expert set 代表更强能力;
- CV 一定下降或负载一定更均衡;
- 结果代表完整 27 层;
- 结果代表线上多轮对话;
- 24 个区间是多重校正后的总体显著性结论。
## 19. 下一步
1. **EOS 控制**:尽可能固定可见 token 文本,只切换 assistant EOS / turn closure;
2. **角色控制**:相同 token 序列放入 user / assistant / system 的不同角色;
3. **内容控制**:固定长度,比较正确、无关、冲突与重复示例;
4. **多 filler 控制**:使用多个 token identity 与随机种子,避免把 `x` 当作总体;
5. **batch-shape 控制**:固定矩阵形状并加入显式 dummy-row contract;
6. **行为联结**:生成答案,用独立任务指标检查 route TV 与能力是否相关;
7. **完整模型**:获得其余 shards 后扩展到全部 27 层。
在这些控制完成之前,本轮结论保持为:
> 固定 DeepSeek-V2-Lite、固定公开 cohort、固定官方模板与固定六格 batch 下的
> **消息历史结构 / 文本替换路由实证**。