截至8月3日,官方未提供在Ascend 310P上使用Deepseekv4的适配。本人获得了一台搭载 4*DUO-96GB 的服务器,故尝试自行实现适配。[Feature][Model] Support DeepSeek V4 on Ascend 310P by fwerkor · Pull Request #13705 · vllm-project/vllm-ascend
前置条件
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。
第十三阶段(开始优化性能)
重新测了一次:
- 首 token:约 1.06 秒
- 后续 token 间隔:约 0.82 秒
- 输出速度:约 1.22 token/s
- 8 个芯片平均 AICore 利用率:4.2%
- 平均 HBM 带宽利用率:2.2%
- AICore 峰值也只有:6%
因此当前瓶颈不是矩阵计算能力,也不是显存带宽,而是下面这些兼容 fallback。
1. 当前运行在纯 eager 模式
启动参数包含:
--enforce-eager
日志明确显示:
CompilationMode.NONE
CUDAGraphMode.NONE
torch.compile disabled
CUDAGraph disabled
DeepSeek V4 有 43 层。每生成一个 token,每层都会启动大量很小的算子。没有计算图后,Python、PyTorch dispatcher、ACL runtime 和多进程 RPC 的固定开销无法被摊薄。
这与 GPU/910B 上经过图融合的成熟后端差距很大。
2. DSA 目前是逐步拼出来的 dense fallback
当前日志写得很明确:
Unsupported fused operators are being replaced incrementally.
310P 没有可直接使用的 DeepSeek V4 DSA 融合算子,所以目前使用普通 PyTorch/NPU 操作模拟。运行路径中存在:
query_start_loc.to("cpu").tolist()
seq_lens.to("cpu").tolist()
torch.all(...).item()
以及逐请求、逐 token 的 Python 循环:
for request_idx ...
for local_query_idx ...
matmul
softmax
matmul
对于 decode,每层只处理一个 token,计算量很小,但每层都需要:
- 从 NPU 同步少量元数据到 CPU
- Python 分支和循环
- 启动多个小 NPU 算子
- 等待结果
- 再进入下一层
这正好解释了为什么 AICore 利用率只有约 4%。
3. MoE 通信与计算没有融合
模型每层包含:
- 256 个 routed experts
- 每 token 激活 6 个 experts
- TP=8
- EP=8
当前配置又关闭了:
VLLM_ASCEND_ENABLE_FUSED_MC2=0
VLLM_ASCEND_ENABLE_MLAPO=0
所以每层的 MoE 大致需要独立执行:
路由 Top-K
→ 8 卡 token dispatch/all-gather
→ 第一遍 grouped matmul
→ SwiGLU
→ 第二遍 grouped matmul
→ 8 卡 combine/reduce
一共重复 43 次。单 token 场景下,每张卡实际只有极少量 token,矩阵特别小,通信和调度时间远大于计算时间。
4. SwiGLU 仍是非融合实现
310P 上当前没有适用的 DeepSeek V4 融合量化 SwiGLU,因此代码实际执行:
gate_up.float()
torch.clamp(...)
F.silu(gate)
gate * up
.to(float16)
动态量化
也就是:
- FP16 转 FP32
- clamp
- SiLU
- multiply
- FP32 转 FP16
- 再量化
这些是多个独立 kernel。它们在大 batch 下还能接受,在 batch=1 的逐 token decode 下启动开销非常明显。
5. 原始 FP8/MXFP4 不能原生执行
模型 checkpoint 大约 166.9 GB,包含 FP8 和 packed MXFP4。
310P 无法直接执行模型需要的这些格式,因此启动时将本地专家转换成 W8A8。这样解决了:
- 模型能否装入
- 算子是否支持
- 输出是否正确
但没有得到原生 DeepSeek V4 FP4/FP8 内核的效率。当前重点是兼容性和正确性,尚未做到针对 310P 的完整算子融合。
6. 几乎没有并发空间来摊薄开销
目前每张 NPU:
- 模型占用约 35.4 GB
- 总显存占用约 39–40 GB
- KV cache 只配置了 128 MiB
- KV cache 总容量只有 232 tokens
- 128 token 请求的理论最大并发只有 1.81
因此无法靠较大的 continuous batching 提高吞吐。即使设置了 max-num-seqs=8,显存和 KV cache 实际上也不允许跑到 8 路完整请求。
7. CPU 绑定也没有成功
8 个 worker 都出现:
Bind cpus failed ... conflict with NUMA affinity
这不是最主要原因,但会进一步增加:
- worker 调度抖动
- Host 算子提交延迟
- 跨 NUMA 访问
- HCCL 控制路径延迟
结论
当前的 1.1–1.2 token/s 是“正确性兼容后端”的速度,不是优化后端的速度。
根本证据是:
AICore 只有 4.2%,HBM 带宽只有 2.2%。
如果是 310P 硬件算力不足,AICore 或显存带宽应该长期接近饱和。现在大部分时间芯片都在等待 Host 和通信调度。
优化优先级应当是:
- 去除 DSA 每层的 CPU 同步和 Python 循环,改成纯设备端批量实现。
- 实现 310P DSA/MLA 融合 kernel。
- 融合 MoE dispatch、GMM、SwiGLU、combine。
- 开启图编译,消除
--enforce-eager。 - 启用或自行实现 fused MC2。
- 修正 NUMA/CPU affinity。
- 压缩模型驻留显存,扩大 KV cache 和实际 batch。
仅调整启动参数不会从 1 token/s 直接变成几十 token/s;当前主要缺的是底层融合算子和图执行路径。
第十四阶段
先做低风险、高收益的性能拆分:移除每层 CPU 同步、减少 decode 小算子数量、修复 CPU/NUMA 绑定,再评估是否能关闭 eager。每一步都用相同基准测量,避免牺牲正确性。检查代理技能、仓库状态并优化测试注意力实现
先做第一项可测优化:为 decode attention 增加纯设备端批量路径,消除每层 to(cpu) / tolist / item 和逐 token Python 循环。这个改动不触碰模型权重或 MoE 数值。优化并验证MoE路由、注意力及Token分发合并流程
注意力优化测试正在跑。并行分析 MoE 时发现当前每个 EP rank 都为 6 条全局路由执行专家 GEMM,其中大多数其实属于其他卡;我正在验证一种固定形状的本地路由压缩,可将每卡实际专家计算降到约 1–2 条。完成NPU注意力路由、配置与性能基准测试
NUMA 拓扑也确认了:8 个芯片分布在两组 PCIe/NUMA 域,而 vLLM 的自动绑核失败后 8 个 worker 可在 96 个核心间漂移。这个会增加控制与通信延迟,但主瓶颈仍是 decode attention 的 Host 同步和 MoE 小算子。检查基准测试输出及批量注意力性能瓶颈
首项基准结果:纯设备端批量 attention 与旧路径数值完全一致,但单层只从约 4.04 ms 降到 3.98 ms,收益很小。说明 0.82 秒/token 的主要瓶颈不在那几个 Host 同步,而在 43 层 MoE 与 TP/EP 通信;接下来转向路由计算裁剪和图执行。优化图编译、稀疏注意力及MoE通信配置
除了单请求延迟,我还发现当前只给 KV cache 分配了 128 MiB,而每卡仍有约 4.5 GiB 空闲。这使并发被人为限制在约 1.8 路。后续会把吞吐优化分成两条:单流图执行/算子融合,以及将 KV 扩到安全上限提高并发吞吐。检查并检索 vLLM 与 DeepSeek MTP 推测配置支持
模型 checkpoint 自带 1 层 MTP。这可能是单流速度最现实的高收益路径:主模型一次验证 2 个 token,并行度也更高。我会先用 dummy 权重验证 310P 的 MTP/图执行兼容性,再决定是否让真实服务重载,避免无效的 8 分钟启动。检查并修补MTP与DeepSeek V4配置兼容性
下一步会短暂停掉当前生产容器,先用 dummy 权重验证 MTP + decode ACL graph。若启动或图捕获失败,会直接恢复原生产服务;若通过,再用真实权重测实际加速。优化启动配置并检查 MTP 推理任务及容器状态
dummy 验证尚未进入模型加载,失败仅是启动脚本的嵌套 JSON 引号被外层 bash -lc 吃掉;不是 MTP 或图执行不兼容。已定位,修正后立即重试。修复嵌套Bash JSON引号并验证脚本配置
已修正实验启动参数。现在重新验证 MTP + decode-only ACL graph;这一步仍使用 dummy 权重,不承担真实模型重载成本。验证推测解码与图捕获并检查容器日志
MTP 配置已通过 CLI 解析,容器进入正常引擎初始化,尚未出现架构或量化兼容错误。继续观察到模型加载和图捕获阶段。修复并验证NPU拓扑映射与模型服务加载状态
dummy 权重已完成 MTP 模型加载;额外 MTP 层约占 1 GiB/卡,仍有约 3.5 GiB 余量。现在进入 decode graph 捕获,这是本轮最关键的兼容性检查。检查编译日志并监控图捕获执行状态
图编译已完成,失败发生在捕获 warmup 的 dummy metadata:其中没有有效 slot,现有代码无法自动推断逻辑块拆分因子。真实运行固定为 32-token 物理块 / 2-token 逻辑块,即因子 16;我会从 block-table 配置直接读取该值,而不是依赖请求数据推断。优化并测试DSA静态块几何推断修复
第一次图捕获失败点已修复:block 几何现在从静态 table shape 得出,不再依赖 dummy slot。顺便将编译范围从 256 收紧到 128,减少编译时间和无效图尺寸。优化MTP虚拟图编译并完成测试验证
为保证 MTP 图回放正确,我继续将 2-token speculative decode 也改成纯设备端批量 attention;否则捕获时的 CPU 循环会把序列长度固化成 dummy 值。完成多令牌注意力改造并监控编译部署与NPU状态
MTP 图路径已推进到 draft model,当前阻断是 310P W8A8 线性只接受二维输入,而 MTP 会传入三维候选张量。先把量化线性改为“展平前导维—计算—恢复形状”,再重跑 dummy 图验证。修复并测试动态W8A8线性层多维张量处理
W8A8 已支持任意前导维,MTP 的 [tokens, candidates, hidden] 会被安全展平后恢复。先跑量化、attention、CPU 绑核三组目标测试,再启动第四轮 dummy 图捕获。运行回归测试并检查Docker任务状态
目标测试中 97 项通过,唯一失败只是旧测试用 assert_called_with(tensor) 比较张量产生歧义,功能结果没有失败。修正断言后继续。修复量化测试断言并验证重启任务输出
98 项功能测试已全部通过;失败码仅来自该旧测试文件的 CRLF 行尾被 git diff --check 识别为尾随空白。先统一为 LF,然后启动第四轮 MTP 图验证。完成测试文件规范化并检查 Dummy v4 启动状态
第四轮已进入 MTP 引擎初始化,最新代码和编译缓存均生效。CPU 绑核修复将在 worker warmup 阶段验证;之后重点看 target graph 与 draft graph 是否都能完成捕获。监控模型编译加载及服务启动状态
第四轮仍在 draft model 的量化线性失败,但堆栈显示实际执行的不是刚改的 310P scheme:输入仍以三维直接送入 npu_quant_matmul。下一步确认 MTP draft 绑定的具体量化类,并在真正调用点修复。修复并扩展通用动态量化及w8a8实现
真正调用点已确认并修复:MTP draft 使用的是通用 W8A8 scheme,而非 310P 专用类。现在两套动态量化线性都支持候选维度,部署脚本也会覆盖通用实现。完成通用与310P量化线性方案测试并检查作业状态
量化形状测试 10 项通过;唯一失败是仓库原有的 BF16 NPU 用例,而 310P 动态量化本来只支持 FP16,与本次改动无关。现在重跑 MTP 图路径,验证 draft 编译是否越过原阻断。启动并检查 MTP 解码图及模型容器日志
已开始实施优化,当前完成的是第一阶段代码和兼容性改造。
已完成
- Decode attention 设备端向量化
- 消除了每层
to(cpu) / tolist / item和逐 token Python 循环。 - 支持普通单 token decode 和 MTP 的双 token decode。
- 与旧实现数值逐元素一致。
- 单层微基准约从 4.04 ms 降至 3.98 ms。收益较小,确认 attention 元数据同步不是主要瓶颈。
- 消除了每层
- MTP speculative decoding 适配
- 模型自带一层 MTP,已配置为每轮预测 1 个额外 token。
- 修复 MTP 三维候选张量与 310P W8A8 线性不兼容的问题。
- 通用和 310P 专用 W8A8 现在都会展平前导维执行量化 GEMM,再恢复原始形状。
- 相关 mock/功能测试通过。
- Decode-only ACL Graph 适配
- 配置为只捕获 batch size 1、2 的 decode 图,不编译 prefill。
- 修复图捕获 dummy metadata 无有效 slot 时,无法推断 hybrid block 几何的问题。
- 现在从静态 block-table shape 推导 16 倍逻辑块拆分。
- CPU/NUMA 绑定修复
- 原代码混淆了板卡 ID 与逻辑芯片 ID,导致所有 worker 绑核失败。
- 已按
npu-smi映射把每块 Atlas 300I Duo 的两个逻辑芯片映射到对应 CPU NUMA 域。 - 增加了对应回归测试。
当前验证状态
第四轮 MTP 图测试确认:
- 主模型图可以完成编译。
- MTP draft model 已成功加载。
- MTP 增加约 1.06 GiB/卡,转换后仍剩约 3.6 GiB/卡。
- 先前的 block-table 图捕获错误已经越过。
- 随后发现 draft model 实际使用通用 W8A8 scheme;该调用点现已修复。
第五轮 dummy 验证正在执行专家 W8A8 转换,尚未到最终图捕获和性能测试阶段。因此目前还没有可靠的新端到端 token/s 数据。
当前服务状态
为避免生产模型和实验模型同时占用八张 NPU,原 dsv4-310p 生产容器已经停止;当前运行的是:
dsv4-310p-opt-dummy
它使用 dummy 权重,端口 8000 尚未就绪。真实模型 API 当前不可用。
尚未完成:
- MTP target/draft 两套图全部捕获成功;
- speculative acceptance rate 测量;
- 真实权重输出正确性验证;
- 与原始 1.22 token/s 的正式性能对比;
- 最终代码提交与 GitHub 推送。
第十五阶段
继续推进第五轮验证:先确认 MTP 图是否越过 W8A8 阻断;若通过,立即切到真实权重做正确性与吞吐对比。读取了npu310p远程任务输出
第五轮已越过 W8A8 和 draft 编译,新的阻断位于图回放的 KV 写入:布尔索引会生成 310P 不支持的 NonzeroV2。我将改成无 nonzero 的固定形状 masked scatter。修复并验证Dense DSA缓存更新及NPU写入
固定形状写入已改完,当前在单卡验证 argsort + index_copy 是否均由 310P 原生支持。通过后才重跑八卡,避免再次浪费完整模型初始化时间。等待并检查单卡 NPU 测试及作业状态
单卡验证通过,且没有再触发 NonzeroV2。测试同时暴露 argsort(int32) 会落到 AICPU;我会改成 FP32 排序键并使用 32 位索引,避免把每层 KV 写入变成新瓶颈。优化数据类型后运行并重试NPU超时测试
单卡验证命令因远程执行超时被中断,不代表算子失败。我先清理残留并读取实际日志,再决定是否直接进入八卡图捕获。修复索引兼容性并完成单卡KV写入测试验证
单卡 NPU 测试通过,且不再出现 AICPU 排序或 64 位 gather 警告。现在启动第六轮八卡图捕获,目标是同时完成 target 与 MTP draft 图。完成 v6 Dummy Graph 作业并检查模型转换状态
第六轮没有报错,当前仍在 43 层专家常驻 W8A8 转换阶段。该阶段历史耗时约 5–6 分钟,完成后才会进入图编译。检查NPU转换、图编译与图捕获进度
第六轮已完成 target 与 MTP draft 的 AOT 编译;失败发生在真正捕获时的 HCCL 事件查询,说明 310P 当前无法把八卡通信纳入 FULL ACL Graph。下一步改为 MTP + eager target,先争取真实可用的 speculative 加速,再单独研究通信图。完成MTP全Eager模式推理验证并检查模型加载
MTP eager 参数已正确生效,编译与图捕获均已关闭。目前只剩常规权重转换;完成后会直接进入服务启动,不再有 HCCL 图捕获风险。检查并等待 MTP Eager 模型转换、预热及 API 服务就绪
MTP eager 没有架构错误,但两张卡在长时间 MXFP4→W8A8 转换末尾出现异步 ACL 错误;其他六张已完成。先确认是残留设备状态、超时还是内存峰值,再决定重试或缩小转换分块。诊断 Repeat_interleave 异步失败并优化 MXFP4 转换路径
先定位转换链中实际触发 RepeatInterleave 的调用,并用单卡复现完整专家权重转换。目标是消除 AICPU 路径,而不只提高超时阈值掩盖问题。定位了 MXFP4 转换中的 RepeatInterleave 来源
转换失败具有非确定性:同一代码在图实验中能完成,说明更像长队列累积导致 AICPU 超时。修复会同时做两点:用位运算直接解码 E2M1,移除查表高级索引;每 128 个转换分块同步一次设备队列。修改并验证 MXFP4 转 W8A8 转换及 NPU 状态
完整 W13 分片已无 AICPU 调用并通过,但当前 128 行分块加频繁同步耗时 74.99 秒,不适合全模型。下一步扩大分块并取消分块内同步;位运算解码已消除原始超时源,可用最终同步保证完成。完成分块反量化及不同MXFP4分块性能基准测试
完整分片基准结果:512 行 70.20 秒,1024 行 35.31 秒,2048 行 39.80 秒;1024 最优,且三组均无 RepeatInterleave/AICPU 超时。采用 1024 行并默认不做中途同步。优化 MXFP4 转换默认分块参数
宿主机 Python 环境没有 pytest;容器内的 7 项转换测试此前已通过,默认参数改动只影响性能。先做静态检查,然后直接重跑 MTP eager 全模型验证。验证MXFP4配置及MTP转换与初始化状态
优化后的转换已进入实际专家阶段,暂未出现任何 AICPU 或 RepeatInterleave 错误。预计模型加载完成时间应与原来的约 5–6 分钟接近。检查优化后模型转换、加载日志及NPU状态
转换仍在正常计算,8 卡均健康、显存约 28–29 GiB,且无 AICPU 超时;但位运算解码明显降低了转换吞吐。先让本轮完成,用总加载时间判断是否需要换成 INT32 index_select 查表。检查转换状态与日志并评估性能瓶颈
稳定性问题解决了,但 12 分钟仍未完成,位运算解码的性能不可接受。我将终止本轮,改测 INT32 index_select 查表;该索引类型已确认在 310P AI Core 上执行,不会走原来的 64 位/AICPU 路径。完成多种索引选择实现基准测试并检查作业输出
INT32 index_select 完整分片为 68.50 秒,比位运算的 35.31 秒更差。继续保留纯算术路径,但将 E2M1 映射化简为分段线性公式,减少约一半逐元素算子。完成分段线性 MXFP4 解码基准测试
分段线性为 60.96 秒,同样更慢;当前位级解码仍是无 AICPU 方案中最快的 35.31 秒。为保留原始 5–6 分钟加载速度,我转而确认 CANN 是否支持提高 AICPU 算子超时,再评估恢复快速查表路径。查找了 CANN AICPU 超时配置
CANN 只提供运行时 API,没有对应环境变量。可在 worker 初始化后调用 aclrtSetOpExecuteTimeOut(600)。先用单卡恢复原始快速查表并设置 600 秒超时,测完整分片速度与稳定性。测试查表超时并检查分片基准输出
原始 LUT 在单次冷启动基准为 53.15 秒,不如位运算单次基准;但全模型历史加载只需约 5–6 分钟,而位运算路径超过 12 分钟,说明 LUT 的缓存复用更好。采用“原始 LUT + 600 秒 CANN 超时”方案。检查310P Worker文件并准备设置算子超时
worker 中其实已有 aclrtSetOpExecuteTimeOut,默认甚至是 1800 秒;因此上次超时不是缺少设置,而是该 AICPU 内核本身在部分卡上失去进展。不能依赖延长超时,继续保留无 AICPU 的位运算实现。验证并检查热缓存MTP及专家转换状态
热缓存未显著缩短转换准备阶段,但 8 卡仍无 AICPU 错误。继续等待完整结束;若超过 15 分钟仍未完成,将放弃运行时重转换,改做离线持久化 W8A8 权重。监控位运算转换进度与设备利用率
已继续完成一轮优化和验证。
已确认
- 修复 ACL Graph 中 KV cache 写入触发的
NonzeroV2:- 改为固定形状 masked write。
- 单元测试和单卡 310P 原语测试通过。
- 不再落到 AICPU 排序或 64 位 gather。
- Target 模型和 MTP draft 模型均已成功完成 AOT 编译。
- FULL ACL Graph 最终被八卡 HCCL 限制阻断:
- 错误为
Not allow to query captured-event。 - 当前 CANN/torch_npu 组合不能可靠捕获包含八卡通信的完整 decode 图。
- 因此优化方向改为 MTP + eager。
- 错误为
- 修复 MTP 三维候选张量的 W8A8 量化线性:
- 通用和 310P 专用实现均支持展平前导维再恢复。
- 相关测试通过。
MXFP4 转换优化结果
原实现偶发 AICPU operator execution timed out。测试了多种替代方案:
| 解码方式 | 完整 W13 分片时间 |
|---|---|
| 位运算解码,1024 行分块 | 35.31 秒 |
| 原始 LUT,600 秒超时 | 53.15 秒 |
| 分段线性公式 | 60.96 秒 |
INT32 index_select | 68.50 秒 |
当前采用位运算解码和 1024 行分块。完整分片验证没有出现 RepeatInterleave 或 AICPU 超时。
当前状态
最新 MTP eager dummy 全模型验证在最后一次检查时:
- 已运行约 12 分钟;
- 8 张卡状态正常;
- 没有 AICPU、RepeatInterleave、OOM 或模型错误;
- 仍处于专家权重转换阶段,API 尚未启动。
这说明稳定性问题基本解决,但运行时转换速度明显不可接受。当前尚未完成:
- MTP dummy API 启动;
- speculative acceptance rate 和 token/s 测量;
- 真实权重 MTP 验证;
- 恢复生产 API;
- Git 提交和推送。
下一项高收益优化应是离线生成并持久化 W8A8 checkpoint,避免每次启动重新转换全部专家权重。
第十六阶段
继续处理离线持久化方案:先确认当前 MTP eager 进程是否已结束,再检查 vLLM 的 sharded-state 保存路径,目标是生成一次性 W8A8 权重并用于后续快速启动。
本轮最终确认:目标模型和 MTP draft 均已加载完成,但初始化尾部仍因 AICPU 超时失败,证明运行时转换路线不可靠。现在停止残留进程,直接转入离线分片保存。
现有 310P 代码已提供离线保存入口,但实现很粗:每 rank 直接把 state_dict 写成 safetensors,且未处理目录、分片尺寸和设备格式。我先核对官方示例与加载协议,再补齐 DeepSeek V4 所需的可重载元数据。
离线 checkpoint 不能直接复用原模型配置:保存后的专家和 FP8 线性权重都已变成展开的 INT8,而默认构造仍会分配 MXFP4/FP8 原始形状。解决方案是增加 preconverted_w8a8 加载模式,由 310P sharded loader替换参数存储,并让量化方法只恢复 NZ 格式、不再二次量化。
关键原因已纠正:这次不是算子本身卡死,而是 MTP 初始化时目标权重、转换临时张量和 draft 权重叠加导致 HBM 分配失败,随后异步报成 AICPU timeout。离线 checkpoint 能同时消除启动转换和这段峰值内存。下一步补自定义加载器并先做小模型形状替换测试。
开始落地三部分:自定义 dsv4_310p_w8a8 loader、预转换权重的 NZ 恢复分支、按 4 GiB 流式保存。这样目标模型和 MTP draft 都能从同一套 rank 分片直接加载。
自定义 loader 已写入。现在先做小规模 CPU round-trip 和注册测试,确认“形状/类型替换、draft 子集加载、分片保存”都正确,再启动数百 GB 的离线转换。
测试容器里也没有 ruff,属于工具缺失,不是代码问题。改为直接跑 pytest、compileall 和注册验证;样式稍后用仓库 CI 或可用的 lint 环境检查。
pytest 导入 torch_npu 时需要设备与驱动挂载;上一轮失败在测试环境初始化。补齐单卡设备挂载后重跑,不涉及模型加载。
loader 的 5 项 round-trip 测试和注册验证已通过。下一步验证量化层能从“已转换 INT8”直接恢复 NZ 格式,同时确认 speculative JSON 能给 draft 指定同一自定义 loader。
方法测试失败是因为我覆盖了镜像 entrypoint,导致 CANN 的 tbe 环境未初始化。恢复镜像默认 entrypoint 后重跑;代码尚未执行到 NZ 恢复分支。
根因进一步定位为测试命令把 PYTHONPATH 覆盖成 /work,删掉了 CANN 的 Python 路径。改为在原 PYTHONPATH 前追加仓库目录后重跑。
NZ 恢复已在真实 310P 上通过。speculative 配置测试只因缺少 target_model_config 被校验器拒绝,与自定义 draft loader 无关;实际 EngineArgs 会自动提供该字段。现在开始构建正式离线转换脚本,并先检查宿主内存和输出空间。
宿主可用内存 487 GiB、输出盘可用 705 GiB,足够同时保留 311 GiB 原模型和约 292 GiB 的 TP8 W8A8 checkpoint。转换将写入 .partial 目录,全部 rank 校验通过后原子改名,避免留下伪成功产物。
转换脚本参数和自定义 loader 注册均已通过验证。现在启动真实 TP8 离线转换;阶段顺序为目标模型加载、MXFP4/FP8 转 W8A8、每 rank 流式写 4 GiB 分片、全量头部校验、原子发布。
转换在容器启动前即退出,日志为空,说明是外层脚本的 shell 校验/引用问题,不是模型或 NPU 失败。我先用 bash -x 定位并修正。
已定位:安装清单沿用了旧 probe 中已删除的 debug_probe.py,test -f 静默终止了容器。移除陈旧条目并让以后缺文件时明确报出路径。
第二次转换已正常进入 8 卡真实权重加载,设备显存约 22–23 GiB,输出目录尚未开始写入。当前无错误,下一阶段是专家常驻 W8A8 转换。
已进入专家转换阶段,说明目标模型路径和保存流程前半段正常。趁转换运行,我同步准备预转换 checkpoint 的 target-only 与 MTP 启动脚本,避免生成完成后再等待配置工作。
7 个 rank 已完成模型加载,耗时约 478–485 秒;rank0 仍在收尾,宿主可用内存 442 GiB,未出现分配失败。保存尚未开始,因为 collective 会等待全部 rank 就绪。
模型已完整初始化,target-only 转换成功,rank0 仍有 4.50 GiB 空闲。分片保存正在进行,首轮 8×约 3.98 GiB 已落盘,当前输出 51 GiB;共享内存 60 秒提示只是 collective 等待写盘。
保存进度正常:已写 129 GiB、32 个正式分片,预计总计约 72 个;宿主仍有 400 GiB 可用内存和 576 GiB 磁盘。与此同时我发现 loader 对同形状权重会先创建 NPU 临时副本,已改为 CPU→目标参数直接 copy,进一步降低加载峰值。
保存已到 282 GiB、75 个分片,接近完成;预计最终略高于 290 GiB。资源余量仍充足,当前只剩最后几个 rank 的尾部分片和校验。
离线 checkpoint 已成功生成并发布:80 个分片,285.12 GiB,最终目录 286 GiB。接下来先做结构抽检,再启动 target-only 预转换加载,验证 API 输出与启动耗时。
预转换 target 服务已进入多进程初始化,自定义 loader 在主进程、EngineCore 和 8 个 worker 中均完成注册。当前尚未开始读取分片,NPU 显存基本空闲,继续等待分布式初始化。
预转换权重已全部进入 HBM,当前各卡约 40.7–41.7 GiB,尚无 OOM。这个峰值高于预期,说明 ND→NZ 恢复和模型构造占用了额外缓存;我先检查 maybe_trans_nz 是否复制存储,并准备在加载器中逐张量直接恢复 NZ,避免加载后统一二次转换。
target-only 预转换加载成功,API 健康检查 200。模型加载耗时约 328–349 秒,比原始 checkpoint 的 478–492 秒减少约 30%,且没有运行时量化转换或超时。现在验证文本正确性和吞吐。
文本正确性已恢复:介绍输出正常,“法国首都”稳定回答“巴黎”。target-only 16 token 请求约 1.06 tok/s。现在切换到预转换 MTP,验证 draft 子集加载、显存峰值、接受率和实际加速。
MTP JSON 已被 vLLM 正确解析,draft_load_config=dsv4_310p_w8a8 生效;没有再回退到原始 FP4/FP8 loader。当前处于 target 分片加载阶段。
继续盯住预转换 MTP 启动。当前显存接近上限;重点确认 target 加载结束后是否及时释放被替换的原始参数,再决定是否在 loader 末尾加入强制回收。
MTP 失败原因已明确,且不是显存:target-only checkpoint 不包含 draft 专属的 69 个 MTP 参数。原始 loader 会把源 checkpoint 的 next-token 层重映射到 model.layers.0.*;离线保存 target 时这些键未进入 state_dict。现在补生成一套小型 MTP 专用 TP8 分片,并让 draft 指向该目录。
先采用更直接的路线:target 继续使用预转换 checkpoint,draft 单独从原始模型只加载 1 个 MTP 层。这样无需再生成 286 GiB checkpoint;但必须在 target 完成后、draft 构造前立即回收被替换的旧参数缓存。现在补这个精确回收点并重跑。
缺失键验证证明 draft 必须走原始 MTP 权重映射。修复方案已确定:target 预转换加载结束后立即 gc + empty_cache,随后 draft 从原始 checkpoint 只加载 mtp.0.* 并完成单层转换。
第二轮 MTP 启动已开始:target 使用 286 GiB 预转换分片,draft 使用原模型中的 mtp.0.*。这次日志应明确显示 target 回收后的空闲显存,再进入 draft 加载。
target 分片加载进度正常,当前各卡约 30–31 GiB;尚未到 NZ 恢复峰值。目标是看到回收日志后空闲至少约 5 GiB,再加载单层 draft。
已继续推进,当前结果如下。
已完成
- 成功生成并校验离线 TP8 W8A8 checkpoint:
- 路径:
/var/lib/dsv4-model/DeepSeek-V4-Flash-0731-W8A8-310P - 80 个 safetensors 分片,每个 rank 10 个
- 有效权重 285.12 GiB,目录总计约 286 GiB
- 专家、Attention FP8 线性权重均已转换为 INT8
- 路径:
- 新增自定义加载格式:
dsv4_310p_w8a8 - target-only 预转换加载验证成功:
- API health:HTTP 200
- 加载时间约 328–349 秒,原始 checkpoint 为 478–492 秒
- 正确回答“巴黎”
- 16 token 请求约 1.06 tok/s
- 输出文本正常,无数值错误
- 已修复 target 与 draft 间的显存回收点:
- target 加载完成后立即执行
gc.collect()和torch.npu.empty_cache() - 避免等待整个
worker.load_model()返回才清理
- target 加载完成后立即执行
- MTP draft 已切回正确路径:
- target:预转换 W8A8 checkpoint
- draft:原始模型中的
mtp.0.* - draft loader:
auto - 原来的 custom draft loader 缺少 69 个 MTP 专属参数,已不再使用该方案
当前验证状态
最新任务:job_c2bf79abd4e5
容器:dsv4-310p-preconverted-mtp
当前正在加载 target 预转换分片。最近一次检查时:
- 容器已运行约 8 分钟
- 8 张卡健康
- 显存约 41.2–42.3 GiB
- 尚未输出 target 回收日志
- 尚未开始 draft 加载
- 暂无 OOM、AICPU timeout 或其他错误
- API 尚未启动
当前仍未完成 MTP API、接受率和实际吞吐验证。下一步是确认 target 回收后剩余显存,再观察原始单层 MTP draft 是否能在约 2–5 GiB 空间内完成加载。
第十七阶段
继续按“单请求速度优先”推进:先检查当前 MTP 启动是否越过显存峰值;若仍失败,就立即放弃低收益路径,转向更直接的 MoE/通信减法。查看了npu310p任务日志及容器
MTP 已越过显存问题,当前失败只是模式串扰:全局 preconverted_w8a8 让 draft 按 INT8 形状构造,却从原 checkpoint 读取 FP8/MXFP4。将 draft 构造期间临时切回 eager_w8a8,加载完成后恢复。切换草稿模型量化模式并修复形状断言
第二轮已确认显存回收有效,draft 能读到原始 MTP shard;现在卡在一个具体线性权重的 shape 不匹配。先把失败键名和两侧 shape 打出来,再做定点兼容,不再整轮盲跑。诊断临时环境并检查MTP模型分片格式异常
MTP shard 本身未损坏;其 header 很大且包含新型 FP8 dtype,宿主 safetensors 版本无法解析。改用原始 header JSON 直接读取 shape,继续定位失败参数。分析 MTP 权重形状并检查投影映射逻辑
为避免每次等 8 分钟,我改用“dummy target + 原始 MTP draft”的快速诊断启动,只加载 1 层 draft。先给失败断言补充参数名和 shape,上线后一分钟内即可得到精确键。增强并启动 DeepSeek MTP 权重诊断实验
快速诊断容器已启动。它跳过 43 层 target 权重读取,只保留模型构造并加载原始 MTP 层;下一次日志应直接给出失败权重名。检查MTP诊断容器日志并等待权重加载
快速诊断被 vLLM 的 dummy FP8 初始化提前阻断,与 MTP shape 无关。直接检查加载补丁:当前 checkpoint 把输入投影存成一个 main_proj[4096,12288],而运行时拆成 e_proj 和 h_proj,很可能正是缺失的映射。排查MTP权重加载与张量并行分片
确认了:当前 V4 checkpoint 的 draft 不是旧版 e_proj+h_proj 结构,而是 main_proj(3×hidden→hidden)。现有 MTP 实现与权重版本不匹配。接下来按 checkpoint 的真实结构改造 draft,而不是继续修补错误映射。检查并适配 DeepSeek V4 MTP 配置
配置已经说明正确方向:checkpoint 自带 dspark_target_layer_ids=[40,41,42] 和 dspark_block_size=5,应使用仓库现成的 DSpark proposer,而不是旧 MTP。现在直接切换到 DSpark,预期一次验证最多 5 个 token,潜在收益明显更大。查找并检查 DSpark 推测解码与 DeepSeek-V4 配置
DSpark 是当前 checkpoint 的原生加速路径,官方测试 7 个 speculative token 的接受率约从 88% 递减到 18%。我会先用 5-token DSpark + 预转换 target 跑通,避免旧 MTP 继续消耗时间。验证了DSpark配置、模型注册及V4架构选择逻辑
开始落地 DSpark:target 保持预转换 W8A8;draft 构造期间临时切换到 eager 转换,加载 3 个 DSpark 层后恢复生产模式,避免量化布局串扰。修正量化加载并测试DSpark脚本
DSpark 启动器已准备好。先做静态检查后直接加载;本轮成功标准是:3 个 draft 层完成转换、API 正确生成、接受率可观,并且实际 tok/s 高于 1.06。完成DSpark启动检查、性能验证及模型加载日志核查
DSpark 已被引擎正确识别为 5-token block proposer,target 正在加载预转换分片。当前没有架构回退或参数解析问题。检查DSpark权重加载、初始化及量化状态
DSpark target 进入 NZ 恢复峰值,部分卡仅剩约 0.3–1.5 GiB;尚未开始 draft。若回收点按预期执行,显存会先回落到约 39 GiB,再加载 3 层 DSpark。检查DSpark草稿加载及目标模型显存状态
DSpark 已成功完成 target 回收,失败只剩 draft 某个线性权重 shape 不匹配。现在给 DSpark loader 增加精确键名诊断,并优先从 checkpoint 映射逻辑直接修正,避免继续整轮盲试。检查 DSpark 权重映射及形状兼容性
目前最可能的冲突是 DSpark 共享 embedding/head 或 main_proj 的 FP8 表示。先列出 checkpoint 中所有 DSpark 非专家权重,并与 loader 目标名逐一映射,直接找出 shape 不一致。检查了MTP嵌入与输出权重形状
checkpoint 结构本身完整。下一步确认报错所在的 vLLM 线性类型:linear.py:1664 会告诉我们是 replicated、column-parallel 还是 vocab 分片,从而无需再等待一轮日志。定位了 DSpark 权重形状不匹配原因
报错来自 RowParallelLinear。我先给 DSpark loader 加精确诊断;同时改自定义 loader 支持“只按 header 建立 target 参数、不搬运 286 GiB 数据”的诊断模式,把后续迭代从 8 分钟压到约 1–2 分钟。诊断 DSpark 权重形状错误并检查分片加载器
为了加快迭代,我正在加入“header-only target”诊断模式:只按 80 个分片的元数据建立相同参数布局,不读取 286 GiB 权重内容。这样可以快速进入 DSpark draft 加载并拿到精确失败键。添加Safetensors与DSpark权重诊断加载功能
header-only 诊断已启动。它不会读取实际 target 权重内容,目标是尽快进入 DSpark draft 并打印精确失败参数。检查DSpark容器状态、日志及NPU初始化
继续处理 DSpark 的首个确定性阻断:修复 RowParallel FP8 scale 的 TP 分片,并让 main_proj 按 checkpoint 的 FP8 配置走 310P W8A8,而不是误用非量化线性。修复并静态验证 DSpark FP8 投影缩放加载
首个 scale 分片规则已修复,main_proj 也已接回 FP8→W8A8 路径。现在用 header-only 快速回归继续扫下一处不兼容,单轮约两三分钟。完成DSpark分片量化修复及推理转换状态检查
关键突破:header-only DSpark 已完整启动,3 个 draft 层、102 个参数和专家转换全部通过,加载总计约 114 秒。现在切到真实 target 权重,验证正确性、接受率和实际单流加速。停止头文件服务并检查DSpark真实目标模型加载
真实 DSpark 服务正在读 80 个预转换分片,8 卡均正常活跃,暂无 OOM 或加载错误。draft 兼容问题已在快速模式中全部越过。检查DSpark权重加载及服务启动状态
真实 DSpark 权重已全部加载完成:每卡模型约 38.19 GiB,比 target-only 多约 2.79 GiB;当前仍有约 0.9–1.9 GiB 余量。正在初始化 draft KV cache 和服务。检查DSpark缓存初始化及服务启动状态
真实 DSpark 服务已健康启动,5-token speculative 路径和 203-token KV cache 均正常。现在做正确性、冷/热吞吐和接受率测量。完成聊天推理基准及DSpark正确性吞吐测试
DSpark 已完成启动,但第一个请求触发 HTTP 500。现在读取运行时堆栈;这类问题通常是 draft KV metadata 或 target hidden-state 收集,不涉及权重加载。检查容器状态并分析运行时日志
运行时阻断已精确定位:DSpark 输入扩展依赖 Triton 的 kernel[grid] 语法,而 310P 镜像没有 Triton,导入后退化成普通函数。需要补纯 torch/NPU fallback;它只做索引展开,适合直接设备端实现。修复DSpark Triton回退并完善NPU测试
纯 NPU fallback 已实现,语义与 Triton kernel 一致:上下文复制、query position、block-table slot 和采样索引全部设备端向量化。先跑 DSpark 单测和小型原语验证,再重启真实模型。运行完整驱动并验证 D-Spark 采样器测试
单测失败来自旧测试只 mock 了 Triton kernel,却没有把 HAS_TRITON 切回 true,导致新 fallback 在刻意构造的不完整 metadata 上执行。运行时数据不受影响;我会更新旧测试并新增 fallback 的精确布局测试。更新并运行DSpark输入展开与回退相关测试
DSpark proposer 回归 25/25 通过。先用 header-only target 做一次完整请求路径冒烟,快速清除后续运行时问题;通过后再投入真实权重的长启动。完成无 Triton DSpark 请求路径及错误日志诊断
输入展开已越过,下一处是 310P 的 npu_rotary_mul 不支持 interleave 模式。将复用 target DSA 已验证的纯 torch 交错 RoPE,避免调用该硬件限制算子。调查了 DSV4 交错 RoPE 软件回退实现
继续修复当前唯一阻断:把 DSpark 的交错 RoPE 切到 target DSA 已验证的 310P 纯算子实现。先核对张量布局和函数签名,再做 header-only 请求回归。核对并添加交错式RoPE补丁及针对性测试
RoPE 已切换到 target DSA 同款实现。先做公式级回归,确认 interleaved 配对和 inverse 精确;通过后直接重启 header-only 请求诊断。验证 DeepSeek V4 RoPE 修复并启动 DSpark 头文件诊断
继续优化中的进展:
- 已确认 checkpoint 的正确加速方案是 DSpark,不是旧 MTP。
- 已跑通 5-token DSpark 的完整模型加载:
- 预转换 target + 3 层 DSpark draft。
- draft 加载 102 个参数。
- 每卡模型约 38.19 GiB,剩余约 1–2 GiB。
- API 能完成启动并通过健康检查。
- 已解决:
- DSpark FP8
main_proj量化。 - RowParallel FP8 scale 的 TP8 分片。
- target 与 draft 间的显存峰值回收。
- 310P 无 Triton 时的 DSpark metadata 展开。
- 相关 proposer 测试 25/25 通过。
- DSpark FP8
- 第一条请求已继续推进到 DSpark KV 预计算,随后发现 310P 不支持硬件
interleaveRoPE。 - 现已复用 target DSA 的纯 tensor 交错 RoPE:
- 正向公式验证通过。
- inverse 回转验证通过。
- 不再调用受限的
npu_rotary_mul(interleave)。
最新 header-only 快速诊断任务已经启动:
job_e2a7de274529
dsv4-dspark-runtime-diagnostic-v4
它正在验证 RoPE 修复后的完整请求链。尚未完成实际 token/s 和 DSpark 接受率测量;必须先确认该诊断请求能执行到底,之后再用真实 target 权重启动并测量相对基线约 1.06 tok/s 的加速幅度。
第十八阶段
继续检查 header-only DSpark 请求链;若 RoPE 已越过,就按新堆栈逐项清零,直到完整请求成功。检查任务进度并验证远程服务状态
RoPE 已越过。新阻断是 310P 缺少自定义 npu_scatter_nd_update_v2;target 路径早已用图安全的普通 tensor KV 写入替代。DSpark context KV 改为复用同一实现。修复310P分页SWA缓存写入并检查归一化逻辑
KV 写入已切换到 target 同款图安全实现。该原语此前已在 310P 实卡验证;现在重启快速诊断,继续推进到 draft attention 前向。重启v5并验证DSpark服务及KV写入路径
v5 仍在模型加载阶段,未出现新错误。header-only 此轮比前几次慢一些,继续等到健康检查通过后立刻发请求。等待并检查DSpark服务状态后测试KV回退路径
重大进展:header-only DSpark 已完成端到端请求,HTTP 200,Triton、RoPE、context KV 三个运行时阻断均已清除。现在切换真实 target 权重,验证文本正确性和加速。启动并检查真实 DeepSeek V4 DSpark 服务状态
真实 target 正常并行读取 80 个预转换分片,8 卡都在工作,当前没有显存或加载异常。后续重点是首次真实请求是否保持正确输出。检查 DSpark v2 模型分片加载与启动状态
真实 DSpark 已健康启动:target+draft 每卡约 38.19 GiB,仍有约 1.3–1.9 GiB 余量。现在直接做官方编码的正确性与吞吐测试。测试消息编码并评估模型推理性能指标
正确性已通过,长请求达到 1.225 tok/s,较 1.06 基线约提升 15.6%。但 DSpark 接受率仅 2/145(1.38%),说明 draft 数值或输入仍明显不对;接下来优先修接受率,而非微调 token 数。诊断DSpark投机解码并检查隐藏状态提取
层索引与拼接逻辑表面一致:采集的是第 40/41/42 层输出,且在 HC head 前做分支均值。下一步核对 checkpoint 自带的 DSpark 参考实现与我们前向公式,优先找结构偏差。审查DSpark投机解码与官方模型前向量化实现
找到一个高概率主因:官方 DSpark 的第 2–5 个查询 token 固定使用 checkpoint 的 dspark_noise_token_id=128799;当前 proposer 继承了通用 DFlash 的 parallel_drafting_token_id,很可能是错误 token。先确认运行值并直接修正。检查并确认DSpark与vLLM推测令牌初始化逻辑
确认了:运行时实际使用的占位 token 是父类默认 0,而官方 checkpoint 明确要求 128799。这足以解释 1.38% 接受率。现在修正并回归后重启真实服务。修复DSpark噪声令牌初始化并运行Proposer测试
测试桩没有执行父类完整初始化,因此暴露了默认值访问问题;生产路径不受影响。改成安全默认 0 后继续全量回归。修复回退属性并完善DSpark单元测试
noise token 修复回归 26/26 通过。这是 checkpoint 参考实现与当前代码之间的明确差异,预期接受率会从接近随机显著恢复;现在重启真实服务验证。重新测量并检查DSpark修复版服务加载与量化路径
重载仍在 target 分片阶段。参考实现已确认 main_proj 调用正确;除 noise token 外,下一项可能影响接受率的是官方对 KV 非 RoPE 部分做 FP8 QAT 回写,但先等待 noise 修复的独立效果。核对DSpark采样逻辑并检查服务模型加载状态
noise token 修复已被新进程加载,draft 102 个参数已完成读取,正在做最后的专家转换和 KV 初始化。马上进入接受率验证。完成引擎初始化并基准测试健康状态与推理指标
事实题仍正确;64-token 基准触发了新的运行时错误,可能是跨 32-token block 后的 DSpark KV 元数据问题。先抓堆栈,同时读取短请求后的接受率,确认 noise token 是否有效。
第十九阶段
继续处理 DSpark。先定位这次 GatherV2 越界对应的具体张量与索引,再修复并重新跑真实请求验证。
定位 DSpark GatherV2 越界并诊断启动与NPU状态
这次故障很像“首个请求结束后,第二个请求复用 DSpark 缓冲区时产生非法索引”。我会用同步执行模式复现两次连续请求,以获得准确的 Python 调用栈。
检查并修复 DSA 缓存槽位越界及同步诊断逻辑
同步诊断实例已启动。加载完成后我会连续发送两次相同请求;如果是缓冲区复用问题,第二次会在准确的算子调用处报错。
排查并重启DSpark诊断任务及路由数据问题
同步实例还在容器创建阶段,尚未进入模型加载。我同时检查了候选路径,除 cache slot 外,Hash Router 的 token→expert 表也存在未校验上界的 GatherV2 风险。
检查诊断实例、模型服务、远程任务及注意力掩码状态
模型进程仍在加载,但远端短命令偶发被 NPU 初始化阻塞。我改用持久终端监控,避免重复创建检查进程干扰诊断实例。
启动并监控DSpark及vLLM服务状态
同步诊断服务已就绪。现在执行第一次短请求,随后立即执行第二次,重点观察第二次是否在同一 GatherV2 位置失败。
发送API请求并监控作业状态与日志
已定位根因:DSpark 将“混合块表中的逻辑子块 ID”误当成 32-token 物理块 ID。当前表的拆分因子是 16,导致合法位置 334 被算成 5134,直接越过 4640 行缓存。现在修正两处映射:query slot 生成和 DSpark 可见窗口索引生成。
修复并测试DSpark与DSA索引、元数据及查询映射
两处映射修复和回归用例已经写入。先跑纯 CPU 语义测试,再在 310P 容器中跑相关单测,确认不会破坏普通块表路径。
完成格式检查、编译与定向单元测试
首轮测试失败是容器未挂载 NPU 驱动,代码尚未执行。改为带单卡设备和驱动库的测试容器重新运行。
运行特权设备测试并读取修复效果输出
定向测试已全部通过:30 项通过。现在启动真实 8 卡 DSpark 服务,保留 slot 越界校验,随后验证完整请求和连续请求稳定性。
启动并监控 DSpark、DeepSpeed 与 vLLM 验证任务
真实模型已进入专家权重加载阶段,修复代码已被容器加载。当前没有新的 slot 越界或算子异常。
监控推理服务、数据加载及远程任务执行状态
关键崩溃已修复:真实请求已经从序列长度 70 连续推进到 77,所有 query slot 都在合法范围内,EngineCore 未退出。下一步关闭高开销诊断日志,做受控吞吐和接受率测试。
检查服务状态并完成会话基准测试
先核对当前实例为何在健康检查后出现连接拒绝,并确认是否存在新的运行时错误;随后会用关闭诊断日志的实例测真实接受率。
检查任务状态、Docker日志及监控输出
连接拒绝来自另一个验证实例重新加载,不是刚修复的实例再次崩溃。趁加载期间,我开始比对上游 DSpark 语义与当前 310P fallback,定位 0% 接受率的数值偏差。
检查并分析DSpark模型、提议器及输出差异
0% 接受率已经缩小到数值语义问题。当前优先检查三条链:目标层隐藏状态拼接、main_proj 的 FP8→W8A8 转换、Markov 修正后的实际草稿 token。
排查DeepSeek V4映射、采样配置与运行输出
基础模型输出已经正确,三次连续请求均成功;问题仅剩 DSpark 草稿完全不命中。接下来加一个低开销 rank-0 token 跟踪,直接记录 seed、未修正草稿和 Markov 修正后的 5 个 token。
增加并验证DSpark草稿Token跟踪诊断
当前验证实例已证明稳定性,但全量 slot 日志拖慢推理且无法解释 0% 命中。我现在切换到仅记录草稿 token 的诊断实例。
停止验证并检查DSpark推测器实现、日志及任务状态
我发现一个更可疑的数值点:目标模型采集第 40–42 层辅助状态时只取了 hidden_states.mean(),但该层实现可能把残差单独返回。若未把 residual 合回去,DSpark 的 main_proj 输入会整体错位。正在核对这一点。
检查并核对DSpark首轮推理、KV缓存及检查点参数
我继续从草稿 token 跟踪实例入手。当前目标是判断偏差来自 DSpark 主干、Markov Head,还是目标辅助隐藏状态。
检查 dsv4-310p-dspark 和当前训练运行状态
草稿跟踪已经给出明确方向:DSpark 主干的 5 个位置在不同上下文下始终把同一 token 60058 作为 raw argmax,Markov Head 只是在其上强行改写。这说明问题在 Markov 之前,优先检查草稿 lm_head、主投影和主干隐藏状态。
检查DSpark隐藏状态、Logits、权重布局及运行输出差异
根因基本确定:原始 checkpoint 根本没有 mtp.*.embed.weight 或 mtp.*.head.weight,但当前 310P 代码因启用了量化配置,错误地给 DSpark 创建了独立 embedding 和 lm_head,并阻止它们与目标模型共享。这个未加载的独立 lm_head 正是恒定输出 token 60058 的来源。现在修正共享逻辑。
检查 DSpark 权重共享与语言头加载日志
共享逻辑在当前实例中已经生效,说明恒定 60058 不是未加载 lm_head。下一步直接分段测量隐藏状态:目标三层主投影输入、query embedding、每个 DSpark 层输出以及 lm_head 前状态,找出首次塌缩的位置。
调试模型隐藏状态与首次GPU实现代码
对比官方实现后发现另一个结构性偏差:官方 DSpark 的 3 个 MTP 层共享并传递 Hyper-Connection 的 residual/post-mix 状态,只在末层完成最终 hc_post;当前 Ascend 版本把每层当成普通目标层,层内就把连接闭合并重置状态。这个偏差足以让主干输出失真。先复用现有 MTP 的正确 Hyper-Connection 链路,而不是继续调小数值参数。
检查并验证DeepSeek V4层实现及DSpark隐藏状态诊断
当前 trace 已确认共享词表权重正常。我切换到分段隐藏状态诊断实例;它会只记录前四轮,因此不会长期拖慢服务。
检查并监控DSpark模型加载、映射及服务状态
已继续适配 DSpark,并完成了一个关键运行时修复。
已修复
此前 DSpark 请求触发的 GatherV2 / MTE DDR address out of range 已定位为 hybrid KV block table 坐标解释错误:
- 物理 cache block 大小为 32 token。
- 每个物理块被拆成 16 个逻辑子块,每个逻辑块实际对应 2 token。
- 原实现将逻辑块 ID 直接乘以 32,生成了
5134–5138等非法 slot。 - 正确映射应为
334–338。
已经同时修正:
- DSpark query KV slot mapping。
- 非因果 DSpark SWA 可见窗口索引。
- 越界 slot 防护与诊断。
- 对应 hybrid block table 回归测试。
测试结果为 30 项通过。
真实模型验证
修复后,8 卡真实模型能够连续完成请求,不再导致 Device 2 AICore 异常或 EngineCore 退出。基础输出正确,例如:
The capital of France is
→ Paris. The capital
连续三次不同请求均成功,说明 DSpark 运行时路径和 KV cache 生命周期已经基本打通。
当前剩余问题
DSpark 尚未产生有效加速,草稿接受率通常接近 0%,偶尔第一位置命中约 1%–2%。
增加 token 级跟踪后发现:
raw_argmax = [60058, 60058, 60058, 60058, 60058]
无论上下文和 seed token 如何变化,DSpark 主干在五个位置的原始预测始终是 token 60058。Markov Head 会将其修改成不同 token,但这些 token 基本不被目标模型接受。
已经排除:
- 独立、未加载的 embedding。
- 独立、未加载的 lm_head。
- checkpoint 中确实没有 DSpark 专用 embed/head,当前实例已经正确共享目标模型的 embedding 和 lm_head。
- Markov Head 权重缺失,其两组 BF16 权重已正常存在。
- query slot 越界。
- 目标模型输出错误。
因此剩余偏差位于 Markov Head 之前的 DSpark 主干隐藏状态,重点包括:
main_proj的 FP8→W8A8 数值。- 三层 DSpark Decoder 的输出。
- 非因果 SWA attention 输出。
- 最终 Hyper-Connection head 输出。
- checkpoint 参数是否存在未加载项。
我已经加入分段张量诊断,记录:
- 目标第 40–42 层辅助状态。
main_proj + main_norm输出。- query embedding。
- 三个 DSpark 层各自输出。
hc_head输出。- 各张量的均值、标准差、范数及不同 token 行之间的最大差异。
- 未被 checkpoint 覆盖的参数列表。
新的真实 8 卡诊断实例已经启动加载,但本轮结束时尚未取得这组分段结果。因此目前完成的是 DSpark 稳定运行修复,草稿数值正确性和接受率优化仍未完成。
第二十阶段
继续推进分段张量诊断。先读取 v10 实例的加载与首轮请求结果,确定隐藏状态首次塌缩的位置,再直接修复。
检查并修复训练作业及DSpark服务就绪状态
v10 已运行约 8 分钟,但日志停在权重加载早期,超过此前正常加载节奏。我先判断是正常转换、内存抖动,还是某个 rank 卡死,避免继续无效等待。
诊断了DSpark模型加载进程状态
发现异常:NPU 上仍驻留 PID 731584–731591,占用约 38–42 GB/卡,但当前 v10 容器的进程是 1040xxx。旧实例没有真正释放设备内存,导致新实例卡在加载阶段。先清理残留进程并重启诊断实例。
检查旧NPU进程及其容器归属
进一步核对后,731584–731591 不是宿主机残留 PID,而是驱动侧进程标识,不能直接判定为旧实例。当前更像是 rank 0 已接近显存上限、其余 rank 仍在静默加载;继续检查各 worker 的真实状态与 I/O。
核查进程与容器状态并等待模型服务就绪
v10 已正常启动;此前只是完整加载用了约 449 秒。现在发送短请求并抓取分段张量,定位 raw_argmax 恒定的首个异常节点。
运行受控请求并收集张量追踪
分段结果已定位:main_proj 输出正常(RMS≈0.072),embedding 也正常;第一个 DSpark Decoder 层输出立即饱和到 FP16 的 ±65504,随后所有层都在饱和数据上运行。下一步只追踪 layer0 内部的 hc_pre → attention → hc_post → MLP → hc_post,并检查该层量化权重与 scale。
检查DeepSeek-V4量化转换与专家运行逻辑
layer0 的输出饱和可能来自 attention、MoE 或 HC 混合中的任一处。当前实例无法动态插桩,我会加入仅针对 draft layer0、仅前两轮的内部统计,然后重启一次;这次诊断可直接决定修复点。
检查并启动DeepSeek-V4与DSpark追踪任务
v11 正在加载。并行检查表明 main_proj 与普通 FP8 线性转换是正常的,因此当前优先级转为:DSpark 非因果 attention 输出是否先爆炸;若 attention 正常,再检查 MXFP4→W8A8 MoE。
检查并验证DeepSeek V4解码器、诊断进度及MXFP4精度
在等待 v11 加载时,我会利用已验证正确的预转换目标模型作为“金标准”,直接比较当前 MXFP4 转换函数与预转换 expert 张量。这样能提前排除或确认 MoE 转换问题。
比较原始与预转换权重及专家缩放并检查v11进度
v11 已进入 raw DSpark 权重加载阶段。目标模型仍使用已验证的预转换专家;接下来内部 trace 会区分 attention 与 MoE 哪一段首先饱和。
检查DSpark服务并获取模型层追踪信息
根因已进一步收敛:attention 全程有限,attn.out RMS≈17;进入 FFN 前也正常。首次非有限值出现在 layer0 的 self.mlp() 输出,因此问题明确位于 DSpark 的 MoE,不在 attention 或 Hyper-Connection。现在区分 routed expert 与 shared expert,并核对 raw MXFP4 转换。
检查并添加DeepSeek V4 MoE输出追踪路径
MXFP4 转换本身已经排除:当前转换得到的 w13/w2 scale 与已验证可用的预转换 checkpoint 逐元素完全一致。因此更可能是 MTP expert 的加载映射、routed MoE 执行或 EP 聚合,而不是 E2M1/E8M0 解码。
验证草稿路由与共享MoE追踪补丁
已加入 MoE 内部诊断,将分别记录 router_logits、shared expert、routed expert 和最终合并输出。需要重启一次实例;下一轮即可确定 NaN 来源。
检查并追踪 v12 MoE 服务、专家权重及 NaN 根因
官方 DSpark 加载逻辑与当前映射整体一致,没有发现明显的 w1/w2/w3 命名偏差。v12 的 routed/shared 分离结果将决定下一步是修 expert 执行,还是修 shared FP8 线性。
排查DeepSeek V4专家映射并验证MoE服务运行
v12 显示 FusedMoE 直接返回单个张量,说明当前路径将 shared expert 融合进 MoE 执行;NaN 已在融合输出内部产生。接下来检查 expert dispatch/GMM 的中间结果,而非上层合并逻辑。
检查310P融合专家执行链路并定位NaN源
下一步不再通过完整服务反复试错。我会停止当前实例,用单卡直接加载一个 MTP expert,逐步执行 GMM1、SwiGLU、GMM2,并与 CPU 反量化参考比较;这样可在分钟级确认是权重布局还是 310P grouped matmul。
检查并诊断单专家MXFP4量化推理及容器NPU状态
单卡诊断首次启动失败,原因是测试脚本用 PYTHONPATH=/work 覆盖了 CANN 的 TBE 路径,并非算子错误。改为追加仓库路径后重新执行。
修复环境并监控MTP诊断及NPU转换任务
单 expert 测试暴露了一个算子约束:310P 的 NZ grouped matmul 在 expert 数为 1 时会折叠存储维度并拒绝执行。改用两个 expert(第二个零 token)复现真实 GMM 布局。
完成双专家GMM存储形状诊断并检查任务输出
隔离测试已经确认:MTP expert 权重、MXFP4→W8A8 转换和两段 grouped matmul 都能输出有限值。当前故障范围已缩小到 EP 路由/Token Dispatch/Group List 或共享专家融合,继续从这一层修。
检查了310P Token Dispatch与混合专家量化实现
发现一个高度可疑的差异:310P 自定义 dispatcher 把 npu_moe_init_routing_v2 返回的 expert_tokens 标记为 累计值模式(type=0);通用实现对同一类返回值标记为 计数模式(type=1)。若 310P 算子实际返回每专家计数,GMM 会把非单调计数当累计边界,直接造成未定义输出。现在用小规模算子实验确认。
检查并验证MoE路由及专家令牌语义
算子实验确认 expert_tokens=[2,3,5,8],确实是累计边界,group_list_type=0 正确。下一步转向 权重装载完整性和本地 expert slot 对应关系:检查 DSpark 3 层每个 rank 的 32 个 routed experts 是否全部写入、是否存在未初始化或错位 expert。
验证专家权重映射与加载完整性
根因已经找到:部署脚本为目标模型设置了全局 preconverted_w8a8,但 DSpark 草稿仍从原始 MXFP4 checkpoint 加载。量化适配器因此把草稿的 半宽 packed FP4 字节误判成已转换 INT8,完全跳过解包与重定标;这正好解释 FusedMoE 的 NaN。现在改为按张量布局识别,而不是只信全局环境变量。
更新预转换布局逻辑并运行MXFP4回归测试
修复代码已通过语法与 diff 检查。首轮 pytest 只是测试容器未挂载 NPU 后端导致 conftest 导入失败;改用带单卡驱动环境的测试容器重跑。
运行 NPU 容器回归测试并检查设备加载配置
布局修复及回归测试通过,9 项全部通过。现在启动真实 TP8/EP8 DSpark;预期日志应同时出现“目标专家加载 preconverted”和“草稿 raw MXFP4 被检测并即时转换”,随后验证 MoE 不再产生 NaN、草稿 token 随上下文变化及接受率。
监控并验证 DSpark 草稿专家转换服务状态
v13 仍处于目标权重加载阶段,进程未报错。该阶段此前约需 6–7 分钟;修复只影响随后 3 层草稿 expert 转换。
监控目标进程、NPU状态及模型加载回退
v13 已按预期完成两种布局分流:目标 40 层使用预转换 W8A8,草稿 3 层检测到半宽 packed MXFP4 并完成即时转换;服务健康。现在验证 MoE 数值、草稿 token 与接受率。
检查了受控请求及其追踪信息
布局误判已修复,但 full EP MoE 仍产生 NaN;因此还有第二个问题。隔离 GMM 正常,下一步检查 32 个 routed expert 与 shared expert 的实际装载/融合布局,尤其是全局 shared expert 是否被错误塞入本地 routed slots。
Interacted with local-shell-mcp
继续向下定位:当前需要区分 NaN 是在 GMM1、SwiGLU 还是 GMM2 首次出现,并同时记录真实 group_list、权重形状和 scale 范围。该诊断只在 rank 0、首次非有限输出时触发。
检查并增强MoE非有限值追踪,重启任务定位首次异常涌现
v14 正在重新加载。等待期间我补查原始 MTP E8M0 scale 的字节分布;若部分 expert 含保留码 255,而转换器按 2^(code-127) 解码,就会只在特定路由 expert 上生成 Inf。
监控DSpark v14模型加载、GMM转换及服务健康状态
关键点已确认:NaN 首次出现在 GMM2,而且运行时所有 expert scale 都异常地变成同一个值 6.04724。我现在直接修复 scale 在权重后处理阶段被错误保存的问题。
检查并追踪多种量化实现及专家权重处理流程
验证参数dtype与.data赋值行为
验证并测试容器中 Float8 参数赋值与数据替换 поведению
6.04724 的来源已经解释清楚:原始 E8M0 scale 字节约为 120–126,但加载器先 view(uint8),随后复制进 float8_e8m0fnu 参数时发生了数值转换,全部被舍入成约 128;解码后 row scale 正好变成 6×128/127 = 6.04724。修复 raw scale 的位级加载即可。
修复并验证 DSpark E8M0 专家权重缩放加载”】【
E8M0 位级加载修复已完成,36 项测试通过。接下来重启真实 8 卡实例;转换日志应从错误的 6.04724 恢复到约 1e-3,随后检查 GMM2、MoE 和接受率。
已重启并验证V15模型加载状态
分析已暂停
继续适配后取得了两个关键进展。
已修复
- DSpark KV slot 越界
- 修正 hybrid block table 的逻辑块与物理块换算。
- 消除了
GatherV2 / DDR address out of range崩溃。 - 相关测试 30 项通过。
- DSpark 原始专家权重布局误判
- 目标模型使用预转换 W8A8,但 DSpark 草稿模型仍从原始 MXFP4 checkpoint 加载。
- 已改为根据权重和 scale 的实际形状、dtype 判断是否预转换,不再只依赖全局环境变量。
- 找到并修复 E8M0 scale 损坏的直接原因
- 原始 scale 的 E8M0 exponent byte 为
120–126。 - 加载器错误地先将它们
view(uint8),再复制进float8_e8m0fnu参数。 - 这会发生数值转换,所有字节都被舍入成
134,解码结果统一为128。 - 因而运行时所有 expert row scale 都变成:
6 × 128 / 127 = 6.04724 - 这正是 GMM2 溢出并产生 NaN 的原因。
- 原始 scale 的 E8M0 exponent byte 为
现在改为:
float8_e8m0fnu → float8_e8m0fnu直接复制,保留原始 exponent bits。- 只有目标参数明确使用
uint8存储时才做位视图转换。
验证实验结果:
原始字节: 120 121 122 123 124 125 126
float8 → float8: 120 121 122 123 124 125 126
uint8 → float8(旧): 134 134 134 134 134 134 134
相关量化、MoE 和 DSpark proposer 测试目前为 36 项全部通过。
当前状态
新的真实 TP8/EP8 验证实例 v15 已启动,正在重新加载模型。它将验证:
- 转换后的 expert scale 是否从错误的
6.04724恢复到约10⁻³。 - GMM2 是否保持有限值。
- DSpark MoE 是否不再输出 NaN。
- 草稿接受率和实际吞吐是否改善。
本轮结束时实例仍处于目标模型加载阶段,端口 8000 暂未恢复服务,因此 E8M0 修复的完整真实模型结果尚未取得。
第二十一阶段
继续检查 v15 的真实加载与首轮推理结果。重点验证 E8M0 修复后 scale、GMM2 数值、MoE 有限性和 DSpark 接受率。
v15 已稳定运行约 10 小时,健康检查正常,期间没有自动请求或异常。现在执行真实短生成和连续请求,直接读取 GMM scale、MoE 数值及累计接受率。
E8M0 修复已在真实 8 卡实例中生效:MoE 全程有限,隐藏状态恢复到正常量级,DSpark 接受率由 0–2% 升至约 32–40%。下一步关闭诊断日志,做稳定性与吞吐基准,并按位置接受率调低 speculative token 数。
当前 5-token DSpark 已确认正确,但位置 3–5 的接受率明显偏低。先做一条 64-token 基准作为对照,再切换到 3-token、关闭 trace 的生产配置。
v16 已按 3-token、无 trace 配置启动。加载期间同步清理临时诊断代码并跑完整相关测试,避免把排障插桩带入最终提交。
清理插桩时发现 deepseek_v4.py 留下了一组缩进残片,尚未影响正在运行的 v16 容器。先修正源码并重新执行语法与测试检查。
回归结果为 152 通过、3 失败。三项均是无 NPU 测试容器缺少 torch_npu.npu_dynamic_quant/.npu(),不涉及功能回归;其中两个 mock 需要显式允许创建缺失符号,设备实测项应在无 NPU 环境跳过。
临时 trace 已从源码移除;相关测试现为 9 通过、1 个无 NPU 环境跳过。接下来等待 v16 完成加载,同时跑全部相关回归并检查最终 diff。
v16 在启动早期退出,尚未进入模型加载。原因很可能是 SPEC_TOKENS 只在宿主脚本定义,却在容器内的单引号命令中展开,触发未定义变量;先读取日志并修正参数传递。
v17 已正常进入启动流程。并行启动更广的 310P 回归测试;待服务就绪后直接对比 3-token 与 5-token 的 64-token 吞吐和接受率。
静态检查发现 5 个纯样式问题:3 处 import 排序、1 处嵌套 with、1 行超长。全部属于机械修正,不改变运行逻辑。
广泛回归为 258 通过、3 跳过、1 失败;唯一失败同样是无 NPU 容器无法 patch 缺失的 npu_dynamic_quant。补上 create=True 后重跑全套。
SwiGLU 单测环境适配已修复,2 项通过。现在重新跑广泛回归,并检查 v17 是否进入目标权重加载阶段。
v17 配置校验表明 DSpark 模型的原生 block size 是 5,num_speculative_tokens < 5 会产生错误输出,不能降到 3。恢复最小合法值 5,保留无 trace 配置并重新启动。
广泛回归已通过:259 通过、3 跳过。v18 加载期间整理最终变更集并提交;真实服务验证通过后再推送远端。
修复已提交为 8464845a fix(310p): stabilize DeepSeek V4 DSpark inference,工作区已清洁。现在等待 v18 就绪,随后做无 trace 的 64-token 基准、连续稳定性测试,再推送远端。
v18 已进入 8 卡目标模型加载阶段,暂无异常。预计仍需完成预转换目标权重映射和 3 层 DSpark 草稿加载;同时补充仓库部署与已验证状态文档。
v18 仍在目标权重静默加载阶段,进程持续存活且无错误。该阶段与已验证实例一致,通常在启动后约 7 分钟进入 DSpark 草稿加载。
v18 已完成模型与草稿加载:总加载约 449 秒,剩余显存约 2.31 GiB,KV cache 203 tokens。当前只剩引擎初始化和 API 启动。
v18 已健康启动。E8M0 scale 现处于 7.38e-4–2.36e-2 的合理范围,不再是错误的 6.04724。现在执行无 trace 基准和连续稳定性测试。
无 trace 的 64-token 基准达到 2.326 tok/s,比 trace 实例的 2.147 tok/s 高约 8.3%,服务仍健康。现在跑连续请求稳定性测试,再更新文档并推送分支。
连续稳定性测试 8/8 成功,共生成 128 tokens,聚合吞吐 2.708 tok/s;日志无 AICore、越界、NaN 或引擎异常,健康检查仍为 200。累计 DSpark 接受率为 129/395 = 32.7%。
文档已更新为当前真实路径与数据。还需拆分一处过长的 JSON 命令行,然后提交文档、推送分支,并确认远端提交状态。
代码与文档已本地提交。首次推送因 GitHub HTTPS 连接被远端异常终止,属于传输层错误;服务和仓库内容未受影响。改用 HTTP/1.1 并重试。
远端仍停在旧提交,本地领先 13 个提交;第二次重试未完成传输。现在检查该服务器可用的 GitHub 认证通道,优先切换到 SSH,避免继续依赖不稳定的 HTTPS/GnuTLS。
API 域名可正常访问,故障集中在 github.com 的大流量 Git Smart HTTP 路径。先确认现有 HTTPS 凭据能否被非交互读取;若可用,将通过 GitHub Git Data API 同步提交,避免依赖故障链路。
aia 服务器在线,可作为独立推送节点。先检查其 GitHub 网络与凭据;若可用,将通过 git bundle 保留全部 13 个提交并从该节点推送。
备用节点网络正常,但没有可用 GitHub 凭据。继续检查两台机器是否存在未被 Git credential helper接管的 GitHub 令牌环境;只检测变量名和是否为空,不读取秘密值。
推送阻断已确认是该服务器当前没有 GitHub HTTPS/SSH 凭据,而非网络故障;本地提交完整保留。继续做代码质量审查和下一轮性能优化,不让认证问题阻塞开发。
代码质量扫描未发现需要立刻重写的严重结构债务:新增 fallback 都位于明确的 310P 算子缺失边界,属性探测用于版本/后端兼容;扫描到的宽泛异常处理均为原文件既有逻辑。下一步针对当前吞吐做配置级 profiling。
profiling显示当前瓶颈仍在解码计算:10 个请求累计 prefill 12.2 秒、decode 65.2 秒;队列时间可忽略。更关键的是 310P AllGather dispatcher 可能让每个 EP rank 都计算全部 routed token,再用零权重丢弃非本地结果,存在接近 8 倍的专家冗余计算空间。先做隔离算子原型验证本地路由压缩。
可行的无同步压缩方案已经形成:把非本地路由映射到排序末尾的虚拟 expert,routing 仍保持固定 30 行,但给 GMM 的累计边界只覆盖前面的本地行;尾部由现有清零逻辑处理。这样无需每层 CPU 同步,也不改变 combine 映射。先在单卡算子上验证。
单卡原型在共享 NPU0 上超时,可能与正在运行的 v18 设备上下文竞争有关;生产服务仍需优先保持。先确认测试容器是否残留,并改用 CPU mock/算子单测建立行为约束,不中断服务。
为避免污染已验证分支,我会在独立 worktree 上实现“虚拟 expert 尾部压缩”原型。先用 mock 精确约束 routing 参数、累计边界和 combine 权重;通过后再安排一次短维护窗口做真实 NPU 算子验证。
原型单测已通过(6/6)。要确认 CANN 310P 对 expert_num=33 和尾部虚拟 expert 的真实行为,需要短暂释放设备上下文;我将停止 v18、执行单卡 routing→尾部清零→unpermute 验证,然后立即恢复稳定服务。
真实 routing 已完成,失败仅因测试 hidden size=32 不满足 310P MoeTokenUnpermute 的 128 对齐约束,不是否定方案。改用实际合法的 hidden size=128 立即重测。
真实算子验证通过:虚拟 expert 被稳定排序到尾部,前 4 个本地 expert 的累计边界为 5,3 个非本地路由位于尾部;清零后 token_unpermute 与参考结果逐元素一致,最大误差 0。下一步验证量化 GMM 只计算本地前缀。
下一项验证将直接覆盖真实量化 GMM:先检查虚拟尾部行确实保持为零,再以 DeepSeek V4 实际 hidden/intermediate 维度对比“30 行全算”和“约 4 行本地前缀”耗时。完成后恢复 v18。
真实量化 GMM 验证通过:虚拟尾部保持全零且无 NaN;按实际 4096/2048 维度,单层 MoE MLP 中位耗时从 1.274 ms 降至 1.035 ms,提升 1.23×。现在跑全量 310P 回归,随后用该原型启动完整 TP8/EP8 服务做端到端对比。
路由压缩分支已提交为 37d4a7be,全量相关回归 260 通过、3 跳过。现在用该 worktree 启动完整 TP8/EP8 实例,保持其余配置与 v18 完全一致,做严格端到端对照。
v19 已启动,完整加载期间不再改动原型代码。验收标准与 v18 相同:健康启动、正确输出、8 次连续请求无异常,以及 12/64-token 吞吐对照。
v19 已正常进入 8 卡目标权重加载,未出现 expert 数量、routing 或权重形状错误。当前阶段与 v18 的启动轨迹一致。
v19 已通过目标模型加载并进入 DSpark 草稿阶段,说明虚拟 expert 数量不会影响权重结构和初始化。接下来只需完成草稿转换与首轮真实请求验证。
v19 已健康启动,模型加载与显存占用正常。现在按与 v18 完全相同的提示顺序执行 12-token、64-token 和 8×16-token 三组对照,并扫描所有设备/引擎异常。
v19 稳定性通过且无异常。初步结果中 64-token 请求由 2.326 提升到 4.542 tok/s,但 8 个短请求聚合从 2.708 波动到 2.518 tok/s;这说明单条结果受接受率和输出路径影响较大。暂不合并,改做同一提示集的 v18/v19 严格 A/B。
v19 固定基准结果:3×64 tokens 聚合 3.104 tok/s,DSpark 接受率 36.8%。为排除提示与接受率波动,现在切回未压缩的 v18 代码,使用同一脚本、同一提示和同一顺序采集基线。
严格基线 v20 已启动。路由压缩的完整服务已证明 expert_num=33、零本地路由等实际分布不会触发算子异常;当前只对比吞吐与 token 序列,不再改动代码。
v20 已进入与 v19 相同的 8 卡目标权重加载阶段,暂无异常。基线完成后将直接运行已保存的固定脚本,避免测试过程差异。
v20 已完成目标权重并进入相同的 DSpark 转换阶段。A/B 两次启动轨迹一致,代码差异仅为 dispatcher 的虚拟 expert 尾部处理。
严格 A/B 首轮没有证明端到端收益:基线 3.173 tok/s,压缩版 3.104 tok/s,差约 -2.2%;两者 DSpark 接受率分别 41.3% 与 36.8%,且后两条 token 序列不同,接受率波动盖过了 GMM 微基准收益。先在同一基线实例重复一次,测量自身方差。
同一基线实例重复后聚合吞吐从 3.173 波动到 3.448 tok/s(约 8.7%),token 序列也发生变化;因此 2% 的首轮差异没有统计意义。接受率相对稳定在 41–43%。我会再启动压缩版并做两轮固定基准,以均值和方差决定是否合并。
v21 复测已启动。基准方法调整为:第一轮仅作为实例内 warm-up,第二轮作为可比数据;这样与 v20 的第二轮基线 3.448 tok/s 对齐。
已继续完成稳定性验证、文档整理和下一轮性能优化原型。
稳定版本
E8M0、MXFP4/W8A8 布局、KV block table 和 DSpark 路径已经稳定:
- 连续请求测试:8/8 成功
- 相关回归:259 passed,3 skipped
- 64-token 吞吐:2.326 tok/s
- 8×16-token 聚合吞吐:2.708 tok/s
- 累计 DSpark 接受率:32.7%
- 无 AICore 异常、越界访问、NaN、worker 退出或引擎关闭
已提交:
8464845a fix(310p): stabilize DeepSeek V4 DSpark inference
c4cc23c3 docs(310p): document validated DeepSeek V4 DSpark path
新性能原型
发现原 dispatcher 会在每个 EP rank 上计算大量非本地 expert 行,最后再用零权重丢弃。
已实现虚拟 expert 尾部压缩:
37d4a7be perf(310p): skip non-local expert rows in GMM
验证结果:
- CANN routing + token unpermute 数值参考:最大误差 0
- 虚拟尾部输出:全零,无 NaN
- 实际 4096/2048 expert 维度微基准:
- 原路径:1.274 ms
- 压缩路径:1.035 ms
- MoE MLP 层级提升:1.23×
- 全量相关回归:260 passed,3 skipped
端到端 A/B
固定三条 64-token 请求:
| 版本 | 聚合吞吐 | DSpark 接受率 |
|---|---|---|
| 压缩版首轮 | 3.104 tok/s | 36.8% |
| 基线首轮 | 3.173 tok/s | 41.3% |
| 基线重复 | 3.448 tok/s | 42.6% |
同一基线实例自身存在约 8.7% 吞吐波动,而且 greedy token 序列也会因 NPU 数值非确定性变化。因此目前不能依据单轮数据认定压缩版有端到端收益,尚未合并到稳定分支。
当前正在启动压缩版 v21,以 warm-up 后第二轮数据与基线第二轮严格比较。最后一次检查时模型仍在加载,端口 8000 尚未恢复健康。
尚未完成
GitHub 推送未完成。服务器网络已经恢复,但当前没有 GitHub HTTPS 凭据、SSH key 或 gh 登录;本地稳定分支领先远端 13 个提交。所有提交和独立性能分支均已完整保存在服务器工作区。
第二十二阶段
继续将稳定分支部署为正式 DSpark 服务,先推送提交,再用默认确定性脚本重启并做最终健康、重复性和性能校验。
检查代理技能、NPU310P任务及Docker状态
正式服务当前已停止,但代码与部署脚本完整保留。先推送 129c819a,随后启动标准容器 dsv4-310p-dspark。
扫描密钥并推送DeepSeek-V4分支,检查差异和敏感信息
推送因服务器未配置 GitHub HTTPS 凭据失败,提交仍安全保留在本地分支。部署不依赖推送,现先启动正式服务,同时检查可用的 SSH/gh 认证方式。
启动并验证服务及 GitHub 推送认证
控制端已登录 fwerkor,无需复制凭据到服务器。将通过 Git bundle 把服务器分支安全转移到控制端,再由控制端推送 GitHub。
创建并传输DeepSeek分支Git Bundle并监控作业
正式容器已启动加载,Git bundle 正在传输。当前分支无未提交改动,推送将保持 fast-forward。
检查容器与传输任务并创建推送增量补丁
GitHub 推送已完成,远端分支与本地均为 129c819a。正式服务已加载约八分钟,现检查健康状态并执行最终验收。
检查服务状态并完成健康检查
正式容器的目标权重加载已开始,预计阶段与已验证 v26 一致;当前无报错。健康探针正在持续检查,完成后直接跑重复性与 64-token 基准。
检查并等待训练任务执行完成
正式服务已于 14:35:08 健康,HTTP 200。开始生产实例的 6 次固定请求验收,核对 token 序列和 speculative 路径。
完成生产环境重复验证与基准测试并轮询输出
生产实例验收通过:6/6 输出完全一致,每次均为 50 drafted / 25 accepted;稳态 32-token 耗时约 9.8 秒,日志无异常。继续执行固定 3×64-token 性能基准。
执行令牌基准测试并检查生产状态及任务输出
生产基准完成:192 tokens 用时 51.17 秒,3.752 tok/s;接受率仍为 137/285(48.07%),HTTP 200 且错误扫描为空。最后清理临时 worktree、bundle 和测试容器。
清理临时资源并验证服务、分支及NPU状态
已完成正式部署与验收。
- 正式服务:
dsv4-310p-dspark - API:
0.0.0.0:8000 - 健康检查:HTTP 200
- 运行配置:8× Ascend 310P、DSpark 5-token draft、确定性模式开启
- 当前提交:
129c819a17777120853e4b24e1ff45e8eee34b2e - GitHub 分支
feat/deepseek-v4-310p-bootstrap已推送到同一提交 - 仓库工作区干净
- 8 张 NPU 健康状态均为
OK - 最近日志中 AICore、越界、NaN、Traceback 等错误数量为 0
生产实例重复性测试:
- 6 次相同的 32-token greedy 请求输出完全一致
- 每次均为
50 drafted / 25 accepted - speculative 执行路径完全一致
- 稳态耗时约 9.8 秒/32 tokens
- 6 次平均耗时 10.20 秒
固定 3×64-token 基准:
- 总输出:192 tokens
- 总耗时:51.17 秒
- 聚合吞吐:3.752 tok/s
- Draft:285 tokens
- Accepted:137 tokens
- DSpark 接受率:48.07%
代码回归为 261 passed,3 skipped。临时 worktree、bundle、测试脚本和旧测试容器也已清理。路由压缩实验未合入,因为未观察到实质性能收益。下一阶段应转向多请求并发和更长上下文验证。
第二十三阶段
进一步做四类验证:API兼容性、并发稳定性、上下文边界、长时间重复请求。先读取当前服务参数和资源余量,再按低风险到高压力顺序执行。
检查了服务状态与资源指标
基线正常。先验证 OpenAI 兼容接口:普通 completion、chat completion、流式 SSE、logprobs、模型错误处理和工具调用解析;随后再施加并发与边界压力。
测试并读取基础API兼容性与并发结果
扩展验证发现一个真实缺陷:某个 API 场景触发 310P AICPU 内存分配失败,进而导致整个引擎退出。普通推理此前稳定;当前优先恢复服务并精确隔离是 logprobs、tool calling 还是 streaming 触发。
Interacted with local-shell-mcp
触发场景已精确定位:前两个请求(completion、chat)均成功,第三个 DSpark + logprobs=5 请求在 rejection sampler 的 aclnnNonzeroV2 路径触发 AICPU OOM。工具调用和流式接口尚未执行。现在修复该专用路径,并恢复服务。
修复DSpark拒绝采样Logprobs内存溢出
根因明确:上游 logprobs 代码用布尔索引赋值清理 -1 占位符,310P 将其实现为 aclnnNonzeroV2 动态输出,导致 AICPU 分配失败。改为等价的 torch.where,完全绕开 NonzeroV2。
修复并验证采样器分配及部署补丁
修复单测通过(6/6)。部署脚本此前未覆盖 _310p/sample/rejection_sampler.py,因此需要显式加入;随后重启正式服务并首先复测 logprobs=5,确认不会再杀死引擎。
更新部署脚本并重启任务验证正式服务修复
服务重载期间并行执行完整 310P/DSpark 回归。复测顺序将改为逐项输出,任何接口一旦异常就立即停止,避免再次连锁影响。
完成DSV4 Logprobs回归测试并检查作业状态
完整回归已通过:262 passed,3 skipped。服务仍在重载,接下来直接做真实 logprobs=5 验证;这是当前最关键的阻断项。
检查容器状态并监控模型服务加载进度
修复版已正常进入 8 卡目标模型加载,未出现导入或形状错误。加载完成后先只发单个 logprobs 请求,验证引擎存活,再继续其他接口。
检查并验证修复版目标模型服务状态
当前仍处于目标权重静默加载阶段,容器和 worker 均存活,无错误。继续等待所有 rank 汇合,不中断加载。
检查修复版服务及DSpark模型加载启动状态
修复版已健康启动,模型加载约 458 秒。现在发送与崩溃时完全相同的 logprobs=5 请求,并在请求后检查全部 worker、显存和健康状态。
测试了单次生成的对数概率
第一次修复仍未通过,单请求返回 500。需要确认容器确实加载了新代码,并读取新的首个失败算子;当前先不继续其他压力测试。
检查容器补丁与服务日志
新的首个失败算子是 IndexPutV3,不是 NonzeroV2。它来自同一 logprobs 组装函数中的索引写入;异步错误直到后续 draft 更新时才暴露。继续消除该函数内全部索引赋值,改用直接复用 raw logits 与 index_copy。
替换索引写入并修补采样器Logits路径
第二版已移除函数内全部索引赋值:生产使用的 raw-logprobs 模式直接复用原始 logits,不再调用 NonzeroV2 或 IndexPutV3。先做 CPU 回归和单卡真实 NPU 方法级验证,再重载完整模型。
验证拒绝采样器并执行NPU方法测试
单卡真实算子测试超时,可能是上一个异常实例的 NPU 上下文仍在释放,或测试容器停在初始化。先清理残留并确认设备空闲,再决定是否重跑。
检查并清理残留容器进程及NPU状态
超时容器已自动退出,设备已释放。改用可跟踪作业重跑真实 NPU 方法测试,避免公共命令时限掩盖最终结果。
运行并检查单卡NPU长任务及vLLM进程状态
单卡测试并非死锁:Torch/vLLM 插件初始化启动了多个 forkserver 进程,CPU 正在持续运行。继续让其完成,不中断设备验证。
等待NPU验证并查看作业最新输出
单卡测试失败原因与代码无关:测试容器把 /work 只读挂载,CANN 无法写 kernel_meta,导致 Add 算子编译失败。改为可写挂载后重跑真实 NPU 测试。
重新运行并检查NPU方法测试输出
真实 310P 方法级验证通过:raw 与 processed 两种模式均正确清理占位符,且不再触发 AICPU 索引错误。现在第三次启动完整服务,复测原始 logprobs 请求。
启动生产服务并验证 Logprobs 修复状态
完整服务正在加载,工作区只包含 rejection sampler 修复和对应测试,没有残留缓存。并行重跑最终全套回归。
完成第二版修复回归测试并查看输出
最终全套回归通过:263 passed,3 skipped。完整服务仍在加载;加载完成后将先验证单个 logprobs,再继续 API、并发和上下文边界测试。
监控并检查服务启动与模型加载状态
第二版仍在目标权重静默加载,容器与 8 个 worker 均存活,无错误。继续等待,不中断当前加载。
监控并等待DSV4与DSpark第二版服务启动
第二版完整服务已健康,加载约 448 秒。现在复测原始 logprobs=5 请求,并立即检查引擎、设备和错误日志。
测试单次Logprobs请求并处理HTTP错误
关键缺陷已修复:原始 logprobs 请求返回 200,top-5 数据完整,引擎和 8 张 NPU 均健康。继续逐项验证 streaming、chat、工具调用和错误响应,每项后检查健康。
验证了流式响应、工具调用及未知模型支持
completion、chat 和 SSE streaming 均通过,流式 [DONE] 与 usage 完整,服务无错误。下一项单独验证强制工具调用,避免结构化输出问题影响其他测试。
测试强制工具调用并检查模型健康状态
工具调用第一次返回预期的 400:工具 schema 后 prompt 为 97 tokens,加 32 输出会超过 128 上限;服务健康。将输出降到 24 tokens 后重试。
重试工具调用并验证天气函数输出
工具模板实际输入为 105 tokens,24 输出仍超限。降到 16 tokens;足以生成 {"city":"Paris"}。
测试了工具调用的最大令牌限制
工具调用在当前 128-token配置下不可用:DeepSeek V4工具模板本身使“输入+至少1个输出”超过128,三次均被API层安全拒绝,服务未受影响。下一步验证4路并发排队与跨请求确定性。
测试并发工具调用并查看最新输出
四路并发验证通过:最大运行数1、等待数3,四个请求均200,输出逐token一致,服务无错误。下一步验证128-token精确边界与超限拒绝。
验证了上下文边界与请求模式
128-token边界验证通过:总长度128正常生成,129在API层返回400;tokenize/detokenize往返正确。继续验证随机采样的固定seed复现性、不同seed差异及penalty/stop路径。
验证随机采样惩罚参数并读取最新输出
随机采样验证通过:固定seed三次完全一致,不同seed产生不同序列,presence/frequency/repetition penalty路径也稳定。现在对修复后的logprobs执行12轮耐久测试并检查显存变化。
验证了Logprobs稳定性与内存占用
继续读取12轮 logprobs 耐久结果;通过后再做混合请求耐久、提交修复,并仅从 local 推送。
查看了作业最新输出
12轮 logprobs 耐久测试全部通过:token序列、每个token的logprob和top-5长度完全一致;测试前后8卡显存逐卡不变,错误数为0。现在执行混合接口耐久测试。
完成混合API耐久测试并读取作业输出
20轮混合耐久全部通过:五类接口各4轮均200,各类别响应逐项一致,8卡显存保持不变,错误数0。再验证 prompt logprobs 与错误响应,然后提交修复。
验证补全日志概率并提交修复
prompt logprobs 返回200,输入5个token与输出4个token的logprobs均完整;未知模型正确返回404,服务继续健康。现在更新文档、提交,并通过local控制端推送。
更新 DeepSeek V4 文档并验证推测式采样修复
修复已提交为 a0227fb9,工作区干净,仅领先远端1个提交。现在生成增量bundle并由local控制端推送,NPU服务器不执行push。
生成验证并同步增量Bundle后推送修复
bundle已到local且哈希一致;使用干净的 /workspace/vllm-ascend-push 仓库导入,验证远端是祖先后执行fast-forward推送。
推送并验证Logprobs修复分支
远端已由local推送到 a0227fb9,哈希核对一致。最后清理bundle与临时分支,并确认生产服务、8卡状态、指标和日志。
清理部署资源并检查服务健康状态
进一步验证已完成,并发现、修复了一个此前未覆盖的严重问题。
新发现与修复
DSpark + logprobs 原先会触发 310P AICPU 动态内存分配失败,导致整个推理引擎退出:
- 首次故障算子:
aclnnNonzeroV2 - 后续定位到:
IndexPutV3 - 根因:speculative logprobs 组装使用布尔索引和索引赋值
现已改为:
torch.where清理占位 token- raw-logprobs 模式直接复用原始 flattened logits
- processed-logprobs 模式使用 out-of-place
torch.index_copy torch.cat构造累计偏移,避免切片赋值
真实 310P 方法级测试和完整 TP8/EP8 服务测试均通过。
扩展验证结果
- 全量相关回归:263 passed,3 skipped
- 12轮连续 top-5 logprobs:
- 12/12 HTTP 200
- token IDs 完全一致
- 每个 token 的 logprob 完全一致
- 每个位置均返回5个候选
- 测试前后8卡显存逐卡不变
- 20轮混合接口耐久:
- completion、chat、logprobs、随机采样、SSE streaming 各4轮
- 20/20 HTTP 200
- 固定seed输出逐项一致
- 日志错误数0
- 四路并发:
- 4/4 HTTP 200
max_running=1max_waiting=3- 四个输出逐token一致
- 上下文边界:
120 prompt + 8 output = 128:成功121 prompt + 8 output = 129:正确返回400
- 其他接口:
- completion logprobs:通过
- prompt logprobs:通过
- chat completion:通过
- SSE streaming:通过,包含
[DONE]和 usage - tokenize/detokenize:往返一致
- 未知模型:正确返回404
- 固定seed随机采样:可复现
- 不同seed:产生不同结果
- presence/frequency/repetition penalty:通过
工具调用在当前 max_model_len=128 下无法实际生成:DeepSeek V4工具模板本身占用约112个以上token,连同生成预算会超过128。API会安全返回400,不会影响服务。需要更大的已验证上下文预算后才能启用。
当前状态
- 提交:
a0227fb9 fix(310p): stabilize speculative logprobs - 已通过 local 控制端推送至 GitHub
- 远端哈希:
a0227fb9edb26fca74ffde8dda43f926094cb99d - 仓库工作区干净
- 正式服务:
dsv4-310p-dspark - 健康检查:HTTP 200
- 8张310P:全部
OK - 当前容器启动以来相关错误数:0
- 服务保持运行,端口8000。
第二十四阶段
先把当前分支按可审查标准整理:核对提交历史与相对上游差异,压缩无关改动,补齐测试与文档说明,再跑完整检查并生成PR说明。
整理代码并检查分支差异以准备提交 PR
当前分支对 fork 的 main 只多5个提交,但真正面向上游的改动有54个文件、约4000行,直接PR会过大且历史分散。先拉取官方上游最新 main,再决定是可安全重放,还是整理为一组依赖清晰的分层PR。
整理并形成可提交的PR提交栈
310P服务器拉取官方仓库时TLS中断;改由local控制端获取上游基线,再把必要引用同步回310P,避免在服务器侧依赖不稳定网络。
获取上游主分支并检查DeepSeek-V4分支差异
官方 main 已前进60个提交,其中包含 DeepSeek-V4/DSpark 文档、310P nightly、量化与路由重构。不能直接把旧分支原样PR;需要基于最新上游重放,并删除与上游重复或无关的提交。先做提交级拆解和冲突预判。
梳理并整理 DeepSeek V4 分支变更
整理策略确定:保留现有已验证分支不动,在local新建基于官方最新 main 的独立PR分支,用一次三方合并吸收最终实现,统一解决15个重叠文件,删除Dependabot等无关改动,再重组为少量逻辑提交。
重建上游分支并合并功能变更
三方合并只产生5个实质冲突,范围可控;Dependabot删除会直接丢弃。接下来逐个按最新上游结构吸收310P特化,避免覆盖官方近期的router、dynamic EPLB和平台注册改动。
检查并解决路由架构冲突并接入哈希路由
冲突解决将以最新上游实现为主,不保留旧分支对公共基础设施的大段覆盖。先提取每个冲突文件中“310P确实需要”的最小改动,再应用到上游版本。
梳理并精简310P适配变更
上游已把路由和shared-expert执行重构为独立组件。旧分支在量化scheme和fused_moe.py中重复实现的逻辑会删掉;哈希路由迁入310P router,shared-expert回退迁入最新AscendSharedExperts,这样PR能顺着官方架构审查。
完成310P DeepSeek V4共享专家与路由量化适配
已完成冲突架构迁移,当前重点是补齐新扩展点的测试,并清理自动合并进来的旧式重复实现。先让最新上游树通过针对性测试,再按文件审计。
补充专家选择器与共享融合测试
新架构测试已补齐。现在运行格式、静态检查和最小相关单测;这一步会暴露接口迁移遗漏,再进入大范围文件审计。
完成融合专家模块格式化与测试
静态检查只发现一处测试文件导入顺序问题,没有接口或语法错误。修正后运行router、量化和shared-expert相关测试。
修复导入并运行测试
该测试文件沿用了上游的 CRLF 行尾,新增段落导致 diff --check 将整段识别为尾随空白。统一为 LF,不改变内容。
规范化文件并运行 Ruff 检查及架构迁移测试
local主机没有安装PyTorch,改用项目310P测试镜像执行;这与此前生产分支回归环境一致。
完成Docker中310P针对性测试
local没有Docker,因此真实单测需同步到310P执行。在此之前先完成PR审计:取消暂存但保留工作树,按文件识别自动合并的过时覆盖和无关改动,减少传输与返工。
审计并统计工作树变更
审计发现部分大改动只是旧分支把上游 CRLF 文件改成 LF,形成无意义的整文件diff。先计算“规范化行尾后的真实差异”,再恢复纯格式噪声。
审计文件差异并识别换行噪声
真实差异统计确认只有两个文件存在行尾噪声:专家路由测试与W8A8测试。将它们恢复为上游CRLF格式,同时保留新增测试内容。
恢复测试文件CRLF格式并总结代码差异
由于Git会把新增CRLF行视为尾随空白,PR不能直接修改这两个上游CRLF测试文件。将新增覆盖迁移到独立LF测试文件,原文件完全恢复,既保留测试又消除格式风险。
重构测试并创建 DeepSeek V4 路由器测试文件
格式噪声已清除。接下来审计公共模块的小改动,优先恢复与310P DeepSeek V4无关的全局行为,缩小回归面。
审计文件差异并检查310P导入及分片状态加载
公共小改动中,MTP权重加载的异常包装只改善报错,不参与功能,先恢复以减少无关变更;其余均直接支撑310P加载、DSA元数据或多维量化。继续审计注意力与模型层。
审计DSA注意力与模型适配改动
模型层审计发现一个上游重构后的语义点:路由缩放现在由router统一处理,旧分支通过量化scheme标志判断组合方式已不可靠。先追踪最新quant_method包装层与DeepSeek共享专家合并语义,避免保留无效分支。
修正 DeepSeek 路由缩放并检查 Triton 算子代码
路由缩放的旧标志在最新包装层上不可见,属于无效分支。改为明确的310P语义,并移除两处仅用于调试的异常包装;保留实际需要的scale分片。
更新并审计 DeepSeek-V4 路由专家运行逻辑
DSpark公共路径大部分是310P无Triton与混合KV页所必需,但其中保留了一个环境变量控制的slot诊断日志。该调试分支不应进入PR,先删除;随后复用现有混合页辅助函数,避免重复推导。
检查并清理物理块推断及重复诊断逻辑
公共路径已删去运行时调试分支。现在检查测试质量与新文件边界,尤其删除“检查源码字符串”这类脆弱测试、重复测试和未使用的实验开关。
检查310P源代码变更与实验性标记
审计命中两类需要整理的问题:新DeepSeek测试包含源码字符串断言;loader仍保留header-only诊断模式。先把新测试改为行为测试,并评估诊断模式是否能完全删除。
审查并重构 DeepSeek 测试源代码
新DeepSeek测试末尾四项确实是旧架构遗留:其中一个检查已不存在的scheme标志,三项只匹配源码字符串。全部删除,保留功能门控和backend选择的行为测试;缩放语义由后续真实模型回归覆盖。
精简 DeepSeek V4 测试并清理 Header-Only 诊断模式
header-only模式没有文档入口或正式测试,只会构造未初始化权重,属于危险诊断路径。将其完全删除,loader始终加载真实tensor,同时删掉专用dtype映射。
移除Safetensors头部加载并审计310P运行器工作器
310P runner新增的KV分配测试是行为测试,可保留;底部压缩slot测试仅检查源码字符串,删除。worker中的超时、HCCL预热和显存回收均对应已复现的加载失败点,暂时保留并在NPU回归验证。
移除冗余测试并审查310P MoE差异
MoE审计发现token_dispatcher.py中保留了一个已不再调用的EP rank解析函数,实际rank修复已集中在AscendRoutedExperts。删除重复函数和导入,保留全局专家ID到本地slot映射。
移除Token Dispatcher冗余依赖并整合MoE测试覆盖
MoE测试中有一项仍引用刚删除的dispatcher rank函数;对应rank行为已在公共RoutedExperts测试覆盖。删除该项,并把近重复的test_moe_mlp_310p.py改名为DeepSeek专用测试模块。
清理并重命名310P测试文件
MoE测试结构已收敛。下一步审计loader测试的大幅改写:目标是保留参数替换、TP校验、分片保存等行为覆盖,去掉重复mock和实现细节。
审计预转换加载器与量化测试
loader测试已从旧mock式测试重写为真实safetensors往返、shape/dtype替换、TP不匹配和分片保存,属于有效行为覆盖。继续清理DSpark测试中新增的源码检查与重复断言。
审计并精简DSpark测试回归项
DSpark新增测试均为行为测试,保留。现在完成剩余测试与公共模块审计,重点排除新增源码字符串断言、重复覆盖和与本PR无关的全局修复。
检查新增测试并审计MoE、CPU与A2差异
剩余公共测试均直接覆盖已复现问题:rfork EP rank、双芯片310P亲和、MTP多维量化和压缩KV slot映射,保留。现在对全部改动执行统一lint、语法和文档检查,再同步到310P跑真实测试。
完成代码质量检查、编译验证与文档格式验证
全量静态检查通过:60个Python文件无lint或语法问题,diff与文档行宽干净。当前真实改动约1648行;在提交前再审计转换工具与部署文档,避免把本地脚本细节或过度结论带入PR。
审查了DeepSeek转换示例与文档
文档中仍使用“This fork”,不适合上游PR;同时当前验证数字来自旧基线,需在最新上游回归后再更新。先改为中性上游措辞,并确认开发者指南已被目录索引。
更新后端文档索引与DeepSeek-V4-Flash部署指南
文档已改为上游中性措辞并加入Developer Guide索引。接下来按审查边界重组为四个提交:310P目标运行时、DSpark、speculative logprobs、文档与转换工具;每个提交都可单独理解。
整理 DeepSeek V4 提交并扫描敏感信息
静态扫描未发现本PR新增密钥;命中的4处均是上游既有测试/源码变量。开始生成第一组提交:目标模型运行时、310P算子回退、W8A8转换加载与基础并行修复。
暂存文件并提交更改
第一组提交已整理完成:虽然功能面较大,但内容只包含目标模型可运行所需的attention、MoE、量化转换、预转换loader与310P基础修复;DSpark、logprobs和文档均未混入。现在提交该组。
提交 DeepSeek V4 运行时与 DSpark 解码支持
目标运行时和DSpark现已分成两个独立提交。第三组只处理310P speculative logprobs中的动态AICPU索引算子,范围为实现与专用回归测试。
提交310P采样修复及DeepSeek V4文档工具更新
PR分支已重组为4个提交,工作区干净,基于官方最新main。现在生成相对310P仓库已有公共基线的增量bundle,在服务器创建独立测试worktree,不触碰生产分支和运行服务。
生成并传输PR增量Bundle及创建工作树
增量bundle仅672 KiB,已传输并校验一致。现在在310P上导入最新上游与PR分支,创建独立验证worktree,然后先跑完整相关单测。
验证并创建PR工作树并运行Docker单元测试
最新上游PR分支的全量相关单测已启动,生产容器不受影响。测试覆盖整个tests/ut/_310p及DSpark、CPU亲和、公共MoE和W8A8路径。
等待PR图像回归测试并查看任务输出
最新上游回归结果为 291 passed、3 skipped、2 failed。两项都是测试适配问题:一个mock缺少create=True,另一个2D输入被无必要地创建reshape视图。实现改为2D保持原tensor,多维才展开,并修正mock。
修复量化测试并完成提交、同步及全面验证
两项失败已修复并通过。现在重跑完整相关套件;通过后进行latest-upstream真实TP8/EP8服务验证,而不是沿用旧分支的结果。
重跑并跟踪PR全量单元测试结果
最新上游完整相关回归通过:293 passed,3 skipped。下一步做真实TP8/EP8服务验证;会短暂停止当前生产容器,使用独立PR worktree启动同配置实例,验收后恢复稳定生产分支。
验证上游服务并检查DeepSeek V4运行脚本
单测已验证代码级兼容。真实服务将直接以PYTHONPATH=/work加载完整PR worktree,避免旧部署脚本遗漏最新上游新增的router/shared-expert文件,也避免依赖镜像内源码恰好同一提交。
创建PR验证脚本并启动检查服务作业
PR服务容器已启动,早期未出现导入或CLI错误;当前处于Python/插件初始化阶段。继续观察到8个worker开始加载或出现首个阻断。
检查了服务启动状态与日志
PR服务已成功注册新loader并解析目标与DSpark模型,未出现接口冲突。当前只有vLLM对插件自定义环境变量的通用“unknown”警告;它们仍由vLLM-Ascend读取,不是启动失败。继续等待worker加载。
检查容器与服务状态及模型加载日志
最新上游PR实例已进入8卡目标权重加载,deterministic在HCCL初始化前生效,TP/EP rank均正确。继续等待目标与draft加载完成。
检查模型加载、NPU及远程服务健康状态
PR实例仍在目标权重加载,8卡健康、显存逐步增长且无错误。已改用后台健康探针监测容器,服务就绪后立即执行重复性、logprobs和固定性能基准。
检查服务加载、作业健康状态及容器NPU日志
真实服务发现最新上游结构迁移问题:AscendSharedExperts包装器把同一组共享专家参数暴露出第二套_shared_experts._layer.*别名,而现有预转换checkpoint只含原始规范键。权重本身已加载,loader却把172个重复别名判为缺失。现在修正loader的别名去重,而不是重新生成数百GB checkpoint。
调查共享专家模块命名与检查点加载兼容性
真实TP8/EP8验证暴露了上游重构后的checkpoint兼容问题:新wrapper产生重复参数别名,旧预转换checkpoint不含这些重复键。修复方向是按参数/缓冲区对象身份将已加载规范键同步标记为其全部别名,并补真实safetensors回归。
完成别名兼容性验证并更新提交 NPU 修复代码
checkpoint别名回归通过(6/6)。现在重新启动latest-upstream真实服务;目标权重无需重转换,loader会识别并满足wrapper产生的重复别名。
检查并重启DeepSeek-V4服务后验证健康状态
修复后的真实服务正在重新加载。加载期间同步准备上游PR说明和checklist,避免服务验证完成后再补材料。
检查并完善拉取请求模板及NPU模型加载状态
第二次PR实例已进入8卡目标加载,别名校验尚未触发错误。加载期间检查上游贡献规范与PR格式,确保分支不仅能运行,也符合提交要求。
阅读并检查贡献指南要求
上游规范要求所有提交含DCO sign-off,PR标题采用[Type][Module]格式;当前4个提交会在最终autosquash时统一补签。另一个关键规范是环境变量必须集中在envs.py,现在检查并消除代码中的直接字符串读取。
集中管理并修复DSV4环境变量及提交签名
贡献规范审计发现3个自定义环境变量仍在模块内直接定义。服务加载继续进行的同时,将这些变量统一迁入vllm_ascend.envs,包括临时切换draft expert模式所需的集中键名。
更新模型运行器环境变量配置并完善相关测试
环境变量集中化已完成:实现中只通过vllm_ascend.envs读取,自定义键名仅在中心模块定义。接下来分别压入目标运行时和DSpark提交,保持提交边界。
修复 Ruff 导入顺序并提交验证修复
继续完成最后一轮:先读取latest-upstream真实服务结果;随后同步环境变量规范修复、重跑全量测试、autosquash并补DCO,最后恢复稳定生产服务。
检查服务作业输出与vLLM作业状态
latest-upstream真实服务已健康:TP8/EP8目标与DSpark加载完成,耗时约473秒,KV容量203 tokens,8卡均正常。现在执行重复性、spec路径、logprobs与固定性能基准。
验证上游功能并检查作业最新输出
latest-upstream功能验收通过:6/6输出与spec路径完全一致,每次50 drafted/25 accepted;top-5 logprobs完整,HTTP 200且错误数0。继续跑固定3×64-token性能基准。
完成路由性能测试、环境修复同步及单测回归验证
latest-upstream固定基准完成:192 tokens / 53.09秒,3.616 tok/s,DSpark接受率仍为137/285(48.07%),无错误。现在对包含envs规范修复的最终代码重跑全量单测。
完成最终单元测试回归验证
最终latest-upstream回归通过:294 passed,3 skipped。现在将文档中的旧回归数字与性能数据更新为本次PR分支实测,再autosquash为4个DCO签名提交。
更新 DeepSeek V4 文档指标与基准并验证提交
latest-upstream真实验收和最终回归均已完成。现在恢复稳定生产服务,同时在local进行最终静态检查、autosquash、DCO签名和PR分支推送。
恢复稳定服务并完成代码质量检查
静态检查全部通过。文档索引中新增入口为127字符,按项目风格拆成两行,避免给PR增加新的长行。
整理并提交文档修复,准备自动压缩
最终改动已稳定。现在执行autosquash,将6个fixup压回4个逻辑提交,然后逐提交补DCO Signed-off-by,并核对树内容未变化。
压缩提交历史并完成签名验证
4个提交已完成autosquash与DCO签名,文件树与实测版本完全一致。现在按仓库模板生成PR说明,执行最终差异审计后从local推送独立PR分支。
检查PR模板并审计分支后推送DeepSeek V4 Ascend更改
最终审计通过:4个逻辑提交、DCO完整、diff与密钥检查干净,远端目标分支不存在且dry-run成功。现在从local实际推送PR分支。
已推送分支并核验提交哈希及生产服务恢复状态
PR分支已从local推送,远端HEAD为3b01abd9。生产服务仍在恢复加载;并行确认该仓库是否为官方GitHub fork,确保分支能直接向上游发PR。
验证仓库拓扑与PR分支状态
当前仓库是独立仓库,并非vllm-project/vllm-ascend的GitHub fork,因此不能直接作为上游PR head。下一步将分支同步到fwerkor/vllm-ascend官方fork;若不存在则由local创建fork。
检查官方仓库状态并创建 vllm-ascend Fork
官方forkfwerkor/vllm-ascend已创建并确认父仓库正确。现在由local将最终分支推送到该fork,之后即可直接向官方main发PR。
添加远程 Fork 并推送分支
官方fork创建时同步到了更新的main(dab1c351),比本地先前基线9f3aa1e7更前。为避免PR刚创建就显示落后,现在拉取最新官方main并检查增量;若有变更则重新rebase并回归。
同步并核对上游主分支最新提交
官方main仅新增5个提交,但最新DSA重构与本PR有8个重叠文件。现在在local重新rebase,按新DSA接口解决冲突;完成后重跑相关单测并强制更新fork分支。
正在将DCO提交重放到最新官方主分支
最终rebase只产生1个冲突,位于RoutedExperts的EP rank解析;其余DSA重构均自动合并。按最新上游EPLB逻辑保留原结构,仅叠加rfork后的live EP rank修复。
合并路由专家冲突并完成变基验证
分支已重新基于当前官方main(dab1c351),只需解决1个EPLB/EP-rank冲突;4个DCO提交仍完整。现在对最终树重跑静态检查和310P全量回归,之后再更新fork分支。
完成最终静态检查、回归测试及官方分支验证工作树重建
稳定生产服务已于18:11:17恢复健康。最终PR分支的dab1c351全量回归仍在执行,完成后再更新fork远端并做最终状态核对。
检查生产恢复后的测试结果
dab1c351最终回归通过:301 passed,3 skipped。上游新增测试使计数从294增至301;先更新文档与PR说明并修改文档提交,然后对最终树再做一次真实TP8/EP8启动验收。
更新文档、测试数量并验证DCO签署
最终代码树已确定。为覆盖官方最新DSA重构,现用dab1c351验证worktree再启动一次TP8/EP8实例;只做启动、短请求与logprobs冒烟,完成后立即恢复稳定生产服务。
启动并完成PR服务最终验证
最终PR真实服务正在加载。此轮重点验证官方最新DSA重构没有破坏导入、backend选择和实际注意力执行;生产分支已安全保留,验收后会再次恢复。
等待模型加载并检查日志,准备双仓库分支强推
dab1c351最终实例已完成最新DSA backend选择并进入目标权重加载,EP rank修复也在新EPLB代码上生效。继续等待target+draft加载完成,随后复跑相同冒烟与固定基准。
检查作业状态并更新基准PR
已整理到接近可提交状态,但最终实机冒烟和远端分支更新尚未完成,因此目前不能声称已经完全 PR-ready。
已完成
分支已基于官方最新 vllm-project/vllm-ascend/main:
- 上游基线:
dab1c351 - 最终本地 HEAD:
b9d0a94d - 工作区干净
- 仅保留4个逻辑提交:
dfd7e235 feat(310p): add DeepSeek V4 target runtime
9fd09c2a feat(310p): support DeepSeek V4 DSpark decoding
94e66e9b fix(310p): stabilize speculative logprobs
b9d0a94d docs(310p): document DeepSeek V4 deployment
四个提交均包含:
Signed-off-by: Cao Yuhang <caoyuhang@fwerkor.com>
代码整理包括:
- 按最新上游 router、shared-expert、EPLB 架构重新接入310P实现
- 删除旧架构重复路由和公共模块覆盖
- 删除 header-only 未初始化权重模式
- 删除运行时诊断开关和源码字符串断言测试
- 集中管理全部 DeepSeek V4 310P 环境变量
- 兼容最新 shared-expert wrapper 的参数和buffer别名
- 文档加入 Developer Guide 索引
- 准备了符合仓库模板的PR标题和正文
建议PR标题:
[Feat][Model] Add experimental DeepSeek V4 support for Ascend 310P
验证结果
最终 dab1c351 基线相关回归:
301 passed, 3 skipped
60个修改的Python文件均通过:
ruff check
python -m py_compile
git diff --check
此前在稍早的上游基线上完成了完整TP8/EP8实机验证:
- 目标模型和DSpark正常加载
- 6次相同请求输出及spec路径完全一致
- 每次
50 drafted / 25 accepted - top-5 logprobs正常
- 固定192-token基准:
3.616 tok/s - DSpark接受率:
137/285 = 48.07% - HTTP 200
- 无AICore、NaN、越界、
NonzeroV2或IndexPutV3错误
尚未完成
最终 dab1c351 版本的TP8/EP8实例已经启动,并成功进入8卡目标权重加载:
- 最新DSA backend选择成功
- deterministic初始化成功
- EP rank在最新EPLB代码上解析正确
- 尚未等到服务健康并执行最终请求
远端方面:
- 已创建官方GitHub fork:
fwerkor/vllm-ascend - fork中的PR分支目前仍是最终rebase前的旧哈希
3b01abd9 - 本地最终分支
b9d0a94d尚未 force-with-lease 更新到fork - 实际PR尚未创建
另外,为执行最终PR实机验证,稳定生产服务已被暂时停止;当前最终PR实例仍在加载,稳定生产服务尚未再次恢复。
第二十五阶段
继续完成最后闭环:等最终PR实例健康,跑短请求、logprobs和固定基准;随后恢复稳定生产服务,更新官方fork分支,并创建上游PR。
检查作业状态并核查模型服务日志健康
最终dab1c351实例已健康,加载耗时约454秒,KV容量203 tokens。现在执行确定性重复、logprobs和固定192-token基准,并扫描运行日志。
完成了功能验证、基准测试及任务输出检查
最终服务功能正常,但最新上游重构后基准接受率和输出序列发生变化。为避免把单次波动写入PR,先复跑同一3×64-token基准,确认输出与接受路径是否可重复。
验证第二轮基准结果及JSON结构一致性
两轮最终基准完全一致:三条输出逐token相同,均为151/230接受(65.65%),吞吐分别4.458和4.627 tok/s,日志错误数0。现在恢复稳定生产服务,并把这些最终数字写入文档和PR说明。
更新生产服务并完善DeepSeek V4文档与PR验证
最终指标已写入文档,DCO保持完整。接下来确认官方main未再次前进,执行最终审计,然后用--force-with-lease更新fork分支并创建上游PR。
完成最终审计并推送分支创建拉取请求
上游PR已创建:vllm-project/vllm-ascend#13705。现在核对base/head、提交数、DCO及首轮CI状态,同时等待稳定生产服务恢复健康。
检查PR状态、生产健康及提交前验证
PR的DCO和中英文Read the Docs已通过,pre-commit等首轮CI仍在运行。稳定生产服务处于正常加载阶段,继续等到健康端点恢复后再收尾。
检查生产服务启动、模型加载及任务进度
稳定生产服务已恢复,加载耗时约452秒,健康端点返回200。最后做一次生产短请求和日志扫描,并读取PR当前CI状态。
验证生产服务健康、短请求及CI状态
PR已创建且生产服务正常,但GitHub pre-commit失败;DCO和双语文档构建已通过。现在读取失败日志,修复后更新PR分支。
检查并修复 Pre-commit 及 GitHub Actions 问题
失败原因仅是标题前缀:仓库CI接受[Feature],不接受[Feat]。代码检查尚未执行。现在改为[Feature][Model]触发重新检查。
修正PR标题描述并检查CI及生产健康状态
标题修改不会重新触发已失败的pre-commit。我将仅重写最后一个文档提交的提交对象,不改变文件树或4提交结构,然后用lease保护更新分支,触发完整CI重跑。
修正文档提交并触发双远程CI后检查运行状态
修正标题后的新CI已启动,旧失败记录被新提交替代;当前DCO通过,main和PR创建流程运行中。继续等待首轮静态检查结果。
检查PR预提交及修正提交工作流状态
新的合并冲突检查已通过,PR创建工作流仍在分类并触发后续测试。为不被GitHub队列拖住,先在local按仓库配置运行完整增量pre-commit,提前处理格式或策略问题。
运行 Pre-commit 检查并读取作业输出
local环境缺少pre-commit命令,并非代码失败。安装仓库要求的工具后重跑增量hooks。
安装 pre-commit 并完成代码预提交检查
local仓库hooks发现两处可直接修复的问题:一处由官方ruff format重排字符串,另一处loader使用了仓库禁止的init_logger(__name__)。修正并压回第一个逻辑提交,再重跑全部hooks。
修复日志导入并完成仓库提交前检查
所有仓库hooks已在local通过。最后两处改动仅为日志器和格式,但仍将最终树同步到310P并重跑301项相关回归,再更新PR分支。
完成Git分支迁移、PR传输及NPU回归测试验证
最终hook修复后的精确分支已通过 301 passed、3 skipped。现在再次确认官方main未前进,随后更新两处远端并等待GitHub新的pre-commit结果。
审计并清理仓库后推送分支并检查CI
最终分支已同步到两处远端,HEAD为ceb4384b;DCO通过,双语文档重新构建中。GitHub的PR创建工作流仍需完成分类,之后才会启动正式pre-commit。
检查PR创建及CI与E2E工作流状态
最终分支的E2E工作流已创建,但仍在等待GitHub自托管runner;local同一套pre-commit已经全部通过。继续等官方runner接单,确认线上结果。
诊断并检查待处理的官方 CI 任务状态
官方E2E工作流停留在pending且没有生成任何job,这通常表示fork PR需要维护者批准Actions,而非代码或runner失败。先核对PR标签、机器人评论和当前合并状态,确认没有其它可由我们处理的阻断。
检查 PR 状态标签及 CI 审批阻塞
PR当前可合并,标签已正确生成,未发现新的结构性阻断。PR创建和文档链接检查已实际运行;E2E仍等待自托管runner。继续跟进到首轮线上静态检查落地。
检查并汇总PR工作流及CI状态
PR元数据、合并冲突检查和英文文档构建已通过;Markdown链接检查仍在运行。E2E仍无job,基本可确认在等待上游对fork Actions的首次批准。继续检查自动代码审查是否给出可处理意见。
检查了自动化审查反馈
自动审查给出5项有效意见,其中两项涉及注意力正确性/同步开销,另外三项是配置、转换工具和通用sharded-save兼容性。先逐项核对实现与现有测试,再集中修复并回复审查。
审查并修复DSA代码、元数据及预填充解码逻辑
5项审查意见均有依据。先确认普通310P分片保存原有元数据流程,避免修复DeepSeek标记时破坏其它模型;随后一次性补齐attention分类、配置契约、路径保护和回归测试。
完善了310P分片保存与量化元数据
普通310P原逻辑已确认:量化类型应来自quant_config,且不写DeepSeek marker。修复将把DeepSeek标记显式门控在“310P特性开启且模型类型为deepseek_v4”,普通模型恢复上游元数据语义。
测试了DeepSeek V4分片检查点门控逻辑
修复方案已收敛:decode统一长度和fresh-prefill均在CPU metadata builder中一次计算,attention层只读取布尔/整数标志;转换器增加祖先路径检查;普通sharded-save恢复上游量化描述,DeepSeek marker改为显式模型门控。
完善修改检查并补充DSA元数据测试
五项意见的代码与测试已落地。现在先跑格式、类型前置检查和新增定向测试;重点验证metadata字段在普通DSA构造路径中没有遗漏,并确认普通量化描述与DeepSeek marker行为分离。
运行 Ruff 检查并修复格式问题
静态审计通过,attention热路径已不再调用.item(),混合decode只有CPU metadata确认统一长度时才走向量化路径。下一步运行完整仓库hooks和新增定向测试,检查公共DSA metadata兼容性。
完成变更检查、修复同步、打包传输及NPU专项测试验证
定向测试唯一失败是测试文件在CPU镜像中直接导入NPUWorker310,触发缺失的ATB插件;实现本身未执行。将门控判断下沉为纯模型配置函数,在已有DeepSeek轻量测试中覆盖,避免为一个布尔判断引入worker运行时依赖。
迁移检查点门控并更新DeepSeek测试后重跑预提交检查
依赖问题已消除,全部hooks再次通过。NPU验证worktree会先重置到已提交HEAD,再覆盖当前11个修复文件,确保不残留上一轮测试改动。
完成修复同步、重新提取并通过针对性测试
定向测试已通过18项,剩余2项暴露了顶层参数名语义:上游普通元数据只对.weight/.bias键标记量化,而DeepSeek旧行为对全部整数张量标记W8A8。将两种规则分开,并用嵌套linear.weight验证普通路径。
调整量化参数逻辑并同步文件,执行传输回归与定向测试
新增定向回归 20/20通过。现在运行完整310P相关套件;通过后将修复分别压回目标运行时与文档/转换工具提交,再更新PR并逐条回复5项审查。
运行并检查 NPU 全量回归测试
完整回归通过:307 passed,3 skipped。修复增加6项测试。现在更新文档/PR测试计数,并将attention、环境变量、loader修复压回目标运行时提交;转换器路径保护压回文档/工具提交。
更新文档与测试计数并提交修复
4个逻辑提交与DCO保持不变。接下来对autosquash后的精确树运行全量hooks、确认官方main未前进,再做一次TP8/EP8启动与短请求冒烟,验证新增metadata字段在真实构造路径中生效。
验证同步、打包传输并完成完整回归测试
精确autosquash分支再次通过 307 passed、3 skipped。现在做最终实机冒烟:短暂停止稳定实例,加载审查修复后的TP8/EP8分支,验证prefill/decode metadata构造和API;结束后恢复稳定服务。
完成生产作业切换、硬件验证与恢复
开始最终实机闭环:切换到审查修复后的精确分支实例,验证真实prefill/decode路径;完成后立即恢复稳定生产服务。
停止CI监控并启动PR服务及健康检查
精确审查分支已开始8卡加载。首先观察最新metadata字段是否在worker构造阶段触发接口错误;若通过,再等目标与draft权重完成。
监控并检查模型服务初始化状态
新字段已顺利通过worker和backend初始化,未出现fresh_prefill或uniform_query_len接口错误;当前8个rank正在加载目标权重。
检查模型检查点加载及NPU服务启动状态
8卡显存持续增长、容器正常,尚未到loader完成日志;没有worker、attention或metadata异常。继续等最后加载阶段。
检查模型加载及容器启动监视器日志
审查修复后的target与draft已全部加载,耗时约476秒,KV容量203;真实metadata构造未报错。API正在完成最后启动阶段。
完成启动健康检查及终检烟雾测试与错误扫描
API已健康。正在用真实请求覆盖fresh-prefill、连续speculative decode和top-5 logprobs,并检查新增字段相关异常。
等待40秒并查看任务最新输出
最终实机冒烟通过:3次输出与spec路径完全一致,每次50 drafted/22 accepted;top-5 logprobs完整,健康200,错误数0。现在恢复稳定生产服务。
重启监控并恢复稳定生产服务
稳定服务正在恢复加载。并行完成PR更新:核对官方main和远端旧HEAD,使用lease保护从local推送最终4提交分支。
验证同步提交状态并推送租约保护分支
最终HEAD a33bc849 已从local同步到官方fork和项目仓库。现在更新PR正文,并逐条回复5项自动审查意见,说明修复位置和回归覆盖。
更新PR描述并整理代码审查评论
新一轮自动审查又补充了5项问题,均涉及真实部署契约:转换模式、EP拓扑、draft超时、显式KV预热和FP8适配器作用域。先逐项核对并补测试,暂不回复旧评论,避免遗漏。
修复转换器拓扑量化配置并扩展分片加载测试
第二轮修复方案确定:转换器显式强制eager模式;marker加入并强校验EP world size;preconverted模式也提前扩展ACL超时;显式KV仍执行profile预热;FP8/MXFP4适配器同时校验模型类型。
实现Dsv4适配器辅助函数并添加转换加载及FP8测试
第二轮修复和回归测试已加入。先跑仓库hooks与定向测试;若通过,再验证显式KV的profile_run()在真实DeepSeek服务上不会造成OOM或初始化回归。
执行第二轮修复、打包传输并完成定向测试
第二轮定向回归 13/13通过。现在运行完整310P相关套件,同时确认稳定生产服务恢复状态。
完成二次审查回归测试并检查生产监控
第二轮完整回归通过:311 passed,3 skipped。接下来更新测试计数、压回4个逻辑提交并运行全量hooks;随后用精确分支实测新增的显式KV profile_run() 和EP marker校验。
更新 DeepSeek V4 文档并完成主干回归与生产监控检查
稳定生产服务已恢复健康。最终4提交分支hooks通过;现在把精确autosquash树同步到310P,重跑311项回归,并为现有内部checkpoint补充新的EP=8 marker字段后做实机启动。
完成精确回归分支打包传输及测试验证
精确autosquash分支再次通过 311 passed、3 skipped。下一步迁移内部测试checkpoint marker,加入expert_parallel_size: 8,然后实测新增EP校验、扩展超时和显式KV profile预热。
检查并更新NPU测试标记及评审服务状态
最终实例已启动。前期重点看三项:EP=8 marker校验、preconverted模式是否提前设置1800秒ACL超时、FP8适配器是否仍正确识别DeepSeek V4。
等待分布式初始化并检查并发定时任务日志
EP marker校验已通过,preconverted模式也确实提前设置了1800秒超时。日志措辞仍显示“eager conversion”,先核对精确分支源码是否在autosquash时丢失了文案修改;功能条件已从实际行为确认生效。
核查310P超时文案及容器模型加载状态
已继续处理,当前状态如下。
已完成
上游PR已创建:
vllm-project/vllm-ascend#13705[Feature][Model] Add experimental DeepSeek V4 support for Ascend 310P
自动审查共提出10项问题,当前本地分支已全部修复,包括:
- 混合query长度不能误走统一decode路径
- prefill分类移至CPU metadata,删除逐层NPU
.item()同步 - 完整记录expert mode环境变量契约
- 禁止转换输出目录位于源模型目录内部
- 普通310P sharded-save不再写DeepSeek专用marker
- 转换工具显式启用
eager_w8a8 - checkpoint marker记录并校验EP world size
- preconverted target加载时也提前设置draft转换ACL超时
- 显式KV缓存配置仍执行
profile_run()预热 - FP8/MXFP4适配器仅作用于DeepSeek V4模型
当前本地最终分支:
aa658f4d docs(310p): document DeepSeek V4 deployment
28fd9d0b fix(310p): stabilize speculative logprobs
94d7fe6d feat(310p): support DeepSeek V4 DSpark decoding
afe3cf1b feat(310p): add DeepSeek V4 target runtime
仍为4个逻辑提交,DCO全部有效。
验证结果:
311 passed, 3 skipped
完整仓库pre-commit hooks全部通过,包括ruff、格式化、codespell、typos、gitleaks、logger规则和禁止导入检查。
内部测试checkpoint marker已安全迁移为:
{
"tensor_parallel_size": 8,
"expert_parallel_size": 8
}
旧marker已备份为:
dsv4_310p_w8a8.json.pre-ep-marker.bak
正在进行
精确最终分支的TP8/EP8实机实例正在加载。
目前已确认:
- EP=8 marker校验通过
- preconverted模式成功提前设置1800秒ACL执行超时
- DeepSeek V4专用FP8/MXFP4适配器选择正常
- 8个worker均已进入目标权重加载
- 暂无worker、AICore、拓扑或量化错误
尚未完成:
- 等待target和DSpark draft加载结束
- 验证新增
profile_run()不会造成OOM或启动回归 - 执行最终重复请求与logprobs冒烟
- 恢复稳定生产服务
- 将本地最终HEAD
aa658f4d从local推送到两个远端 - 更新PR正文测试数为311
- 回复全部10条自动审查意见
当前PR远端仍是上一版HEAD a33bc849,没有把未完成实机验证的第二轮修复提前推送。稳定生产服务目前为最终实机验证暂时停止。
第二十六阶段
继续完成第二轮实机验证、恢复生产服务,并在验证通过后从local更新PR分支和逐条回复审查。
目标权重已完成,draft权重正在加载。新增profile_run()尚未执行;继续观察其预热阶段是否引发显存或算子问题。
新增显式KV预热已真实执行并成功:加载447秒,预热后仍有足够显存,KV容量203,API健康200。现在做最终确定性、speculative decode与logprobs冒烟。
最终实机验证通过:3次输出和spec路径完全一致,每次50 drafted/22 accepted;top-5 logprobs完整,健康200,错误数0。立即恢复稳定生产服务。
稳定服务开始加载。并行修正唯一剩余的日志措辞,使其与“eager或preconverted resident模式均设置超时”的实际行为一致,然后更新最终4提交分支。
最终4提交分支已通过全部hooks和DCO检查,官方main未前进。现在从local用lease保护更新fork与项目远端。
远端已同步到最终HEAD e315beef。接下来更新PR正文为311项回归,并逐条回复10项审查意见,说明对应修复与测试覆盖。
10项审查意见已全部回复。现在尝试将对应线程标记为已解决,并检查新提交触发的CI及稳定生产服务恢复状态。
自动审查又新增3项有效问题:DSA backend模型作用域、DP场景下hash路由token ID对齐、转换器TP大小约束。先修复并补回归,再统一解决全部13个线程。
修复路径已确定:backend选择读取当前模型类型;310P hash router复用通用路由器的ID预处理;转换前直接从模型配置读取O-LoRA group数并要求TP完全一致。
稳定生产服务已恢复健康。继续修复新增3项审查问题,不再影响线上服务。
三项修复及对应测试已写入,静态格式检查通过。现在运行完整增量hooks和定向回归,重点验证平台选择器与DP hash路由上下文。
新增3项定向回归 15/15通过。继续跑完整310P相关套件;通过后更新测试计数并压回4个逻辑提交。
完整回归通过:314 passed,3 skipped。现在更新文档与PR测试计数,将三项修复压回对应逻辑提交,并重新生成精确4提交分支。
精确4提交分支已再次通过全部hooks、DCO和主线祖先检查。现在同步到310P验证仓库,重跑314项精确回归,再做真实TP8/EP8启动。
精确分支回归再次通过:314 passed,3 skipped。现在切换一次真实TP8/EP8实例,验证模型身份感知的backend选择与更新后的hash路由不影响现有部署;随后恢复稳定服务。
模型身份感知的backend选择已在真实worker路径成功执行,未出现配置上下文错误;当前进入8卡目标权重加载。
8卡容器持续运行,尚未到目标loader完成日志;当前没有backend、hash路由或拓扑异常。继续等待draft与预热阶段。
最终第三轮实机实例已健康:加载约449秒,backend选择、EP校验、draft转换和显式KV预热均正常。现在执行最终重复输出与logprobs冒烟。
第三轮最终实机验证通过:三次输出与spec路径完全一致,logprobs完整,健康200,错误数0。现在恢复稳定生产服务,再更新PR。
稳定服务正在恢复加载。并行从local核对最终HEAD、官方main和远端lease,随后更新两处远端与PR正文。
最终HEAD 9231404c 已从local同步到两处远端。现在更新PR为314项回归,回复新增3项审查并解决全部线程。
13个审查线程已全部回复并标记解决。最后核对新HEAD的CI、合并状态、是否出现新增审查意见,以及稳定生产服务健康状态。
13项审查均已解决,最终分支和PR正文已更新。当前只剩稳定生产服务恢复健康,以及新HEAD的CI和新增评论核对。
新HEAD当前可合并且无冲突;DCO、双语文档、链接检查和测试推荐均通过,官方pre-commit正在运行。继续核对是否出现第四轮审查意见。
发现1条遗漏的旧审查线程:ACL超时只校验正数,未限制uint32上界。修复范围很小,将补充1..4294967295契约和边界测试。
超时边界修复已通过全部hooks,正在310P环境执行新增边界测试和完整回归;生产稳定服务的恢复加载仍并行进行。
超时边界修复完整回归通过:315 passed,3 skipped。现在更新测试计数、压回首个运行时提交,并重新生成最终4提交分支。
官方main刚前进了2个提交,当前分支因此落后;尚未推送旧基线版本。现在先审查上游改动并重新变基,再重跑hooks与310P回归。
新上游仅涉及文档和CI,与本分支无文件重叠;变基已干净完成,全部hooks通过。现在在新main基线上重跑315项精确回归。
稳定生产服务已于21:11恢复健康。最新上游基线的精确回归仍在运行,完成后即可更新PR最终HEAD。
最新上游基线的精确回归再次通过:315 passed,3 skipped。现在从local用lease保护更新两处远端和PR。
第14条线程已回复并解决;PR现基于最新main,HEAD为528970e6。现在做稳定生产服务的最终短请求和错误扫描。
稳定生产服务已最终确认:短请求200、健康200、容器运行、错误扫描0,KV容量203 tokens。最后等待新HEAD线上pre-commit并检查新增审查。
自动审查又补充3项问题,均有依据:流式模式不应写预转换marker、feature gate需完整环境契约、eager target也应在加载draft前释放旧buffer。继续集中修复。
三项修复已通过全部hooks:marker仅限resident模式,feature gate契约完整,eager/preconverted均在draft前释放旧target buffer。现在进行310P完整回归。
三项修复完整回归通过:316 passed,3 skipped。现在按逻辑分别压回target运行时和DSpark提交,并更新PR测试计数。
最终4提交分支已通过DCO、全部hooks和最新主线检查。现在从local更新远端HEAD,并回复这3项审查。
当前17个审查线程已全部解决。新HEAD线上检查已触发,继续等待官方pre-commit并确认没有新增线程。
官方pre-commit失败,测试推荐已通过。现在读取失败日志;本地hooks全绿,因此大概率是CI环境特有检查或上游新规则。
线上失败来自4个mypy错误,不是运行测试:量化分支复用了不同类型的scheme变量,另有profiling路径把None传给严格类型签名。现在做纯类型修复并在CI同款mypy环境复现。
mypy修复已通过本地hooks。现在在官方310P镜像中复现CI的Python 3.10/3.11/3.12 mypy矩阵,并重跑完整回归。
310P运行镜像未预装mypy,因此复现命令本身失败于mypy: command not found,并非代码错误。先读取仓库锁定版本,在控制端准备离线wheel后注入同一镜像复测。
目录打包传输异常停在packing阶段;改用单个tar文件传输,避免继续等待。
离线wheel已传到机器,但目录权限为700,容器无法枚举,因此pip显示无可用版本。修正只读目录权限后重新运行同一矩阵。
独立bind mount在该自定义Docker daemon下不可见;将wheel复制到已验证可见的仓库挂载目录内,再从/work/.mypy-wheels安装。
原因确认:控制端下载的是x86_64 wheel,而310P主机为aarch64。改为下载CPython 3.12 aarch64 wheel后继续复现;代码尚未进入mypy执行。
已继续处理,当前状态:
- PR:
vllm-project/vllm-ascend#13705 - 当前远端HEAD:
4d926ded6449bfc14d2bcd939a2a50703503a505 - 已重新变基到最新上游
main:c134bb95b41b02115cc7c0d2584374b49cea2410 - 仍保持4个逻辑提交,DCO完整
- 310P完整回归:316 passed,3 skipped
- 本地全部pre-commit hooks通过
- 目前共17条审查意见,均已修复、回复并标记解决
- 稳定生产服务已恢复:
- 健康端点:200
- 短请求:200
- 容器:running
- KV容量:203 tokens
- 运行日志错误扫描:0
官方CI的pre-commit发现4个mypy问题:
- FP8线性与MoE分支复用了不同类型的
scheme变量 - 310P DSA profiling路径的
attn_metadata=None与基类类型声明不一致
这些问题已在local修复,并通过ruff、格式化和普通pre-commit检查。为复现CI的mypy矩阵,已准备并传输仓库锁定的mypy 1.11.1离线wheel;前两次执行失败分别因为:
- 310P镜像未预装mypy
- 最初下载的是x86_64 wheel,而310P环境为aarch64
兼容aarch64的纯Python wheel现已成功传到:
/mnt/caoyuhang/mypy-wheels-aarch64
尚未完成的最后步骤:
- 在310P镜像运行Python 3.10、3.11、3.12 mypy矩阵
- 重跑316项回归
- 将mypy修复压回4个逻辑提交
- 从local更新两处远端和PR
- 确认官方
pre-commit转绿,并再次检查是否产生新审查意见
当前未将未经mypy复验的修复推送到PR。
第二十七阶段
后续AI审查只按“是否存在真实正确性、兼容性或维护性风险”处理;纯风格、过度推断或缺乏证据的意见会直接说明并resolve,不再机械采纳。
执行并监控 aarch64 多版本 Mypy 类型检查矩阵
mypy正在正常运行,当前Python 3.10全树检查占用CPU约93%,不是卡死。完成三个版本后再进入回归和提交整理。
等待类型检查矩阵完成并查看最新输出
这次mypy失败不代表代码有问题:CI依赖一个额外检出的vllm-empty源码树,而当前验证工作区没有它,因此出现1332个全局vllm.*导入错误。先复现CI的checkout布局,再只判断真实类型错误。
检查 CI 依赖并获取压缩指定 vLLM 提交
已获取CI固定的vLLM源码提交。下一步不再依赖运行镜像里缺失的类型依赖,优先在local构建与官方lint镜像等价的mypy环境;这能更直接复现线上4个错误是否已消失。
检查了 lint 依赖、Mypy 配置及控制器 Python 环境
控制端缺少PyTorch,不适合直接跑全树mypy。采用更接近官方CI的方式:把固定vLLM源码和lint依赖注入现有310P镜像,保留镜像内Torch/vLLM运行依赖。
完成跨架构 Mypy 资源准备并运行类型检查矩阵
精确布局后只剩5个环境差异错误:运行镜像缺少triton类型包和types-psutil,已不再出现此前4个PR类型错误。补齐这两个CI镜像依赖后再跑完整三版本矩阵。
检查 Triton 依赖并完成 Mypy CI 验证
Python 3.10已完成vllm_ascend和examples,当前在检查tests,说明此前4个源码类型错误已经消失。继续等3.10/3.11/3.12全部结束。
等待 Mypy 测试矩阵完成并读取任务输出
源码部分已在Python 3.10下全量mypy通过。剩余7项中,4项是验证镜像缺少测试依赖;3项来自本PR新增测试,属于真实CI阻断,直接修复。
修复测试类型与依赖问题并重跑检查
剩余4项均来自运行镜像缺少测试依赖,与PR无关。使用local-only类型桩补齐pytest_mock、sentence_transformers和jsonschema,不修改仓库内容,然后重跑完整矩阵。
创建依赖存根并完成多目标 Mypy 类型检查
这两项是我写的本地sentence_transformers桩过度具体导致的伪错误,仓库代码没有问题。将该环境桩改为Any后继续矩阵。
放宽本地类型存根并验证测试环境】【。
Python 3.10的整个tests树已通过mypy(524 files)。现在跑完整3.10/3.11/3.12矩阵,随后重跑316项回归。
完成 Python 矩阵类型检查并确认 mypy 进程
3.10整套已通过;3.11也已完成源码和examples,当前在tests阶段。剩余3.12后即可结束类型检查。
检查并等待 Python 测试及 MyPy 矩阵进度
完整mypy矩阵已通过:Python 3.10、3.11、3.12下,vllm_ascend 474个文件、examples 36个文件、tests 524个文件全部无问题。现在重跑310P相关回归。
监控回归测试并读取最新输出
类型修复后的完整310P回归仍为 316 passed,3 skipped。接下来只做提交历史整理和线上CI验证,不再重启实机服务。
运行预提交检查并提交修复重放
mypy修复已压回原有逻辑提交,历史仍为4个DCO提交。现在检查官方main是否前进,并对精确autosquash树再跑全部hooks。
核验更新并推送分支验证同步
最终HEAD 080e8d8f 已从local同步到两个远端,PR仍保持Draft。现在等待官方pre-commit复验,并检查是否产生新的AI审查意见。
检查草稿PR与CI结果并验证生产服务健康状态
生产服务保持健康:HTTP 200、容器running、近30分钟错误数0。官方CI已排队,等待pre-commit和mypy线上结果。
检查 CI 状态并审核未解决线程
新出现4条AI意见中,3条属于真实隔离性问题,准备采纳:deterministic仅作用于DeepSeek V4、补完整环境契约、shared-expert fallback限制模型类型。逐层CPU元数据转换属于当前禁用路径的性能优化,将说明范围后直接resolve,不扩张本PR。
完成DeepSeek V4隔离配置与共享专家修复
三项隔离性修复已落地并通过静态检查。现在同步到310P验证环境,先跑determinism/shared-expert定向测试,再跑完整回归和三版本mypy。
完成模型作用域修复并运行定向确定性测试
定向测试 16/16通过。现在执行完整310P回归;预计因新增3个模型隔离用例,测试计数从316增至319。
运行回归测试并检查 Mypy 与任务输出
完整回归通过:319 passed,3 skipped。继续跑三版本mypy矩阵;通过后更新文档计数、压回4个逻辑提交并更新Draft PR。
运行多版本 Mypy 矩阵并查看最新输出
三版本mypy再次全绿。现在更新验证计数为319,将模型隔离修复压回首个运行时提交,并保持PR的4提交结构。
更新测试计数并压缩提交修复
模型隔离修复已压回首个提交,历史仍为4个DCO提交。现在检查最新上游并验证精确autosquash树。
同步上游并变基后运行钩子,强制推送分支
最终HEAD 61e294e9 已推送。现在更新PR正文,并按选择性审查原则处理4条意见:采纳3条隔离性修复;对当前禁用路径的性能优化明确说明范围后直接resolve。
更新PR描述并回复审查线程,检查CI状态
4条线程已全部处理并resolve,其中1条明确不采纳。现在只剩线上CI与是否出现新审查意见的核对。
检查官方CI、端到端工作流及未解决审查线程
当前21条审查线程全部已解决,没有新意见。CI仍是平台队列状态,代码侧所有本地等价检查已通过;继续排查是否被旧workflow并发占用。
检查了分支工作流运行状态
发现上一版HEAD仍有3个过期workflow处于queued状态,可能占用同一分支的并发队列。先取消这些旧运行,只保留最新61e294e9的检查。
取消过时工作流以清理队列
旧workflow无法由外部贡献者取消(GitHub返回403),只能等待上游队列自行淘汰。代码和审查侧已完成,继续观察最新HEAD的官方pre-commit是否接单。
检查并等待 CI 与重试队列运行结果
官方队列两分钟未变化,且旧HEAD的过期任务也未被自动取消;这属于上游Actions调度问题。继续读取run元数据,确认是审批等待、并发锁还是runner短缺。
诊断 GitHub Actions 工作流队列状态
E2E run显示pending且没有生成任何job,符合外部贡献者workflow等待维护者批准;其它workflow是普通runner队列。代码侧无法推进该平台状态,先把验证环境同步到最终HEAD并清理临时资产。
创建并转移最终PR代码包,获取补丁并清理验证资源
NPU验证worktree已干净同步到最终HEAD。清理共约20余MB的临时bundle、review tar包和mypy依赖,不影响生产模型或仓库。
清理临时资源并验证仓库状态
本地与NPU验证环境均已清理,两个远端和验证worktree统一到61e294e9。再确认workflow是否因Draft条件主动跳过,而不是实际runner故障。
检查工作流是否受草稿状态限制
继续跟进Draft PR的线上状态;代码、回归、mypy和审查均已收敛,现在只处理新出现的有效问题或确认平台队列阻断。
检查了 PR 状态与未解决审查线程
上游队列开始推进:合并冲突检查已通过,21条审查仍全部resolved。E2E仍处于外部贡献者审批前的pending/no jobs状态;继续等待文档与PR元数据检查。
等待工作流完成并检查PR与端到端测试进度
PR元数据工作流已开始运行;文档链接检查仍排队,E2E仍等待审批。继续等可由平台自行完成的检查收敛。
检查PR状态并等待工作流完成
PR元数据、冲突检查、DCO和双语文档构建均已通过;自动标签已生成。只剩Markdown链接检查排队,以及需维护者批准的E2E工作流。
检查文档并确认 PR 审核状态
Markdown链接检查已开始运行;审查线程仍为21/21 resolved。等该检查结束后,平台侧将只剩维护者批准E2E。
检查文档链接并确认端到端测试状态
链接检查仍在执行,没有失败信号;继续等结果。E2E仍明确为pending且jobs为空。
检查 Markdown 链接验证结果
维护者审批已通过,E2E正式生成jobs;官方pre-commit与测试推荐正在运行。重点等待线上mypy矩阵确认。
确认官方E2E、预提交与覆盖率任务状态
E2E已获批准,但两个jobs仍在上游自托管runner队列,尚未执行。继续等runner;本地等价pre-commit与mypy已全绿。
检查官方作业运行器需求
两个任务都在等待同一linux-amd64-cpu-8-hk自托管runner池,runner尚未分配;这是纯队列等待。继续跟进到pre-commit落地。
检查官方CI作业状态并等待共享运行器容量释放
runner池开始释放容量:测试推荐已运行,pre-commit仍排队。继续等待pre-commit分配runner。
检查CI运行状态并等待测试完成
测试推荐已通过;只剩官方pre-commit等待同一runner池。继续等其启动并读取线上mypy结果。
检查官方预提交任务运行状态
pre-commit仍未分配runner。检查上一HEAD的遗留E2E是否在同一池前排队,判断还需经过多少旧任务。
比较过时与当前的端到端任务
上一HEAD遗留E2E已全部结束,不再阻塞;当前pre-commit单纯等待上游CPU runner。继续跟进。
检查最终官方预提交任务状态
官方pre-commit已开始执行。等待其完成;若失败,只处理真实代码问题,环境或过度审查问题不扩大范围。
监控并检查官方预提交结果
官方pre-commit已通过,包括线上三版本mypy。现在只剩测试选择器;由于PR保持Draft且没有ready标签,重型E2E预计会按仓库策略跳过。
检查PR工作流并等待测试选择完成
官方Draft工作流已全部成功:pre-commit、线上mypy、测试选择、文档链接和推荐分析均通过;重型E2E按无ready标签的WIP策略正确跳过。最后核对审查、仓库和生产服务。
验证评审线程、PR、生产环境及本地工作区状态
已继续完成,当前达到稳定的 WIP / Draft PR 状态。
PR状态
- PR:
vllm-project/vllm-ascend#13705 - Draft:保持开启
- 最终HEAD:
61e294e9f09ced18c493165db301c453f522e441 - 基于最新上游:
c134bb95 - 可合并、无冲突
- 本地、官方fork和项目仓库三处HEAD一致
- 工作区干净
- 仍保持4个DCO逻辑提交
官方CI
已通过:
- 官方
pre-commit - 官方Python 3.10 / 3.11 / 3.12 mypy
- DCO
- Markdown链接检查
- 中英文Read the Docs
- PR标题与元数据检查
- 合并冲突检查
- 测试范围选择
- HiTest推荐与失败分析流程
重型selected E2E被跳过,原因是PR仍为Draft且没有ready标签,符合仓库工作流策略。
验证结果
- 310P相关回归:319 passed,3 skipped
- mypy:
vllm_ascend:474个文件- examples:36个文件
- tests:524个文件
- Python 3.10、3.11、3.12全部通过
- 所有本地pre-commit hooks通过
AI审查处理
共21个审查线程:
- 已解决:21
- 未解决:0
最后4条中:
- 采纳3条真实模型隔离问题
- 拒绝1条当前不支持路径的性能扩展建议,并说明范围后resolve
没有机械采纳全部AI意见。
生产服务
- API健康检查:HTTP 200
- 容器:running
- 最近60分钟相关错误:0
- NPU验证worktree:干净且与PR HEAD一致
当前PR已经适合作为WIP交给维护者提前查看;在改回Ready之前,不会触发仓库要求的重型E2E测试。