截至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、postcomb 的精确公式。

已经完成并实机验证

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;这次应同时越过 w13w2 的 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_int64weight_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 秒

当前运行状态

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 个本地专家的 w13w2 从 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_awo_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 构造运行参数时漏传 activationswiglu_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 运行参数传递 activationswiglu_limitswiglu_alphaswiglu_beta
    • 310P MoE MLP 增加与官方公式一致的限幅 SwiGLU。
    • 保留之前修复的 token-ID 哈希专家路由。
  • 联合目标测试: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模型

共享专家缩放修复仍未恢复输出。现在转向两个尚未验证的高风险点:

  1. 压缩层的 DSA fallback 忽略了短上下文中的压缩 KV;
  2. LM head 可能被错误套用 W8A8,导致隐藏状态正常但词表行映射/数值错误。先核对量化规则和 head 权重加载。

检查了量化配置与模型层信息

已定位到高度确定的根因:FP8 配置把 BF16 的 head.weight 也误当作 FP8 线性层转换。checkpoint 没有 head.scale,因此 LM head 的 weight_scale 未加载、保持未初始化值;这会直接把正常隐藏状态映射成随机词表 logits,完全符合当前乱码现象。现在改为 310P 上 LM head 保持非量化。修复并验证DeepSeek量化配置及任务输出

checkpoint 已确认:head.weightBF16 [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 缓存残留。
  • 已分别对 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,确认:

  1. 日志显示实际 swiglu_limit=10.0
  2. layer0 SwiGLU 输出不再达到 ±65504
  3. layer1 及后续层解除 FP16 饱和。
  4. 两次首 token 和 logits 恢复确定性。
  5. 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_outshared_out,随后再缩放相加。下一轮探针将直接打印 layer40 两支输出;同时先比较 39/40/41 层原始专家和共享专家 scale,判断是否为单层权重异常。检查并比较DeepSeek-V4 MoE专家权重缩放分布

原始 scale 分布显示 layer40 并无异常指数;相邻层专家 scale 同量级。进一步直接解码 39/40/41 层共享专家,计算其网络增益,判断爆炸是否来自共享支路本身。计算了共享专家层前向增益

软件精确前向显示 layer40 共享专家输出 RMS 约 1.23,与相邻层一致,因此 checkpoint 本身正常。接下来直接探测运行时 routed_outshared_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_outshared_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,并使生成结果乱码。
  • 根因是 rfork 后 FusedMoEConfig.ep_rank 保留父进程的 rank 0。
  • 已修复:
    • 初始化 routed experts 时使用实时 get_ep_group().rank_in_group 刷新配置。
    • AscendRoutedExperts.ep_rank 改为读取实时 EP group rank。
    • 新增回归测试,相关测试 36/36 通过
  • 发现第一次验证时部署脚本没有覆盖修改后的 routed_experts.py;现已补入覆盖清单。
  • v50 已确认容器内实际包含 sync_live_ep_rank 修复。
  • 当前 v50 已完成 48 个权重分片读取,正在执行八卡 MXFP4 → W8A8 专家转换,暂未出现异常。

尚未完成的最终验证:

  1. 确认八个 rank 分别贡献各自专家结果。
  2. 确认 layer40 MoE 不再爆炸。
  3. 执行 48-token 中文生成,检查是否恢复正常文本。
  4. 再做两次相同请求的确定性测试。

第十阶段

继续完成 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_table
  • slot_mapping
  • input_positions
  • query_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/格式工具,若环境也缺失则至少完成 compilealldiff --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,计算量很小,但每层都需要:

  1. 从 NPU 同步少量元数据到 CPU
  2. Python 分支和循环
  3. 启动多个小 NPU 算子
  4. 等待结果
  5. 再进入下一层

这正好解释了为什么 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 和通信调度。

优化优先级应当是:

  1. 去除 DSA 每层的 CPU 同步和 Python 循环,改成纯设备端批量实现。
  2. 实现 310P DSA/MLA 融合 kernel。
  3. 融合 MoE dispatch、GMM、SwiGLU、combine。
  4. 开启图编译,消除 --enforce-eager
  5. 启用或自行实现 fused MC2。
  6. 修正 NUMA/CPU affinity。
  7. 压缩模型驻留显存,扩大 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 解码图及模型容器日志

已开始实施优化,当前完成的是第一阶段代码和兼容性改造。

已完成

  1. Decode attention 设备端向量化
    • 消除了每层 to(cpu) / tolist / item 和逐 token Python 循环。
    • 支持普通单 token decode 和 MTP 的双 token decode。
    • 与旧实现数值逐元素一致。
    • 单层微基准约从 4.04 ms 降至 3.98 ms。收益较小,确认 attention 元数据同步不是主要瓶颈。
  2. MTP speculative decoding 适配
    • 模型自带一层 MTP,已配置为每轮预测 1 个额外 token。
    • 修复 MTP 三维候选张量与 310P W8A8 线性不兼容的问题。
    • 通用和 310P 专用 W8A8 现在都会展平前导维执行量化 GEMM,再恢复原始形状。
    • 相关 mock/功能测试通过。
  3. Decode-only ACL Graph 适配
    • 配置为只捕获 batch size 1、2 的 decode 图,不编译 prefill。
    • 修复图捕获 dummy metadata 无有效 slot 时,无法推断 hybrid block 几何的问题。
    • 现在从静态 block-table shape 推导 16 倍逻辑块拆分。
  4. 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_select68.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.pytest -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() 返回才清理
  • 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_projh_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 KV 预计算,随后发现 310P 不支持硬件 interleave RoPE。
  • 现已复用 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.weightmtp.*.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 主干隐藏状态,重点包括:

  1. main_proj 的 FP8→W8A8 数值。
  2. 三层 DSpark Decoder 的输出。
  3. 非因果 SWA attention 输出。
  4. 最终 Hyper-Connection head 输出。
  5. 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模型加载状态

分析已暂停

继续适配后取得了两个关键进展。

已修复

  1. DSpark KV slot 越界
    • 修正 hybrid block table 的逻辑块与物理块换算。
    • 消除了 GatherV2 / DDR address out of range 崩溃。
    • 相关测试 30 项通过。
  2. DSpark 原始专家权重布局误判
    • 目标模型使用预转换 W8A8,但 DSpark 草稿模型仍从原始 MXFP4 checkpoint 加载。
    • 已改为根据权重和 scale 的实际形状、dtype 判断是否预转换,不再只依赖全局环境变量。
  3. 找到并修复 E8M0 scale 损坏的直接原因
    • 原始 scale 的 E8M0 exponent byte 为 120–126
    • 加载器错误地先将它们 view(uint8),再复制进 float8_e8m0fnu 参数。
    • 这会发生数值转换,所有字节都被舍入成 134,解码结果统一为 128
    • 因而运行时所有 expert row scale 都变成: 6 × 128 / 127 = 6.04724
    • 这正是 GMM2 溢出并产生 NaN 的原因。

现在改为:

  • 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/s36.8%
基线首轮3.173 tok/s41.3%
基线重复3.448 tok/s42.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=1
    • max_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创建时同步到了更新的maindab1c351),比本地先前基线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修复。

