截至8月3日,官方未提供在Ascend 310P上使用Deepseekv4的适配。本人获得了一台搭载 4*DUO-96GB 的服务器,故尝试自行实现适配。
前置条件
8月1日,vllm-ascend main 分支有一个提交:[Refactor][Ops] Move Ascend routed experts logic out of MoE runner (#13268)
310P 新路径注册了:
_MoECommMethods[MoECommType.ALLGATHER] = \
AllGatherCommImpl310(self.moe_config)
并使用专门的:
TokenDispatcherWithAllGather310
该 dispatcher 会实际读取:
get_ep_group().rank_in_group
num_experts_local
expert_map
并计算每个 EP rank 的专家范围:
first_expert_idx = get_ep_group().rank_in_group * self.num_experts_local
last_expert_idx = first_expert_idx + self.num_experts_local
这说明 310P 已经具备了按 EP rank 分配本地专家,并通过 AllGather 完成 token 通信的实现。
第一阶段
基于 vLLM-Ascend 最新 main 建一个公开开发仓库,先完成可运行骨架:310P DeepSeek V4 接入、EP 保留、W8A8 路径和 MLA/DSA fallback 的最小实现与测试框架。检查账户与Git身份并匹配编码流程
GitHub 认证已确认,公开仓库名采用 fwerkor/vllm-ascend-deepseek-v4-310p。保留上游完整历史,并把原仓库设置为 upstream,便于后续持续同步和提交上游 PR。
公开仓库已经创建。现在先确认上游历史是否完整推送成功,然后直接建立第一个可测试分支和最小接入代码。
第一批代码不会直接删除限制。我会先新增一个显式实验开关和 310P DSV4 能力检查,让默认行为保持不变,并让启用时进入专用 KV-cache 分配路径,而不是误用普通 K/V 双缓存。
后端分派里还发现了第二个明确问题:310P 当前把所有 MLA/DSA 配置静默回退成普通 Attention backend。第一版会同时修正分派和 KV-cache 初始化,并把真正未实现的计算路径放到独立 310P 类中,便于逐个替换。
静态检查只发现一个 import 顺序问题;功能 helper 和语法检查尚未继续执行。我先修正后跑完整首轮测试。
首个公开提交已推送,提交 020f98877。它已完成正确分派、实验开关和 DSV4 KV-cache 接入;下一步直接在 310P 上用匹配的最新 main 环境跑启动探针,找出新的最前阻断点。
下一项优先处理权重量化。因为最新 main 已有 EP,最现实的方案是把每张卡本地专家从 MXFP4 在加载期转换成 310P 原生 W8A8,而不是让每卡持有全量 W8 权重。
权重路径可以在不依赖 FP4 硬件 dtype 的情况下实现,但必须先确认 DeepSeek checkpoint 的 nibble 顺序和 E8M0 scale 解码。否则“能加载”也可能 silently 产生错误权重,所以我先从现有转换实现和格式定义中提取精确规则。
第二个里程碑已经写入工作区:加载时将本地 EP 专家从 MXFP4 精确解码并重定量化为 310P 原生 W8A8。现在先做静态与数值单测,避免错误权重静默通过。
控制端没有安装 PyTorch,因此数值测试不能在这里执行;静态检查已通过。我把改动同步到 310P 机器,使用现有 torch-npu 镜像做 CPU/NPU 两侧数值验证。
CPU 数值验证通过。下一步验证同一转换在 310P 张量上可执行;若高级索引或位运算缺少 NPU kernel,就需要改成 CPU 流式转换或更基础的 ACLNN 运算。
310P 实机转换已通过:packed MXFP4 在 NPU 上完成解码、分组缩放和 per-row INT8 重定量化,没有再触发 FP4 custom-dtype 错误。首轮编译约 100 秒,后续会缓存。
量化提交已推送,当前分支头为 fa33fb654。接下来使用最新 nightly-main-310p 和真实 checkpoint 启动 TP=8、EP=8 探针,目标是定位量化阻断消除后的第一个实际失败点。
远端 Git 拉取遇到一次 TLS 中断,代码未损坏,仍停在首提交。我会重试同步;这与 NPU 后端无关。
远端 Git 仍未更新,但首提交完整存在。为避免网络干扰实机测试,我直接同步量化实现的运行时文件;公开仓库已包含相同代码。
在启动全模型前,我会加入一次性形状日志,确认 EP=8 时每个 rank 只转换 32 个本地专家;这是显存可行性的关键验证。
诊断日志已本地提交为 64b8319a6;GitHub 临时返回 503,稍后重推。实机测试不受影响,我先同步该文件并继续。
夜间镜像基线为 vLLM 0.26.0、torch-npu 2.10.0.post2、vLLM-Ascend 提交 8f3fd59a。现在开始八卡 dummy 权重启动,先验证模型构造、EP 分片、KV-cache 与后端分派。
探针已启动,当前仍处于容器和 Python 初始化阶段,尚未进入模型日志。该镜像首次导入通常需要较长算子初始化;我同时检查 NPU 进程和显存变化。
探针在进入 vLLM 前退出,且 job 未捕获到 stderr;NPU 未启动,说明是容器准备阶段问题,不是模型错误。我先验证同步文件和脚本展开,再保留失败容器日志。
源码覆盖与模块导入均通过。上次退出很可能发生在文件同步尚未完成的窗口;我将探针改为保留容器并开启命令追踪,重试后可直接读取 docker logs。
容器保持运行,但 Python 仍未刷新日志;八卡均尚未创建 worker。继续观察到首次插件导入完成。
已找到退出原因:不是模型,而是 set -e 下重复 source set_env.sh,脚本内部一次未匹配的 grep 导致容器提前退出。镜像本身已经设置环境,删除重复 source 后重跑。
修复后已进入 vLLM 插件初始化,说明源码覆盖正常。尚未看到 CLI/引擎配置,继续等待 tokenizer 和模型配置解析。
CLI 参数已完整接受,包括 --enable-expert-parallel;目前正在解析 DeepSeek V4 配置,NPU worker 尚未创建。继续跟踪到模型 executor 启动。
新的首个真实阻断已定位:还没到 MoE/DSA,普通 FP8 线性层被 vLLM 上游 GPU ScaledMM 内核接管,310P 找不到实现。需要让 deepseek_v4_fp8 确实映射到 Ascend 的 FP8 线性方法,而不是仅注册同名配置。
根因修复很小但关键:310P 平台初始化此前没有导入 AscendFp8Config,所以同名量化配置没有覆盖上游 GPU 实现。现在补上注册后重跑同一探针。
当前仍在插件和 tokenizer 初始化阶段,尚未到 worker。修复是否生效要等模型构造日志出现;继续观察。
FP8 修复已生效:日志出现 Using the vLLM Ascend fp8 Quantization,8 个 rank 分别获得 EP rank 0–7,HCCL 初始化完成。模型现已进入参数创建,下一步看本地专家数量与显存。
FP8 后端已修复;当前失败只来自 --load-format dummy:dummy loader 试图把 E8M0 自定义 scale 转成 FP16,310P 的 aclnnInplaceCopy 不支持。它不影响真实 checkpoint,但会阻断结构探针。我会只在探针脚本中为自定义 dtype 写入安全零值/单位 scale。
探针脚本的嵌入源码包含 doesn't,打断了外层单引号;这是纯脚本转义问题。改成无撇号文本后继续。
第五次探针已启动。此前已排除平台注册和 E8M0 dummy 初始化问题;这次预期进入本地专家后处理,关键日志是 experts=32。
第五次探针未进入模型:探针补丁匹配了修改后的注释文本,而镜像源码仍保留原注释,导致上下文不匹配。我改成只替换稳定的 if torch.finfo(...) 行,避免依赖注释内容。
第六次探针正在重复八卡初始化。我同时检查为什么当前选择的是 AscendMLABackend310 而不是 DSA,避免模型加载后才发现 KV-cache 类型不匹配。
第六次仍停在探针自身:嵌入 Python 把换行写成了字面量 \\n,因此匹配不到源码。后端没有继续执行。我先把探针补丁单独验证通过,再重跑八卡,避免重复消耗初始化时间。
已确认探针兼容补丁可应用。另一个分派问题也已确认:DeepSeek V4 所有层都构造 DSAAttention,压缩比是逐层决定的,不能用全局 use_compress 选择 MLA。实验开关启用时应统一进入 DSA 后端。
DSA 分派修复已推送,分支头为 e6e7dbdf2。下一次探针将同时验证:dummy E8M0 初始化、本地 EP 专家数量、MXFP4→W8A8 后处理,以及 DSA KV-cache 初始化。
第七次探针已正常进入引擎配置,未再出现 dummy loader 补丁错误。现在等待八卡 HCCL 和模型后处理阶段;这一阶段会直接验证 EP 是否只保留 32 个专家。
DSA 分派已经验证生效。当前仍是 dummy loader 的第二种 FP8 dtype:E8M0 已绕过,但 E4M3 仍被强制转 FP16。真实权重加载不走这段逻辑;我会让探针直接按位填充所有 FP8 dummy 参数,再进入专家后处理。
全 FP8 dummy 填充已在 310P 实机验证,八卡探针 v8 已启动。等待期间我会提前核对 W8A8 MoE 参数创建与 EP 分片语义,避免下一个接口错误再靠整模初始化发现。
关键里程碑已确认:EP=8 生效,每个 rank 只保留并转换 32 个专家。当前单卡约占 22.4–23.0GB,离 44GB 上限尚有约 21GB;量化与显存路线成立。现在等待 43 层转换完成并进入 KV-cache/首次前向。
转换仍在持续,单卡显存升至约 29.4–30.0GB。这里正在暴露真实容量边界:每个本地专家从 4bit 扩成 8bit,最终权重预计接近每卡 38–40GB;是否能留下 KV-cache 空间要看转换完成后的稳定占用。
W8A8 全量展开已验证能加载完整模型并进入 profile_run,但稳定占用约 39.6–40.3GB,HCCL 连 2MB 缓冲都无法再申请。下一步改为保留 packed MXFP4,仅在当前 MoE 层执行时临时转 W8A8,将常驻显存降回约 20GB。
全量展开路线的结论已经明确:模型能够加载并进入首次 profile forward,但约 40GB/卡导致 HCCL 初始化 OOM。流式版本先做小张量实机验证,确认临时转换后的格式能直接交给现有 310P W8A8 MoE。
小张量流式测试超过 120 秒限制,原因是首次 JIT 编译,不代表失败。改用持久任务继续执行并读取结果。
流式专家小张量实机验证通过:packed (2,16,16) 正确物化为 INT8 (2,16,32),scale 转为 FP32,NZ 格式准备可执行。现在提交该内存修复,并重新跑完整八卡 profile。
流式版本完整探针 v9 已启动。预计常驻显存降至约 21–23GB;我同时解析第 0 层的 DSA 压缩比和调用顺序,提前准备第一个算子 fallback。
流式权重路线已把常驻显存降到约 22GB/卡。当前首个计算阻断是 Hyper-Connection 的 npu_hc_pre_v2 缺失,我会先按算子语义实现 310P 组合算子 fallback。
源码中已经存在官方 composite 参考路径:npu_hc_pre,它由 HcPreInvRms + Linear + HcPreSinkhorn 组成。先确认 nightly 310P 是否只缺融合版 v2,而 composite 版和 hc_post 已存在。
310P 镜像中五个 HC 自定义算子全部未注册,因此需要纯 torch_npu 组合实现。下一步从 DeepSeek V4 原始模型代码和 AscendC kernel 中恢复 Sinkhorn、post、comb 的精确公式。
已经完成并实机验证
1. DeepSeek V4 的 310P 后端入口
加入显式实验开关:
export VLLM_ASCEND_ENABLE_DSV4_310P=1
新增:
vllm_ascend/_310p/deepseek_v4.py
vllm_ascend/_310p/attention/dsa_v1.py
vllm_ascend/_310p/attention/mla_v1.py
并修改了:
vllm_ascend/platform.py
vllm_ascend/_310p/model_runner_310p.py
现在不会再被这两个原始限制直接挡住:
Deepseek Sparse Attention is not supported for 310P
MLAAttention is not supported for 310P
DeepSeek V4 的注意力层已经正确选择:
AscendDSABackend310
2. 修复了 FP8 后端错误分派
原先 310P 没有注册 AscendFp8Config,导致 DeepSeek V4 的普通 FP8 线性层进入 GPU ScaledMM 实现。
修复后实机日志为:
Using the vLLM Ascend fp8 Quantization now!
普通 FP8 线性层已经使用 Ascend 后端。
3. 验证 310P 的 Expert Parallel
最新 vLLM-Ascend main 的 AllGather EP 路径在这台机器上可以初始化:
TP rank 0–7
EP rank 0–7
每个 rank 实际只保存 32 个本地专家:
w13=(32, 4096, 2048)
w2=(32, 4096, 1024)
experts=32
所以,310P 并非不能做 EP;当前开发直接复用了上游最新的 AllGatherCommImpl310。
4. 实现 MXFP4 软件解码
已经实现 checkpoint 使用的精确格式:
- E2M1 FP4 数值映射;
- 每字节两个 FP4,低 nibble 在前;
- E8M0 scale 解码;
- group size 32;
- 对称 per-row INT8 重定量化;
- 310P NZ 格式转换。
CPU 数值测试和 310P NPU 小张量测试均已通过,不再调用芯片不支持的:
float4_e2m1fn_x2 → float8_e4m3fn
因此硬件 ERR00007 已经绕开。
5. 解决 W8A8 常驻显存问题
第一版将所有本地专家长期展开成 W8A8。模型能够完整加载并进入第一次 profile_run,但显存达到:
约 39.6–40.3 GB/卡
HCCL 随后连约 2 MB 通信缓冲都无法申请。
现在改为默认:
VLLM_ASCEND_DSV4_310P_EXPERT_MODE=streaming_w8a8
即:
常驻 packed MXFP4
→ 当前执行层临时解码成 W8A8
→ 调用现有 310P W8A8 MoE
→ 下一层复用临时空间
实机稳定显存已降至:
约 22.1–22.7 GB/卡
八卡模型已经成功加载到第一次 decoder layer,显存路线成立。
当前阻断
第一次实际前向运行到 Hyper-Connection 时失败:
AttributeError:
'_OpNamespace' '_C_ascend' object has no attribute 'npu_hc_pre_v2'
310P nightly 中以下五个 HC 算子均未注册:
npu_hc_pre_v2
npu_hc_pre
npu_hc_pre_inv_rms
npu_hc_pre_sinkhorn
npu_hc_post
不过 checkpoint 自带的官方参考实现包含完整公式。我已经提取出来:
x_flat = x.flatten(2).float()
rsqrt = torch.rsqrt(x_flat.square().mean(-1, keepdim=True) + norm_eps)
mixes = F.linear(x_flat, hc_fn) * rsqrt
pre = sigmoid(mixes[..., :hc] * hc_scale[0] + hc_base[:hc]) + eps
post = 2 * sigmoid(
mixes[..., hc:2 * hc] * hc_scale[1]
+ hc_base[hc:2 * hc]
)
comb = mixes[..., 2 * hc:].view(..., hc, hc)
comb = comb * hc_scale[2] + hc_base[2 * hc:].view(hc, hc)
comb = softmax(comb, dim=-1) + eps
# Sinkhorn
comb = comb / (comb.sum(-2, keepdim=True) + eps)
for _ in range(sinkhorn_iters - 1):
comb = comb / (comb.sum(-1, keepdim=True) + eps)
comb = comb / (comb.sum(-2, keepdim=True) + eps)
y = torch.sum(pre.unsqueeze(-1) * x, dim=-2)
对应 hc_post:
y = (
post.unsqueeze(-1) * x.unsqueeze(-2)
+ torch.sum(
comb.unsqueeze(-1) * residual.unsqueeze(-2),
dim=-3,
)
)
因此该阻断可以使用普通 torch_npu 算子补齐,不需要猜测算法。
第二阶段
继续从当前首个阻断 npu_hc_pre_v2 开始,先实现官方参考公式的 310P torch_npu fallback,再跑八卡完整 profile 定位下一处 DSA 算子。完成310P算子适配、测试修补及DeepSeek V4文档更新
Hyper-Connection 组合实现已完成静态检查。下一步在 310P 上做数值对照和实际 NPU 执行测试,确认 Sinkhorn、HC pre/post 都能由现有 ACLNN 算子完成。读取作业最新输出
Hyper-Connection 测试仍在首次编译阶段,尚未返回错误。我检查进程和 NPU 状态;若只是 TBE 编译则继续等待,若卡在 FP32 MatMul 则改用分解路径。检查Hyper-Connection测试进程及作业尾部输出
310P 数值验证通过:y/post/comb/out 与 CPU 参考最大误差不超过 1.2e-7。我现在提交到 main,并把完整八卡探针改为加载这两个新文件。启动DeepSeek V4完整八卡性能探测
完整八卡探针已启动。模型初始化本身约需三分钟;通过 HC 后,下一阶段将实际执行流式 W8A8 MoE,可能暴露 MoE 接口或通信问题。检查八卡容器、Worker、模型加载及显存状态
HC 已通过,新的首个阻断来自流式 MoE 权重布局:w13 被转成了 4 维 NZ,而 310P grouped matmul 要求 5 维。这里是形状适配问题,不是缺算子;我会按原生 W8A8 MoE 的 [E,2,N,K] 布局修正。分析并修复310P W8A8 MoE权重维度重塑
已确认根因:w13 的逻辑布局必须先从 [E, 2I, H] 重塑为 [E, 2, I, H],再转 FRACTAL_NZ,才能得到 grouped matmul 要求的 5 维物理存储;w2 仍保持三维逻辑布局。同步量化方法文件至 NPU 测试机
布局修复已同步。我先用小张量直接检查 4D 逻辑权重转 NZ 后的底层存储维数,再决定是否立即重跑整模。验证Grouped Matmul权重布局及MoE修复探针
v11 已启动。若 w13 布局修复正确,profile 会越过第一层 grouped matmul;随后最可能出现的是 w2 scale/布局或 EP token dispatcher 的接口问题。检查八卡Worker模型加载及v11运行日志
v11 仍显示旧的 4 维物理存储。原因很可能是 unflatten 只是视图,NPU storage descriptor 仍继承三维底层张量;需要显式复制成真正的四维 ND 张量后再转 NZ。验证视图复制并解析310P MoE量化矩阵乘输入
我会用最小 grouped-matmul 直接验证逻辑 4D 权重是否真的生成 5D NZ 存储。这样不用每次等待整模三分钟,也能确定需要哪种物理布局。验证量化矩阵权重布局并检查NPU训练输出
小型算子表明 3D/4D 权重本身都能执行;整模错误不是简单的 unflatten 问题。下一步在真实 profile 中打印传入 GMM 的逻辑形状、format、scale 和 group_list,确定权重在哪一层被重解释成 [128,8192,…]。定位并搜索torch_npu NPU权重存储描述接口实现
从错误形状反推,[128,8192,16,32] 恰好是把 5.36 亿个 w13 元素折叠成二维后得到的 NZ;因此我不再假设 4D gate/up 轴正确。下一步用真实层尺寸直接测试原始 3D [32,4096,4096],确认大尺寸 GMM 的实际要求。复现并检查量化GMM布局及作业结果
真实原因已确定:重定量化函数先分配二维 [E×N,K],最后只做 reshape;NPU 的 storage descriptor 仍是二维,因此转 NZ 后只有 4 维物理存储。直接创建的三维权重可以通过。现在验证 clone 是否刷新 descriptor;若不能,就改为直接按逻辑三维分配输出。验证张量描述符刷新并读取编译任务输出
探针已证明:二维底层张量 reshape 成三维会失败,而 clone/重新分配三维张量后可通过。最优修复是在重定量化函数一开始就按最终逻辑形状分配输出,避免额外整层复制;同时撤销错误的 4D gate/up 改动。修复并验证MXFP4重定量化输出存储形状
静态检查通过;控制端没有 PyTorch,因此数值测试需在 310P 镜像执行。现在同步重定量化文件,并直接用其输出调用 grouped matmul,验证 descriptor 修复而不等待整模。查看作业最新输出
重定量化输出现在是独立三维存储,且其结果已直接通过 310P quantized grouped matmul。接下来重跑八卡 profile;这次应同时越过 w13 和 w2 的 NZ descriptor 问题。完成v12模型初始化并检查流式MoE运行错误
路由专家的两次 grouped matmul 已经通过;当前错误已推进到共享专家:其普通 FP8 权重仍是 float8_e4m3fn,而 310P npu_quant_matmul 只接受 INT8。下一步把所有 DeepSeek V4 FP8 线性层在加载后转换为 310P W8A8。实现FP8权重转换与310P动态量化读取
共享专家只是第一个暴露点;同一 FP8→INT8 转换需要覆盖所有普通线性层。第一版会保持 checkpoint 的 FP8/128×128 block-scale 参数接口,加载后软件解码为 per-row INT8,并复用 310P 动态 W8A8 matmul。检查DSA的W8A8线性识别实现
为兼容 DSA 的现有分支,自定义方案会继承通用 AscendW8A8DynamicLinearMethod,但保留 checkpoint 的 FP8 权重和 block-scale 加载接口;加载完成后转换为 310P per-row INT8/NZ。完成DeepSeek FP8转310P W8A8及静态验证
FP8 线性转换已通过静态检查。下一步用 310P 实机验证三件事:E4M3 解码值、block-scale 重建精度、转换后的 INT8/NZ 权重能直接执行动态量化 matmul。读取任务最新输出
FP8 软件解码和转换后的动态 W8A8 matmul 已在 310P 通过。当前两项修复均有独立实机验证,我先提交到 main,再运行完整八卡 profile。完成量化修复提交并验证FP8八卡性能
v13 正在初始化。共享专家权重问题解决后,紧接着会调用融合的 npu_dequant_swiglu_quant;我并行检查该算子在 310P 镜像中的可用性,提前准备 fallback。检查并实现310P共享SwiGLU融合算子与量化回退
v13 已运行一段时间,我先读取完整结果;若如预期停在共享专家的融合 SwiGLU,我会直接补纯 torch_npu fallback。查看NPU作业输出并读取v13八卡探针结果
v13 还在执行全模型 FP8→INT8 加载期转换,尚未进入 profile。等待期间我先提取缺失融合 SwiGLU 的官方 Python golden,避免下一次再停留。读取并核对 Dequant SwiGLU Quant 黄金测试实现
融合算子的 golden 已确认:先用 int32 × weight_scale × activation_scale 反量化,再执行带可选 clamp 的标准 SwiGLU,最后 npu_dynamic_quant。我现在将其作为 310P 专用共享专家 fallback 接入。检查v13模型转换与加载日志
v13 没有走到融合 SwiGLU;新的首个错误更早:共享专家 gate/up 要求 output_dtype=int32,此模式下 310P npu_quant_matmul 的 scale 必须是 INT64 编码,不能使用 FP32。先修正共享专家的双份 scale 表示。修复共享专家INT32量化缩放类型兼容性
根因不是量化数值,而是 310P 的 output_dtype=int32 接口约定:矩阵乘使用 INT64 位编码 scale,后续反量化仍需要 FP32 scale。我会同时保留 weight_scale_int64 和 weight_scale_fp32,共享专家各阶段分别使用。修复共享专家量化回退并完成SwiGLU检查
静态检查通过。现在做一条完整单卡链路验证:动态量化输入 → INT8 gate/up matmul 输出 INT32 → 组合反量化/Clamped-SwiGLU/再量化 → INT8 down matmul。等待任务完成更多输出
单卡验证发现更深一层限制:310P 的 WeightNZ QuantMatmul 不允许 INT32 输出,只允许 INT8/FP16。因此不能仿照 A2/A3 的“INT32 累加→融合反量化”路径。改为直接输出 FP16 gate/up,再执行 clamp+SwiGLU+动态量化,数值等价且完全使用 310P 支持的接口。重构并验证310P共享专家FP16量化路径
FP16共享专家路径已通过静态检查。现在重复单卡完整链路,确认 gate/up FP16 输出、SwiGLU再量化和 down projection 都能执行。继续等待任务输出
共享专家完整链路已在 310P 通过:FP16 gate/up (7×192) → INT8 SwiGLU (7×96) → FP16 down (7×64)。我提交到 main,然后启动 v14 八卡 profile。完成共享专家回退、算子同步及八卡性能验证
v14 已启动。若共享专家通过,profile 将首次完整遍历 43 层;由于流式专家每层临时解码,这一轮可能明显慢于此前只跑到第一层的探针。检查八卡Worker、模型加载及显存状态完成
本轮完成
最新提交:
09bb8dc6e01b65ef2641ca109dfae249a91d7e14
feat(310p): add shared expert SwiGLU quant fallback
公开仓库:
DeepSeek V4 Ascend 310P backend
已完成并实机验证:
- Hyper-Connection 的 HC pre、Sinkhorn、HC post 组合实现。
- 修复 MXFP4 重定量化张量的 NPU storage descriptor。
- 路由专家两次 310P Quantized Grouped MatMul 已通过。
- 实现 E4M3FN 软件解码。
- 将普通 FP8 线性层和共享专家权重转换为 310P W8A8。
- FP8→W8A8 线性层在 310P 上已完成单卡 MatMul 验证。
- 确认 310P WeightNZ QuantMatmul 不支持 INT32 输出,只支持 INT8/FP16。
- 因此重写共享专家路径为:
输入动态 INT8 量化
→ W8A8 gate/up MatMul,直接输出 FP16
→ Clamp + SwiGLU
→ 动态 INT8 量化
→ W8A8 down MatMul,输出 FP16
该完整共享专家链路已在 310P 上通过:
FP16 gate/up: (7, 192)
INT8 SwiGLU: (7, 96)
FP16 down: (7, 64)
当前探针
八卡探针 v14 已启动,配置为:
TP=8
EP=8
流式 MXFP4 专家
FP8→W8A8 普通线性层
Hyper-Connection fallback
共享专家 FP16 SwiGLU fallback
本轮结束时,v14 仍处于早期容器和八卡初始化阶段,尚未产生新的模型错误或通过结论。
第三阶段
先读取 v14 八卡探针的最终状态和首个新阻断;随后按实际错误继续补 310P fallback,并保持每项修复先做单卡算子验证再重跑整模。查看了 npu310p 远程作业输出
v14 已经越过 43 层模型 profile、路由专家、共享专家和普通线性层,首次到达 KV cache 分配阶段。当前只是 310P 分配器断言只接受普通 AttentionSpec,而 DSV4 返回 AscendMLAAttentionSpec;我现在适配 MLA 压缩 KV 的张量布局。运行静态检查与定向测试
KV 分配修复已通过 lint 和编译检查;控制端缺少 PyTorch,无法运行 pytest。我将改动同步到 310P 机器,在同一 nightly 镜像内运行聚焦单测,并直接启动 v15 验证真实 MLA cache 分配。验证完整实验源码中的键值缓存分配器委托
MLA allocator委派已在同一 310P nightly 环境通过聚焦验证。修复将 AscendMLAAttentionSpec 交给现有通用 MLA 分配/reshape 逻辑,而普通 310P AttentionSpec 路径保持不变;现在提交并启动 v15。扫描敏感信息并修复提交310P MLA KV分配及启动测试
v15 仍在容器和分布式初始化阶段。下一潜在风险是 KV block zeroer 对 MLA cache 元组的处理;我并行检查 310P zeroer 是否仍只假设普通 K/V cache。检查310P零页器兼容性及v15模型加载状态
v15 没有报错,当前处于全模型权重量化/算子编译阶段;八卡显存约 24.3–24.9 GiB,部分卡仍有 AICore 活动。继续等待其越过 profile,不中断进程。检查了 v15 进程进度与日志
模型权重已完成加载,每卡占用约 20.12 GB;当前八个 worker 均接近满 CPU,正在进行 43 层 profile,而非死锁。等待期间我审查 310P DSA/MLA 运行路径中的显式未实现分支,提前处理真实请求可能遇到的阻断。审查310P DSA与MLA实现及算子兼容性
为加快后续迭代,我正在确认 vLLM 是否支持显式指定 KV cache 内存,从而跳过每次约束 profile;若可用,后续探针将直接进入 KV 分配和真实请求路径,不再重复整模 dummy profile。检查 vLLM 参数及远程任务与模型运行状态
v15 已完整成功:43 层 profile、MLA KV cache 分配、warmup 和 OpenAI API 启动均通过,端口 8000 已监听。现在发送最小真实请求,开始验证 prefill、DSA cache 写入和 decode 路径。验证 OpenAI 模型列表接口
健康检查和 /v1/models 均正常。接下来发送 max_tokens=1 的最小 completion;由于每层专家仍是流式 MXFP4→W8A8 转换,首个请求会真实覆盖全部 prefill/DSA 路径。验证真实请求推理流程并监控NPU活动
首个真实请求已进入 attention metadata 构建,当前首个阻断明确为缺失的 npu_sparse_attn_sharedkv_metadata。该算子只生成 decode 稀疏注意力元数据,不做大矩阵计算;我先从现有测试和算子定义提取精确输出契约,再用纯 Torch/NPU 实现 310P fallback。检索并分析稀疏注意力元数据生成实现
我继续解析该元数据算子的调度算法和内核消费方式。目标是先实现一个严格正确的 310P 保守调度版本,再用显式 --kv-cache-memory 缩短整机重启验证周期。检查310P适配器重写与设备算子选择
元数据内核的区间协议已确认。因为参考 AICPU 当前 supportFd=false,它本身不会跨核拆分单行;因此一个合法、保守且精确的方案是仅启用 AIC core 0,并把完整 [BN2=0, batch×KV-head) 区间交给它,其他核全部禁用。先实现这一版本。实现并检查310P稀疏注意力元数据回退 lint
保守调度实现已通过静态检查。其输出与内核半开区间协议一致:core 0 负责全部 BN2,core 1–35 与所有 FD vector 均禁用。现在同步到 310P,验证 NPU 张量输出和 DeviceOperator 选择。同步310P稀疏注意力元数据并验证回退功能
元数据张量函数本身尚未失败;测试因直接把整个源码树置于 PYTHONPATH 触发了仓库现有的循环导入。改用生产探针相同方式,把两个文件安装进镜像内的包目录后重测。验证已安装包元数据回退并测试310P张量生成
元数据张量已在 310P 实机通过。下一步先确认真正的 sparse-attention 计算算子是否也缺失;同时把探针改为显式 8 GiB KV cache,后续重启将跳过约 4 分钟的显存 profile。检查稀疏注意力算子可用性
镜像中 DSA 六个自定义算子全部缺失,包括计算算子本身。单独补元数据不足。当前最可行的正确路径是:在短上下文阶段禁用压缩/稀疏分支,所有层使用原始 MLA KV 做密集注意力;先确认模型 sliding window 与 128-token 探针范围是否完全覆盖。检查 DeepSeek V4 注意力配置及 DSA、MLA 实现
由于 sliding_window=128 且当前服务 max_model_len=128,压缩 KV 在整个允许范围内没有任何可见 token;只使用原始 SWA KV 与完整 DSA 数学严格等价。下一步实现 310P 专用短上下文密集 MLA:跳过 compressor/indexer,自行完成 Q/KV 投影、RoPE、paged cache 写入和 attention。检查并梳理 DeepSeek V4 注意力缓存与计算逻辑
密集 fallback 的数值路径已确定,包括 attention sink:它作为额外 softmax logit、对应零 value。先在 310P 上验证所需基础算子组合:paged cache index_copy_、高级索引 gather、短序列 QK/softmax/V 和部分 RoPE。测试BF16 NPU稠密算子并验证DSA回退原语
基础 cache 写入、gather、QK/softmax/V 均已在 310P 通过;唯一失败是硬件 npu_rotary_mul 不支持 interleave 模式。RoPE 将改为纯张量偶/奇维旋转。同时检查 metadata builder 中剩余的 compressor/indexer 自定义算子,统一在短上下文模式跳过。检查 DSA 元数据构建器算子调用及 DeepSeek V4 RoPE 缓存格式
我继续实现短上下文密集 DSA。当前约束已固定:服务最大长度 128,正好等于 sliding window,因此在该配置内跳过压缩 KV 与 indexer 不改变注意力结果。完善并检查DSA回退及注意力缓存实现
实现将拆成可独立验证的三层:纯张量 interleaved RoPE、paged SWA cache 读写、带 attention sink 的因果滑窗注意力;模型类只负责投影和调度,便于先在 CPU/单卡验证数学契约。实现短上下文注意力后端并添加QLI元数据访问器
密集 DSA 主路径已接入,并将未使用的 lightning-indexer metadata 替换为 310P 零缓冲。现在补充纯数学回归测试,重点验证 interleaved RoPE 可逆、paged cache 映射和 attention sink 分母语义。运行代码检查与测试
静态检查已通过;控制端仍因未安装 PyTorch 无法执行 pytest。接下来在 310P 镜像内运行同样的 RoPE、cache 和 sink 测试,并检查模型类能否正常导入。修复 DSA 注意力计算栅栏导入
导入路径已校正。现在同步模型实现与 metadata builder 改动,在 nightly 包目录中执行:模块导入、纯张量 RoPE 可逆性、paged cache、sink 注意力以及 QLI 零 metadata。运行昇腾设备测试容器
单卡测试首次执行触发了 310P TBE 编译,超过同步命令时限,未返回算子错误。我改为后台作业读取结果,不重复启动另一份编译。完成密集型DSA测试探查与日志配置检查
RoPE、paged cache、因果滑窗及 attention sink 已全部在 310P 实机通过。现在启动 v16;显式 8 GiB KV cache 将跳过完整 profile,服务启动后立即发送一 token 真实请求。完成第十六版服务集成测试并检查启动错误
v16 已接受显式 kv_cache_memory_bytes=8589934592,确认会跳过显存 profile;当前尚在分布式 worker 初始化,未出现导入或配置错误。检查v16模型服务启动及KV缓存配置
模型加载已缩短到约 109 秒;当前 worker 正在分配/初始化 8 GiB KV cache,AICore 有活动,尚无错误。等服务监听后直接发真实请求。检查v16 API启动及KV缓存初始化预热进度
v16 已启动成功,MLA KV cache、warmup 和端口 8000 均完成。现在发送真实 Hello → 1 token 请求;这一轮将首次执行 43 层密集 DSA、真实 cache 写入及后续 MoE。验证服务状态并排查DeepSeek请求错误及NPU占用
请求作业的失败是宿主缺少 /usr/bin/time,请求本身尚未发送,服务仍健康。我去掉计时包装后重新发起。重试并检查日志定位密集型DSA请求阻塞
真实请求没有进入新 fallback:栈仍落在基类 vllm_ascend/attention/dsa_v1.py。这说明 v16 启动时远端 _310p/attention/dsa_v1.py 仍是旧版本,属于同步时序问题,不是密集注意力算法失败;我先核对远端文件和传输任务。验证DSA覆盖文件、容器状态及后端注册实现
根因已定位:DSAAttention.__init__ 硬编码 AscendDSABackend,完全忽略平台返回的 310P backend,所以新实现从未实例化。现在修正构造器在实验开关启用时选择 AscendDSABackend310。修复310P DSA动态选择并检查内存与KV缓存配置
同时修复 310P worker 忽略 kv_cache_memory_bytes 的问题。此前显式 8 GiB 仍做了约 4 分钟 profile;修复后后续启动只需模型加载和 cache 分配。修补并同步310P显式KV缓存及DSA实现并完成验证
远端三项修复已逐项校验存在。启动 v17 后应在模型构造日志中出现 AscendDSAImpl310 警告,并直接使用 8 GiB KV cache,跳过之前约 4 分钟 profile。验证AscendDSAImpl310初始化及模型权重加载完成
v17 已确认实际实例化 AscendDSAImpl310,此前硬编码问题已解决。继续等待约 100 秒完成权重转换;之后应直接跳过 profile。检查模型加载完成及KV缓存启动日志
已解决
- 确认 v15 已完整通过
- 43 层 dummy profile
- MLA KV cache 分配
- warmup
- OpenAI API 启动
/health和/v1/models正常
- 补齐 310P DSA metadata fallback
- 稀疏注意力 metadata 使用合法的单 AIC core 保守调度。
- lightning-indexer metadata 在短上下文模式下使用未消费的零缓冲。
- 实现 310P 短上下文密集 DSA
- 当前
max_model_len=128,等于模型sliding_window=128。 - 在此范围内不存在可见的压缩 KV,因此只使用原始 SWA KV 与完整 DSA 数学等价。
- 已实现:
- 纯张量 interleaved RoPE 及逆 RoPE
- paged SWA KV cache 写入和读取
- 因果滑窗 attention
- attention sink 的额外 softmax 分母语义
- 上述基础路径已在 310P 实机通过。
- 当前
- 修复实际 310P backend 未生效的问题
DSAAttention原先硬编码通用AscendDSABackend。- 已修改为实验开关启用时实例化
AscendDSABackend310。 - v17 日志已经确认实际构造了
AscendDSAImpl310。
- 修复重复 profile
- 310P worker 原先忽略
--kv-cache-memory。 - 现在显式使用 8 GiB KV cache 并跳过 profile。
- 初始化阶段从约 255 秒降至 8.94 秒,模型权重加载仍约 109 秒。
- 310P worker 原先忽略
当前运行状态
v17 服务已成功启动:
AscendDSAImpl310: 已实例化
模型加载: 约 109 秒
KV cache: 8 GiB
KV cache 容量: 14,871 tokens
cache 初始化和 warmup: 8.94 秒
端口 8000: 正常监听
/health: HTTP 200
这是 --load-format dummy 服务,因此生成内容本身没有模型语义,只用于验证执行路径。
尚未完成
由于本轮工具执行时间结束,v17 启动后还没有重新发送真实的一 token 请求。因此当前尚未确认:
- 密集 DSA 是否能完整遍历 43 层;
- decode 是否能返回第一个 token;
- 后续是否还存在普通线性层、MoE 或输出投影的真实数据路径问题;
- 真实 checkpoint 加载和有效文本生成。
第四阶段
先对当前 v17 服务发送真实单 token 请求,确认密集 DSA 是否实际覆盖 43 层;若出现新阻断,就按首个真实错误继续修补。检查服务健康状态并发送请求
请求已进入 v17 的 310P 实现,但仍在 2 秒内触发新错误。现在提取首个完整堆栈,确认是密集 DSA 内部问题还是后续投影/MoE 问题。检查并提取请求失败日志
首个新阻断很明确:310P 的非连续 paged cache 不支持 BF16 index_copy_。模型当前虽以 FP16 运行,SWA cache 仍被硬编码为 BF16;我将 310P 的 SWA cache 改为 FP16,使 cache 规格、写入和计算一致。修复并验证310P及深度搜索FP16缓存补丁
FP16 cache修复已同步并校验。启动 v18;由于已跳过 profile,预计主要耗时只剩约 109 秒权重加载,随后立即重发真实请求。重启并检查深度求索V4八卡服务状态
v18 已进入八卡权重加载,尚无新错误;FP16 cache 变更要到 KV 分配阶段才生效。继续等待加载完成后验证启动和真实请求。检查模型加载、容器日志及服务健康状态
v18 已正常启动,SWA cache 现在为 FP16。开始第二次真实单 token 请求;这次将验证 cache 写入后能否继续进入密集注意力和输出投影。启动并轮询 DeepSeek-V4 单令牌请求
FP16 cache写入已通过,密集注意力也完成;新阻断已推进到第一层输出投影。通用路径假设 wo_a.weight 是三维分组权重,但 310P 当前转换后的权重为二维,导致 batch matmul 维度错误。我先核对 O-LoRA 权重布局,再改用匹配该布局的 FP16 线性路径。检查并修复O-LoRA输出投影形状
当前配置是 o_groups=8、TP=8,因此每卡正好一个 O-LoRA group。输出投影可精确化简为普通两段线性:将本卡 8 个 head 展平为 4096,执行 wo_a,再执行 wo_b;无需三维 batch matmul。修复并验证310P注意力投影及O-LoRA回退流程
O-LoRA 修复已同步。启动 v19 并复用已有编译缓存;服务就绪后再次发送真实请求。重启并检查DeepSeek V4探测任务及日志 白小姐
v19 已完成分布式初始化并进入权重转换,未出现 O-LoRA 构造错误。继续等待服务就绪后重发请求。完成 v19 服务健康检查及 DeepSeek-V4 请求验证
v19 请求已越过之前的 cache 写入和 O-LoRA 阻断,当前八卡有实际 AICore 活动且暂无错误。继续观察是否完成 43 层或暴露后续 MoE 问题。检查任务日志与NPU推理进度错误
请求已持续执行约 3 分钟,八个 worker 均保持高 CPU、AICore 持续活动,响应文件仍为空且无错误,说明正在逐层运行/首次编译而非死锁。继续等待完整 43 层结束。监控了NPU推理进度
v19 已首次端到端成功返回 HTTP 200:密集 DSA、FP16 paged cache、O-LoRA、43 层 MoE 和输出采样全部通过。首请求约 4 分钟,下一步先测第二次热请求,区分首次编译开销与持续推理速度。检查作业尾部并测量预热单令牌性能
开始第二次热请求测试。它将复用现有模型、算子缓存和已转换权重,可直接反映持续推理速度。运行 DeepSeek-V4 预热并监控延迟与 NPU 状态
热请求在 60 秒后仍未完成,说明 252 秒主要不是一次性编译。八卡 AICore 约 65–67%,当前瓶颈更可能是每层专家权重的实时 MXFP4→W8A8 解包/转换。先取得完整热延迟,再定位转换是否被重复执行。检查NPU推理完成情况并获取作业尾部延迟
热请求为 249.676 秒,与首请求 252 秒几乎相同,持续速度只有约 0.1 tok/s。现在直接审查 MoE streaming W8A8 路径,定位每个 token 重复解包、量化或格式转换的位置。优化了 MXFP4 重复转换流程
确认了根因:当前 apply() 每经过一个 MoE 层,都会把该层全部 32 个本地专家的 w13 和 w2 从 MXFP4 重新解包并量化为 INT8;43 层每个请求都重复一次。下一步评估两条优化:低 KV 容量下全量常驻 W8A8,或只转换实际命中的专家。检查310P动态MoE量化与专家选择机制
常驻 W8A8 的显存估算约为每卡 41–43 GiB。我先用仅够 128-token 服务的 128 MiB KV cache 启动 eager 模式;若能装下,专家转换只发生一次,热请求延迟应大幅下降。完成 DSV4 专家模式及模型容器加载测试
eager 模式已进入全量专家转换,当前每卡约 28 GiB,尚未 OOM。转换会按层累积常驻 INT8 权重;继续观察最终显存是否控制在 44 GiB 内。评估了模型转换状态与内存使用
eager 常驻方案成功装入:模型加载和全量转换约 5.8–6.0 分钟,最终每卡约 39.5–40.3 GiB,未 OOM,服务已启动。现在测试首个常驻 W8A8 请求及热请求速度。测试健康状态并监控首请求NPU日志
eager 权重本身能装下,但第一次 TP all-reduce 初始化 HCCL 时因显存碎片化失败;只缺约 2 MiB,并非模型参数绝对超容。修复方向是:全量转换结束后释放旧 packed 权重留下的 allocator cache,并在加载前预初始化 TP/EP HCCL communicator。检查 load_model 方法及相关钩子
eager 请求失败在模型计算开始前的 TP HCCL 懒初始化。加入两项修复:模型加载前预热 TP/EP communicator;全量转换结束后 empty_cache() 释放旧 packed 权重的缓存块。随后重跑 eager。完成HCCL预热修复并启动监控推理任务
TP/EP HCCL 已在低显存阶段成功预初始化。v21 正在重新执行约 6 分钟的全量专家转换;转换后将核对 empty_cache() 实际释放量,再发请求。检查v21模型转换进度、容器健康与内存状态
清理后空闲显存提升到约 4.9 GiB,HCCL 已常驻,服务健康。现在重新测试 eager 首请求;若通过,再测连续多 token 的真实 decode 速度。测量并读取 Eager v21 首次请求延迟
eager 首请求成功,端到端延迟从 252 秒降到 1.972 秒。现在用 ignore_eos=true 连续生成 8 个 token,测实际 decode 吞吐。测试并确认八令牌解码基准输出
常驻 W8A8 的 8-token 测试为 6.006 秒,1.332 tok/s。dummy 权重端到端路径已稳定;下一步切换到真实 checkpoint,保留 eager 常驻专家和 128 MiB KV cache,验证实际文本输出。已启动并监控真实 DeepSeek V4 模型服务部署
真实 checkpoint 已进入 safetensors 加载,但首个形状不匹配被通用 loader 的裸断言吞掉了权重名。先给 load_weights 增加精确诊断,输出参数名、期望形状和 checkpoint 形状,再针对该权重适配。继续等待并检查检查点加载诊断
精确阻断是 model.layers.0.self_attn.wo_b.weight_scale:checkpoint 为 (32,64),TP=8 后本卡应为 (32,8)。这是量化 scale 没经过 RowParallel 切分;权重本体 loader 会切分。现在对 wo_b.weight_scale 沿最后一维按 TP rank 分片。完成DeepSeek-V4权重分片修改并验证检查点加载
wo_b.weight_scale 分片后已越过原先的即时断言,当前正在读取真实 safetensors。继续等待首个新形状阻断或进入全量专家转换。检查模型、服务进程及资源状态
真实权重加载没有死锁:8 个 worker 都在 wait_on_page_bit_common,即同时从磁盘读取/缺页。当前瓶颈是 8 rank 并发读取同一套 155 GiB safetensors。先确认磁盘吞吐;若持续抖动,就改为按 rank 错峰加载或使用预分片 checkpoint。测量八进程加载及磁盘网络资源压力
/models 和工作目录都在 NFS,但主机本地根盘尚有约 1 TiB。当前网络计数没有增长,说明文件页已在宿主页缓存,卡顿主要是 8 rank 同时争用同一 safetensors 页锁。先确认当前进度;若仍停在首 shard,就把模型复制到本地根盘再加载。检查模型加载进度与工作进程状态
加载确实在推进,但每个 rank 仅约 10–13 GiB,平均每 rank 约 20 MB/s;按当前方式可能超过一小时。停止本轮,将 155 GiB 模型只复制一次到本地 1.7 TB 盘,再让 8 rank 从本地并发读取。已启动并监控 DeepSeek V4 模型本地同步作业
本地复制速度约 236 MiB/s,预计还需约 10 分钟。复制期间我并行检查真实 checkpoint 中所有 attention 量化 scale 的形状,提前适配可能的下一处 TP 分片问题。检查模型权重兼容性、命名及本地副本进度
本地复制当前约 30%。刚才 v24 仍在并发读取 NFS,拖慢了复制;形状分片已确认有效,因此先停止 v24,让单次本地 staging 独占 NFS 带宽。停止模型服务并测算检查点复制进度
独占后 staging 约 155 MiB/s,当前 67.5 GiB / 155.4 GiB,预计约 10 分钟。复制完成后生产脚本会把本地 /var/lib/dsv4-model 挂载为容器内 /models,避免 8 rank 再触碰 NFS。修改真实脚本以挂载本地模型路径
本地 checkpoint staging 仍是当前关键路径。我先确认复制是否完成,并校验本地副本与 NFS 源的文件规模;完成后立即从本地盘启动真实权重服务。检查并跟踪模型复制任务进度
复制进度已到 97.5 GiB(62.7%),独占 NFS 后稳定约 154 MiB/s,预计约 6 分钟。期间我整理当前补丁并重新跑静态检查,避免真实服务启动后再因脚本或语法问题中断。检查310P注意力模块及测试代码
已实现端到端 NPU 推理
在 8×Ascend 310P 上,dummy 权重已完整通过:
- 43 层 DeepSeek V4
- 密集 DSA fallback
- FP16 paged SWA KV cache
- MLA cache 分配
- O-LoRA 输出投影
- MXFP4 专家转换为 W8A8
- MoE、采样和 OpenAI API
性能瓶颈也已解决:
| 专家处理模式 | 1 token 延迟 | 8 token 测试 |
|---|---|---|
| 每次请求重新转换 MXFP4 | 约 250 秒 | 不实用 |
| W8A8 常驻显存 | 1.972 秒 | 6.006 秒,1.332 tok/s |
W8A8 常驻模式最终占用约 39.3–40.0 GiB/卡。为避免首次通信时 OOM,已经:
- 在加载专家前预初始化 TP/EP HCCL communicator;
- 转换结束后释放废弃的 packed MXFP4 allocator 缓存;
- 将 KV cache 降为 128 MiB,适配当前 128-token、单并发验证配置。
真实 checkpoint 进展
真实 safetensors 已开始加载,并发现、修复了第一处真实权重适配问题:
model.layers.0.self_attn.wo_b.weight_scale
checkpoint: (32, 64)
本卡目标: (32, 8)
原因是 wo_b 属于 RowParallel,权重会按 TP=8 分片,但量化 block scale 没有自动分片。现在已沿最后一维按 TP rank 显式切片。
修复后已越过原来的形状断言。
当前阻塞:NFS 加载速度
/models 位于 NFS。8 个 rank 同时读取 155.4 GiB checkpoint 时,每个 worker 都阻塞在文件页缺页读取,预计需要很长时间。因此已经停止并发 NFS 加载,改为先把模型复制一份到本地磁盘:
源:/models/DeepSeek-V4-Flash-0731
目标:/var/lib/dsv4-model/DeepSeek-V4-Flash-0731
最新复制状态:
97.46 GiB / 155.44 GiB
完成度:62.7%
速度:约 154 MiB/s
生产探针已改为从本地路径挂载模型。所有当前 Python 修改均重新通过:
ruff check
compileall
git diff --check
尚未完成的是:本地模型复制完成后的真实权重完整加载、真实文本生成验证,以及最终提交当前补丁。
第五阶段
继续完成本地 staging、真实权重加载和真实文本生成验证;若再出现形状或算子阻断,就按首个错误继续修补。检查了暂存作业日志
本地 staging 已完成,共复制 154 个文件、333.8 GB。现在校验副本和启动脚本,然后直接从本地盘启动真实 checkpoint。核实挂载配置并监控模型真实加载状态
本地盘启动已进入 EngineCore,但 8 个 worker 尚未完成初始化。继续观察到真实 safetensors 读取开始或出现明确错误。检查模型加载状态
本地盘加载已明显加速到约 7 秒/分片;新阻断是共享专家 down_proj.weight_scale 同类 TP 分片问题。将修复从特例扩展为所有 RowParallel 量化 scale。修复并验证 DeepSeek V4 权重加载及模型启动流程
v26 尚在 API/EngineCore 初始化阶段,worker 还未全部拉起;继续等待进入本地 safetensors 加载。已等待并检查容器启动及模型加载状态
本地盘读取已稳定到约 4.5 秒/分片,当前完成 24/48,且已越过两处 scale 分片错误。继续等待加载完成并进入 W8A8 常驻转换。检查模型加载结果
真实 48 个分片已全部加载完成。新阻断发生在非专家 FP8→W8A8 转换:某个线性权重带单例前导维 (1,4096,1024),转换器仅接受二维。该布局可安全按二维转换后恢复前导维。验证 FP8 转换补丁并清理容器
真实权重已确认能完整读完;现在重跑仅验证后处理阶段,重点看 FP8 常规线性转换是否能继续进入 MXFP4 专家常驻转换。完成v27真实模型FP8转换并检查容器状态
单例维已处理,当前新阻断仅是该类权重的 block scale 采用转置布局:实际 (8,32),数学期望 (32,8)。加入自动识别并转置,不改变量化值。等待加载完成并检查容器状态
v28 已通过全部真实 checkpoint 加载和所有普通 FP8 线性转换,现已进入 43 层 MXFP4 专家全量常驻 W8A8 转换;当前每卡约 29 GiB。等待转换完成并检查容器、日志与内存
六个 rank 已完成真实模型加载;rank 0/1 仍在最后转换,显存只剩约 110–140 MiB。继续观察它们能否完成并触发旧 packed 权重释放。检查并确认各设备加载状态
rank 2–7 已完成并释放临时缓存;rank 0/1 尚停留在最后几层转换,未报错。它们仍有计算线程活动,先再观察一轮,确认是明显偏慢还是实际卡死。监控NPU模型转换进度
新的阻断不是形状问题,而是 310P 在长时间权重转换中触发 AICPU 算子超时 507017。堆栈落在 FP8 解码的同步 NaN 检查;我先移除该高成本同步检查,并确认是否有可配置的算子执行超时。移除NaN检查并核查AICPU超时机制
超时检索范围过大。改为只检查 torch_npu Python API、运行时库导出符号和 CANN 头文件中的 timeout 接口。定位了 torch_npu 算子超时配置接口
CANN 9.1 提供 aclrtSetOpExecuteTimeOut,单位为秒。将 eager 转换进程的算子超时设为 1800 秒,同时缓存 FP8/FP4 解码表并移除每块同步 NaN 扫描,减少队列同步和 AICPU 开销。优化了FP8解码与NPU算子超时配置
AICPU 超时补丁已完成静态检查。现在同步三处修改到远端,随后启动 v29 验证 1800 秒算子超时和缓存解码表是否能让八个 rank 全部完成。传输量化文件并验证DeepSeek-V4部署及运行状态
v29 已确认八个 worker 均应用 1800 秒算子超时,HCCL 预初始化正常,真实 checkpoint 正从本地盘加载。下一检查点是全部 48 分片完成并进入专家转换。监控容器内存并检查模型转换状态
v29 已成功完成:八个 rank 全部加载真实权重,AICPU 超时未再出现,服务健康且每卡常驻约 39.4–40.0 GiB。现在发送真实 1-token 请求,验证实际 logits、采样和文本解码。执行真实模型请求并检查输出
真实请求在 1.45 秒内触发新的运行期错误,说明加载与转换已完全通过,问题位于首个真实 forward。现在提取首个完整堆栈并定位到具体算子。提取服务引擎崩溃首个错误
首个真实 forward 的根因已明确:wo_a 的真实 checkpoint 参数是单例打包的 [1, input, output] 布局。之前仅去掉单例维,得到 [4096,1024],但逻辑权重应为 [1024,4096];因此量化矩阵乘法报告 K=4096 对 K=1024。将单例打包权重同时转置,scale 保持 (8,32)。继续检查模型转换、容器日志和设备内存状态
v30 已重新启动,修正后的 O-LoRA 权重转换完成且显存正常。现在再次发送真实请求;本次先关闭 logprobs,只验证完整 forward 和文本输出。发送 Hello 请求并测量响应性能
真实 1-token forward 已成功,延迟 2.433 秒,说明真实权重、43 层计算、MoE、采样和解码全部贯通。裸文本 Hello 生成了模型特殊 token;继续用官方 chat template 测试可读输出和连续 decode 速度。测试聊天补全量化与DeepSeek-V4接口响应
连续 16-token chat 的吞吐为 1.259 tok/s,但输出重复特殊 token,说明执行链已贯通而数值仍有错误。下一步不再盲目改算子,先核对真实 checkpoint 的 FP8/E8M0 scale 语义、LM head 类型和单例打包线性的实际布局,定位数值失真来源。检查Safetensors权重格式与量化配置
safetensors 当前版本不识别该 checkpoint 的 F8_E8M0 标头,因此改为直接按 safetensors offset 读取原始字节,再分别用 UE8M0 公式和 PyTorch dtype 转换核对。解析并验证 Safetensors 原始字节的 E8M0 解码
宿主 Python 是旧版 PyTorch,不支持 float8_e8m0fnu。服务容器内是 CANN 9.1 / PyTorch 2.10;直接在同一容器的 CPU 上读取一个 scale tensor,确认 .float() 是否解码为 2^(byte-127)。检查 FP8 解码与数值退化
FP8 E4M3 解码表与容器内 PyTorch 的真实数值完全一致,UE8M0 scale 也正确。下一高风险点是专家 MXFP4 nibble 排列;若低/高半字节顺序错误,所有 MoE 层都会数值失真而仍能正常执行。现在对照仓库和已安装库中的官方解包实现。核查并定位 MXFP4与NVFP4量化实现及解码工具
已找到决定性数值错误:checkpoint 的 FP4 是每个字节按连续元素 [low, high] 交错打包;当前实现却将 16 个 low 全放前面、16 个 high 全放后面。这样每组 32 个专家权重的排列被打乱,正好会导致模型稳定输出同一特殊 token。现在改为逐字节交错解包。修复MXFP4解包交错顺序并完成测试
修复和回归测试代码已写入;控制端缺少 PyTorch,因此 pytest 无法执行,但 Ruff、compileall、diff 检查均通过。接下来同步到远端并启动 v31;这次转换后的专家权重排列将与 compressed-tensors 官方实现一致。监控 v31 模型加载进度
v31 当前已加载 34/48 分片,未出现新错误。完成加载后将重新转换专家权重,再直接复测相同 chat 请求,判断特殊 token 退化是否消失。监控模型加载进度与设备内存
继续后的关键进展:
- 真实权重已成功完整加载并启动 API。
- v30 真实单 token 请求成功:
- 延迟:2.433 秒
- 16-token chat:12.713 秒
- 有效生成速度:1.259 tok/s
- 但 chat 输出重复
<|end▁of▁repo▁name|>,说明执行正常但专家权重数值错误。
已定位根因:MXFP4 checkpoint 按每字节 [low nibble, high nibble] 存放两个连续 FP4 元素;原转换代码错误地排列成“所有 low 后接所有 high”,导致每组 32 个专家权重被打乱。
现已按 compressed-tensors 的实际打包方式修复:
low = packed_u8 & 0x0F
high = packed_u8 >> 4
codes = torch.stack((low, high), dim=-1).flatten(-2)
校验样例:
0x21, 0x43 → [1, 2, 3, 4]
当前 v31 状态:
- 48/48 个真实 checkpoint 分片已加载完成;
- 已进入修正后的 43 层 MXFP4→W8A8 专家转换;
- 暂无新错误;
- 端口 8000 尚未就绪,因为模型转换仍未完成。
仍未完成的验证是:v31 转换完成后重新发送 chat 请求,确认输出从重复特殊 token 恢复为正常文本。
第六阶段
继续观察 v31 转换完成情况,随后立即复测同一 chat 请求;若输出仍异常,就从首个数值偏差继续定位。检查任务状态、日志及Docker服务健康情况
v31 已完成并稳定运行约 9 小时,健康检查正常。现在复测相同 16-token chat,直接判断专家权重排列修复是否恢复正常语言输出。测试 DeepSeek-V4 聊天接口响应
FP4 顺序修复后首 token 已变化,但仍迅速退化为特殊 token,说明还存在第二处数值错误。先做两类独立基准:验证 MXFP4 重量化与官方解包一致,并验证 310P npu_quant_matmul 的 weight scale 语义。检查并对比 W8A8 与310P动态量化实现差异
发现第二处高概率根因:FP8→W8A8 适配器继承了通用 A2/A3 动态量化实现,而仓库已提供专门的 310P W8A8 动态线性实现;两者的激活量化调用不同。先确认 MoE 侧是否也错误继承,再统一切到 310P 专用实现。检查了 MXFP4 适配器继承与量化实现
MoE 已正确继承 310P 专用实现,只有普通 FP8 线性仍走通用路径。先在空闲显存中跑一个小型数值基准,对比两种 npu_dynamic_quant 调用与 FP16 参考,确认切换是否确实修复精度。验证W8A8量化矩阵方向并检查设备与容器状态
小型数值基准首次运行超过前台超时,但未影响服务。改为后台任务记录完整输出,只测小矩阵,避免大形状首次算子编译拖长。完成310P动态量化测试并检查NPU任务输出
动态量化小矩阵基准显示通用与 310P 调用数值完全一致,余弦相似度 0.99997,因此不是激活量化接口问题。继续验证真实专家张量:将当前 MXFP4→INT8 结果与 compressed-tensors 官方解包参考逐元素比较。验证MXFP4转换参考并查看任务输出
专家权重量化与官方参考一致(余弦约 0.99996),可排除 MXFP4 转换本身。下一嫌疑是 DSA 的 wo_a:它是按 O-LoRA group 打包的三维权重,当前被降成普通二维线性,可能破坏组语义。先核对 310P DSA 前向和官方 wo_a 布局。分析了 DSA O-LoRA 权重维度与分组矩阵乘法
wo_a 二维化与 310P DSA 设计一致,可排除组布局问题。现在用真实 wq_a 和 wo_a checkpoint 分片做端到端数值基准:原始 FP8 解量化矩阵乘法对比转换后的 310P W8A8 算子。验证并读取DeepSeek V4 FP8转换任务输出
两类量化路径均已通过真实权重数值基准,矩阵乘法余弦相似度均约 0.9999。问题更可能在模型接口或模板,而非权重转换;先核对 checkpoint 是否本身是代码/base 模型、chat template 及特殊 token 映射。检查模型配置、聊天模板与分词器映射
关键点已确认:该 checkpoint 明确不包含 Jinja chat template,必须使用仓库自带 encoding/encoding_dsv4.py 编码消息。刚才 /v1/chat/completions 只产生 12 个 prompt token,明显未套用官方协议。现在用官方编码器生成 prompt,再走 /v1/completions 复测。检查了 DeepSeek-V4 编码与推理接口示例
官方协议要求 prompt 以 <|begin▁of▁sentence|>...<|Assistant|></think> 结尾。现在直接调用仓库编码器生成该字符串并提交 completions,避免 vLLM 的普通 chat 路径。生成官方提示词并调用补全接口
官方 prompt 已正确生成,但更长的 prefill 触发了新的运行期错误。提取首个完整堆栈,判断是 KV/attention fallback 还是显存工作区问题。检查容器错误日志与NPU内存状态
官方 prompt 触发的是独立的 310P block-table bug:长度跨过第 16 个 token 时,slot mapping 把 token 位置直接当成扁平 block-table 索引,导致 index 16 越界。修复这一索引计算后才能进行有效语言输出验证。检查并对比310P自定义与基类BlockTable实现
当前越界未必是 token 位置本身,也可能是 request row 索引为 1、而某个 KV group 的 block table 只有一行。先从失败请求的 scheduler dump 和运行时 block-table 参数确认 req_indices、block size 与表形状,再做最小修复。检索调度器与块表运行日志
失败发生在官方 prompt 已生成 21 个 token 后、总位置从 31 跨到 32 时。说明 prompt 编码和前向都已工作,当前是 32-token block 边界 的 slot mapping bug。下一步核对多 KV group 的压缩位置传参,修复跨块 decode。检查混合缓存块表与310P压缩位置映射生成
已确认崩溃来自压缩 KV group 沿用原始 token 位置。先核对父类中压缩位置的完整数据流,再把同一逻辑补进 310P runner,避免只修表面越界。检查并修复310P压缩KV缓存调度集成
压缩位置工具只影响各 KV group 的 slot mapping;注意力元数据仍保留原始序列长度。将其接入 310P _prepare_inputs,并增加跨 32-token 边界的回归断言。修复压缩KV分组块表映射
补丁已写入;远端宿主没有 Ruff。改用现有 vLLM Ascend 镜像执行同版本的静态检查和目标单测,避免环境差异。验证模型补丁、镜像版本及测试输出
镜像同样未安装 Ruff;静态编译与 git diff --check 已通过。继续运行目标 pytest,重点验证压缩 group 的跨块映射结果。完成压缩KV槽位映射测试并检查NPU探针参数
pytest 失败仅因容器未挂载 NPU 驱动,不是代码失败。用部署相同的设备与驱动挂载重跑目标测试;不会加载模型权重。完成NPU部署环境单元测试并查看任务输出
目标测试已执行,10 项通过;唯一失败是新测试把 hybrid block 的物理块误当成逻辑块重复展开。修正测试输入为单个物理块,代码路径本身未失败。修正并验证混合块逻辑及压缩映射补丁
压缩 KV slot mapping 补丁已通过同环境目标测试:11/11 通过。现在启动 v32,完成真实权重转换后用官方编码 prompt 跨过 32-token 边界复测。启动并监控 DeepSeek V4 v32 容器及模型加载
v32 已确认加载新补丁,八个 rank 正从本地盘读取真实权重。下一检查点是专家转换完成和 API 启动。监控容器启动及模型加载转换状态
v32 已健康启动。现在用官方编码器生成的 prompt 请求 48 个 token,覆盖 32-token 边界,并用官方解析器还原回复。测试聊天补全跨令牌边界流式传输
跨 32-token 边界已修复,服务完成 48-token 请求且保持健康。输出仍数值异常;下一步重点核对 MoE 融合后的 w1/w3 排列与执行方向,这是尚未被真实加载后张量基准覆盖的部分。检查MXFP4专家权重加载及MoE通信映射规律
先排除协议层最后一个变量:对比官方 tokenizer 与 vLLM deepseek_v4 tokenizer 的 prompt token ID。若完全一致,剩余问题只能在模型前向实现。比较了官方与 vLLM 分词器输出
官方 prompt 的 12 个 token ID 已与 HF tokenizer 完全一致,协议层可排除。现在对照官方 inference/model.py,逐项审查 310P fallback 的 Hyper-Connection、DSA/MLA 和 SwiGLU 公式,寻找结构性偏差。审查并核对 DeepSeek V4 注意力与 DSA 归一化实现
短上下文注意力 fallback 在 128-token 窗口内应是精确路径。出现更高风险的结构差异:官方前若干层使用 token-ID 哈希路由,而 vLLM 层调用表面上没有传 input_ids。现在核对 tid2eid 的实际接线。检查 DeepSeek-V4 哈希路由与Token ID传递
已定位到实质性结构错误:310P W8A8 MoE 路径丢弃了 tid2eid,导致前 3 个哈希路由层错误地按普通 gate logits 选专家。官方模型要求这些层按当前 token ID 查表路由。现在补齐 310P selector 的哈希参数。检查310P专家选择器签名及W8A8调用
继续修复哈希路由。先确认运行时 scoring function 和 MoE 通信模式,再按官方公式实现 310P 的 tid2eid[input_ids] 路由。分析哈希路由实现并完成专家并行通信
310P 固定使用 AllGather,当前 DP=1,因此 forward context 中的 token IDs 与 MoE 输入行数一致。将哈希分支直接按官方公式实现,并保留对未来 DP/填充场景的对齐逻辑。实现并测试310P哈希专家路由及w8a8输入修复
哈希路由实现已补齐:专家 ID 来自 tid2eid[token_id],权重仍按 sqrt(softplus(router_logits)) 取对应项、归一化并乘 1.5。先跑目标单测,再加入部署覆盖列表。运行并读取 DeepSeek V4 哈希路由测试输出
哈希路由目标测试 4/4 通过。现在把 selector 与 W8A8 MoE 实现加入启动覆盖列表,启动 v33 做真实输出验证。更新部署文件并监控DeepSeek V4容器启动及模型加载
v33 已确认加载哈希路由补丁,八个 rank 正常进入真实权重加载。完成转换后将直接复测官方 48-token prompt。监控容器模型加载转换及服务健康状态
v33 已健康启动。现在用同一官方 prompt 复测;本次结果将直接反映前 3 层哈希专家路由修复效果。测试官方提示词推理流程
哈希路由修复已真实生效(首 token 改变),但仍未恢复语言输出。下一步改为定位最早的结构性偏差:重点验证实际加载后的专家融合顺序、共享专家合并和 HC/attention 公式,而不再猜量化误差。检查HC Sinkhorn与Ascend MoE实现及官方内核流程
发现哈希修复尚未真正进入运行:RoutedExperts 调用量化方法时根本不传 tid2eid,而自定义 MXFP4 方法已把表保存在 self.tid2eid。因此 v33 仍使用普通路由。现在改为从实例属性读取真实哈希表。修复专家路由并验证DeepSeek实例使用
实例哈希表接线测试 5/5 通过。启动 v34;这次前 3 层会实际使用 checkpoint 的 token→expert 表,而不是普通 gate top-k。监控v34实例哈希路由容器启动及模型健康状态
v34 已启动,实例哈希表接线确认生效。现在复测官方 prompt;若仍异常,就排除哈希路由并继续做第一层逐模块数值对照。测试了 DeepSeek-V4 模型推理能力
哈希表现已确认实际进入推理,但输出仍异常,说明它不是唯一根因。接下来做“第一层解剖”:核对 checkpoint 的 w1/w2/w3 是否被正确映射到融合 w13/w2,并检查共享专家 SwiGLU 左右半区顺序。检查FusedMoE权重映射加载及SwiGLU实现配置差异
量化、协议、哈希路由和 SwiGLU 配置均已逐项对齐。先检查真实 logits 分布,确认是隐藏状态整体崩坏、NaN/饱和,还是 LM head/HC head 的局部问题。检查了模型输出概率分布
logits 全为有限值且分布平滑,没有 NaN 或饱和;这更像最终表示被错误混合,而非算子崩坏。优先核对 DeepSeek V4 特有的 HC head 权重加载和公式,它直接决定送入 LM head 的隐藏状态。检查并修正HC头加载与前向逻辑
继续从融合专家加载路径入手,先确认 w1/w3 在实际 w13 张量中的排列,再决定是否需要重启验证。检查已安装技能及融合专家加载分片逻辑
融合权重顺序确认是 [w1(gate), w3(up)],与 npu_swiglu 一致。新发现:310P 路由专家执行路径使用普通 npu_swiglu,完全忽略模型要求的 swiglu_limit=10;43 层累积后足以造成明显数值漂移。现在确认实际调用链并补上限幅。追踪310P专家激活与SwiGLU量化路径
已确认真实调用链:自定义 W8A8 MoE 构造运行参数时漏传 activation 与 swiglu_limit,因此路由专家和共享专家都按无限幅 SwiGLU 执行。现在把 limit=10 贯穿到 310P MoE,并用官方公式实现限幅激活。修补并部署310P混合专家SwiGLU量化支持
限幅公式与哈希路由联合测试 6/6 通过。把 310P MoE MLP 文件加入运行时覆盖,启动 v35 验证真实输出。添加覆盖脚本并验证部署及 DeepSeek V4 服务启动
继续后的关键进展:
- 确认融合专家权重排列正确:
w13 = [w1(gate), w3(up)]。 - 定位到新的结构性数值错误:310P W8A8 MoE 路径此前漏传
swiglu_limit=10,导致路由专家和共享专家均使用无限幅 SwiGLU,而官方 DeepSeek V4 每层都要求:gate = clamp(gate, max=10) up = clamp(up, min=-10, max=10) output = silu(gate) * up - 已修复:
- W8A8 MoE 运行参数传递
activation、swiglu_limit、swiglu_alpha、swiglu_beta。 - 310P MoE MLP 增加与官方公式一致的限幅 SwiGLU。
- 保留之前修复的 token-ID 哈希专家路由。
- W8A8 MoE 运行参数传递
- 联合目标测试:6/6 通过。
- 已启动 v35 真实模型验证,容器确认加载了新代码:
clipped_swiglu_310p swiglu_limit=getattr(layer, "swiglu_limit", 0.0) - 当前 v35 正在加载真实权重,尚未完成 API 启动及官方 prompt 输出复测,因此暂时不能确认语言输出是否已经恢复。
第七阶段
继续检查 v35 的加载与启动状态;服务就绪后立即复测官方 prompt,并对比首 token 与 logits 分布。检查任务进度与容器NPU状态并复测v35 Prompt
当前命令落到了控制端而非 310P 主机。先重新定位已注册的远端机器和 v35 任务,再继续原状态检查,不会重启或覆盖现有服务。列出作业并检查远程容器健康状态
v35 已健康启动,限幅 SwiGLU 补丁随真实权重完成加载。现在执行固定官方编码请求,并同时采集首 token 的 top-20 logits。测试官方提示词响应及模型补全重试日志
限幅补丁改变了首 token,但输出仍立即退化,说明还有更早的结构偏差。下一步直接对照官方 DSA 前向,重点检查 KV 的 QAT 仿真和注意力输出的逆 RoPE。对比检查了DSA注意力实现
DSA 已包含逆 RoPE,短上下文可见范围也与官方一致;缺少 KV 的 FP8-QAT 仿真,但这通常不足以解释完全乱码。发现更高风险点:FP16 分支合并共享专家和路由专家时可能错误重复缩放,先核对 muls_add_triton 的参数语义与当前路由权重。调查 W8A8 MoE 缩放语义并检查 Triton 实现配置
确认存在确定性缩放错误:当前 FP16 分支计算的是 routed + shared / 1.5,但路由权重在 selector 中已经乘过 1.5;官方应为 routed + shared。这一偏差会在 43 层反复累积,优先修复。检查 DeepSeek V4 代码路径及 MoE 测试逻辑
将修复限定到当前自定义 W8A8 方法:为其标记“路由输出已包含 1.5 倍缩放”,模型合并时直接执行 shared + routed,避免影响其他 310P/Ascend 路径。修复并测试310P与DeepSeek-V4 MoE缩放逻辑
缩放修复已写入且部署脚本会覆盖对应文件。正在跑 310P 模型、哈希路由和限幅激活联合测试;通过后启动 v36。读取作业输出并检查睡眠超时远程开销日志
联合测试结果为 12 项通过、1 项失败;失败是既有的“无压缩 MLA 后端应选择 MLA”断言,与本次缩放修改无关。新增加的缩放标记和合并逻辑测试均通过。现在启动 v36。修正文档属性并启动监控v36任务及容器日志
v36 已加载新的模型合并逻辑,容器正常存活,正在进行八卡权重加载和专家转换。下一检查点是 API 就绪。监控容器与模型加载转换状态
v36 已健康启动。现在用同一官方 prompt 复测;这次能直接判断共享专家缩放是否为主要剩余根因。测试了DeepSeek-V4 v36模型
共享专家缩放修复仍未恢复输出。现在转向两个尚未验证的高风险点:
- 压缩层的 DSA fallback 忽略了短上下文中的压缩 KV;
- LM head 可能被错误套用 W8A8,导致隐藏状态正常但词表行映射/数值错误。先核对量化规则和 head 权重加载。
检查了量化配置与模型层信息
已定位到高度确定的根因:FP8 配置把 BF16 的 head.weight 也误当作 FP8 线性层转换。checkpoint 没有 head.scale,因此 LM head 的 weight_scale 未加载、保持未初始化值;这会直接把正常隐藏状态映射成随机词表 logits,完全符合当前乱码现象。现在改为 310P 上 LM head 保持非量化。修复并验证DeepSeek量化配置及任务输出
checkpoint 已确认:head.weight 为 BF16 [129280, 4096],且不存在对应 scale。非量化 head 修复已完成;目标测试仍在初始化同版本运行环境。检查NPU资源释放并查看作业最新输出
非量化 LM head 修复的目标测试 13/13 通过。现在启动 v37;该版本会重新加载 BF16 head,不再创建未初始化的 INT8 scale。启动并监控 v37 版本模型加载
v37 已确认使用非量化 BF16 LM head,八卡开始加载 48 个分片。该修改只增加约 80 MiB/卡,现有显存余量足够。检查容器启动、模型加载及排名状态
v37 已健康启动,BF16 LM head 成功加载,显存仍有约 4.7 GiB/卡余量。现在执行官方 prompt 和首 token logits 验证。测试了 DeepSeek-V4 的编码与生成能力
v37 仍未恢复,但出现关键新信号:同一 prompt、temperature=0 的连续请求首 token 不一致。这不是普通近似误差,说明存在请求间状态污染或未初始化内存。先重复采样确认,再检查 SWA paged-cache 的 slot/block 映射。验证重复请求首 token 非确定性
六次相同请求得到六个不同首 token,已确认严重非确定性。接下来并行排查两类来源:未初始化的其他 FP8 scale,以及 prefill 通过 paged KV cache 读取了未写入/错误物理块。分析无缩放权重并检查缓存槽位映射
当前使用到的无 scale 线性中,除 LM head 外,其余均属于被 310P fallback 跳过的 compressor/indexer,不会造成当前首 token 随机。下一步绕过 fresh-prefill 的 paged-cache 回读:仍写 KV 供 decode 使用,但首轮注意力直接使用本次计算出的 KV,消除物理块状态污染。完成 DSA 槽位映射测试并重启 v38
fresh-prefill 直算分支已实现:KV 仍写入 paged cache 供后续 decode,但首轮不再从物理块回读。正在运行完整目标测试。等待后查看任务最新输出
目标测试 14/14 通过。启动 v38,重点验证同一 prompt 的首 token 是否恢复确定性;若确定性恢复,再继续处理压缩 KV 精度。启动并监控 v38 实时推理模型加载
v38 已加载 fresh-prefill 直算补丁,八卡正常读取权重。服务启动后先做 6 次完全相同的单 token 请求,验证确定性。监控模型容器启动加载及服务健康状态
v38 已健康启动。现在只测确定性:同一官方 prompt、temperature=0 连续请求六次,比较首 token 和 top logits。重复测试模型响应一致性
绕过 paged-cache 后仍不确定,说明污染不在 fresh-prefill 缓存回读。下一步用一个批次提交 6 份相同 prompt:若同批也不同,问题在模型计算/并行通信;若同批相同而跨请求不同,问题在请求状态管理。测试了批量操作的确定性与状态差异
同一批次 6 份完全相同 prompt 也产生 6 组不同 logits,已排除请求级 KV 状态管理。问题位于模型前向本身,最可能是 HC fallback 或 310P MoE token dispatch 使用了未初始化/错误索引。先审查这两条路径并做小型同输入一致性基准。检查310P MoE通信分发及NPU路由算子基准测试
独立基准首次被 vLLM 插件的循环导入阻断,未执行算子。改为只调用 torch-npu 原生算子,绕开 vLLM 包初始化。完成昇腾路由算子及混合专家约束性能基准测试
原生 MoE dispatch/unpermute 与 HC fallback 均通过重复一致性基准:输出逐元素完全相同,排除这两条路径。下一步对模型做层级一致性探针,定位同批相同 prompt 首次在哪一层产生差异。检查DeepSeekV4量化结构及分组矩阵乘法确定性
原生小基准表明 HC 与路由重排完全确定。为避免继续盲猜,加入仅在“批内 6 份完全相同序列”时触发的层级探针,记录 embedding 后及每个 transformer block 后的最大差异,直接定位首个异常层。完成 DeepSeek-V4 调试配置检查与重复批次探测
v39 探针版本已启动。它不会改变模型公式,只在匹配 6 份相同序列时同步读取差异;权重加载完成后提交一次 batch-6 请求即可定位首个分叉阶段。监控容器启动、模型加载及健康状态
v39 已启动。现在提交一次 batch-6 相同 prompt,并读取 rank 0 的 [DSV4_DUP_PROBE] 日志,定位 embedding、attention、MoE 中最先出现非零差异的位置。发送Batch6请求并重新运行超时测试
探针未触发,因为 vLLM 将 batch 内 token 按位置交错排列,而不是按请求连续排列。改为按相同 position 分组比较六个副本,随后重启探针版本。修复位置分组探针并检查DeepSeek推理容器启动日志
继续后的进展:
- 已确认异常具有严重非确定性:
- 相同 prompt、
temperature=0,多次请求的首 token 不同。 - 同一批次中的 6 份完全相同 prompt,也得到 6 组不同 logits。
- 因此问题位于模型前向计算,而不是采样器或请求间 KV 缓存残留。
- 相同 prompt、
- 已分别对 310P 原生路径做独立一致性基准:
npu_moe_init_routing_v2+npu_moe_token_unpermute:8 次结果逐元素一致,误差为 0。- HC
hc_pre_310p+hc_post_310p:重复输入和重复运行误差均为 0。 - 这基本排除了 HC fallback 和单独的 MoE 路由重排算子。
- 已加入层级一致性探针,计划比较:
- embedding
- 第一层 attention HC/norm/attention
- 第一层 MoE
- 第 1、2、10、20、30、42 层输出
- 第一版探针未触发,因为 vLLM 将批内 token 按位置交错排列,而不是按请求连续排列。现已改成按相同
position分组比较六个副本。 - v40 探针版本正在加载模型:
- 容器正常;
- 八个 rank 已开始读取 48 个权重分片;
- 尚未完成专家转换和 API 启动;
- 因此当前还没有得到“首次产生差异的具体模块”这一最终定位结果。
第八阶段
继续检查 v40 探针服务状态。服务就绪后提交 batch-6 相同 prompt,直接读取首个出现非零差异的层。检查任务日志、容器状态及 v40 探针就绪情况
v40 已完成 48 个分片读取,正在执行专家 W8A8 转换。待 API 就绪后只需一次 batch-6 请求即可得到层级分叉位置。检查v40引擎启动状态并排查专家转换停滞原因
v40 没有卡死:八个 worker 仍持续占用 AICore,显存已到转换后峰值,说明专家转换仍在进行。继续等待完成,不中断当前进程。等待v40转换并分析批量探针重复输出差异
batch-6 API 实际被 --max-num-seqs 1 拆成六次独立前向,因此探针仍无法看到同一次模型调用中的六个副本。将探针服务并发上限临时改为 8,重启 v41 后再测。启用六路批处理并监控V41探针加载
v41 容器正常,已应用 max-num-seqs=8 和按 position 分组的探针。当前处于 worker 初始化阶段。监控v41权重及检查点加载进度
v41 权重读取已到 85%,状态正常。随后进入约四分钟的专家转换,再执行一次真正的六序列同批探针。监控并检查v41模型转换与专家量化进度
v41 专家转换已完成,八卡均释放旧 packed 权重,显存余量约 4.6 GiB/卡。正在进行 KV cache 初始化和 warmup。验证 v41 API 状态并探测批次层间差异
OpenAI 的 prompt 数组仍可能在 API 层逐项调度。改为六个独立 HTTP 请求同时发起,强制调度器在同一前向中合批,再读取探针日志。完成六序列批处理探针并发测试
并发请求确认已在同一时间窗口进入引擎,但探针日志仍为空。先核对运行中 worker 是否继承环境变量、是否加载了当前探针源码,以及 positions 的实际形状。验证了工作进程探针instrumentation
根因已找到:vLLM worker 启动时会清理未知环境变量,八个 worker 均未继承 VLLM_ASCEND_DSV4_DUP_PROBE,所以探针入口直接返回。移除该环境开关,仅保留“恰好六个相同 position 副本”触发条件,然后重启 v42。已移除门控并重启v42,启动六副本偏差探测及监控
v42 已正常启动并应用无环境变量依赖的探针。当前仍处于 worker 初始化阶段。监控v42权重及模型检查点加载进度
v42 权重加载约 71%,未出现异常。继续等待完成后执行六序列同批探针。监控模型检查点并等待专家转换完成
v42 仍在转换阶段,部分卡出现短时显存满载,这是 eager 转换同时保留 packed 与 INT8 权重时的已知峰值;进程仍在运行,暂不干预。检查 v42 转换完成并确认服务状态
v42 已健康启动。现在同时发起六个独立请求,探针不再依赖环境变量,应该能直接给出首个分叉阶段。执行并发请求并检查探针
六个并发 HTTP 请求仍未形成包含六份相同 position 的单次模型调用。改用更稳妥的跨前向参考探针:第一次请求保存各阶段张量,第二次相同请求逐阶段比较,无需调度器合批。实现张量差异探针并定位重复前向非确定性阶段
v43 跨前向探针已启动。第一次相同请求会保存 embedding/各选定层输出,第二次请求会直接打印逐阶段最大差异。监控 v43 启动状态及权重加载进度
v43 八个 worker 已进入权重加载阶段,当前无异常。后续只需完成一次转换和两次相同请求即可完成定位。监控并完成 v43 检查点加载及专家模型转换
v43 仍处于专家转换高峰,部分卡短时接近显存上限,但 AICore 活跃且没有 OOM。继续等待转换完成。等待 v43 转换完成并检查引擎状态
v43 已健康启动。现在连续发送两次完全相同的单请求;第一遍建立参考,第二遍逐阶段比较,直接定位首次非确定性。执行两次相同请求并收集日志
已完成首次有效定位:
- embedding 到 layer0 attention 输出完全一致;
hc_post仅出现约1.2e-4的浮点扰动;- layer0 MoE 将这点扰动放大为最大 178.95 的差异;
- layer1 起数值直接撞到 FP16 上限
65504。
下一步聚焦 layer0 的 W8A8 MoE:路由、动态量化、grouped matmul 和 combine。检查了W8A8 MoE路由与量化路径
层级探针显示 major divergence 发生在量化专家 MLP 内部。先独立验证 npu_quant_grouped_matmul_dequant:同输入重复执行是否确定,以及 pertoken 模式对输入尺度的语义,避免继续修改上层路由。检查量化分组矩阵乘算子接口与反量化模式已搜索 2 个网站检索已安装量化算子实现与参数校验
首次全目录搜索超时。缩小到 torch-npu Python 元数据和 CANN 算子定义,继续确认该算子的输入/scale 约束。检查并搜索量化 GMM 算子定义及元数据
算子元数据确认 pertoken 模式确实接受 FP16 输入并在算子内完成动态量化,当前调用形式本身合法。接下来检查实际 INT8 权重的 NZ 方向与 scale 维度,并用该算子做可重复性微基准。检查NZ布局转换与量化权重方向
另一个高风险点已出现:hash 层 selector 需要 256 维 router logits,但当前内部路由分支传入的是 4096 维 hidden state。先核对 vLLM is_internal_router 的调用契约,判断 310P scheme 是否漏掉 gate 投影。检查内部路由器与Ascend FusedMoE量化门控实现
内部路由契约已核对:FusedMoE.shared_forward_impl 会先用 gate.weight_fp32 计算正确的 256 维 router logits,因此不存在“直接把 hidden state 当路由分数”的问题。现在直接对量化 grouped matmul 做同输入重复微基准。验证量化分组矩阵乘法确定性
量化 grouped matmul 微基准结果:同输入重复 10 次逐元素一致,max_diff=0;单元素 2.44e-4 扰动甚至被动态量化吸收,输出未变化。异常更可能出在真实专家权重/scale、路由权重或跨卡专家通信。检查了DeepSeek V4路由配置
已将问题收敛到 layer0 的真实 W8A8 专家链路。接下来一次性加入完整内部探针:路由结果、dispatch、GMM1、SwiGLU、GMM2、combine 与共享专家输出,减少重复重启次数。梳理并检查MoE通信、AllGather及专家路由流程
现有证据还指向一个数值问题:layer0 为 hash 路由,专家 ID 固定,微小输入扰动本不应改变专家集合。先验证转换后的真实权重尺度是否异常,尤其是 E8M0 解码和 MXFP4 nibble 排列。检查量化专家权重及MoE融合专家Safetensors分片
准备加入的探针只针对 moe_instance_id=0,不会重复执行模型,也不会改变计算结果。它将在各 rank 上比较两次相同请求的真实路由与专家中间张量,并记录静态权重/scale 的有限性和范围。完成部署检查并运行310P MoE探针测试
内部探针已完成静态检查,当前运行匹配版本的 310P 单元测试。通过后启动 v44;该次重启将给出每个 rank 在 GMM1 前后的首次分叉点。等待测试完成并读取最新任务输出
内部探针测试 13/13 通过。现在启动 v44;它会在 layer0 的八个 rank 上记录路由、dispatch、GMM1、SwiGLU、GMM2、combine 和 finalize 的跨请求差异。重启并监控 DeepSeek V4 v44 探针及权重加载
v44 已确认八个 worker 正常加载,探针模块随容器安装完成。目前读取 48 个权重分片约 23%,未出现导入或运行错误。监控并等待v44模型加载及专家转换完成
v44 已健康启动,专家转换和 warmup 均完成。现在连续发送两次相同官方 prompt,读取八个 rank 的内部探针,确认差异究竟在路由、dispatch、GMM1 还是 GMM2 首次出现。执行双请求并收集全秩日志
已精确定位:
- 路由 ID、路由权重、dispatch 索引和 expert token 计数完全一致;
- 首次灾难性放大发生在 GMM1 输出进入 SwiGLU 后;
- GMM1 仅少数元素相差 512,但 SwiGLU 直接产生
±65504,尽管模型配置swiglu_limit=10; - 这说明当前 310P 限幅 SwiGLU 实现的公式或 gate/up 拆分有误。
现在核对官方 OpenAI SwiGLU 限幅公式并修复该算子。检查并修复SwiGLU推理公式及裁剪溢出
公式本身与模型自带参考一致。真正的问题是参数传播:310P W8A8 方法从 AscendRoutedExperts.swiglu_limit 取值,但 DeepSeek V4 只把 10.0 保存在外层 DeepseekV4MoE,创建 routed experts 后未写入该对象,因此实际执行值大概率为默认 0,等于完全不限幅。修复并传递 SwiGLU 限制与 Routed 配置参数
已确认 RoutedExperts 原生支持 swiglu_limit 参数,而 DeepSeek V4 构造 FusedMoE 时确实漏传。修复为显式传入 10.0,并让 310P 激活在 FP32 中完成后再转回原 dtype,匹配模型自带参考实现。修复并测试 FusedMoE SwiGLU 路由限制
修复已写入:routed experts 现在实际接收 swiglu_limit=10.0,激活按官方参考使用 FP32 计算。正在运行目标测试;通过后启动 v45 验证是否解除 layer1 饱和和首 token 随机。等待SwiGLU测试完成并读取最新输出
目标测试 15/15 通过。启动 v45;验证标准是 SwiGLU 输出绝对值不超过约 100、layer1 不再触及 65504,并检查官方 prompt 是否开始生成正常文本。启动并验证v45路由SwiGLU修复及权重加载
v45 已确认加载到带修复的模型代码,八个 rank 正常开始读取权重。当前没有构造参数不兼容或导入异常。监控v45检查点转换及专家模型加载 progress
继续检查 v45。服务就绪后立即验证 swiglu_limit=10 是否生效、SwiGLU 是否解除 FP16 饱和,以及相同 prompt 是否恢复确定性。验证了 v45 转换与引擎启动
v45 已完成启动:
- 8 个 rank 均成功加载模型并完成 MXFP4 → W8A8 专家转换。
- 模型加载约 475–482 秒。
- 旧 packed 专家权重已释放,约剩余 4.74 GiB/卡。
- KV cache 初始化和 warmup 正常完成。
- API
/health返回 HTTP 200。 - 未出现 OOM、Traceback 或算子错误。
本轮已实装的关键修复:
- 将配置中的
swiglu_limit=10.0显式传入 routed experts。 - routed SwiGLU 改为 FP32 执行 clamp 和激活,再转回 FP16。
- 目标测试 15/15 通过。
尚未完成最终请求验证。下一步需要连续运行两次相同官方 prompt,确认:
- 日志显示实际
swiglu_limit=10.0。 - layer0 SwiGLU 输出不再达到
±65504。 - layer1 及后续层解除 FP16 饱和。
- 两次首 token 和 logits 恢复确定性。
- 48-token 输出能否形成正常中文文本。
第九阶段
继续做最终验证:先用两次完全相同的官方 prompt 检查确定性和内部数值范围,再跑一段多 token 中文生成。验证SwiGLU修复及限幅请求确定性
限幅已生效:rank0 的 SwiGLU 已稳定在 [-100, 100],GMM1/GMM2 也逐元素一致。但全模型仍从 layer0 MoE 后分叉,说明剩余差异来自其他 EP rank 或最终跨卡归约。现在逐 rank 汇总。汇总Rank层级差异并定位跨卡非确定性
逐 rank 结果显示差异集中在 GMM 输出的极少数元素,且值固定跳到 ±512。当前每个 rank 实际只有约 10 个本地专家 token,但算子输出分配了 72 行;高度怀疑未参与计算的尾部行未初始化,并在 combine 中泄漏。先用同形状微基准验证。排查量化分组矩阵乘法尾行未初始化
同形状大权重微基准因在线模型占满显存失败。改用相同 token/group 结构、缩小矩阵维度,只验证尾部行是否被算子写入和是否跨调用变化。验证了分组矩阵乘法的尾部初始化假设
微基准已复现根因:group_list 只覆盖前 10 行时,310P 算子返回的后 62 行包含未初始化值和 NaN,且跨调用变化;有效前 10 行完全确定。将两次 grouped matmul 的无效尾部显式清零,再验证全模型。修复并验证GMM及310P量化MoE尾部清零污染
尾部清零修复测试 17/17 通过。现在重启 v46 做端到端验证;重点观察 layer0 MoE 是否完全确定、layer1 是否解除 65504 饱和,以及生成文本是否恢复。重启并监控v46服务及八个Worker初始化
v46 的八个 worker 已全部正常进入权重加载,当前未出现导入、显存或算子错误。继续完成分片读取和 W8A8 转换。监控模型转换及服务启动进度
v46 已完成 48 个分片读取,正在执行八卡专家 W8A8 转换。所有 NPU 仍正常工作,无 OOM。监控模型服务并验证确定性推理日志
尾部清零后,八个 rank 的 GMM1、SwiGLU、GMM2 和 combine 已全部逐元素确定,数值恢复到正常范围;layer1 不再饱和。剩余差异是 attention/hyper-connection 引入的约 1e-4 扰动,逐层累计。先检查实际 48-token 输出质量。验证了48个令牌的生成质量
端到端已不再随机崩坏,但 44-token 输出仍是乱码,说明还有精度问题。数值从 layer2 的约 1.1 增长到 layer10 的约 15、layer42 的约 3856;下一步定位首次异常增长的具体层及 attention/FFN 子阶段。核查DeepSeek V4注意力、分层前向及Ascend量化实现一致性
W8A8 权重方向与 310P 原生实现一致,暂未发现转置错误。接下来直接读取 safetensors 原始字节,抽样核验 FP8+E8M0 解码及转成 INT8 后的数值误差,排除非专家权重量化偏差。解析了原始FP8权重元数据
原始权重元数据显示非专家线性层为 F8_E4M3 + F8_E8M0 block scale。当前还需排除两个方向:FP8 scale 解码误差,以及请求模板/解码方式不匹配。先核对模型自带官方调用示例和 tokenizer 输出。核对了DeepSeek V4推理模板与编码实现
官方生成脚本与当前 prompt 完全一致,乱码并非模板问题。继续核验 layer0 wq_a 的原始 FP8/E8M0 权重与软件转 INT8 的误差和尺度范围。验证FP8转INT8量化误差
抽样结果显示 FP8→INT8 误差正常:权重相对 L2 约 0.87%、随机 GEMM 余弦约 0.99996,不是乱码主因。下一步定位所有层的 attention 与 FFN 输出范围,找出首次结构性异常。检查模型权重加载完整性
现有数据表明 decode 阶段数值较正常,而 12-token prefill 在中后层放大到数千,问题更像压缩/稀疏注意力的 prefill 路径。将加入轻量逐层统计,覆盖每层 attention、MoE 与 HC 输出,精确找出首次跳变层。添加了预填充数值统计探针
逐层统计将仅在 rank0 的多 token prefill 上触发,不保存张量;记录每层输入、attention、attention-HC、MoE、层输出,以及最终 HC head/norm。这样可以一次重启定位异常来源。完成DeepSeek V4逐层Prefill统计探针添加与验证
逐层统计探针测试 12/12 通过。启动 v47 后只执行一次 12-token prefill,直接输出 43 层数值曲线,定位首次异常层。启动并监控 V47 Prefill 探针及八个 Worker 加载
v47 八个 worker 均正常进入权重加载,逐层统计代码已成功导入;目前没有构造或运行错误。监控模型启动加载及专家转换进度
v47 已完成权重分片读取,正在进行专家转换;逐层统计尚未触发。服务启动后只发送一次 prefill,避免探针参考被其他请求污染。检查v47容器及服务启动状态
v47 已健康启动。现在执行唯一一次 12-token prefill,并按层汇总 input、attention、attention-HC、MoE 和 output 的 RMS/最大值。运行单次 Prefill 并解析分层统计
异常已收敛到 layer40 MoE:该层 attention 正常,MoE RMS 从约 0–3 直接跳到 92。现在拆分 routed/shared expert,并核对 layer40 原始权重与相邻层差异。检查了 DeepSeek-V4 MoE 组合流程
FusedMoE 在内部先分别得到 routed_out 与 shared_out,随后再缩放相加。下一轮探针将直接打印 layer40 两支输出;同时先比较 39/40/41 层原始专家和共享专家 scale,判断是否为单层权重异常。检查并比较DeepSeek-V4 MoE专家权重缩放分布
原始 scale 分布显示 layer40 并无异常指数;相邻层专家 scale 同量级。进一步直接解码 39/40/41 层共享专家,计算其网络增益,判断爆炸是否来自共享支路本身。计算了共享专家层前向增益
软件精确前向显示 layer40 共享专家输出 RMS 约 1.23,与相邻层一致,因此 checkpoint 本身正常。接下来直接探测运行时 routed_out、shared_out 以及共享专家的 gate/up/down,中间哪一步偏离。调试并验证Layer40共享专家及MoE探针输出
layer40 分支探针测试 19/19 通过。启动 v48 后将一次性确认爆炸来自 routed experts 还是 shared expert,并定位其内部首个异常张量。重启服务并监控v48及八个Worker加载状态
v48 已成功加载带分支探针的代码,八个 worker 正常读取权重。未出现作用域、导入或算子错误。监控v48启动、模型转换及服务健康状态
v48 已健康启动。现在执行单次 prefill,并读取 layer40 八个 rank 的路由选择、GMM、routed_out 与 shared_out。运行提示并提取第40层探针
关键异常是:rank1–7 的 GMM 均算出了非零专家结果,但 routed_out 全为零;只有 rank0 输出非零且异常巨大。这强烈指向 expert_map 掩码错误,而不是权重计算。先核对八个 rank 的 expert_map 分布与应有全局专家区间。核对各EP Rank的Expert Map统计
根因已确认:八个 EP rank 的 expert_map 完全相同,都只映射全局专家 0–31。于是 rank1–7 的本地专家计算结果被掩码清零,所有路由负载错误地落到 rank0。现在修复 expert_map 的 rank 生成逻辑。排查并修复FusedMoE EP Rank初始化与配置问题
FusedMoEConfig.ep_rank 在 worker fork 后保留了父进程的 0;运行时 EP group rank 才是正确值。修复策略是初始化 routed experts 时用实时 get_ep_group().rank_in_group 刷新配置,并让 ep_rank 属性始终返回实时值。修复并验证MoE及EPLB的EP Rank同步
EP rank 修复测试 36/36 通过。启动 v49 后应看到 expert_map 分别覆盖 0–31、32–63 … 224–255;随后验证 layer40 爆炸和文本质量。重启并监控 v49 EP 修复及八个 Worker 权重加载 бары
v49 正常进入加载,运行时已明确建立 EP rank 0–7。待模型启动后,通过八个 expert_map 的非 -1 区间验证修复是否真正生效。监控模型服务启动加载及健康状态
v49 已健康启动。现在检查各 rank 的 routed 分支是否均贡献非零结果、layer40 是否解除爆炸;随后直接跑 48-token 文本。验证专家映射并检查首Token输出
修复代码没有进入 v49:部署脚本未覆盖 vllm_ascend/ops/fused_moe/routed_experts.py,容器仍在使用镜像内旧实现。将该文件加入覆盖清单后重启验证。修复并验证部署脚本及 routed_experts.py 安装配置
覆盖清单已修正。启动 v50;这次容器会实际加载实时 EP rank 修复。启动并监控v50实时EP修复及八个Worker初始化
已确认 v50 容器实际包含 sync_live_ep_rank 修复。当前八个 worker 正常加载,无初始化异常。监控模型及v50模型启动与专家转换进度
当前进展:
- 已定位 layer40 MoE 爆炸的直接原因:
- 八个 EP rank 的
expert_map都错误地映射到全局专家 0–31。 - rank1–7 虽完成了本地专家 GMM,但结果被错误掩码为零。
- 所有有效路由集中到 rank0,layer40 的 routed output 达到约
±1930,导致该层 RMS 从约 7 跳到 114,并使生成结果乱码。
- 八个 EP rank 的
- 根因是 rfork 后
FusedMoEConfig.ep_rank保留父进程的 rank 0。 - 已修复:
- 初始化 routed experts 时使用实时
get_ep_group().rank_in_group刷新配置。 AscendRoutedExperts.ep_rank改为读取实时 EP group rank。- 新增回归测试,相关测试 36/36 通过。
- 初始化 routed experts 时使用实时
- 发现第一次验证时部署脚本没有覆盖修改后的
routed_experts.py;现已补入覆盖清单。 - v50 已确认容器内实际包含
sync_live_ep_rank修复。 - 当前 v50 已完成 48 个权重分片读取,正在执行八卡 MXFP4 → W8A8 专家转换,暂未出现异常。
尚未完成的最终验证:
- 确认八个 rank 分别贡献各自专家结果。
- 确认 layer40 MoE 不再爆炸。
- 执行 48-token 中文生成,检查是否恢复正常文本。
- 再做两次相同请求的确定性测试。
第十阶段
继续完成 v50 的最终验证:先确认服务状态和实时 EP 映射,再检查 layer40 数值与 48-token 中文输出。检查容器、远程机器及NPU健康状态
v50 已健康运行,八卡显存稳定。现在执行一次受控 prefill,检查各 EP rank 是否都产生 routed 输出,以及 layer40 是否恢复正常范围。完成单Token探针与DeepSeek-V4单标记推理测试
实时 rank 修复仍未生效:expert_map 依旧相同。说明模型构造阶段 get_ep_group().rank_in_group 在 rfork 子进程中也返回了 0,或后续被覆盖。现在追踪配置初始化顺序和实际 rank 来源。检查 get_ep_group 导入及 GroupCoordinator 组内排名实现
问题进一步确认:get_ep_group().rank_in_group 是创建 coordinator 时缓存的普通字段,rfork 后不会更新。改为用当前进程的 torch.distributed.get_rank() 在 EP 组的全局 rank 列表中重新定位。修复并测试路由专家实时EP Rank缓存同步
新的 rank 解析测试 37/37 通过。启动 v51;启动日志会直接打印每个 worker 的 cached/live/global,可在加载前确认映射。完成 v51 分布式EP映射修复验证及容器加载监控
v51 已进入八卡加载,但预期的 rank 解析日志未出现。先确认容器内新函数是否已覆盖,并检查日志是否被 info_once 过滤。检查部署代码并搜索专家并行日志
expert_map 的统计摘要无法区分正确区间,因为任意 rank 都包含 -1 与本地编号 0–31。当前需转向数值根因:只有 rank0 的某些 layer40 专家产生超大 SwiGLU/GMM2。先核对官方 MoE 权重排列与激活公式。检查并实现 MXFP4 转 W8A8 及 SwiGLU 配置
配置确认 swiglu_limit=10,当前激活公式与官方一致。更可疑的是 MXFP4 解包:文件注释同时描述了“低 16/高 16 分区”和“逐字节交错”两种互斥布局。现在核对官方转换/内核的实际 nibble 顺序。验证了 DeepSeek V4 FP4 打包顺序
官方 convert.py 明确采用逐字节低/高 nibble 交错,当前 FP4 解包顺序正确。v51 继续加载;服务启动后先看修复是否改变 layer40,再决定是否进入单专家级定位。等待服务启动并分析MXFP4专家路由异常
v51 尚未完成专家转换,服务端口仍未开放;检查容器状态和各卡负载,确认是否仍在正常计算或已卡住。检查容器状态并确认服务健康运行
v51 已健康启动。现在重新测 layer40;若数值仍爆炸,就直接进入单专家定位,不再继续围绕 rank 映射猜测。验证了 v51 单 Token 探针映射
EP rank 修复未改变结果,已排除 rank 缓存是 layer40 爆炸的主因。下一步对 layer40 的 32 个 rank0 专家做离线权重统计,找出是否存在天然高增益或转换异常的专家。检查并修补专家权重与调试探针
离线统计显示 layer40 的原始 W1/W3/W2 范数与相邻层一致,checkpoint 权重无异常。下一轮将保存 rank0 layer40 的排序输入、GMM1、SwiGLU、GMM2 和 group list,精确复现单个专家。增强调试探针并完成第40层快照及v52测试准备
单专家诊断代码测试 36/36 通过。启动 v52;这次一次请求即可获得 exact top-k、group list、最大值坐标和可离线复现的 layer40 快照。启动并监控 v52 快照任务及模型加载
v52 已加载带精确快照的代码,八个 worker 正常读取权重。当前没有新增异常。监控模型加载及服务健康状态
v52 已健康启动。现在执行一次请求并提取 exact top-k、group list、最大值坐标与 rank0 layer40 快照。运行单请求并分析日志快照
已锁定到 layer40 的 expert29。现在用保存的精确输入重放该专家,分别比较原始 FP4、软件 W8A8 和 NPU 实际三个阶段。分析第40层第29位专家精度
离线重放结果明确:NPU 与软件 W8A8 几乎逐元素一致,expert29 的大输出是当前输入和权重的真实结果。与此同时发现更直接的 EP 错误:八个 rank 的 group_list 完全相同,说明 310P dispatcher 仍在用缓存的 rank0 区间。现在修复 dispatcher 的实时 EP rank。修复TokenDispatcher排名缓存并完成部署检查与单元测试
dispatcher rank 修复测试 30/30 通过。启动 v53;验证标准是八个 rank 的 group list 必须分别对应各自全局专家,而不再完全相同。验证310P AllGather Dispatcher修复并监控容器进度
v53 八个 worker 已正常进入权重加载,dispatcher 修复已部署,暂未出现构造或算子错误。继续完成转换后直接做单次 prefill 验证。监控模型加载与服务健康状态直到启动完成
v53 已完成主要转换,正在等待最后一个 worker 和引擎初始化。启动后将一次性检查八组 group list、layer40 数值和 48-token 输出。等待服务就绪并运行预填充检查分组列表
active_expert_range 修复未改变算子结果,说明 310P 的 npu_moe_init_routing_v2 在当前 CANN 上没有按该区间过滤全局 expert ID。先用微基准确认算子语义,再决定采用本地 ID 重映射还是软件 dispatch。检查基础分发器及AllGather实现
对照通用 AllGather 实现发现关键差异:310P override 将 expert_num 错设为本地 32,而 active_expert_range 语义要求传全局专家数 256。先在空闲显存内跑一个小算子基准确认。验证了全局专家数与激活范围行为
微基准暴露了 310P 算子的限制:expert_num 必须等于本地专家数,不能直接采用通用实现的全局 256。继续验证“全局 ID + 区间”与“显式本地 ID 重映射”两种输入。测试昇腾MoE专家索引映射完成
微基准确认当前 CANN 310P 行为:active_expert_range 被忽略,全局 ID 实际按本地 32 个专家处理。可靠方案是先用 expert_map 显式映射为本地 ID,非本地路由映射到 expert0 并将权重置零。新增专家ID映射测试并重启v54
显式本地 ID 重映射测试 38/38 通过。启动 v54;该版本应首次让 rank1–7 的本地专家结果进入 combine。验证Expert ID重映射并监控模型转换加载进度
v54 已正常进入八卡加载。此次改动只影响运行时 dispatch,不改变权重转换流程;服务启动后重点检查各 rank 的 group list 是否分化。监控模型加载、NPU资源及服务健康状态
v54 已接近完成,当前六个 worker 已完成加载,剩余两个仍在转换。未出现 OOM 或算子错误。检查服务状态并测试令牌输出及超时情况
显式重映射已经生效:各 rank 的 group list 首次分化,rank1–6 均产生有效 routed 输出;首 token 从乱码恢复为高置信度 “你好”。现在跑完整 48-token 中文生成。完成48令牌生成测试并按日期重新运行推理
48-token 结果揭示了新的边界:prefill 首 token 已正确恢复为“你好”,从第一个 decode token 开始立即变成乱码。因此剩余主问题已收敛到 KV cache / decode attention 路径。接下来做 teacher-forcing 等价性对比。实现并验证预填充与解码隐藏状态等价性
将使用两条数学等价路径定位首个 decode 分叉:
1)13-token 全量 prefill(末 token 为“你好”);2)12-token prefill 后用 KV cache decode“你好”。两者在 position 12 的每层结果应一致。检查并定位 DeepSeek DSA 注意力实现及缓存缺陷
为减少重启次数,将同时加入两级等价性探针:模型每层输入/attention/MoE/output,以及 DSA 内部 q、当前 kv、缓存回读 keys、attention。一次 v55 即可定位首个不一致点。完成Prefill与Decode等价性探针及部署编译测试检查
teacher-forcing 探针测试 29/29 通过。启动 v55;服务起来后先跑 13-token 参考 prefill,再跑 12-token+decode,对比 position 12。启动并监控v55解码等价性测试容器加载
v55 八个 worker 已正常进入加载,等价性探针已部署。完成后两次请求即可定位首个 decode 分叉。监控模型加载、NPU状态及服务健康状况
v55 已完成八卡权重与专家转换,正在进行引擎初始化。下一步直接执行 reference prefill 与 cached decode 两条路径。检查服务健康状态并比较提示解码结果
继续验证后的结论:
- EP dispatch 已修复。 310P CANN 会忽略
active_expert_range,因此改为通过expert_map显式把全局专家 ID 映射成本地 ID;非本地路由权重清零。相关测试 38/38 通过。 - 修复后八个 rank 的 group list 已正确分化,rank1–6 均产生有效 routed 输出。
- Prefill 首 token 已从乱码恢复为高置信度 “你好”。
- 但 48-token 生成仍是:
你好: & 吃食0ediVtdisfah...即错误从第一个 decode token开始。
Teacher-forcing 对比已精确定位:
- position 12 的 13-token 全量 prefill,与“12-token prefill + KV-cache decode”进行逐层比较。
- layer0 完全一致:
- Q:零误差
- 当前 KV:零误差
- KV cache 回读:零误差
- attention:零误差
- 首次分叉发生在 layer1 attention:
- layer1 Q:零误差
- layer1 当前 KV:零误差
- layer1 KV cache 回读:相对 L2 误差 1.0
- layer1 decode attention 输出为全零,而 reference 最大值约 4.70
- 此后误差逐层累计,最终 hidden state 相对误差约 0.71。
- 多个后续奇数层也出现“缓存误差 1.0、decode attention 全零”的规律。
因此已排除:
- FP4/W8A8 权重转换;
- Q/KV 投影;
- RoPE;
- EP 路由;
- MoE grouped matmul。
剩余根因已收敛为:layer1 起部分 DSA/SWA paged KV cache 的缓冲区绑定、slot mapping 或 block-table metadata 使用错误。v55 当前保持健康运行,无 OOM 或运行时异常。下一步需要直接对比 layer0/layer1 的 cache tensor 地址、slot mapping 和 block table,修复 layer1 的缓存写入或回读路径。
第十一阶段
继续定位 layer1 的 KV cache 分叉:先核对 layer0/layer1 的 cache tensor、slot mapping、block table 与压缩比配置,再做最小修复验证。检查服务状态配置及DSA KV缓存构建绑定顺序
规律已经很明确:layer1、3、5…等奇数层 cache 失败,而偶数层能回读。当前重点转向 310P 自定义 KV 分配器,检查是否把同一组中的第二个层绑定到了错误的 K/V 视图。检查310P模型缓存绑定与通用KV分配器
通用分配器中存在“同一 shared_by 组共用 raw tensor”的路径,但仅凭源码还不能断定。下一步先确认每层实际 compress_ratio 与 attention metadata 列表,避免把 layer1 的异常归错到缓存分配。检查并验证DeepSeek-V4层索引与注意力元数据映射
当前最可疑的是 metadata 列表选择和缓存绑定两处。先读取 vLLM 对 KVCacheTensor.shared_by 的定义与 bind 语义,确认通用分配器是否错误地让多层共享同一底层缓存。核对了 vLLM KV 缓存共享语义
容器源码检查受独立启动开销影响超时。当前更直接的假设是 attn_metadata[-1] 选错了缓存组;这能同时解释“slot mapping 未写入、奇数层 attention 全零”。先检查 SWA cache 模块保存的精确层名,并改为按键选择 metadata。修复SWA元数据选择逻辑并定位vLLM字段定义
SWA cache 对象明确保存了 prefix。我将去掉“取过滤列表最后一个 metadata”的假设,改为按 model.layers.N.self_attn.swa_cache 精确选择;同时保留严格校验,避免静默选错缓存组。修正并测试DSA及SWA元数据筛选逻辑
精确 SWA metadata 选择已补齐测试。先执行相关 attention、EP 与模型测试;通过后启动 v56 做 teacher-forcing 回归。验证DSA元数据实现并运行测试
相关新测试已通过;唯一失败是仓库原有的 “plain MLA backend” 预期,与当前统一 310P DSA 路径冲突。另发现 metadata 改动必须仅限 310P,正在收窄作用范围,避免影响 A2/A3/A5 通用 DSA。修复并验证元数据过滤测试及容器作业
310P 专用回归 17/17 通过。现在启动 v56;若 metadata 选择正确,layer1 cache 回读应从相对误差 1.0 降为接近零,第二 token 将不再立即乱码。更新部署脚本并验证v56 SWA Metadata加载
v56 容器已正常运行,尚处于多进程初始化阶段,未出现 metadata 数量校验错误。继续等八个 worker 进入权重加载。监控模型权重加载并检查服务健康状态
v56 已完成 48 个 checkpoint shard,正在执行八卡专家 W8A8 转换。精确 metadata 校验尚未触发异常,部署路径正确。检查模型转换服务健康状态及NPU日志
v56 已健康启动,八卡显存稳定。现在执行 13-token reference prefill 与 12-token+cached decode 等价性测试,重点检查 layer0–3 的 cache 和 attention。执行并比较教师强制测试日志
精确 metadata 选择没有修复 layer1 cache,但两步生成已恢复为正确的 “你好!”。先跑 48-token 判断是否已具备可用生成;同时继续追查奇数层 cache 被清零的原因。测试缓存修复后的令牌生成一致性
48-token 仍在第三 token 后迅速失真,因此必须修复奇数层 cache。下一轮将直接打印 layer0–3 的 SWA cache 地址、slot mapping、block table 和写后回读值,确认是写入槽位错误还是层间缓存别名。增强了注意力缓存探针
下一步不再猜测。将对 layer0–3 记录实际 cache 底层地址、shape/stride、slot mapping、block table,以及“写后当前槽位是否等于 KV”。一次请求即可区分缓存别名、写入失败和回读映射错误。添加缓存布局探针并完成编译测试
KV 布局探针回归 11/11 通过。启动 v57;服务起来后只需一次 12→13 decode,即可得到 layer0–3 的缓存地址和写后校验结果。启动KV缓存布局探针并跟踪八卡权重加载进度
v57 容器正常,仍在多进程初始化阶段。继续等待 checkpoint 加载;本轮只新增只读探针,不改变推理逻辑。跟踪八卡模型加载及专家转换进度
v57 已完成全部 checkpoint shard,正在专家转换。服务启动后将只跑一组短请求并读取四层布局,不再做长生成。监控模型转换服务并检查容器日志与NPU状态
各卡 AICore 仍在运行,显存处于转换峰值,未卡死或 OOM。继续等待转换结束。等待 v57 专家转换完成
v57 已健康启动。现在执行一组 13-token reference 与 12-token+decode,并提取 layer0–3 的缓存地址、slot/block 映射及写后校验。执行教师强制解码并解析布局日志
根因已抓到:相邻两层确实共享同一 SWA cache tensor,但各自使用不同物理块;写入本身完全正确。真正错误在 block table 编码——例如 layer1 写入物理块 10,读取表却给出 160..175,即 16 倍展开索引。当前 fallback 把展开索引直接当物理块号读取,导致越界/错误数据。检查了DSA分页缓存块映射逻辑
block table 的 16 倍展开并非偶然,310P 自定义 block table 明确维护 blocks_per_phys_block。现在读取该实现和 format_dsa_slot_mapping,按同一几何关系修正 dense fallback 的回读。检查块表初始化及DSA槽位映射格式化公式
修复公式已明确:block table 存的是拆分后的逻辑块 ID;SWA cache 存物理块。需用 physical_id = logical_id // 16,并把逻辑子块偏移折回 32-token 物理块。为避免硬编码,将用当前 slot_mapping + input_positions 自动推断拆分因子。确认 Ascend DSA 元数据位置字段
已确认根因是混合 block table 的逻辑块 ID 被当成物理块 ID。现在实现通用反向映射与自动拆分因子推断,并补齐单测。检查并修补 DSA 注意力及缓存实现
反向映射已接入运行路径。现在补三类单测:拆分因子推断、展开 block table 回读、未拆分兼容性。完成混合块划分与缓存聚集测试并运行编译
实现逻辑通过,唯一失败是测试期望张量默认为 int64。修正测试 dtype 后重新执行完整相关回归。修正Block Table测试张量类型并重新运行测试
混合 block table 回归 20/20 通过。为避免每个 decode、每层重复把 metadata 拷回 CPU,先将推断出的拆分因子缓存在各 attention 实例中,再启动 v58。完成缓存优化检查并启动混合Block修复验证
v58 容器正常,仍在 worker 初始化阶段。该版本首次会对 block table 做严格边界校验,若映射仍有误将直接报错,不再静默读取越界缓存。监控模型加载进度与显存状态
v58 已完成全部 checkpoint shard,正在八卡专家转换。启动后先执行严格 teacher-forcing;只有所有层 cache 接近零误差后才做长生成。检查容器与NPU状态并等待模型及API启动
NPU 仍在活跃转换,显存和算力状态正常。继续等待最后几个 worker 完成。检查模型转换状态与服务健康状况
v58 已健康启动。现在执行 teacher-forcing;预期所有 43 层的 blocks_per_phys_block=16,cache 回读与 reference 接近逐元素一致。运行教师强制推理并汇总缓存错误
越界读取已彻底消除:奇数层 attention 不再为零,layer1 cache 误差从 1.0 降至 9.2×10⁻⁴,首个 attention 分叉仅约 1%。后续误差是该微小差异逐层放大。现在检查 48-token 实际生成质量。测试令牌生成并评估缓存稳定性
核心功能已恢复:48-token 生成自然结束并输出完整中文句子。下一步进入收尾:清理/关闭诊断探针,跑多提示词与连续请求回归,再保留一个可长期运行的最终服务版本。检查并禁用 DeepSeek V4 调试探针以优化推理性能
诊断探针目前会在层0/40执行大张量 D2H,并保存 layer40 快照,显著拖慢推理。将所有探针统一放到默认关闭的 VLLM_ASCEND_DSV4_310P_DEBUG=1 开关后,核心边界校验保留。完成 DSV4 诊断开关及生产模式调试探针修补
顺便修正已长期被排除的旧测试:当前设计明确让 DeepSeek V4 的所有压缩比统一走 310P DSA backend,未压缩层不应再期待独立 MLA backend。并添加诊断开关默认关闭测试。更新DSV4后端并完成全量测试编译检查
完整回归为 141 通过、2 跳过、1 失败。唯一失败是旧测试仍断言调用 torch_npu.npu_swiglu,而当前正确实现已改为支持 swiglu_limit 的组合算子;更新该测试即可。更新310P测试模拟依赖并完成编译检查
完整回归现为 142 通过、2 跳过、0 失败。接下来启动默认关闭诊断的 v59,并对中文、英文、数学和连续请求做最终回归与性能测量。检查并加固生产部署配置
将诊断启动器保留,另生成正式启动器:容器名改为 dsv4-310p,设置 restart=unless-stopped,显式关闭调试探针。随后用它启动 v59。创建并启动生产探测服务并跟踪权重加载
v59 正式容器已运行,名称为 dsv4-310p,重启策略已生效。当前仍在 worker 初始化阶段。跟踪 v59 权重加载及服务健康状态
v59 checkpoint 已加载至 90%,无错误。完成专家转换后将执行四类回归,并确认日志中不再出现诊断标记。监控并等待 v59 模型加载完成
继续完成了核心修复和生产部署。
当前状态
- 正式容器:
dsv4-310p - API:
http://127.0.0.1:8000 - 健康检查:HTTP 200
- Docker 重启策略:
unless-stopped - 8 张 310P 均已成功加载模型
- 当前最大上下文:128 tokens
- TP=8、EP=8
- 专家权重启动时执行 MXFP4 → W8A8 转换
- 生产模式已关闭所有昂贵诊断探针
本轮定位并修复的根因
310P 的 block table 使用了混合块布局:
- SWA cache 的物理块大小为 32 tokens。
- Attention kernel 使用 2-token 逻辑子块。
- 一个物理块因此展开为 16 个逻辑 block ID。
- 原 fallback 直接把逻辑 block ID 当成物理 cache block ID,导致错误甚至越界读取。
已实现正确映射:
physical_block = logical_block_id // blocks_per_phys_block
physical_offset =
(logical_block_id % blocks_per_phys_block) * logical_block_size
+ token_position % logical_block_size
拆分因子不再硬编码为 16,而是通过:
block_tableslot_mappinginput_positionsquery_start_loc
自动推断,并缓存在每个 attention 实例中。
同时加入了严格边界检查,后续 block table 错误会直接抛出异常,不会再静默读取错误显存。
修复效果
修复前:
- layer1、3、5 等奇数层 decode attention 输出全零。
- KV cache 相对误差为 1.0。
- 生成在第二、第三个 token 后变为乱码。
修复后:
- 所有层 attention 都产生有效输出。
- layer1 cache 相对误差降至约
9.2×10⁻⁴。 - 48-token 测试生成:
你好!我是DeepSeek,由深度求索公司创造的AI助手,致力于为你提供热情、细腻的帮助,解决各种问题。😊
模型在第 31 个生成 token 正常输出停止标记,没有乱码。
测试结果
完整 310P 与 fused MoE 回归:
142 passed
2 skipped
0 failed
覆盖内容包括:
- 310P DSA/SWA attention
- 混合 block table 映射
- KV cache 写入与回读
- EP 全局专家到本地专家映射
- W8A8 grouped matmul
- clipped SwiGLU
- inactive GMM row 清零
- DeepSeek V4 backend 选择
- 模型 runner 与 KV cache 初始化
诊断代码处理
所有 teacher-forcing、KV 回读、MoE 大张量 D2H 和 layer40 快照现已默认关闭。
需要重新诊断时可设置:
VLLM_ASCEND_DSV4_310P_DEBUG=1
正式启动器位于:
/mnt/caoyuhang/deploy/deepseek-v4-310p/run-production.sh
尚未在关闭诊断后的 v59 上完成中文、英文、数学四组连续请求和最终吞吐测量;v59 本身已健康启动,核心功能使用相同的、已在 v58 验证通过的 block table 修复。
第十二阶段
先完成 v59 的连续请求与吞吐回归,确认生产容器稳定;随后整理提交范围、检查 diff 和许可证/测试,再提交并推送当前 GitHub 分支。完成生产服务连续请求回归与稳定性验证
三类连续请求均正常,数学结果正确,服务无错误、无 OOM、无诊断日志泄漏;当前组合 fallback 输出约 1.1 token/s。再补代码生成与并发双请求,随后整理 Git 提交。验证并发请求隔离并检查Git分支代码差异
代码审查发现仍包含约 500 行临时 teacher/MoE 探针及 /tmp 快照逻辑。它们虽默认关闭,但不适合进入正式分支;我会删除临时探针,仅保留运行时边界校验和必要日志,再重新跑全套测试与生产冒烟。清理并验证模型各路径中的调试探针
临时诊断代码已全部删除,核心实现规模明显收敛。现在重新跑完整 310P/Fused-MoE 回归,并执行格式与静态检查。运行完整测试并执行 Ruff 格式静态检查
功能回归通过;容器镜像没有安装 Ruff,未能执行该项。改用仓库现有的 pre-commit/格式工具,若环境也缺失则至少完成 compileall、diff --check 和人工 diff 审查。检查代码格式并使用Ruff验证变更文件
Ruff 找到两处清理遗留:一个未使用 import 和一处 import 排序。先自动修复并按项目配置格式化全部改动文件,然后再跑测试。修复并格式化 Python 代码以通过 Ruff 检查
Ruff 已全部通过,36 个改动文件格式一致。现在再跑最终单测;之后用清理后的代码重启正式容器并做一次生成冒烟,再提交推送。完成格式化测试、部署脚本整理及DeepSeek文档更新
现有文档仍写着“剩余执行阻塞”,已经过时。我会将其改为可复现的已验证启动说明,并明确当前性能与上下文限制。更新并启动清理后的DeepSeek V4生产服务
最终服务正在重新加载,预计仍需完成专家转换。等待期间我会做提交前审查:检查硬编码路径、临时文件、异常大改动和文档一致性。审查代码改动并运行测试完成提交准备
新增模块引用检查发现 dequant_swiglu_quant.py 没有被任何运行路径导入,正式服务也未复制它,属于早期尝试遗留。我会删除该孤立文件,避免误导后续维护。删除孤立模块并检查服务启动日志
最终容器已正常创建,仍在多进程初始化阶段。代码侧已无本机路径、临时快照或孤立模块;接下来检查远端分支是否有新提交,避免推送时覆盖他人工作。同步远端并检查分支状态
远端已找不到该功能分支,说明 GitHub 上的同名分支被删除了;本地仍保留旧 tracking 引用。下一步检查远端默认分支和仓库状态,再以普通新分支推送,不使用强制覆盖。检查 Git 配置并同步远端 main 提交
远端 main 已包含此前 10 个阶段性提交,且删除了功能分支。本地工作树仍基于 bootstrap,因此提交前必须把最终增量移到最新 main 上;先比较工作树与 origin/main,避免重复提交已合入内容。评估了工作区相对主分支的真实增量
远端 main 已合入此前阶段性提交;本地最终代码仍基于旧 bootstrap,直接推送会产生重复/伪删除。先将当前最终增量提交到本地,再把该单一提交 rebase 到最新 origin/main,冲突按最终已验证实现整理。创建并变基 DeepSeek V4 推理路径提交
冲突仅出现在远端阶段性文件与本地最终版本的重叠处。对于这些文件采用已完整测试的最终版本;其余文件由 Git 自动合并保留远端新增内容。解决 rebase 冲突并继续变基
Rebase 已完成,最终提交现在只比 origin/main 前进 1 个提交。由于自动合并可能改变了非冲突文件,重新执行 Ruff、编译和完整回归。验证 rebase 后代码质量
Rebase 后 Ruff 抓到一处阶段性提交与最终代码的重复 import,位于 310P FP8 配置注册。删除重复分支后继续验证。修复重复导入注释并运行Ruff检查
重复 import 已清理,Ruff 仅要求重新格式化 platform.py。处理后进行最终回归并 amend 提交。完成平台代码格式化并通过rebase后完整回归测试
最新 main 自带的更完整测试暴露了 rebase 冲突处理中的三处回退:Hyper-Connection 输出 dtype,以及 MXFP4 nibble 解码/重量化。将对照 origin/main 恢复这些已验证实现,再确认本轮新增路径兼容。比较了 Hyper-Connection 与 MXFP4 实现差异
两个结论不同:Hyper-Connection 确实应恢复 main 的输出 dtype;MXFP4 测试仍沿用早期“先全部低 nibble、再全部高 nibble”的错误假设,而真实 checkpoint 按字节交错,当前端到端正确生成依赖交错解码。修正实现 dtype,并更新 MXFP4 测试为真实布局。修复 HyperConnection 类型及尾部并调整 MXFP4 测试
进一步核对表明 Hyper-Connection 实现已正确返回 FP16,失败源于 main 新测试的参考张量被 FP32 参数提升;应修正测试 dtype。MXFP4 也保留真实逐字节交错布局,并相应修正断言。修正并验证MXFP4量化测试与解码输出
目标测试命令遗漏了 NPU 设备挂载,导致 torch_npu 初始化失败;这是测试容器参数问题。按完整测试容器配置重新执行。使用设备挂载完成回归测试并检查生产容器进度
最终完整回归现为 154 通过、2 跳过、0 失败,覆盖了远端 main 新增的 HC/MXFP4 测试。先将测试修正 amend 到最终提交,再核对正式容器是否加载了同一份代码。检查生产服务状态并完成最终代码提交更新
正式容器已健康运行,且容器内全部覆盖文件的 SHA-256 与最终提交完全一致,无需再次重启。最后执行一次完整中文生成和日志检查,然后 fast-forward 推送到 main。执行端到端冒烟测试并推送分支
最终smoke成功:完整中文回答正常停止,约 1.12 token/s,服务无错误、无 OOM。