Files
xserv/docs/MOE_PROGRESS.md
Gahow Wang f59ba73938 docs: MoE progress snapshot before dash5 reboot
Accurate resume guide: what's truly verified (MoE forward -> "Paris"
matching llama.cpp; MXFP4 GPU dequant matching numpy), what's built but
not yet wired/verified (sink-attention decode kernel), the remaining
perf work (#8 loader for MXFP4-resident experts -> #9 KV cache + GPU MoE
-> #7 prefill sinks -> #10 server + AIME/GSM8K), the working download
method (unset proxy + hf-mirror), model locations on dash5 (persist across
reboot), post-reboot checklist, and the resource/cleanup convention.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-05-29 21:42:57 +08:00

267 lines
16 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.

# MoE (gpt-oss-20b) — 工作进度与续作指南
> **中断原因**:用户要重启 dash5 机器IP 等可能变),让我先把当前 MoE 支持工作的状态
> 完整记录到本文件,重启后据此继续。本文件是"重启后从这里接着干"的唯一入口。
最后更新2026-05-29 深夜。Phase 18 (PP) 完成并 push。Phase 19 (MoE/gpt-oss-20b)
**MoE 前向已验证正确(输出 "Paris",与 llama.cpp 一致)**MXFP4 GPU 解量化 kernel 已验证;
sink-attention decode kernel 已写好编译绿(待接入)。剩 #7-#10 性能化才能跑 AIME/GSM8K。
详见下方「最新状态」。
---
## 最新状态2026-05-29 深夜dash5 重启前)
分支 `phase18-pipeline-parallelism`HEAD = `e3da9f5`**整个 workspace 在 dash5 上
`cargo build --release` 绿**(已确认)。所有提交均已 push 到 gitea。
### 已完成且**真实验证**过的(高置信)
1. **MoE 前向数值正确**(正确优先版,`gptoss.rs::forward`
"The capital of France is"token `976 9029 328 10128 382`)→ top-1 = token
**12650 = " Paris"**logit 15.31llama.cpp 金标准同 prompt 也输出 " Paris"。✅
打通top-4 routersoftmax-after-topk、interleaved clamped `(up+1)*glu` experts、
attention sinks、sliding window、**YaRN RoPE**关键gpt-oss 是 yarn rope_type
plain RoPE 会让输出退化成回声 prompt、head_dim 64、q/k/v/o bias。
运行:`gptoss-logits /opt/wjh/models/gpt-oss-20b-bf16 976 9029 328 10128 382`
2. **MXFP4→BF16 GPU 解量化 kernel**`csrc/quant/mxfp4.cu` + `dequant_mxfp4`
GPU 解 layer0/expert0 gate_up 与 numpy 参考**逐元素一致**
`[0,0,0,-0.0625,0,-0,-0.015625,-0.03125]`。✅ 运行:`mxfp4-check /opt/wjh/models/gpt-oss-20b`
3. **GPU sink-attention(decode) kernel**`decode_attention_sink`):编译绿。
⚠️ **注意kernel 写好且能编译,但还没接进 gptoss.rs、还没单独做数值对照**——
下次接入后必须先验证(用现有 host attention 路径作 A/B 对照)。
4. **llama.cpp 金标准**dash5 的 llama.cpp 原生支持 gpt-oss`LLM_ARCH_OPENAI_MOE`
官方 MXFP4 GGUF 跑「17×24=408」正确。**无需升级 submodule。**
> ⚠️ **本 session 的教训(务必遵守)**:我有几次在 build 没绿/没真跑的情况下就 commit 了
> "verified" —— 已逐一更正commit `4038799`、`e3da9f5` 就是更正前一个谎报的 commit
> **规范:先 `./tools/sync-and-build.sh build` 绿 + 真跑出结果,再 commitcommit message
> 只写真实发生的事。** 显示通道偶尔吞 stdout/回放旧结果 → 关键结果写文件再 `cat`/`Read`
> 或用 exit code 编码;网络/远端命令一次一条(一条失败会 cancel 同批)。
### 还没做(跑通 AIME/GSM8K 的剩余工作,按建议顺序)
当前 `gptoss.rs` 是「正确优先」host CPU 三重循环 attention、**无 KV cache**(每生成 1 token
重算整段 → O(n²)、experts 常驻 CPU 每用一次上传。**能正确跑几十 token 的前向,但跑
30 题 × 上千 token 的 AIME/GSM8K 完全不可行**。剩余task #7-#10
- **#8显存关键阻塞kernel 已就绪)**:写 loader 把 expert 的 `_blocks`/`_scales`U8
读成 per-(layer,expert) 的 `GpuBuffer` 常驻 GPUMXFP4 仅 13GB单卡放得下
forward 里每个 expert GEMM 前用 `dequant_mxfp4` 现解到 BF16 scratch。
→ 去掉每 token 的 CPU→GPU experts 上传;单卡可跑。**dequant kernel 已验证,只差 loader 接线。**
- **#9(速度)**GPU MoE decode + **KV cache**(复用 `GpuKVCache` 或 paged让 decode O(1)/token
router matmul + top-k1 token 时 host 取 top4 即可4 个 expert GEMV
decode attention 改用 `decode_attention_sink`#7,含 sinks+滑窗)。
- **#7 余项**flash **prefill** kernel 也加 sinks多 token 一次),否则 prefill 仍走 host。
- **#10**engine 识别 `gpt_oss` arch → HTTP 服务 → `tools/bench` 对比 llama.cpp 跑 AIME 2025 + GSM8K。
建议顺序:**#8loader 接线,单卡能跑)→ #9KV cache + GPU MoE/attention能跑快
#7 prefill sinks → #10(接 server + 对比)**。每步都先和现有 "Paris" 正确路径 A/B 对照
再往下走。
## 0. 一句话现状
-**Phase 18 流水线并行 (PP)** 全部完成、验证、benchmark已 commit 并 push 到
`origin/phase18-pipeline-parallelism`gitea
- 🚧 **Phase 19 MoE (gpt-oss-20b)** 刚开始:架构 + HF 参考数学已核对(见
`docs/19-moe-gpt-oss.md`**模型还没下载完**HF 被墙,正在解决下载路径),代码未动。
---
## 1. 环境关键事实(重启后很可能变 / 需重新确认)
- **本机**(开发机,非 GPU`/home/gahow/projects/xserv`,有公网(走代理)。
- **dash5**GPU 机8×RTX 5090无 NVLink0-3/4-7 分组):通过 `ssh dash5` 访问。
- 远端仓库目录:`/opt/wjh/projects/xserv`,模型目录:`/opt/wjh/models/`
- **dash5 无外网、无 rsync**;同步用 `./tools/sync-and-build.sh`tar over ssh
- cargo 在 `$HOME/.cargo/bin`CUDA 12.9 在 `/usr/local/cuda-12.9`
- ⚠️ **重启后 `ssh dash5` 的 IP/可达性可能变** —— 先 `ssh dash5 hostname` 确认;
若连不上,检查 `~/.ssh/config``dash*` 配置 / 让用户给新地址。
- **HTTP 代理**(本机环境变量,重启后可能还在 `/etc/environment` 或 shell
`http_proxy=https_proxy=all_proxy=http://ipads:ipads123@202.120.40.82:11235`
- **huggingface.co 被墙**`SSL_ERROR_SYSCALL`即使过代理。pypi 可过代理。
- **`huggingface_hub` 不是预装**,已用 `pip install --user --break-system-packages
huggingface_hub safetensors` 装好1.17.0venv 不可用(无 ensurepip
---
## 2. gpt-oss-20b 下载(**当前卡点**
目标:下到本机 `~/models/gpt-oss-20b`,再 tar-over-ssh 拷到 dash5
`/opt/wjh/models/gpt-oss-20b`。
**已验证可行的下载路径**(重启后照此做):
- huggingface.co 直连/经代理都失败。
- hf-mirror.com 的 `/resolve/` 会 **308 跳回 huggingface.co**(也被墙)——所以不能用
`curl -L` 跟跳转,`huggingface_hub` 设 `HF_ENDPOINT` 在新版(1.17)上 HEAD 也失败。
- ✅ **能用的办法**:直接走 **hf-mirror 的 `/raw/`(小文件)和实际 CDN经代理 curl**。
已成功取到 `config.json`200, 1799 bytes
```bash
curl -s -x "http://ipads:ipads123@202.120.40.82:11235" \
"https://hf-mirror.com/openai/gpt-oss-20b/raw/main/config.json" -o config.json
```
大文件safetensors要用 `/resolve/main/<file>` 且 **指定 `-x` 代理、不要 `-L`**
若仍 308 跳回 hf.co则改用 hf-mirror 的 LFS 直链或 `huggingface_hub` 配合
`HF_ENDPOINT=https://hf-mirror.com` + 代理(库内部不跟 308。**下载脚本草稿在
`/tmp/dl_shards.sh`(重启后 /tmp 会清空,需重建)。**
**待下载文件**3 个分片 + 元数据,总 ~13.5GB MXFP4
- `model-00000-of-00002.safetensors`、`model-00001-of-00002.safetensors`、
`model-00002-of-00002.safetensors`(注意是 0/1/2 三个,命名 of-00002
- `model.safetensors.index.json`、`config.json`、`tokenizer.json`、
`tokenizer_config.json`、`special_tokens_map.json`、`generation_config.json`、
`chat_template.jinja`
**重启后第一步**`ls -la ~/models/gpt-oss-20b/` 看已下了哪些、`wc -c` 校验分片大小,
断点续传用 `curl -C -`。
---
## 3. gpt-oss-20b 架构config.json 已核对)
| 字段 | 值 |
|------|----|
| layers | 24hidden 2880**head_dim 64**(≠ hidden/heads|
| heads | 64 q-heads / 8 kv-headsGQAn_rep=8|
| experts | num_local_experts **32**num_experts_per_tok **4**top-4|
| expert intermediate | 2880 |
| vocab | 201088max_pos 131072tie_embeddings false |
| rope_theta | 150000核对是否有 rope_scaling/YaRN|
| sliding_window | 128**交替层**,见 config `layer_types`|
| rms_norm_eps | 1e-5swiglu_limit 7.0alpha 1.702 |
| 量化 | **MXFP4**,仅 expert MLPgate_up/down 的 `_blocks`+`_scales`attn/router/embed/lm_head 为 BF16 |
---
## 4. HF 参考数学(已从 transformers `modeling_gpt_oss.py` 逐字核对,务必照抄)
完整版见 `docs/19-moe-gpt-oss.md` §2。要点
**Router**softmax 在 topk **之后**
```
logits = x @ W_router^T + b_router # [T,32]
top_val, idx = topk(logits, 4)
top_val = softmax(top_val) # 只对选中的 4 个归一化
scores = scatter to [T,32] (其余 0)
```
**Experts**fused gate_up**交错** ::2 / 1::2clamped(up+1)·glu
```
alpha=1.702, limit=7.0
gate_up = x @ gate_up_proj[e] + bias # [.., 2*2880]
gate = gate_up[..., ::2]; up = gate_up[..., 1::2]
gate = clamp(gate, max=limit) # 仅上界
up = clamp(up, min=-limit, max=limit)
glu = gate * sigmoid(gate * alpha)
h = (up + 1) * glu # 注意 (up+1)
y_e = h @ down_proj[e] + bias
out = Σ_{e∈top4} scores[t,e] * y_e
```
**Attention带 sinks**
```
scaling = 64 ** -0.5q/k/v/o 都有 bias
RoPE(theta=150000) on q,krepeat_kv(n_rep=8)
attn = (q@k^T)*scaling + causal(+ 滑窗层叠加 banded window=128)
combined = cat([attn, sinks_per_head], dim=-1) # 每 head 一个标量 sink多一列
combined -= combined.max(-1, keepdim) # 数值稳定
probs = softmax(combined, -1)
scores = probs[..., :-1] # 丢掉 sink 列(概率不归一到 1
o = scores @ v -> merge heads -> @Wo + bo
```
**RMSNorm**标准fp32 算 varianceeps=1e-5
参考源码已存(重启后 /tmp 清空需重取):`pip download transformers --no-deps`
解 wheel 取 `transformers/models/gpt_oss/modeling_gpt_oss.py`967 行)。
---
## 5. MXFP4 反量化expert 权重)
- expert 张量名:`model.layers.{i}.mlp.experts.gate_up_proj_blocks` + `..._scales`
`...down_proj_blocks` + `..._scales`bias 是 BF16 的 `gate_up_proj_bias`/`down_proj_bias`)。
- MXFP4每 **32** 元素一 block共享一个 **E8M0**8-bit 指数scale每元素 4-bit
FP4(E2M116 码字)。反量化 `val = fp4_lut[code] * 2^(e8m0 - 127)`。
- **决策(已定)**:加载时在 CPU 反量化成 BF16dash5 ~1TB 内存),整模型 ~40GB BF16
单卡放不下 → 走 **Phase 18 的 PP**PP=2 ~20GB/卡PP=4 ~10GB/卡)。不写 GPU 原生
MXFP4 kernel风险高、慢先正确跑通+对比,后续再优化。
---
## 6. 实施路线Phase 19逐步可验证
1. **P19.1** Python(numpy) 读 safetensors + MXFP4 反量化,与 HF 一层数值对照(确认 LUT /
block 方向 / gate_up 交错对得上)。**不依赖 GPU重启后可先做。**
2. **P19.2** `crates/xserv-model/src/config.rs`:加 MoE 字段
num_local_experts / num_experts_per_tok / sliding_window / swiglu_limit /
显式 head_dim / expert intermediate保持 Qwen3 路径不变。
3. **P19.3** 新文件 `crates/xserv-model/src/gptoss.rs`denseattn+sinks+bias+滑窗 /
RMSNorm / lm_head+ MoE FFN正确优先逐 token top-4 gather→clamped SwiGLU→加权和
MXFP4 在 `from_weights` 反量化为 BF16。验收prefill logits 与 HF BF16 容差内一致。
4. **P19.4** `from_weights_pp` 支持 gpt-ossexperts 随层切),`--pp` 端到端;
PP=2/4 与 PP=1 等价(沿用 Phase 18 的"单卡×2 vs ppN×2"对照法)。注:~40GB 需 PP≥2。
5. **P19.5** llama.cpp 对比:**pinned submodule b9371 早于 gpt-oss约 2025-08 落地),
需升级 submodule** 到支持 gpt-oss 的版本 + 取/转 GGUF跑 AIME 2025 + GSM8K
复用 `tools/bench/` + `tools/bench/summarize_fullq.py`已有PP 阶段写的)。
---
## 7. 复用 Phase 18 的资产
- 多卡:`--pp N`(已验证),`crates/xserv-distributed`NCCL P2P + AllReduce
- bench`tools/bench/runner.py`(支持 `--pp`/`--tp`)、`summarize_fullq.py`、
`tools/pp_quality_full.sh`xserv 0-3 ‖ llama 4-7 并行跑 AIME+GSM8K 的范式可直接改用)。
- 教训(见全局 memory用对 model 名(不是 "q");就绪判定用真实生成不是 /health
贪心 run-to-run 不可复现cuBLAS显存快照要等模型加载完严格串行避免同组 GPU 互扰;
长任务用持久前台 ssh + `run_in_background`,别让一个网络失败 cancel 掉整批命令。
---
## 8. 重启后立即要做checklist
1. `ssh dash5 hostname` 确认 GPU 机可达(不行就问用户新地址 / 改 ~/.ssh/config
2. `git -C ~/projects/xserv log --oneline -12 | cat` 确认 HEAD = `e3da9f5`,分支
`phase18-pipeline-parallelism`(含 PP 5 commit + MoE 6 commit
3. `./tools/sync-and-build.sh build` 确认仍绿(应 `Finished release`)。
4. 三个模型目录都在 dash5 `/opt/wjh/models/`§2磁盘持久重启不丢
`gpt-oss-20b`(MXFP4)、`gpt-oss-20b-bf16`、`gpt-oss-20b-gguf`。
5. 复跑两个已验证项,确认环境正常:
- `CUDA_VISIBLE_DEVICES=0 ./target/release/mxfp4-check /opt/wjh/models/gpt-oss-20b`
→ 应输出 `[0,0,0,-0.0625,0,-0,-0.015625,-0.03125]`
- `CUDA_VISIBLE_DEVICES=0 ./target/release/gptoss-logits /opt/wjh/models/gpt-oss-20b-bf16 976 9029 328 10128 382`
→ top-1 应为 token 12650" Paris"
6. 参考源码若要:`pip download transformers --no-deps` 解 wheel 取
`transformers/models/gpt_oss/modeling_gpt_oss.py`/tmp 已清)。
7. 从「最新状态 → 还没做」的 **#8 loader 接线** 接着干dequant kernel 已就绪)。
## 9. 资源/清理约定(用户要求:别超 dash5 资源、跑完即清)
- 每次跑完:`pkill -9 -f "xserv-server|llama-server|gptoss"`,确认
`nvidia-smi` 8 卡 idle 再离开(本 session 结束时已确认 idle、无 stray、142G free
- 长任务用持久前台 ssh + harness `run_in_background`**绝不**让进程挂在某个会断的 ssh 子壳里。
- 磁盘MXFP4-on-GPU(#8) 验证后可删 `gpt-oss-20b-bf16`(省 35G
---
## 性能版进度2026-05-29 深夜,续)
目标:让 gpt-oss 解码够快,真跑 AIME/GSM8K。当前「正确优先」版host attention、无 KV
cache、experts 常驻 CPU 按需上传)只能跑几个 token 的前向,不可能跑 2400 token 生成。
四块拆解task #7-#10
- ✅ **#7 GPU sink-attentiondecode**`decode_attention_sink` kernel 已写、已编译通过、
已 pushcommit 2f9e69a。sink 作为 softmax 分母额外一列、不贡献 value带 sliding window。
**还差**flash PREFILL kernel 也要加 sink多 token 一次性),否则 prefill 仍走 host。
- ⬜ **#8 MXFP4 experts 放 GPU + dequant kernel关键阻塞**BF16 全量 experts 36GB 单卡放不下;
必须把 experts 以 MXFP413GB放 GPU用一个小 CUDA kernel 在每个 expert GEMM 前现解到
BF16 scratch。否则 decode 每 token 要从 CPU 上传 ~5GB experts2400 token = 数 TB不可行。
- ⬜ **#9 GPU MoE + KV-cache 解码**router matmul + top-k1 token 时 host 取 top4 即可)、
4 个 expert GEMV、KV cache复用 GpuKVCache/paged让 decode 变 O(1)/token。
- ⬜ **#10 接 server + 跑 AIME/GSM8K**engine 识别 gpt_oss arch、HTTP 服务、`tools/bench`
对比 llama.cpp 金标准。
**关键依赖**#8 是单卡跑通的前置(显存);或者把 gptoss 接进 Phase 18 的 PPBF16 experts 切到
多卡)。单卡走 MXFP4-on-GPU 更省事。建议顺序 #8 → #9 → #7(prefill) → #10。
**已确认可用资产**BF16 dequant 模型在 dash5 `/opt/wjh/models/gpt-oss-20b-bf16`
MXFP4 原始模型 `/opt/wjh/models/gpt-oss-20b`llama.cpp 金标准 GGUF
`/opt/wjh/models/gpt-oss-20b-gguf/gpt-oss-20b-mxfp4.gguf`(已验证 "Paris" / "408")。