合并路由专家冲突并完成变基验证

分支已重新基于当前官方maindab1c351),只需解决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、越界、NonzeroV2IndexPutV3错误

尚未完成

最终 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_prefilluniform_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
  • 已重新变基到最新上游 mainc134bb95b41b02115cc7c0d2584374b49cea2410
  • 仍保持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;前两次执行失败分别因为:

  1. 310P镜像未预装mypy
  2. 最初下载的是x86_64 wheel,而310P环境为aarch64

兼容aarch64的纯Python wheel现已成功传到:

/mnt/caoyuhang/mypy-wheels-aarch64

尚未完成的最后步骤:

  1. 在310P镜像运行Python 3.10、3.11、3.12 mypy矩阵
  2. 重跑316项回归
  3. 将mypy修复压回4个逻辑提交
  4. 从local更新两处远端和PR
  5. 确认官方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_ascendexamples,当前在检查tests,说明此前4个源码类型错误已经消失。继续等3.10/3.11/3.12全部结束。

等待 Mypy 测试矩阵完成并读取任务输出

源码部分已在Python 3.10下全量mypy通过。剩余7项中,4项是验证镜像缺少测试依赖;3项来自本PR新增测试,属于真实CI阻断,直接修复。

修复测试类型与依赖问题并重跑检查

剩余4项均来自运行镜像缺少测试依赖,与PR无关。使用local-only类型桩补齐pytest_mocksentence_transformersjsonschema,不修改仓库内容,然后重跑完整矩阵。

创建依赖存根并完成多目标 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测试。

Castronaut的头像

作者 Castronaut

行走在地狱边缘,狂舞于悬崖之巅。

发表回复