feat: trace DeepSeek V2-Lite real routes
This commit is contained in:
@@ -0,0 +1,340 @@
|
||||
# DeepSeek-V2-Lite 真实权重执行审计
|
||||
|
||||
> 状态:DeepSeek 专题第三轮工件;2026-07-29
|
||||
> 目的:把“MLA 会压缩缓存”“MoE 会选择专家”从论文概念推进到固定官方权重、真实 tokenizer、真实 hidden states 和逐 token 路由记录。
|
||||
> 边界:这不是完整模型 benchmark、训练 trace、生产服务复现、专家语义分析或总体负载估计。
|
||||
|
||||
## 0. 一页结论
|
||||
|
||||
这次实验固定官方 `deepseek-ai/DeepSeek-V2-Lite` revision
|
||||
`604d5664dddd88a0433dbae533b7fe9472482de0`,使用官方 tokenizer、配置、模型代码和
|
||||
BF16 checkpoint 第一分片,在 RTX 5090 上依次执行 embedding 与 decoder layer 0–6。
|
||||
第 0 层是 dense FFN,第 1–6 层是完整 MoE 层;第 7 层横跨第一、第二分片,因此明确停止。
|
||||
|
||||
四条最重要的结果:
|
||||
|
||||
1. 4 条人工固定 prompt 共 90 个有效 token,在 6 个 MoE 层产生
|
||||
`6 layers × 90 tokens × top-6 = 3,240` 次真实 routed-expert 选择。
|
||||
2. 每个执行层都实际观测到 MLA 的 `[B,T,576]` 压缩投影;其中 512 是
|
||||
KV latent,64 是 decoupled RoPE key。
|
||||
3. 官方 Hugging Face eager 实现仍把 cache 物化为
|
||||
key `[4,16,27,192]` 和 value `[4,16,27,128]`。以 BF16 计,
|
||||
每 token、每层是 10,240 bytes;按配置保存 latent + RoPE key 只需 1,152 bytes,
|
||||
相差 `8.8889×`,后者相对前者减少 `88.75%`。
|
||||
4. 两次独立执行的来源、配置、tokenization、hidden-state hashes、MLA shapes、
|
||||
aggregate loads 与全部 token routes 共 `31/31` 项完全一致;计时明确不参与一致性检查。
|
||||
|
||||
这里最反直觉的发现不是某个“神奇专家”,而是:
|
||||
|
||||
- **覆盖不等于均衡。** 90 个 token 在单层可触达 60–64/64 个专家,但各层
|
||||
CV 为 0.549–0.925,Gini 为 0.303–0.420。
|
||||
- **路由 ID 不等于语义标签。** `E8` 只表示某一层内部数组的第 8 号专家;跨层的
|
||||
`E8` 是不同参数,四条 prompt 也不足以赋予“代码专家”等语义。
|
||||
- **算法压缩不等于实现已经压缩存储。** MLA 的低秩状态合同与 HF eager cache
|
||||
的实际物化格式是两张账,必须同时报告。
|
||||
|
||||
## 1. 证据身份
|
||||
|
||||
### 1.1 官方工件
|
||||
|
||||
| 工件 | 固定值 |
|
||||
|---|---|
|
||||
| Hugging Face model | `deepseek-ai/DeepSeek-V2-Lite` |
|
||||
| revision | `604d5664dddd88a0433dbae533b7fe9472482de0` |
|
||||
| checkpoint tensor bytes | `31,412,968,448`,约 29.261 GiB |
|
||||
| shard 1 bytes | `8,594,887,408`,约 8.005 GiB |
|
||||
| config SHA-256 | `f346286b0f1c8b044252fd54cb4fa78b9fab6472a6e8bebb9edfe03d414ea03d` |
|
||||
| modeling code SHA-256 | `7d8e5221095286eea991137760893fd7ba52727c0b4ebf48ec09e8bc56b45b9c` |
|
||||
| tokenizer SHA-256 | `41f3bf64213da8c012d8bd0871a58a1fdf70463e8f08f110ddbb1082f529f669` |
|
||||
| index SHA-256 | `d2cdb2f325f6682cf3ad1ad2526a9f979d857390b579380c0331d975136e0acf` |
|
||||
| shard 1 SHA-256 | `0d7e9f39bde40111a4c0f390b87497dce4565cf578d916395e6b2c7851f1e8da` |
|
||||
|
||||
第一分片完整容纳 embedding、layer 0–6 和 layer 7 的一部分。为了不把缺参数的
|
||||
layer 7 冒充完整执行,本实验把证据边界钉在 layer 6。
|
||||
|
||||
原始 checkpoint 分片不进入 Git;仓库只提交:
|
||||
|
||||
- 可复现执行脚本;
|
||||
- 机器可读 trace;
|
||||
- 独立复跑比较结果;
|
||||
- 研究审计与网页可视化。
|
||||
|
||||
### 1.2 模型配置
|
||||
|
||||
| 对象 | 官方配置 |
|
||||
|---|---:|
|
||||
| reported total / active | 15.7B / 2.4B |
|
||||
| decoder layers | 27 |
|
||||
| hidden size | 2048 |
|
||||
| attention heads | 16 |
|
||||
| qk NoPE / RoPE head dim | 128 / 64 |
|
||||
| value head dim | 128 |
|
||||
| KV LoRA rank | 512 |
|
||||
| routed experts / active | 64 / 6 |
|
||||
| shared experts | 2 |
|
||||
| expert intermediate | 1408 |
|
||||
| dense prefix | 1 layer |
|
||||
| router | softmax + greedy top-k |
|
||||
| selected top-k normalization | false |
|
||||
|
||||
`max_position_embeddings=163840` 与 YaRN 配置属于 checkpoint config;
|
||||
官方发布表中的上下文口径不应被本实验自行改写成同一个数字。
|
||||
|
||||
### 1.3 软件与硬件
|
||||
|
||||
| 对象 | 值 |
|
||||
|---|---|
|
||||
| GPU | NVIDIA GeForce RTX 5090,32,607 MiB |
|
||||
| driver | 595.84 |
|
||||
| Python | 3.10.14 |
|
||||
| PyTorch | 2.11.0+cu128 |
|
||||
| CUDA runtime | 12.8 |
|
||||
| Transformers | 4.41.2 |
|
||||
| safetensors | 0.8.0 |
|
||||
| TF32 matmul | disabled |
|
||||
|
||||
官方 2024 remote code 在当前 Transformers 5.5 环境中会因已移除的
|
||||
`is_torch_fx_available` 入口而导入失败。因此实验使用隔离的 Transformers 4.41.2。
|
||||
模型源码保持只读、不打补丁;runner 只通过本地 package 方式导入官方
|
||||
`configuration_deepseek.py` 与 `modeling_deepseek.py`。
|
||||
|
||||
这条版本边界很重要:**“模型代码公开”不等于“任意未来依赖版本都可直接运行”。**
|
||||
|
||||
## 2. 实验设计
|
||||
|
||||
### 2.1 为什么选择截断的精确 forward
|
||||
|
||||
完整 15.7B BF16 权重与运行时状态虽然可能勉强接近单卡边界,但没有必要为了观察
|
||||
前六层真实路由而把“全模型能否高效生成”混进同一实验。本 runner:
|
||||
|
||||
1. 用官方 tokenizer 一次编码 4 条 prompt;
|
||||
2. 从第一分片读取官方 embedding;
|
||||
3. 每次在 meta device 构造一个官方 decoder layer;
|
||||
4. 为这一层绑定真实 safetensors 参数并传到 GPU;
|
||||
5. 用上层输出作为下一层输入;
|
||||
6. 通过 hook 捕获实际 `kv_a_proj_with_mqa` 与实际 MoE gate 输出;
|
||||
7. 释放当前层,再加载下一层。
|
||||
|
||||
因此得到的是**真实权重、真实层类、真实连续 hidden states**,而不是随机初始化、
|
||||
只读 config 或合成 router;但它仍不是完整 27 层生成。
|
||||
|
||||
### 2.2 固定 prompt
|
||||
|
||||
| ID | 标签 | token |
|
||||
|---|---|---:|
|
||||
| `zh_explanation` | 中文解释 | 26 |
|
||||
| `en_architecture` | English architecture | 18 |
|
||||
| `code` | Python code | 19 |
|
||||
| `math` | 数学推理 | 27 |
|
||||
|
||||
batch padding 后形状为 `B=4, T=27`,有效 token 共 90。prompt 是用于建立可复现
|
||||
探针的人工样本,不是自然语料分布、benchmark 数据集或统计代表样本。
|
||||
|
||||
## 3. MLA:一张算法状态账,一张实现物化账
|
||||
|
||||
### 3.1 实际观测
|
||||
|
||||
每个执行层的 `kv_a_proj_with_mqa` 输出都是:
|
||||
|
||||
```text
|
||||
[batch, sequence, kv_lora_rank + qk_rope_head_dim]
|
||||
= [4, 27, 512 + 64]
|
||||
= [4, 27, 576]
|
||||
```
|
||||
|
||||
这 576 个元素可以分为:
|
||||
|
||||
- `c_t^KV`:512 维 joint latent;
|
||||
- `k_t^R`:64 维 decoupled RoPE key。
|
||||
|
||||
后者不能因为体积小就从缓存公式中消失。
|
||||
|
||||
### 3.2 HF eager 实际保存了什么
|
||||
|
||||
本次 `use_cache=True` 的官方 Hugging Face eager 路径实际返回:
|
||||
|
||||
```text
|
||||
key [4, 16, 27, 192]
|
||||
value [4, 16, 27, 128]
|
||||
```
|
||||
|
||||
所以每 token、每层的缓存元素是:
|
||||
|
||||
```text
|
||||
expanded eager = 16 × (192 + 128) = 5,120 elements
|
||||
latent contract = 512 + 64 = 576 elements
|
||||
```
|
||||
|
||||
在 BF16 下:
|
||||
|
||||
```text
|
||||
eager bytes = 5,120 × 2 = 10,240
|
||||
latent bytes = 576 × 2 = 1,152
|
||||
ratio = 10,240 / 1,152 = 8.8889×
|
||||
reduction = 1 - 1,152 / 10,240 = 88.75%
|
||||
```
|
||||
|
||||
### 3.3 为什么这不是论文 93.3% 的复跑
|
||||
|
||||
V2 报告的 `93.3%` 是完整 V2 相对 DeepSeek 67B、在论文指定配置和比较口径下的
|
||||
作者报告结果。本实验的 `88.75%` 是 V2-Lite 配置中:
|
||||
|
||||
- HF eager 展开 K/V 元素;
|
||||
- 与 latent + RoPE key 理论存储元素;
|
||||
|
||||
之间的逐 token、逐层 BF16 算术比较。模型、维度、基线和实现口径都不同,
|
||||
二者不能互相替代。
|
||||
|
||||
进一步说,低秩架构只定义“可以保存什么最小状态”;生产系统是否真的只保存 latent,
|
||||
还取决于 attention kernel、权重吸收、RoPE 分叉、paged cache 和服务框架。
|
||||
|
||||
## 4. MoE:真实路由显微镜
|
||||
|
||||
### 4.1 总量守恒
|
||||
|
||||
每个 MoE 层都满足:
|
||||
|
||||
```text
|
||||
90 valid tokens × top-6 = 540 routed selections
|
||||
```
|
||||
|
||||
6 个层合计 `3,240` 次。两条 shared expert 等价路径始终运行,但它们不属于 router
|
||||
输出的 0–63 routed expert ID,因此不写进 top-6 列表。
|
||||
|
||||
### 4.2 六层聚合负载
|
||||
|
||||
| layer | selections | used / 64 | zero | CV | Gini | effective experts | top expert |
|
||||
|---:|---:|---:|---:|---:|---:|---:|---|
|
||||
| 1 | 540 | 63 | 1 | 0.925 | 0.420 | 46.66 | E8 · 48 |
|
||||
| 2 | 540 | 64 | 0 | 0.549 | 0.303 | 55.08 | E62 · 23 |
|
||||
| 3 | 540 | 62 | 2 | 0.569 | 0.322 | 53.51 | E54 · 19 |
|
||||
| 4 | 540 | 62 | 2 | 0.866 | 0.417 | 47.03 | E48 · 40 |
|
||||
| 5 | 540 | 60 | 4 | 0.642 | 0.332 | 52.14 | E14 · 32 |
|
||||
| 6 | 540 | 61 | 3 | 0.765 | 0.378 | 49.48 | E25 · 40 |
|
||||
|
||||
三个指标回答不同问题:
|
||||
|
||||
- `used experts`:这批 token 是否至少触达某专家一次;
|
||||
- `CV = std / mean`:计数离散程度;
|
||||
- `effective experts = exp(entropy)`:若把当前熵换算成均匀分布,相当于多少个专家。
|
||||
|
||||
因此 layer 1 触达 63 个专家,却只有 46.66 个 effective experts,且 E8 承担 48/540
|
||||
次选择。只报“63/64 被使用”会掩盖负载长尾。
|
||||
|
||||
### 4.3 prompt 之间看到的差异
|
||||
|
||||
同一层内,四条 prompt 的 used-expert set Jaccard 与 CV 会变化。例如:
|
||||
|
||||
- layer 1:中文 prompt 使用 54 个专家、CV 0.898;英文架构 prompt 使用 40 个、
|
||||
CV 1.360;代码 prompt 44 个、CV 1.263;数学 prompt 45 个、CV 1.184。
|
||||
- layer 4:聚合 top expert 是 E48;英文和代码各把 E48 路由 11 次,
|
||||
中文 prompt 的 top expert 却是 E29、16 次。
|
||||
- layer 6:英文 prompt 使用 42 个专家、CV 1.439;中文为 49 个、1.031;
|
||||
数学为 48 个、0.915。
|
||||
|
||||
这些是**描述性 route traces**,说明 token 与上下文确实改变 gate 输出;它们不证明
|
||||
“E48 是代码专家”,更不允许以四条 prompt 推断训练语料上的领域分工。
|
||||
|
||||
### 4.4 top-6 权重没有重新归一
|
||||
|
||||
配置 `norm_topk_prob=false`。router 先对 64 个专家做 softmax,再选 top-6;
|
||||
被选中的 6 个概率不会重新缩放到和为 1。各层选中权重和的均值:
|
||||
|
||||
| layer | mean selected top-6 weight sum |
|
||||
|---:|---:|
|
||||
| 1 | 0.3949 |
|
||||
| 2 | 0.4801 |
|
||||
| 3 | 0.4898 |
|
||||
| 4 | 0.4749 |
|
||||
| 5 | 0.4832 |
|
||||
| 6 | 0.4440 |
|
||||
|
||||
所以网页显示某 token 的六个权重和小于 1 是真实配置行为,不是漏算。
|
||||
|
||||
## 5. 可复现性闸门
|
||||
|
||||
正式 trace:
|
||||
|
||||
```text
|
||||
src/data/deepseek-v2-lite-trace.json
|
||||
SHA-256 81ff4ab34d20121fe42219c566dd4780f4c7f74252a31b596f90e5280e1f1aef
|
||||
captured 2026-07-29T05:55:35.599912+00:00
|
||||
```
|
||||
|
||||
第二次独立执行:
|
||||
|
||||
```text
|
||||
SHA-256 b5e2e7567e17765195313473499522a4529b9d37ea96963ba2b9455c3c0b86e6
|
||||
captured 2026-07-29T05:56:32.527770+00:00
|
||||
```
|
||||
|
||||
比较结果:
|
||||
|
||||
```text
|
||||
31 / 31 exact
|
||||
timing compared: false
|
||||
```
|
||||
|
||||
精确检查覆盖:
|
||||
|
||||
- provenance、configuration、prompt tokenization;
|
||||
- initial / final hidden hashes;
|
||||
- layer 0–6 hidden hashes 与 MLA shapes;
|
||||
- layer 1–6 aggregate loads;
|
||||
- layer 1–6 全部 token routes。
|
||||
|
||||
计时会受首次 kernel、频率、温度、后台进程与同步位置影响,因此没有伪装成 deterministic
|
||||
evidence。本轮只把计时保留在原始 trace,网站不把它包装成性能 benchmark。
|
||||
|
||||
## 6. 绝对禁止的外推
|
||||
|
||||
| 本实验能够说 | 本实验不能说 |
|
||||
|---|---|
|
||||
| 固定 revision 的前 7 层产生了这些 hidden states | 完整模型会生成什么回答 |
|
||||
| 四条 prompt 在 6 层产生这些 top-6 routes | 训练集或线上请求的总体专家负载 |
|
||||
| 某层某 expert ID 被选中多少次 | 该专家具有什么稳定语义 |
|
||||
| HF eager 物化了展开 K/V | 所有 MLA serving kernel 都这样缓存 |
|
||||
| V2-Lite 配置可导出 576 元素 latent state | 完整 V2 的 93.3% 已被复跑 |
|
||||
| 两次相同环境执行 31/31 exact | 跨 GPU、依赖版本和 kernel 仍 bitwise identical |
|
||||
| layer 0–6 在第一分片内完整 | layer 7 或 layer 8–26 已执行 |
|
||||
|
||||
跨层连线也被禁止:layer 1 的 E8 与 layer 2 的 E8 是不同参数对象。可视化只能在同一层内
|
||||
比较 expert load,不能画一条 “E8 专长” 纵贯 6 层。
|
||||
|
||||
## 7. 复现入口
|
||||
|
||||
环境与命令见:
|
||||
|
||||
- `experiments/deepseek/README.md`
|
||||
- `experiments/deepseek/v2_lite_trace.py`
|
||||
- `experiments/deepseek/compare_v2_lite_traces.py`
|
||||
|
||||
执行一次:
|
||||
|
||||
```bash
|
||||
python experiments/deepseek/v2_lite_trace.py \
|
||||
--artifact-dir /path/to/deepseek-v2-lite \
|
||||
--output /path/to/trace.json
|
||||
```
|
||||
|
||||
比较两次:
|
||||
|
||||
```bash
|
||||
python experiments/deepseek/compare_v2_lite_traces.py \
|
||||
--first /path/to/trace-1.json \
|
||||
--second /path/to/trace-2.json \
|
||||
--output /path/to/repro.json
|
||||
```
|
||||
|
||||
## 8. 下一道研究闸门
|
||||
|
||||
本轮已经把 DeepSeek 第三轮从“计划真实 trace”推进到真实 tokenizer、MLA state、
|
||||
MoE routes 与确定性复跑,但仍有四块未闭合:
|
||||
|
||||
1. 用真正只保存 latent 的 MLA kernel 对照 HF eager materialization;
|
||||
2. 扩大公开语料样本,给 aggregate load 置信区间,并考察 batch / padding / sequence
|
||||
对 expert parallel 的影响;
|
||||
3. 复跑 FP8、pipeline 或通信 trace,而不是继续用教学 schedule;
|
||||
4. 做可审计的 R1-like 小模型训练实验,记录 rollout、reward、KL、长度与梯度统计。
|
||||
|
||||
在这些闸门完成之前,DeepSeek 专题保持“第三轮进行中”,不写成完整独立复现。
|
||||
Reference in New Issue
Block a user