【免费下载链接】cannbot-skillsCANNBot 是面向 CANN 开发的用于提升开发效率的系列智能体本仓库为其提供可复用的 Skills 模块。项目地址: https://gitcode.com/cann/cannbot-skillsname: model-infer-runtime-debug description: 基于 PyTorch 框架的昇腾 NPU 模型推理运行时错误诊断与修复技能。系统化排查模型加载、初始化、推理执行全链路的运行时错误包括 aicore timeout、HCCL 通信错误、OOM、算子约束违反、推理卡住等。触发场景NPU 运行时错误RuntimeError、aicore timeout 507014、HCCL timeout、device synchronize 失败、kernel crash、EZ9999/EE9999 错误码、推理过程卡住不返回、权重加载阶段 crash、模型加载成功但 forward 失败、分布式推理某些 rank 挂死等。NPU 推理运行时错误诊断与修复核心理念先定位再修复。不覆盖精度问题精度调优见 model-infer-precision-debug。 —— 通过二分法逐步缩小故障范围避免在错误方向浪费时间。诊断路径总览问题发生 │ ├── 有明确错误信息 → 通用诊断流程 │ ├── aicore timeout (507014) → 二分法定位 │ │ ├── 定位到阶段 → 层 → 模块 → 算子 │ │ └── 查表「常见算子约束」→ 修复策略 → 验证 │ ├── OOM → 检查参数量 / batch_size / seq_len / 中间 buffer │ ├── Shape 不匹配 → 检查 TP/EP 切分维度 / Prefill vs Decode 分支 │ └── HCCL timeout → 检查各 rank 代码路径一致性 / 通信组创建 │ └── 无明确错误 → npu-smi 状态检查 ├── 部分 rank 缺失 / HBM 不均 → 多卡部署诊断 │ ├── 权重加载 crash → TP 切分越界 / vocab pad │ ├── Config 字段缺失 → Config 兼容性 │ └── 静默失败 → 逐 rank 检查日志 ├── 有进程 HBM 不变 CPU 100% → 推理卡住诊断 - 模型构造阶段 ├── 有进程 HBM 不变 CPU 0% → 推理卡住诊断 │ ├── 检查残留进程 │ ├── eager 也卡 → syncprint 定位通用流程第二步 │ └── 仅 graph 卡 → 比较 eager/graph 代码路径差异 └── 0 进程 → 查 rank 0 日志 → 通用诊断流程npu-smi 状态检查当没有明确错误信息时通过设备状态判断问题类型npu-smi infonpu-smi 表现含义诊断路径前 N 进程存在后面缺失HBM 不均高位 rank 在权重加载时 crash→ 多卡部署诊断8 进程HBM 均匀AICore 全 0%所有 rank 卡在通信等待→ 推理卡住诊断有进程HBM 不变 ~3GBCPU 100%CPU 密集操作模型构造/权重初始化→ 推理卡住诊断 - 模型构造阶段有进程HBM 不变 ~3GBCPU 0%死锁/通信等待→ 推理卡住诊断8 进程HBM 持续增长权重加载中等待0 进程全部 crash查 rank 0 日志 → 通用诊断流程通用诊断流程适用于有明确错误信息的场景aicore timeout、HCCL error、OOM、shape mismatch 等。按分类 → 定位 → 查表 → 修复 → 验证线性推进。第一步错误分类拿到错误信息后先判断属于哪一类。不同类别的根因和排查路径完全不同分类错误会浪费大量时间。A. aicore timeout错误码 507014特征AclrtSynchronizeDeviceWithTimeout、error code is 507014、aicore timeout、fftsplus aivector error、Kernel task happen error, retCode0x25含义某个 NPU 算子在设备上执行时超时未返回。这是最常见也最难排查的错误因为报错的位置synchronize 调用处通常不是出错的位置某个具体算子。常见根因算子入参违反硬件约束如 MC2 要求 ep_world_size 16见「常见算子约束」算子 shape 超出硬件限制如单次 matmul 的 M/N/K 维度超限死锁部分 rank 走了不同的通信路径导致集合通信永远等不齐内存越界slot_mapping/block_table 索引超出 KV cache 分配范围B. HCCL 通信错误特征HCCL_CONNECT_TIMEOUT、HCCL error、AllReduce/AllToAll timeout、HCCL_EXEC_TIMEOUT含义分布式通信操作超时或失败。常见根因各 rank 进入通信操作的顺序/次数不一致代码分支导致部分 rank 跳过某次通信通信组创建时参数错误group_stride、group_num 不匹配 world_size网络问题跨节点时 HCCL_IF_IP 配置错误某些 rank 已经 crash 但其他 rank 还在等它参与通信C. OOM显存不足特征NPU out of memory、Tried to allocate X GiB、ENOMEM含义NPU HBM 不够。常见根因模型参数/KV cache/activation 总和超过单卡显存中间 tensor 未及时释放常见于 MoE EP all-to-all 中间 bufferbatch_size 或 seq_len 超出预期D. Shape 不匹配特征RuntimeError: shape mismatch、expected size X but got Y、mat1 and mat2 shapes cannot be multiplied含义tensor 维度不对。常见根因TP 切分后维度未正确除以 tp_sizeEP 切分后每卡专家数计算错误Prefill/Decode 分支传入了错误 shape 的 tensorE. 算子约束违反特征不直接报约束错误通常表现为 aicore timeout 或 SIGABRT。需要通过二分法定位后查阅算子文档确认。含义NPU 自定义算子对入参有隐含约束数据类型、维度范围、硬件平台限制违反时行为未定义。第二步二分法定位syncbarrier 检查点法核心方法。当错误发生在torch.npu.synchronize()时错误信息只告诉你设备上有东西出错了不告诉你具体哪个算子。通过插入检查点逐步缩小范围。2.1 定位到阶段Prefill vs Decode在 runner 的model_inference方法中prefill 和 decode 调用之间插入同步检查# 在 prefill 之后、decode 之前 torch.npu.synchronize() logging.info(prefill passed)关键陷阱NPU 操作是异步的。model.prefill()返回不代表 prefill 完成 —— 只有torch.npu.synchronize()返回才代表所有已提交的操作完成。所以报错位置synchronize 调用处不一定是出错位置某个具体算子。确保检查点覆盖所有可能的异步操作。2.2 定位到层确认出错阶段后如 Decode在每个 decoder layer 之间插入检查点for i, layer in enumerate(self.layers): hidden_states layer(hidden_states, ...) torch.npu.synchronize() logging.info(flayer {i} passed)如果 Layer 0 就超时 —— 问题在第一层内部。如果 Layer 2 超时 —— 问题在第 2 层或其子模块。2.3 定位到模块进入出错层在各子模块之间插入检查点# 在 DecoderLayer.forward 中 hidden_states self.input_layernorm(hidden_states) torch.npu.synchronize(); logging.info( norm passed) hidden_states self.self_attn(hidden_states, ...) torch.npu.synchronize(); logging.info( attention passed) hidden_states self.mlp(hidden_states) # MoE torch.npu.synchronize(); logging.info( MoE passed)2.4 定位到算子进入出错模块在每个 NPU 算子调用之间插入检查点。此时通常可以定位到具体算子及其入参结合下文「常见算子约束」判断根因。2.5 注意事项先用torch.npu.synchronize()做单卡定位确认是哪个算子出错。不要一开始就加dist.barrier()——barrier 会在某 rank 已崩溃时导致其他 rank 永久挂起怀疑多 rank 不同步时用dist.barrier()或torch.distributed.monitored_barrier()确认各 rank 是否走到同一位置。monitored_barrier在超时后会报告哪个 rank 未到达查看所有 rank 的日志确认各 rank 到达的检查点是否一致不一致说明有条件分支差异 → 通信死锁不要一次插入太多检查点—— 每次 sync 有开销且大量 sync 可能改变时序。先粗粒度再细粒度保留日志把每轮定位的检查点输出保存供后续分析第三步常见 NPU 算子约束速查以下约束来自本仓实际调试经验定位到具体算子后应回到当前调用的 API 签名和官方文档核对不要跨算子套用规则。违反约束的典型表现是 aicore timeout。MoE 相关算子算子约束违反表现解决方案npu_moe_distribute_dispatch_v2(MC2)Atlas A2:ep_world_size须为 {16,32,64,128,256}fullmesh或 {16,32,64}hierarchyaicore timeoutDecode 阶段挂死EP16 时回退到 double_routing 路径npu_moe_init_routing_v2 manual all_to_allnpu_moe_distribute_combine_v2(MC2)同上同上同上npu_moe_init_routing_v2无 EP 最小限制但moe_chunk_max_len为 0 可能导致空 tensorSIGABRT 或 shape error设置合理的 moe_chunk_max_len如 1024npu_moe_gating_top_kk不能超过专家总数静默错误输出或 crash检查 reduced model 的 moe_topk 是否已调整FA (Flash Attention) 算子约束说明head_num须匹配实际 Q headsMLA 模型中 head_num num_attention_heads不是 kv_headsPrefillsparse_mode3需配合atten_maskmask shape 须为[1, 1, max_s, max_s]不能省略input_layout按 API 和阶段区分npu_fusion_attention用 BSH/SBH/BSND/BNSD/TNDnpu_fused_infer_attention_score用复合 layout 如 TND_NTD、BSND_NBSD以实际 API 签名为准Decode PA 模式下block_tableshape[batch, max_blocks]值不能超出 cache 分配的 block 数NZ 格式 cache需要torch_npu.npu_format_cast转换且 hidden_dim 须为 16 的整数倍actual_seq_lengths相关参数以当前调用算子的签名与官方 API 文档为准不跨算子套用规则torch_npu.npu_fused_infer_attention_score/torch_npu.npu_fusion_attentionactual_seq_lengths*为List[int]文档为 int64 语义torch_npu.npu_kv_quant_sparse_flash_attentionactual_seq_lengths_query/kv为Tensor文档为 int32通信算子约束说明all_to_all_single的 split sizesinput_splits 和 output_splits 之和须分别等于 input 和 output 的第 0 维通信组内所有 rank 须同时到达任何条件分支差异都可能导致部分 rank 跳过通信 → 死锁HCCL group 创建顺序所有 rank 须以相同顺序创建相同的通信组第四步修复策略模式定位根因后选择合适的修复策略。模式 1算子回退Operator Fallback当某个高性能算子在当前硬件/配置下不可用时回退到功能等价但限制更少的替代算子。# 示例MC2 MoE 算子 EP16 时回退到 double_routing def forward(self, hidden_states, is_prefill): topk_indices, topk_weights, _ self.router(hidden_states) if is_prefill: return self.moe_infer_double_routing(hidden_states, topk_indices, topk_weights) else: if self.moe_ep_size 16: # MC2 requires ep_world_size 16 on A2; fall back to double_routing return self.moe_infer_double_routing(hidden_states, topk_indices, topk_weights) return self.moe_infer_dispatch_combine(hidden_states, topk_indices, topk_weights)适用场景硬件约束、EP/TP size 不满足算子要求注意回退通常有性能损失需记录在优化报告中模式 2参数修正Parameter Fix算子入参计算错误如 FAhead_num用了 KV heads 而非 Q heads、TP 切分后维度未除以 tp_size。定位到具体算子后逐个核对入参与算子文档/参考模型的差异。适用场景shape 不匹配、dtype 错误、维度计算错误模式 3路径统一Path Unification部分 rank 走不同代码路径导致通信死锁。# 错误不同 rank 可能在不同 step 进入 prefill/decode if is_prefill: self.all_reduce(...) # rank 0 执行 # rank 1 已进入 decode不执行 all_reduce → 死锁 # 修复确保所有 rank 同步状态后再分支 dist.barrier() is_prefill_tensor torch.tensor([int(is_prefill)], devicenpu) dist.broadcast(is_prefill_tensor, src0) is_prefill bool(is_prefill_tensor.item())适用场景多 rank 死锁、HCCL timeout模式 4配置降级Configuration Downgrade配置组合不兼容时调整 YAML 参数如降低moe_chunk_max_len、减小batch_size。适用场景OOM、性能异常第五步验证清单修复后按以下清单验证单步验证在出错位置前后加 syncbarrier确认不再超时全流程验证移除所有调试检查点运行完整 warmup inference全 rank 验证检查所有 rank 的日志确认全部成功grep model run success log_*.log输出一致性各 rank 的最终输出应一致对 DP 模式同 DP group 内的 rank 输出应一致性能记录记录修复后的 Prefill/Decode 耗时与修复前对比回退文档如果使用了算子回退记录性能影响和未来可恢复条件特定场景诊断以下场景有独立的诊断路径不走通用流程。通过入口 npu-smi 表判断后直接跳转。多卡部署诊断多卡部署引入了一类单卡不存在的问题权重加载切分、vocab 对齐、部分 rank 崩溃、config 兼容性。共同特点部分 rank 成功、部分 rank 失败错误出现在权重加载阶段而非 forward 阶段。权重加载 TP 切分越界典型错误RuntimeError: start (105984) length (35328) exceeds dimension size (131125)或ValueError: 131125 is not divisible by 8根因ColumnParallelLinear / VocabParallelEmbedding 将权重沿 output 维度切分为 tp_size 份。如果 checkpoint 的实际维度不等于模型参数的维度或者不能被 tp_size 整除高位 rank 的narrow()操作就会越界。常见场景场景说明修复多模态模型文本推理embed_tokens用 full vocab (282624) 但lm_head用 textspecial (131125)两者维度不同lm_head 单独使用text_vocab_plus_multimodal_special_token_sizevocab 不整除 tp_size131125 % 8 ≠ 0向上 pad 到最近的 tp_size 倍数padded ((raw tp - 1) // tp) * tppadded 参数 vs 原始 checkpoint模型参数 131128padded但 checkpoint 权重只有 131125加载时先 pad checkpoint weight 再传给 weight_loader修复模板vocab pad weight pad# 1. 创建 lm_head 时 pad vocab size lm_head_raw getattr(config, text_vocab_plus_multimodal_special_token_size, config.vocab_size) self.lm_head_vocab_size ((lm_head_raw tp_size - 1) // tp_size) * tp_size # 2. 加载权重时 pad checkpoint tensor if lm_head in name and loaded_weight.shape[0] self.lm_head_vocab_size: padded torch.zeros(self.lm_head_vocab_size, *loaded_weight.shape[1:], dtypeloaded_weight.dtype, deviceloaded_weight.device) padded[:loaded_weight.shape[0]] loaded_weight loaded_weight padded排查技巧如果只有高位 rank (rank 3-7) crash 而低位 rank (0-2) 正常几乎一定是切分越界 —— 因为低位 rank 的start_idx还在合法范围内。Config 兼容性问题从 HuggingFace 原始模型加载时config.json 可能缺少代码期望的字段或字段格式不同。常见问题问题表现修复缺少rope_parametersTypeError: NoneType object is not subscriptableat RotaryEmbedding initConfig__init__中当rope_parametersNone时构造 default{rope_type: default, rope_theta: self.rope_theta}vocab_size含多模态 tokenEmbedding 过大 / lm_head 维度不匹配区分vocab_sizeembedding 用和text_vocab_plus_multimodal_special_token_sizelm_head 用num_hidden_layers歧义Dual-sublayer 架构下 HF 可能存 28attention 层数但物理层只有 14用 property 覆盖property num_hidden_layers - return self.num_layersauto_map指向原始模型代码加载时尝试 import 原始 modeling 文件传入自定义 config class 到from_pretrained最佳实践在 config class 的__init__末尾为缺失字段补 defensive defaults。对有模型差异的参数如rope_theta从 config.json 读取而非硬编码默认值缺失时报错。部分 Rank 静默失败有时 rank crash 了但错误被吞掉存活的 rank 卡在下一个dist.barrier()或集合通信上看起来像推理卡住。诊断流程# 1. npu-smi 确认进程数 npu-smi info | grep Process id # 2. 逐 rank 检查日志末尾 for i in $(seq 0 7); do echo Rank $i tail -5 logs/log_${i}.log done # 3. 检查是否所有 rank 都到达了同一个里程碑 grep model run success logs/log_*.log # 或 grep Loading weights took logs/log_*.log多卡权重加载检查清单在发起多卡推理前逐项确认embed_tokens 维度checkpoint 里 embed_tokens.weight.shape[0] 和 config.vocab_size 一致lm_head 维度checkpoint 里 lm_head.weight.shape[0] 可能小于 embed_tokens多模态模型常见vocab 整除 tp_sizelm_head 和 embed_tokens 的 output_size 都能被各自的 tp_size 整除不能则 padignore 规则覆盖_keys_to_ignore_on_load_unexpected包含所有不需要的权重前缀ngram、visual、audio、mtp 等config 字段完整rope_parameters、num_layers、zero_expert_num等代码必需字段在 config.json 中有或有 default模型路径绝对路径executor 框架中相对路径可能在不同 rank 的 cwd 下解析不同推理卡住诊断推理卡住与 crash 不同——进程仍在运行但不产出结果。需要区分真卡住和假卡住。先通过入口 npu-smi 表判断状态再按以下路径排查。eager 模式复现卡住 → 换 eager YAML 跑同样模型 ├── eager 也卡 → bug 在模型代码 → 用 syncprint 定位 ├── eager 正常 → bug 在图模式适配 │ ├── 看报错ERR03007 / graph break → 找不兼容的算子 │ └── 无报错但慢/卡 → 比较 eager 和 graph 模式代码路径差异 └── 两者都正常但上次卡了 → 检查是否有残留进程占 NPU模型构造阶段卡住CPU 密集症状日志停在 HCCL init 之后HBM 不增长但 CPU 100%常见根因原因机制修复nn.Embedding大 vocab 初始化大 vocab 的nn.Embedding用normal_()填充随机值多个 embedding 累计耗时可达数分钟用no_init_weights()上下文包裹跳过将被 checkpoint 覆盖的参数初始化VocabParallelEmbedding瞬态内存继承nn.Embeddingsuper().__init__(full_vocab, dim)先创建全 vocab tensor再用 per-partition tensor 替换瞬态 CPU 内存远超最终占用用nn.Moduletorch.empty(per_partition_size)直接创建 per-partition 权重避免瞬态全 vocab 分配post_init()遍历所有参数HuggingFacePreTrainedModel.post_init()调用_init_weights对每个参数做初始化大模型参数量多时很慢对从 checkpoint 加载的大参数模块用no_init_weights()跳过诊断技巧# 区分真卡和 CPU 密集慢 ps aux | grep infer.py | awk {print $2, $3%CPU, int($6/1024)MB} # CPU 100% 还在算慢但没死 # CPU 0% 真卡住等通信/IO修复模板大 embedding 模块from transformers.modeling_utils import no_init_weights # 用 no_init_weights 包裹避免对即将被 checkpoint 覆盖的参数做随机初始化 with no_init_weights(): self.large_embeddings LargeEmbeddingModule(config, ...)残留进程导致 HCCL 卡住症状新启动的推理卡在 HCCL init不报错不超时根因上次推理的进程未正确退出仍占用 NPU 设备或 HCCL 端口修复# 1. 杀死残留进程 ps aux | grep infer.py | grep -v grep | awk {print $2} | xargs kill -9 # 2. 等待 NPU 释放 sleep 3 # 3. 确认 NPU 完全空闲 npu-smi info | grep No running # 期望输出 8 行 No running processes found # 4. 重新启动推理预防每次启动推理前先检查并清理残留进程。附录运行监控与提效以下命令示例基于当前仓默认的日志路径和启动脚本约定executor 或日志组织变更后需相应调整。核心原则判断完成状态看进程不看日志流。多卡推理通过infer.sh后台启动 N 个进程再wait。rank 0 的 stdout 通过tee到终端可能缓冲截断其他 rank 只写日志文件。完成检测方法方法命令说明查 NPU 进程npu-smi info \| grep running process无进程 已结束查非 rank0 日志grep model run success logs/*/log_1.logRank 1-7 日志不经 tee完整写入。不要只查 rank 0查所有 rankfor i in $(seq 0 7); do grep -l model run success logs/*/log_${i}.log; done \| wc -l期望输出 world_size日志关键字判断阶段grep Loading safetensors logs/*/log_1.log # 正在加载权重 grep Loading weights took logs/*/log_1.log # 加载完成 grep inference time cost of prefill logs/*/log_1.log # 推理已开始 grep model run success logs/*/log_1.log # 推理已结束一条命令获取全局状态echo NPU npu-smi info | grep -E Process|HBM | head -5 \ echo Log tail -3 logs/*/log_1.log \ echo Done? grep -c model run success logs/*/log_*.log 2/dev/null常见误判场景现象原因正确做法终端无新输出以为在运行Rank 0 的 tee 管道已关闭或缓冲未刷查npu-smi或查 rank 1-7 日志Rank 0 日志没有 model run successtee 截断查 rank 1 的日志sleep 120后还没完成模型大/首次编译慢先npu-smi判断存活再看 HBM 变化判断阶段grep 日志找不到关键字进程 crash 了没写 success查npu-smi确认进程不在 → 查tail -20 log_*.log看错误Agent 工作模式启动推理bash infer.sh前台或run_in_background不要盲目 sleep—— 用run_in_background等通知或前台直接看输出10 分钟无进展 → 主动排查推理启动超过 10 分钟仍无model run success输出不要继续等待按「推理卡住诊断」流程排查npu-smi→ 判断状态 → 分流超时后第一步查npu-smi不要先查日志检查完成时查 rank 1不是 rank 0—— rank 1 日志完整无截断一次检查多个信号npu-smitail log_1.loggrep model run success log_*.log并行执行【免费下载链接】cannbot-skillsCANNBot 是面向 CANN 开发的用于提升开发效率的系列智能体本仓库为其提供可复用的 Skills 模块。项目地址: https://gitcode.com/cann/cannbot-skills创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
CANN NPU推理运行时错误诊断
发布时间:2026/7/17 10:10:53
【免费下载链接】cannbot-skillsCANNBot 是面向 CANN 开发的用于提升开发效率的系列智能体本仓库为其提供可复用的 Skills 模块。项目地址: https://gitcode.com/cann/cannbot-skillsname: model-infer-runtime-debug description: 基于 PyTorch 框架的昇腾 NPU 模型推理运行时错误诊断与修复技能。系统化排查模型加载、初始化、推理执行全链路的运行时错误包括 aicore timeout、HCCL 通信错误、OOM、算子约束违反、推理卡住等。触发场景NPU 运行时错误RuntimeError、aicore timeout 507014、HCCL timeout、device synchronize 失败、kernel crash、EZ9999/EE9999 错误码、推理过程卡住不返回、权重加载阶段 crash、模型加载成功但 forward 失败、分布式推理某些 rank 挂死等。NPU 推理运行时错误诊断与修复核心理念先定位再修复。不覆盖精度问题精度调优见 model-infer-precision-debug。 —— 通过二分法逐步缩小故障范围避免在错误方向浪费时间。诊断路径总览问题发生 │ ├── 有明确错误信息 → 通用诊断流程 │ ├── aicore timeout (507014) → 二分法定位 │ │ ├── 定位到阶段 → 层 → 模块 → 算子 │ │ └── 查表「常见算子约束」→ 修复策略 → 验证 │ ├── OOM → 检查参数量 / batch_size / seq_len / 中间 buffer │ ├── Shape 不匹配 → 检查 TP/EP 切分维度 / Prefill vs Decode 分支 │ └── HCCL timeout → 检查各 rank 代码路径一致性 / 通信组创建 │ └── 无明确错误 → npu-smi 状态检查 ├── 部分 rank 缺失 / HBM 不均 → 多卡部署诊断 │ ├── 权重加载 crash → TP 切分越界 / vocab pad │ ├── Config 字段缺失 → Config 兼容性 │ └── 静默失败 → 逐 rank 检查日志 ├── 有进程 HBM 不变 CPU 100% → 推理卡住诊断 - 模型构造阶段 ├── 有进程 HBM 不变 CPU 0% → 推理卡住诊断 │ ├── 检查残留进程 │ ├── eager 也卡 → syncprint 定位通用流程第二步 │ └── 仅 graph 卡 → 比较 eager/graph 代码路径差异 └── 0 进程 → 查 rank 0 日志 → 通用诊断流程npu-smi 状态检查当没有明确错误信息时通过设备状态判断问题类型npu-smi infonpu-smi 表现含义诊断路径前 N 进程存在后面缺失HBM 不均高位 rank 在权重加载时 crash→ 多卡部署诊断8 进程HBM 均匀AICore 全 0%所有 rank 卡在通信等待→ 推理卡住诊断有进程HBM 不变 ~3GBCPU 100%CPU 密集操作模型构造/权重初始化→ 推理卡住诊断 - 模型构造阶段有进程HBM 不变 ~3GBCPU 0%死锁/通信等待→ 推理卡住诊断8 进程HBM 持续增长权重加载中等待0 进程全部 crash查 rank 0 日志 → 通用诊断流程通用诊断流程适用于有明确错误信息的场景aicore timeout、HCCL error、OOM、shape mismatch 等。按分类 → 定位 → 查表 → 修复 → 验证线性推进。第一步错误分类拿到错误信息后先判断属于哪一类。不同类别的根因和排查路径完全不同分类错误会浪费大量时间。A. aicore timeout错误码 507014特征AclrtSynchronizeDeviceWithTimeout、error code is 507014、aicore timeout、fftsplus aivector error、Kernel task happen error, retCode0x25含义某个 NPU 算子在设备上执行时超时未返回。这是最常见也最难排查的错误因为报错的位置synchronize 调用处通常不是出错的位置某个具体算子。常见根因算子入参违反硬件约束如 MC2 要求 ep_world_size 16见「常见算子约束」算子 shape 超出硬件限制如单次 matmul 的 M/N/K 维度超限死锁部分 rank 走了不同的通信路径导致集合通信永远等不齐内存越界slot_mapping/block_table 索引超出 KV cache 分配范围B. HCCL 通信错误特征HCCL_CONNECT_TIMEOUT、HCCL error、AllReduce/AllToAll timeout、HCCL_EXEC_TIMEOUT含义分布式通信操作超时或失败。常见根因各 rank 进入通信操作的顺序/次数不一致代码分支导致部分 rank 跳过某次通信通信组创建时参数错误group_stride、group_num 不匹配 world_size网络问题跨节点时 HCCL_IF_IP 配置错误某些 rank 已经 crash 但其他 rank 还在等它参与通信C. OOM显存不足特征NPU out of memory、Tried to allocate X GiB、ENOMEM含义NPU HBM 不够。常见根因模型参数/KV cache/activation 总和超过单卡显存中间 tensor 未及时释放常见于 MoE EP all-to-all 中间 bufferbatch_size 或 seq_len 超出预期D. Shape 不匹配特征RuntimeError: shape mismatch、expected size X but got Y、mat1 and mat2 shapes cannot be multiplied含义tensor 维度不对。常见根因TP 切分后维度未正确除以 tp_sizeEP 切分后每卡专家数计算错误Prefill/Decode 分支传入了错误 shape 的 tensorE. 算子约束违反特征不直接报约束错误通常表现为 aicore timeout 或 SIGABRT。需要通过二分法定位后查阅算子文档确认。含义NPU 自定义算子对入参有隐含约束数据类型、维度范围、硬件平台限制违反时行为未定义。第二步二分法定位syncbarrier 检查点法核心方法。当错误发生在torch.npu.synchronize()时错误信息只告诉你设备上有东西出错了不告诉你具体哪个算子。通过插入检查点逐步缩小范围。2.1 定位到阶段Prefill vs Decode在 runner 的model_inference方法中prefill 和 decode 调用之间插入同步检查# 在 prefill 之后、decode 之前 torch.npu.synchronize() logging.info(prefill passed)关键陷阱NPU 操作是异步的。model.prefill()返回不代表 prefill 完成 —— 只有torch.npu.synchronize()返回才代表所有已提交的操作完成。所以报错位置synchronize 调用处不一定是出错位置某个具体算子。确保检查点覆盖所有可能的异步操作。2.2 定位到层确认出错阶段后如 Decode在每个 decoder layer 之间插入检查点for i, layer in enumerate(self.layers): hidden_states layer(hidden_states, ...) torch.npu.synchronize() logging.info(flayer {i} passed)如果 Layer 0 就超时 —— 问题在第一层内部。如果 Layer 2 超时 —— 问题在第 2 层或其子模块。2.3 定位到模块进入出错层在各子模块之间插入检查点# 在 DecoderLayer.forward 中 hidden_states self.input_layernorm(hidden_states) torch.npu.synchronize(); logging.info( norm passed) hidden_states self.self_attn(hidden_states, ...) torch.npu.synchronize(); logging.info( attention passed) hidden_states self.mlp(hidden_states) # MoE torch.npu.synchronize(); logging.info( MoE passed)2.4 定位到算子进入出错模块在每个 NPU 算子调用之间插入检查点。此时通常可以定位到具体算子及其入参结合下文「常见算子约束」判断根因。2.5 注意事项先用torch.npu.synchronize()做单卡定位确认是哪个算子出错。不要一开始就加dist.barrier()——barrier 会在某 rank 已崩溃时导致其他 rank 永久挂起怀疑多 rank 不同步时用dist.barrier()或torch.distributed.monitored_barrier()确认各 rank 是否走到同一位置。monitored_barrier在超时后会报告哪个 rank 未到达查看所有 rank 的日志确认各 rank 到达的检查点是否一致不一致说明有条件分支差异 → 通信死锁不要一次插入太多检查点—— 每次 sync 有开销且大量 sync 可能改变时序。先粗粒度再细粒度保留日志把每轮定位的检查点输出保存供后续分析第三步常见 NPU 算子约束速查以下约束来自本仓实际调试经验定位到具体算子后应回到当前调用的 API 签名和官方文档核对不要跨算子套用规则。违反约束的典型表现是 aicore timeout。MoE 相关算子算子约束违反表现解决方案npu_moe_distribute_dispatch_v2(MC2)Atlas A2:ep_world_size须为 {16,32,64,128,256}fullmesh或 {16,32,64}hierarchyaicore timeoutDecode 阶段挂死EP16 时回退到 double_routing 路径npu_moe_init_routing_v2 manual all_to_allnpu_moe_distribute_combine_v2(MC2)同上同上同上npu_moe_init_routing_v2无 EP 最小限制但moe_chunk_max_len为 0 可能导致空 tensorSIGABRT 或 shape error设置合理的 moe_chunk_max_len如 1024npu_moe_gating_top_kk不能超过专家总数静默错误输出或 crash检查 reduced model 的 moe_topk 是否已调整FA (Flash Attention) 算子约束说明head_num须匹配实际 Q headsMLA 模型中 head_num num_attention_heads不是 kv_headsPrefillsparse_mode3需配合atten_maskmask shape 须为[1, 1, max_s, max_s]不能省略input_layout按 API 和阶段区分npu_fusion_attention用 BSH/SBH/BSND/BNSD/TNDnpu_fused_infer_attention_score用复合 layout 如 TND_NTD、BSND_NBSD以实际 API 签名为准Decode PA 模式下block_tableshape[batch, max_blocks]值不能超出 cache 分配的 block 数NZ 格式 cache需要torch_npu.npu_format_cast转换且 hidden_dim 须为 16 的整数倍actual_seq_lengths相关参数以当前调用算子的签名与官方 API 文档为准不跨算子套用规则torch_npu.npu_fused_infer_attention_score/torch_npu.npu_fusion_attentionactual_seq_lengths*为List[int]文档为 int64 语义torch_npu.npu_kv_quant_sparse_flash_attentionactual_seq_lengths_query/kv为Tensor文档为 int32通信算子约束说明all_to_all_single的 split sizesinput_splits 和 output_splits 之和须分别等于 input 和 output 的第 0 维通信组内所有 rank 须同时到达任何条件分支差异都可能导致部分 rank 跳过通信 → 死锁HCCL group 创建顺序所有 rank 须以相同顺序创建相同的通信组第四步修复策略模式定位根因后选择合适的修复策略。模式 1算子回退Operator Fallback当某个高性能算子在当前硬件/配置下不可用时回退到功能等价但限制更少的替代算子。# 示例MC2 MoE 算子 EP16 时回退到 double_routing def forward(self, hidden_states, is_prefill): topk_indices, topk_weights, _ self.router(hidden_states) if is_prefill: return self.moe_infer_double_routing(hidden_states, topk_indices, topk_weights) else: if self.moe_ep_size 16: # MC2 requires ep_world_size 16 on A2; fall back to double_routing return self.moe_infer_double_routing(hidden_states, topk_indices, topk_weights) return self.moe_infer_dispatch_combine(hidden_states, topk_indices, topk_weights)适用场景硬件约束、EP/TP size 不满足算子要求注意回退通常有性能损失需记录在优化报告中模式 2参数修正Parameter Fix算子入参计算错误如 FAhead_num用了 KV heads 而非 Q heads、TP 切分后维度未除以 tp_size。定位到具体算子后逐个核对入参与算子文档/参考模型的差异。适用场景shape 不匹配、dtype 错误、维度计算错误模式 3路径统一Path Unification部分 rank 走不同代码路径导致通信死锁。# 错误不同 rank 可能在不同 step 进入 prefill/decode if is_prefill: self.all_reduce(...) # rank 0 执行 # rank 1 已进入 decode不执行 all_reduce → 死锁 # 修复确保所有 rank 同步状态后再分支 dist.barrier() is_prefill_tensor torch.tensor([int(is_prefill)], devicenpu) dist.broadcast(is_prefill_tensor, src0) is_prefill bool(is_prefill_tensor.item())适用场景多 rank 死锁、HCCL timeout模式 4配置降级Configuration Downgrade配置组合不兼容时调整 YAML 参数如降低moe_chunk_max_len、减小batch_size。适用场景OOM、性能异常第五步验证清单修复后按以下清单验证单步验证在出错位置前后加 syncbarrier确认不再超时全流程验证移除所有调试检查点运行完整 warmup inference全 rank 验证检查所有 rank 的日志确认全部成功grep model run success log_*.log输出一致性各 rank 的最终输出应一致对 DP 模式同 DP group 内的 rank 输出应一致性能记录记录修复后的 Prefill/Decode 耗时与修复前对比回退文档如果使用了算子回退记录性能影响和未来可恢复条件特定场景诊断以下场景有独立的诊断路径不走通用流程。通过入口 npu-smi 表判断后直接跳转。多卡部署诊断多卡部署引入了一类单卡不存在的问题权重加载切分、vocab 对齐、部分 rank 崩溃、config 兼容性。共同特点部分 rank 成功、部分 rank 失败错误出现在权重加载阶段而非 forward 阶段。权重加载 TP 切分越界典型错误RuntimeError: start (105984) length (35328) exceeds dimension size (131125)或ValueError: 131125 is not divisible by 8根因ColumnParallelLinear / VocabParallelEmbedding 将权重沿 output 维度切分为 tp_size 份。如果 checkpoint 的实际维度不等于模型参数的维度或者不能被 tp_size 整除高位 rank 的narrow()操作就会越界。常见场景场景说明修复多模态模型文本推理embed_tokens用 full vocab (282624) 但lm_head用 textspecial (131125)两者维度不同lm_head 单独使用text_vocab_plus_multimodal_special_token_sizevocab 不整除 tp_size131125 % 8 ≠ 0向上 pad 到最近的 tp_size 倍数padded ((raw tp - 1) // tp) * tppadded 参数 vs 原始 checkpoint模型参数 131128padded但 checkpoint 权重只有 131125加载时先 pad checkpoint weight 再传给 weight_loader修复模板vocab pad weight pad# 1. 创建 lm_head 时 pad vocab size lm_head_raw getattr(config, text_vocab_plus_multimodal_special_token_size, config.vocab_size) self.lm_head_vocab_size ((lm_head_raw tp_size - 1) // tp_size) * tp_size # 2. 加载权重时 pad checkpoint tensor if lm_head in name and loaded_weight.shape[0] self.lm_head_vocab_size: padded torch.zeros(self.lm_head_vocab_size, *loaded_weight.shape[1:], dtypeloaded_weight.dtype, deviceloaded_weight.device) padded[:loaded_weight.shape[0]] loaded_weight loaded_weight padded排查技巧如果只有高位 rank (rank 3-7) crash 而低位 rank (0-2) 正常几乎一定是切分越界 —— 因为低位 rank 的start_idx还在合法范围内。Config 兼容性问题从 HuggingFace 原始模型加载时config.json 可能缺少代码期望的字段或字段格式不同。常见问题问题表现修复缺少rope_parametersTypeError: NoneType object is not subscriptableat RotaryEmbedding initConfig__init__中当rope_parametersNone时构造 default{rope_type: default, rope_theta: self.rope_theta}vocab_size含多模态 tokenEmbedding 过大 / lm_head 维度不匹配区分vocab_sizeembedding 用和text_vocab_plus_multimodal_special_token_sizelm_head 用num_hidden_layers歧义Dual-sublayer 架构下 HF 可能存 28attention 层数但物理层只有 14用 property 覆盖property num_hidden_layers - return self.num_layersauto_map指向原始模型代码加载时尝试 import 原始 modeling 文件传入自定义 config class 到from_pretrained最佳实践在 config class 的__init__末尾为缺失字段补 defensive defaults。对有模型差异的参数如rope_theta从 config.json 读取而非硬编码默认值缺失时报错。部分 Rank 静默失败有时 rank crash 了但错误被吞掉存活的 rank 卡在下一个dist.barrier()或集合通信上看起来像推理卡住。诊断流程# 1. npu-smi 确认进程数 npu-smi info | grep Process id # 2. 逐 rank 检查日志末尾 for i in $(seq 0 7); do echo Rank $i tail -5 logs/log_${i}.log done # 3. 检查是否所有 rank 都到达了同一个里程碑 grep model run success logs/log_*.log # 或 grep Loading weights took logs/log_*.log多卡权重加载检查清单在发起多卡推理前逐项确认embed_tokens 维度checkpoint 里 embed_tokens.weight.shape[0] 和 config.vocab_size 一致lm_head 维度checkpoint 里 lm_head.weight.shape[0] 可能小于 embed_tokens多模态模型常见vocab 整除 tp_sizelm_head 和 embed_tokens 的 output_size 都能被各自的 tp_size 整除不能则 padignore 规则覆盖_keys_to_ignore_on_load_unexpected包含所有不需要的权重前缀ngram、visual、audio、mtp 等config 字段完整rope_parameters、num_layers、zero_expert_num等代码必需字段在 config.json 中有或有 default模型路径绝对路径executor 框架中相对路径可能在不同 rank 的 cwd 下解析不同推理卡住诊断推理卡住与 crash 不同——进程仍在运行但不产出结果。需要区分真卡住和假卡住。先通过入口 npu-smi 表判断状态再按以下路径排查。eager 模式复现卡住 → 换 eager YAML 跑同样模型 ├── eager 也卡 → bug 在模型代码 → 用 syncprint 定位 ├── eager 正常 → bug 在图模式适配 │ ├── 看报错ERR03007 / graph break → 找不兼容的算子 │ └── 无报错但慢/卡 → 比较 eager 和 graph 模式代码路径差异 └── 两者都正常但上次卡了 → 检查是否有残留进程占 NPU模型构造阶段卡住CPU 密集症状日志停在 HCCL init 之后HBM 不增长但 CPU 100%常见根因原因机制修复nn.Embedding大 vocab 初始化大 vocab 的nn.Embedding用normal_()填充随机值多个 embedding 累计耗时可达数分钟用no_init_weights()上下文包裹跳过将被 checkpoint 覆盖的参数初始化VocabParallelEmbedding瞬态内存继承nn.Embeddingsuper().__init__(full_vocab, dim)先创建全 vocab tensor再用 per-partition tensor 替换瞬态 CPU 内存远超最终占用用nn.Moduletorch.empty(per_partition_size)直接创建 per-partition 权重避免瞬态全 vocab 分配post_init()遍历所有参数HuggingFacePreTrainedModel.post_init()调用_init_weights对每个参数做初始化大模型参数量多时很慢对从 checkpoint 加载的大参数模块用no_init_weights()跳过诊断技巧# 区分真卡和 CPU 密集慢 ps aux | grep infer.py | awk {print $2, $3%CPU, int($6/1024)MB} # CPU 100% 还在算慢但没死 # CPU 0% 真卡住等通信/IO修复模板大 embedding 模块from transformers.modeling_utils import no_init_weights # 用 no_init_weights 包裹避免对即将被 checkpoint 覆盖的参数做随机初始化 with no_init_weights(): self.large_embeddings LargeEmbeddingModule(config, ...)残留进程导致 HCCL 卡住症状新启动的推理卡在 HCCL init不报错不超时根因上次推理的进程未正确退出仍占用 NPU 设备或 HCCL 端口修复# 1. 杀死残留进程 ps aux | grep infer.py | grep -v grep | awk {print $2} | xargs kill -9 # 2. 等待 NPU 释放 sleep 3 # 3. 确认 NPU 完全空闲 npu-smi info | grep No running # 期望输出 8 行 No running processes found # 4. 重新启动推理预防每次启动推理前先检查并清理残留进程。附录运行监控与提效以下命令示例基于当前仓默认的日志路径和启动脚本约定executor 或日志组织变更后需相应调整。核心原则判断完成状态看进程不看日志流。多卡推理通过infer.sh后台启动 N 个进程再wait。rank 0 的 stdout 通过tee到终端可能缓冲截断其他 rank 只写日志文件。完成检测方法方法命令说明查 NPU 进程npu-smi info \| grep running process无进程 已结束查非 rank0 日志grep model run success logs/*/log_1.logRank 1-7 日志不经 tee完整写入。不要只查 rank 0查所有 rankfor i in $(seq 0 7); do grep -l model run success logs/*/log_${i}.log; done \| wc -l期望输出 world_size日志关键字判断阶段grep Loading safetensors logs/*/log_1.log # 正在加载权重 grep Loading weights took logs/*/log_1.log # 加载完成 grep inference time cost of prefill logs/*/log_1.log # 推理已开始 grep model run success logs/*/log_1.log # 推理已结束一条命令获取全局状态echo NPU npu-smi info | grep -E Process|HBM | head -5 \ echo Log tail -3 logs/*/log_1.log \ echo Done? grep -c model run success logs/*/log_*.log 2/dev/null常见误判场景现象原因正确做法终端无新输出以为在运行Rank 0 的 tee 管道已关闭或缓冲未刷查npu-smi或查 rank 1-7 日志Rank 0 日志没有 model run successtee 截断查 rank 1 的日志sleep 120后还没完成模型大/首次编译慢先npu-smi判断存活再看 HBM 变化判断阶段grep 日志找不到关键字进程 crash 了没写 success查npu-smi确认进程不在 → 查tail -20 log_*.log看错误Agent 工作模式启动推理bash infer.sh前台或run_in_background不要盲目 sleep—— 用run_in_background等通知或前台直接看输出10 分钟无进展 → 主动排查推理启动超过 10 分钟仍无model run success输出不要继续等待按「推理卡住诊断」流程排查npu-smi→ 判断状态 → 分流超时后第一步查npu-smi不要先查日志检查完成时查 rank 1不是 rank 0—— rank 1 日志完整无截断一次检查多个信号npu-smitail log_1.loggrep model run success log_*.log并行执行【免费下载链接】cannbot-skillsCANNBot 是面向 CANN 开发的用于提升开发效率的系列智能体本仓库为其提供可复用的 Skills 模块。项目地址: https://gitcode.com/cann/cannbot-skills创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考