Files
llm-atlas/research/K3_ARTIFACT_AUDIT.md
T
2026-07-29 13:36:49 +08:00

457 lines
18 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.
# Kimi K3 第三轮:开放工件、权重元数据与可复现实验审计
> 研究截点:2026-07-29
> 官方模型修订:`moonshotai/Kimi-K3@9f62e4e9fffbd0a83ddd60e1c209d828994b3569`
> 官方 FlashKDA 修订:`MoonshotAI/FlashKDA@1ce47ea3bb22c84eb9cc665028399cf35e8ffb0b`
> 原则:模型卡、配置、远程代码、safetensors header、kernel API、作者 benchmark 和本机实验分开记账。
## 1. 本轮究竟要推进什么
第二轮已经把 47 页报告拆成问题、公式、图表和教学实验。第三轮不能只是再写一遍报告,而要回答:
1. 开放权重仓库实际包含哪些文件、分片和张量?
2. 报告的 `69 KDA + 24 MLA`、`1 dense + 92 MoE` 是否能在配置和 tensor names 中闭合?
3. Stable LatentMoE 与 MXFP4 在真实 checkpoint 中怎样落成 packed tensors 与 scales?
4. `NoPE` 在公开实现中究竟是“删掉位置相关通道”,还是“不施加 rotary transform”?
5. AttnRes 在 checkpoint 中留下多少 projection / norm 参数?
6. FlashKDA 的公开接口、支持架构、作者 benchmark 和本机可运行边界分别是什么?
7. 哪些可称为真实工件 trace,哪些仍只是确定性推导或 synthetic probe?
本轮不声称完成以下事情:
- 没有在单张 RTX 5090 上加载 1.56 TB checkpoint;
- 没有获得真实 token hidden states、线上 expert load 或生产 cache trace;
- 没有把随机向量上的 router 行为写成真实数据分布;
- 没有把合法 synthetic shape 上的 FlashKDA 实测写成“K3 checkpoint 已跑通”;
- 没有替官方解释下面发现的 `A_log` 形状不一致。
## 2. 一手工件与校验
| 工件 | canonical source | 本地校验 |
|---|---|---|
| 模型配置 | `https://huggingface.co/moonshotai/Kimi-K3/blob/main/config.json` | `9710e121…379213` |
| HF configuration code | `configuration_kimi_k3.py` | `735eb9eb…b416ae` |
| 多模态 modeling code | `modeling_kimi_k3.py` | `b9171c96…65ea2` |
| 文本 backbone code | `modeling_kimi_linear.py` | `9e3564c7…ff44a` |
| tensor index | `model.safetensors.index.json` | `a1c52106…7febd` |
| layer-1 KDA 小范围字节 | shard 1 HTTP Range | `dccb10e7…d9b2` |
| layer-2 router prefix | shard 2 HTTP Range | `dbe66ff8…23ee` |
| FlashKDA | `https://github.com/MoonshotAI/FlashKDA` | git `1ce47ea3…f0b` |
完整校验值保存在 `src/data/k3-artifact-snapshot.json`。原始权重字节不进入公开仓库。
### 2.1 为什么只读 Range
模型 tensor data 为 `1,560,860,324,864` bytes,即:
- `1.56086 TB`(十进制);
- `1.41959 TiB`(二进制);
- 96 个 safetensors shards;
- 497,220 个 tensor entries。
当前机器是 32 GB RTX 5090、123 GiB RAM。完整下载和加载既不必要,也不能支持“单卡复现”。
safetensors 把 JSON header 放在每个分片开头;header 给出 tensor name、dtype、shape 与 byte offsets。
因此可以只读:
```text
8-byte header length
→ JSON header
→ selected tensor byte ranges
```
这足以审计结构,也能读取少量参数做统计,同时避免把 1.56 TB 下载行为伪装成研究必要条件。
## 3. checkpoint 拓扑:配置、索引与 header 闭合
### 3.1 层型
配置精确给出:
- 93 层;
- KDA layers:69;
- full-attention / Gated MLA layers:24;
- MLA 位于 1-based `4, 8, …, 92, 93`;
- 第一层 dense,后 92 层为 MoE;
- AttnRes block size 为 12。
因此真实层条带是:
```text
L01 KDA + dense FFN
L02 KDA + MoE
L03 KDA + MoE
L04 MLA + MoE
...
L92 MLA + MoE
L93 MLA + MoE
```
最后连续两个 MLA 不是排版错误:`L92` 是最后一个 3:1 block 的 MLA,`L93` 是报告所述额外末层 MLA。
### 3.2 tensor counts
| 对象 | index 实际计数 | 为什么是这个数 |
|---|---:|---|
| KDA `A_log` | 69 | 每个 KDA layer 一份 |
| KDA `dt_bias` | 69 | 每个 KDA layer 一份 |
| Router weight | 92 | 每个 MoE layer 一份 |
| Router correction bias | 92 | 每个 MoE layer 一份 |
| Routed expert packed weights | 247,296 | `92 × 896 × 3` |
| Routed expert scales | 247,296 | `92 × 896 × 3` |
| AttnRes projections | 187 | `93 × 2 + output 1` |
| AttnRes norms | 187 | `93 × 2 + output 1` |
| Vision tensors | 165 | 27-layer MoonViT-V2 与输入/输出项 |
| Projector tensors | 3 | 视觉塔到 7168 text hidden |
`497,220` 不是“参数数量”,而是 safetensors 中的命名 tensor entry 数。不能和 `2.78T parameters`
混为一个口径。
## 4. 真实 tensor shape:架构不再只靠报告表格
### 4.1 Dense layer 1 的 KDA
shard 1 header 给出:
| tensor | dtype | shape |
|---|---|---|
| `q/k/v/g_proj.weight` | BF16 | `12288 × 7168` |
| `o_proj.weight` | BF16 | `7168 × 12288` |
| `q/k/v_conv1d.weight` | F32 | `12288 × 1 × 4` |
| `b_proj.weight` | BF16 | `96 × 7168` |
| `f_a_proj.weight` | BF16 | `128 × 7168` |
| `f_b_proj.weight` | BF16 | `12288 × 128` |
| dense FFN gate/up | BF16 | `33792 × 7168` |
| dense FFN down | BF16 | `7168 × 33792` |
`12288 = 96 heads × 128 dims`;ShortConv kernel size 4 也直接出现在 checkpoint shape 中。
### 4.2 MLA layer 4
shard 4 header 给出:
| tensor | shape |
|---|---|
| `q_a_proj` | `1536 × 7168` |
| `q_b_proj` | `18432 × 1536` |
| `kv_a_proj_with_mqa` | `576 × 7168` |
| `kv_b_proj` | `24576 × 512` |
| `g_proj` | `12288 × 7168` |
| `o_proj` | `7168 × 12288` |
关键解释:
- `576 = 512 KV latent + 64 auxiliary q/k channel`;
- `q_b` 输出 `96 × (128 + 64) = 18432`;
- 公开 forward 没有对这 64 维施加 RoPE,但仍投影、拼接并进入 attention;
- 因此 K3 的 `mla_use_nope=true` 应解释为“不施加显式 rotary transform”,不能改写成“MLA 中完全不存在任何额外 q/k 通道”。
### 4.3 一个 routed expert 的 MXFP4 表示
layer 2 / expert 0 的 header:
| tensor | dtype | packed shape | bytes |
|---|---|---:|---:|
| `w1.weight_packed` | U8 | `3072 × 1792` | 5,505,024 |
| `w1.weight_scale` | U8 | `3072 × 112` | 344,064 |
| `w2.weight_packed` | U8 | `3584 × 1536` | 5,505,024 |
| `w2.weight_scale` | U8 | `3584 × 96` | 344,064 |
| `w3.weight_packed` | U8 | `3072 × 1792` | 5,505,024 |
| `w3.weight_scale` | U8 | `3072 × 112` | 344,064 |
这里能直接读出两个结构:
1. routed expert 工作在 `3584` latent width,而不是 `7168` full hidden;
2. scale group size 为 32:`3584 / 32 = 112`,`3072 / 32 = 96`。
每个 routed expert 的 packed weights + scales 为 `17,547,264` bytes。按配置与 index 的统一形状推导,
92 层全部 routed experts 约占 tensor data 的 `92.67%`。这是 header + 配置的确定性推导,不是运行显存。
### 4.4 MoonViT-V2
shard 96 header:
| tensor | shape |
|---|---|
| patch projection | `1024 × 3 × 14 × 14` |
| learned 2D position table | `64 × 64 × 1024` |
| block 0 / 26 QKV | `4608 × 1024` |
| block 0 / 26 MLP up | `4096 × 1024` |
| block 0 / 26 MLP down | `1024 × 4096` |
| final norm | `1024` |
配置、首层和末层 tensor 同时支持“27 layers、patch 14、vision hidden 1024”;这比只引用模型卡更强。
## 5. 小参数 Range audit
### 5.1 KDA layer 1
只读 shard 1 开头的 49,664 bytes:
- checkpoint `A_log`: F32 `[128]`;
- `dt_bias`: F32 `[12288]`,可按公开配置写成 `[96, 128]`。
真实参数统计:
| 参数 | median | p10–p90 | min–max |
|---|---:|---:|---:|
| `A_log` | −0.1533 | −0.5367–0.0743 | −0.7531–2.4661 |
| `exp(A_log)` | 0.8579 | 0.5847–1.0771 | 0.4709–11.7764 |
| `dt_bias` | −4.6220 | −6.4912–−2.5690 | −7.8938–0.1792 |
### 5.2 一个必须公开保留的形状不一致
四份官方工件目前给出:
| 工件 | 观测 |
|---|---|
| `config.json` | `num_heads=96`, `head_dim=128` |
| HF remote code | `A_log` 初始化 shape 为 `[num_heads]`,即 `[96]` |
| FlashKDA API / C++ check | `A_log` 必须 `[H]` |
| checkpoint shard header | `A_log` 实际为 `[128]` |
同时:
- `dt_bias` 可闭合为 `[96,128]`;
- `b_proj.weight` 为 `[96,7168]`,β 显然按 96 heads;
- q/k/v projection 为 `12288 = 96×128`。
因此,**公开工件中存在可复现的 `A_log [128]` vs expected `[96]` 形状不一致**。
当前可下的结论只有:
- 这是 header / code / config / kernel API 四方直接观测,不是 Grok 猜测;
- 公开 remote code 按字面构造时会期待 `[96]`;
- 需要 Moonshot、实际 vLLM/SGLang loader 或后续权重修订解释转换规则。
当前不能下的结论:
- 不能直接宣布 checkpoint 损坏;
- 不能擅自把 `[128]` 解释为 per-channel `A_log`;
- 不能用某个猜测 reshape 得到的曲线冒充模型真实 retention。
数据快照保留了一个明确标成 `noncanonical channel-wise hypothesis` 的数值探针,只用于说明:
若把 `[128]` 当 channel 参数,能得到怎样的 retention 分布;它不进入正式 forward 结论。
## 6. Router:真实权重与 synthetic input 必须分层
读取 layer 2 的:
- correction bias:896 个 F32;
- router weight:`896 × 7168` BF16,约 12.85 MB。
真实参数统计:
- correction bias median `0.00493`,min `−0.08442`,max `0.02861`;
- router row L2 median `5.0364`,min `2.6019`,max `7.0232`;
- bias 与 row norm 的 Pearson correlation `0.4567`。
为了测试“只拿真实 router weights 是否就能评价 Quantile Balancing”,脚本生成 2,048 个固定 seed、
RMS=1 的各向同性随机 hidden vectors,再比较 top-16:
| 条件 | load CV | Gini | zero-load experts |
|---|---:|---:|---:|
| 不加 correction bias | 2.085 | 0.831 | 558 |
| 加 checkpoint correction bias | 2.529 | 0.879 | 673 |
两组 top-16 平均只重合 `2.17 / 16`。
这不是在证明 QB 让真实负载更差,反而证明:
1. router weights 与 hidden-state distribution 是共同训练的;
2. sigmoid top scores 在随机 RMS=1 输入下容易饱和;
3. 小 correction bias 会在饱和的近并列区域强烈改写名次;
4. 没有真实 hidden traces,就不能用随机向量评价真实负载均衡。
因此网站把这组结果命名为 **counterexample / synthetic stress probe**,不是“真实 expert load trace”。
## 7. FlashKDA:作者 benchmark 与本机实验分开
### 7.1 官方仓库事实
[FlashKDA 官方仓库](https://github.com/MoonshotAI/FlashKDA) `1ce47ea3`:
- CUTLASS kernels;
- 支持 `90a / 100a / 103a / 120a`;
- README 要求 SM90+、CUDA 12.9+、PyTorch 2.4+;
- kernel API 固定 `K=V=128`;
- q/k/v/g 为 BF16,`A_log` / `dt_bias` 为 F32;
- 支持 fixed length、variable length、initial / final recurrent state。
官方报告的 `T=8192, H=96, D=128`:
| device | case | FlashKDA | FLA chunk KDA | 作者报告 speedup |
|---|---|---:|---:|---:|
| H20 | fixed | 2.6220 ms | 4.8388 ms | 1.85× |
| H20 | 8×1024 varlen | 2.0432 ms | 4.6723 ms | 2.29× |
| GB200 | fixed | 1.0087 ms | 2.3271 ms | 2.31× |
| GB200 | 8×1024 varlen | 0.7064 ms | 2.3105 ms | 3.27× |
这些是作者仓库 benchmark,不是本站复跑值。
### 7.2 从主机构建失败到隔离 wheel
GPU 主机:
- RTX 5090,compute capability `12.0`;
- Ubuntu 26.04,glibc `2.43`;
- 常用环境为 PyTorch `2.11.0+cu128` / CUDA `12.8`;
- 官方源码明确包含 `sm_120a`,所以不是 GPU architecture 缺失。
主机路径依次暴露了两个不同问题:
1. 系统 `g++ 15.2`:PyTorch extension 在编译前拒绝,CUDA 12.8 要求 host compiler `<14`;
2. 临时解包 `g++ 13.4`:成功进入 nvcc,但 CUDA 12.8 headers 与当前 glibc math declarations
冲突;
3. 新建 PyTorch `2.11.0+cu130` 环境并改用 CUDA 13.1 后,版本主线已经匹配,但仍在
`rsqrt / rsqrtf` exception specification 处失败。
第三步说明“升级到 CUDA 13”还不够。[CUDA 13.1 官方 Linux support matrix](https://docs.nvidia.com/cuda/archive/13.1.0/cuda-installation-guide-linux/index.html) 当前列出的
glibc 上限是 2.41,而主机是 2.43;NVIDIA 官方论坛也记录了同类 CUDA 13.1 / 新 glibc
数学声明[冲突案例](https://forums.developer.nvidia.com/t/fedora-43-and-nvcc-cuda13-1-error-exception-specification-is-incompatible-rsqrt-rsqrtf/354510)。这里能写的是“构建失败与超出验证矩阵一致”,不能写成 CUDA 对未来 glibc
永久不兼容。
最终构建固定为:
| layer | pinned value |
|---|---|
| base image | `nvidia/cuda:13.0.2-devel-ubuntu24.04` |
| container libc | glibc `2.39` |
| Python | `3.12` |
| PyTorch | `2.11.0+cu130` |
| target | `sm_120a` |
| FlashKDA | `1ce47ea3bb22c84eb9cc665028399cf35e8ffb0b` |
| wheel | `flash_kda-0.0.1+1ce47ea-cp312-cp312-linux_x86_64.whl` |
| wheel SHA-256 | `14687b6d84a256d4552f0c73ccf93a601be582aeabcdf49ae3a409266872158d` |
容器没有 NVIDIA runtime,也不需要 GPU 才能为固定 architecture 编译。CUDA 编译器实际产出
`sm_120a` 对象,最终 wheel 为 3,806,174 bytes。wheel 随后装入主机独立 CPython 3.12.11 /
PyTorch 2.11.0+cu130 环境;该运行环境能看到 RTX 5090、capability 12.0,并成功导入
`flash_kda` 与 `flash_kda_C`。
### 7.3 exact correctness:输出与 recurrent state 都必须相等
正确性对照直接调用官方仓库的 `tests/torch_ref.py`,而不是本站重写一份近似参考。
测试输入满足公开 API 的 `A_log[H]`;它们故意不使用 checkpoint 的 `A_log[128]`,因此不会
偷偷替未决形状冲突下结论。
| case | sequence lengths | H | output exact | final state exact | max abs error |
|---|---|---:|---:|---:|---:|
| one chunk | `[16]` | 1 | yes | yes | 0 |
| partial tail | `[17]` | 1 | yes | yes | 0 |
| two chunks | `[32]` | 1 | yes | yes | 0 |
| multi-chunk / multi-head | `[65]` | 2 | yes | yes | 0 |
| K3 head count | `[17]` | 96 | yes | yes | 0 |
| varlen partial chunks | `[17,31]` | 2 | yes | yes | 0 |
六组用 BF16 q/k/v/g、BF16 beta logits、F32 `A_log/dt_bias` 和 BF16 recurrent state;
output 与 final state 全部逐元素相等,所有 max / mean absolute difference 都是 0。
这把证据从“源码声称支持 120a”推进成了“本站 RTX 5090 实际执行并通过官方参考”。
### 7.4 本机受控计时:只报本站 FlashKDA,不伪造本机 FLA 对照
协议:
- deterministic synthetic tensors;
- `D=128`,K3 shape 使用 `H=96, T_total=8192`;
- warmup 20;
- 每轮 100 次、3 repeats,即每个 state mode 300 个 CUDA Event samples;
- output buffer 重用;
- 分开测 BF16 state、无 state I/O、FP32 state;
- throughput 是 sequence tokens/s,不是 head-tokens/s;
- 没有安装并复跑 FLA,所以不计算本站 speedup。
| RTX 5090 case | state mode | mean | P95 | sequence tokens/s |
|---|---|---:|---:|---:|
| fixed `[8192]` | BF16 | 2.6210 ms | 2.6437 ms | 3.126 M/s |
| fixed `[8192]` | none | 2.6154 ms | 2.6362 ms | 3.132 M/s |
| fixed `[8192]` | FP32 | 2.6267 ms | 2.6500 ms | 3.119 M/s |
| varlen `[1300,547,2048,963,271,3063]` | BF16 | 2.3335 ms | 2.3574 ms | 3.511 M/s |
| same varlen | none | 2.3104 ms | 2.3254 ms | 3.546 M/s |
| same varlen | FP32 | 2.3596 ms | 2.3845 ms | 3.472 M/s |
fixed case 三种 mode 合并的 peak allocated 为 1,755.7 MiB;varlen 为 1,845.7 MiB。
作者 H20 fixed 的 `2.6220 ms` 与本站 BF16 fixed 的 `2.6210 ms` 数值接近只是一次观测,
不能据此宣布 RTX 5090 与 H20 等价:软件栈、频率、功耗、输入、测量时段和对照 kernel
都不足以支持这种外推。
## 8. 可复现实验入口
checkpoint 工件脚本:
```text
experiments/k3/checkpoint_probe.py
```
FlashKDA 构建与执行:
```text
experiments/k3/flashkda/Dockerfile
experiments/k3/flashkda/build_reference_helper.py
experiments/k3/flashkda/run_probe.py
experiments/k3/flashkda/README.md
```
提交的数据快照:
```text
src/data/k3-artifact-snapshot.json
src/data/k3-flashkda-runtime.json
```
两条实验路径共同完成:
1. 解析 config、index 与 selected headers;
2. 校验小范围字节长度和 SHA-256;
3. 统计真实 KDA / router 参数;
4. 运行明确标注的 synthetic router counterexample;
5. 解析 FlashKDA 官方 H20 / GB200 benchmark;
6. 在隔离 CUDA 13.0 / glibc 2.39 环境编译 `sm_120a` wheel;
7. 用官方 torch reference 跑六组 exact-match;
8. 在 RTX 5090 跑 fixed / varlen、三种 state mode 的受控计时;
9. 不提交原始权重或二进制 wheel,只提交 checksum、环境、代码和 JSON 结果。
## 9. 网站实现合同
第三轮开放工件实验室必须有四个视图:
1. **Layer map**:93 层真实 config 条带;显示 KDA/MLA、dense/MoE、AttnRes block。
2. **Tensor anatomy**:checkpoint / expert / vision / MLA tensor shape 与数量。
3. **Parameter audit**:真实 Range statistics,并把 `A_log` mismatch 放在主视区。
4. **Reproduction boundary**:作者 benchmark、本站 exact / latency、构建链、未决形状冲突与 synthetic router counterexample。
每个视图必须显示证据类型:
- `O` = official artifact observation;
- `D` = deterministic derivation;
- `X` = executed local experiment;
- `S` = synthetic stress probe;
- `U` = unresolved inconsistency。
## 10. 下一轮证据闸门
- [x] 官方 config / code / index revision 固定;
- [x] 96 个分片与 497,220 tensor entries 审计;
- [x] KDA / MLA / MoE / AttnRes / Vision tensor shapes 入账;
- [x] selected open-weight ranges 做真实参数统计;
- [x] 发现并限定 `A_log` shape inconsistency;
- [x] FlashKDA RTX 5090 构建尝试留下可复现边界;
- [x] 使用 CUDA 13.0 / glibc 2.39 隔离环境产出可校验 `sm_120a` wheel;
- [x] RTX 5090 上六组 FlashKDA / official torch reference exact correctness;
- [x] K3 fixed / varlen shape、三种 state mode 的 1,800 个 CUDA Event samples;
- [ ] 取得真实 hidden-state / router load trace;
- [ ] 取得可加载的 reduced checkpoint、官方 trace 或多机资源;
- [ ] 对 Figure 3 / 4 / 5 做真实数值重绘;
- [ ] 对 AttnRes 读取分布做真实 token / layer trace。
## 11. 发布与回归证据
- 源提交:`be2b291`;
- 不可变镜像:`docker.k1412.top/wuyang/llm-atlas:20260729T044605Z-be2b291`;
- OCI digest:`sha256:99aa953e419d537bc03127616546d201bc25624498f892088e69cc633bd00cdf`;
- NAS:Compose Manager project `llm-atlas`,`12010 → 8080`,容器 health `healthy`;
- 代理:NPM host `31`,certificate `41`,forward `100.94.16.3:12010`;
- 公网:DNS `93.179.98.23`,HTTP → HTTPS 301,`/healthz` 与关键静态资源 200;
- 门户:`LLM ATLAS` / `projects` / order `180`;
- 回归:16 套生产 Chrome 脚本全部通过,包含 K3 四视图、键盘 tabs、桌面和 390px 移动端;
- 回滚镜像:`20260729T040336Z-b669615`。