关键发现: - 07-23: base corex chain 完好(GDN+MoE+FA2全fused), 但OOM(max_model_len=100000) - 08-07: 我们覆盖qwen3_5.py打断corex chain → GDN NaN + MoE Python fallback - 修复: patch_ops.sh v2 不覆盖base, max_model_len=80000 - 新增: verify_deployment.sh 真机验证, COMP168_DIAGNOSIS.md
166 lines
7.9 KiB
Markdown
166 lines
7.9 KiB
Markdown
# comp 168 Docker 诊断 → .so 开发清单
|
||
|
||
> 基于 `2d5232c5d6bc` (comp 168 docker log, 3786 行)
|
||
> 当前 HEAD: `b25fc53e` (414 commits)
|
||
|
||
## 一、comp 168 日志三大致命问题
|
||
|
||
| # | 错误 | 出现次数 | 根因 | 状态 |
|
||
|---|------|----------|------|------|
|
||
| 1 | `GDN NaN frac=0.9998` | 16次(layer 0-4) | 我们的 GDN prefill 实现产生 NaN → replace with zeros → 模型质量归零 | **P0 未修** |
|
||
| 2 | `vllm_moe_topk_softmax not found` | 39次 | `ixformer.functions` 没有 Python binding → fallback to Python for 循环 | **P0 需 .so** |
|
||
| 3 | `CUDA OOM 32 MiB` | 17次 | `max_model_len=100000` 超过 KV cache 容量 → engine 死亡 | ✅ 已修为 80000 |
|
||
|
||
## 二、真机探测确认的事实
|
||
|
||
从你贴的真机 probe 输出:
|
||
|
||
```
|
||
ixformer.functions 有:
|
||
✓ silu_and_mul, rms_norm, fused_add_rms_norm, rotary_embedding
|
||
✓ flash_attn_*, vllm_single_query_cached_kv_attention_v2
|
||
✓ vllm_cache_ops_reshape_and_cache, vllm_swap_blocks, vllm_copy_cache
|
||
✗ vllm_moe_topk_softmax (不存在!)
|
||
✗ moe_compute_token_index_api (不存在!)
|
||
✗ moe_w16a16_group_gemm (不存在!)
|
||
|
||
libixformer.so 中:
|
||
✓ 上述函数全部存在 (C++ 符号, xllm 的 ixformer.h 声明了它们)
|
||
但 Python binding (_C.so) 没有暴露
|
||
```
|
||
|
||
**结论**: MoE 7 步 pipeline 中的 topk_softmax / gen_idx / expand / group_gemm / combine 全部需要通过 `ix_moe_bridge.so` 桥接。
|
||
|
||
## 三、需要开发/修复的 .so 清单
|
||
|
||
### SO-1: `ix_moe_bridge.so` (MoE 7步 pipeline) — ✅ 代码已有,需真机编译验证
|
||
|
||
**源码**: `ex_engine/csrc/ix_moe_bridge.cpp` (258行)
|
||
**编译**: `ex_engine/precompile_ix_bridge.py` → `torch.utils.cpp_extension.load(-lixformer)`
|
||
**状态**: 代码写好了,Dockerfile 有 build step,但从未在真机验证过编译成功
|
||
|
||
真机验证命令:
|
||
```bash
|
||
cd /workspace/ex_engine
|
||
python3 precompile_ix_bridge.py
|
||
ls -la build/ix_moe_bridge*.so
|
||
python3 -c "import torch; from torch.utils.cpp_extension import load; m=load('test', sources=['csrc/ix_moe_bridge.cpp'], extra_ldflags=['-L/usr/local/corex/lib64/python3/dist-packages/ixformer', '-lixformer']); print(dir(m))"
|
||
```
|
||
|
||
### SO-2: GDN prefill 修复 — **P0 最高优先级**
|
||
|
||
**现状**: 我们的 `_torch_chunk_gated_delta_rule` 在 fp16 下产生 99.98% NaN
|
||
**参考**: `upstream_ref/xllm/core/layers/npu_torch/qwen3_gated_delta_net_base.cpp` (576行)
|
||
|
||
关键差异:
|
||
- xllm 用 `fp32` accumulation: `decay_mask = ... .exp().float()`
|
||
- xllm 用 `torch::matmul` 而不是自定义 chunk kernel
|
||
- xllm 的 recurrent state 管理有精确的 `clamp(-20, 20)` 限制
|
||
|
||
**解决方案**: 不写新 .so,而是从 xllm 搬运 GDN 的 PyTorch 实现(C++ torch ops, 全 fp32 accumulation),替换我们的 chunk kernel。
|
||
|
||
### SO-3: `_custom_ops.py` patch — ✅ 已有 fallback 逻辑
|
||
|
||
base image 的 `_custom_ops.py` 调用 `ixf_F.vllm_moe_topk_softmax` 时会报错。
|
||
但 comp 168 的 base 镜像绕过了 `_custom_ops`,直接走 `corex_moe.py` 的 7 步 pipeline。
|
||
|
||
**如果 base 有 corex_moe.py**: 不需要 patch
|
||
**如果 base 没有 corex_moe.py**: 我们的版本 + ix_moe_bridge.so 补位
|
||
|
||
## 四、upstream 已有、不需要重写的代码
|
||
|
||
| upstream 文件 | 行数 | 我们的对应文件 | 搬运状态 |
|
||
|--------------|------|---------------|---------|
|
||
| `xllm/core/kernels/ilu/ixformer.h` | 147 | `ex_engine/csrc/ilu/ixformer.h` | ✅ 已搬 |
|
||
| `xllm/core/kernels/ilu/fused_moe.cpp` | 99 | `ex_engine/csrc/ilu_kernel_fused_moe.cpp` | ✅ 已搬 |
|
||
| `xllm/core/layers/ilu/fused_moe.cpp` | 797 | `ex_engine/csrc/ilu_layer_fused_moe.cpp` | ✅ 已搬 |
|
||
| `xllm/core/kernels/ilu/attention.cpp` | 162 | `ex_engine/csrc/ilu_kernel_attention.cpp` | ✅ 已搬 |
|
||
| `xllm/core/layers/ilu/attention.cpp` | 189 | `ex_engine/csrc/ilu_layer_attention.cpp` | ✅ 已搬 |
|
||
| `xllm/core/kernels/ilu/norm.cpp` | 50 | `ex_engine/csrc/ilu_kernel_norm.cpp` | ✅ 已搬 |
|
||
| `xllm/core/kernels/ilu/activation.cpp` | 32 | `ex_engine/csrc/ilu_kernel_activation.cpp` | ✅ 已搬 |
|
||
| `xllm/core/kernels/ilu/rope.cpp` | 31 | `ex_engine/csrc/ilu_kernel_rope.cpp` | ✅ 已搬 |
|
||
| `xllm/core/kernels/ilu/group_gemm.cpp` | 39 | `ex_engine/csrc/ilu_kernel_group_gemm.cpp` | ✅ 已搬 |
|
||
| `xllm/core/kernels/ilu/matmul.cpp` | 73 | `ex_engine/csrc/ilu_kernel_matmul.cpp` | ✅ 已搬 |
|
||
| `xllm/core/layers/npu_torch/qwen3_gated_delta_net_base.cpp` | 576 | `ex_engine/csrc/qwen3_gated_delta_net_base.cpp` | ✅ 已搬 |
|
||
| `ds_vllm/csrc/moe/topk_softmax_kernels.cu` | 874 | `ex_engine/csrc/moe_v055/topk_softmax_kernels.cu` | ✅ 已搬 |
|
||
| `xllm/core/kernels/cuda/moe/moe_topk_softmax_kernels.cuh` | ~400 | `ex_engine/csrc/moe/moe_topk_softmax_kernels.cuh` | ✅ 已搬 |
|
||
|
||
## 五、真机验证 checklist
|
||
|
||
在真机上按顺序执行:
|
||
|
||
```bash
|
||
# 1. 验证 ix_moe_bridge.so 编译
|
||
cd /workspace/ex_engine && python3 precompile_ix_bridge.py
|
||
ls build/ix_moe_bridge*.so # 必须存在
|
||
|
||
# 2. 验证符号解析
|
||
python3 -c "
|
||
import torch
|
||
import importlib.util
|
||
spec = importlib.util.spec_from_file_location('ix', 'build/ix_moe_bridge.cpython-310-x86_64-linux-gnu.so')
|
||
m = importlib.util.module_from_spec(spec)
|
||
spec.loader.exec_module(m)
|
||
print([x for x in dir(m) if not x.startswith('_')])
|
||
# 应输出: ['topk_softmax', 'moe_gen_idx', 'moe_expand_input', 'moe_group_gemm',
|
||
# 'silu_and_mul', 'moe_combine_result', 'paged_attention', 'rms_norm',
|
||
# 'fused_add_rms_norm', 'linear', 'reshape_and_cache', 'rotary_embedding']
|
||
"
|
||
|
||
# 3. 验证 topk_softmax 功能
|
||
python3 -c "
|
||
import torch
|
||
# ... load ix_moe_bridge ...
|
||
gating = torch.randn(4, 64, device='cuda', dtype=torch.float32)
|
||
tw = torch.empty(4, 8, device='cuda', dtype=torch.float32)
|
||
ti = torch.empty(4, 8, device='cuda', dtype=torch.int32)
|
||
tei = torch.empty(4, 8, device='cuda', dtype=torch.int32)
|
||
m.topk_softmax(tw, ti, tei, gating)
|
||
print('topk_weights:', tw)
|
||
print('topk_ids:', ti)
|
||
"
|
||
|
||
# 4. 验证 GDN 不再 NaN
|
||
# (需要先修复 GDN prefill 代码)
|
||
|
||
# 5. 启动服务验证
|
||
python3 -m vllm.entrypoints.openai.api_server --model /model ...
|
||
```
|
||
|
||
## 六、最关键发现:07-23 的 base image 自带完整 corex_* chain
|
||
|
||
**07-23 日志证据** (dockerrizhi.txt):
|
||
```
|
||
corex_gdn.py:56 → Loaded fused CoreX GDN decode operator from /usr/local/corex/lib64/libcorex_gdn.so ✅
|
||
corex_gdn.py:228 → Using fused CoreX GDN prefill operator ✅
|
||
corex_moe.py:339 → Using CoreX fused MoE prefill operator: tokens=4096, kernel=expert-grouped-wmma ✅
|
||
corex_fa2.py:333 → Using CoreX FA2 packed prefill: B=2 Hq=4 Hkv=1 D=256 ✅
|
||
corex_fa2.py:507 → Using CoreX paged FA2 chunked prefill ✅
|
||
```
|
||
|
||
**08-07 日志**: 零条 corex_* 加载记录。取而代之的是 `qwen3_5.py:445 NaN in prefill` + `_custom_ops.py:58 topk_softmax not found`。
|
||
|
||
**根因**: 08-07 提交部署了我们自己的 `qwen3_5.py`,覆盖了 base image 自带的版本,打断了 `corex_gdn.py` / `corex_moe.py` / `corex_fa2.py` 的调用链。
|
||
|
||
**当前状态**: `patch_ops.sh v2` 已经有条件跳过逻辑(`_QW_SIZE > 1000 → KEEPING IT`),但需要确保下次提交时不再触发 qwen3_5.py 覆盖。
|
||
|
||
**结论**: 如果 base image 有工作的 corex_* chain,我们只需要:
|
||
1. 不覆盖 qwen3_5.py
|
||
2. 只部署 serving 层(protocol/serving_chat/api_server/tool_parser)
|
||
3. `max_model_len=80000`(已修)
|
||
4. `ix_moe_bridge.so` 作为备用(如果 base 的 _custom_ops 有路径碰到 topk_softmax)
|
||
|
||
## 七、代码量评估
|
||
|
||
| 组件 | 文件数 | 总行数 | 状态 |
|
||
|------|--------|--------|------|
|
||
| ex_engine/csrc (C++) | 39 | ~8000 | 全部已有,需真机编译 |
|
||
| ex_engine/python (Python) | 7 | ~1200 | 全部已有,dispatch chain 完整 |
|
||
| qwen3_6_scripts (serving) | 20+ | ~6000 | 全部已有,patch_ops.sh 管部署 |
|
||
| upstream_ref (xllm reference) | 500+ | ~100K | 参考用,关键文件已搬到 ex_engine |
|
||
|
||
**结论**: 代码量是够的。问题不是代码不够,而是:
|
||
1. GDN NaN 没修(需要用 xllm 的 fp32 accumulation 逻辑替换)
|
||
2. ix_moe_bridge.so 从未在真机编译成功
|
||
3. 没有 "不允许 fallback" 的硬要求落实到代码里
|