模型能加载,Loss 开始下降,烟雾测试没有 Crash,迁移任务很容易被标成“完成”。
可从 A100 切到昇腾 910C 后,后续验收往往更费时间:推理延迟没有回到原有 CUDA 基线,长时间训练出现 OOM,错误代码留在 CANN 日志里,Python 调用栈却指不出具体算子。代码能执行,只说明平台已经接上。
更稳妥的做法是准备两张验收表。第一张看功能,确认模型能够启动、训练、保存和推理;第二张看性能与稳定性,包括训练吞吐、模型 FLOPs 利用率(MFU)、推理延迟、设备内存峰值、长稳运行,以及 CANN 版本变化后能否复现。torch_npu 成功加载,属于第一张表里的结果。
兼容接口之后,还有一笔算子账
华为在《构筑开放基础软件栈,共建昇腾AI算力新生态》中,将 CANN(Compute Architecture for Neural Networks)作为昇腾基础软件栈中的异构计算架构来介绍。借助 CANN 和 torch_npu,常见的 PyTorch、Transformer 模型可以减少接入阶段的代码改动。
问题通常藏在模型里最不标准的部分。例如新的注意力机制、自定义量化逻辑,以及原本依赖 Triton 实现的算子。CANN 没有对应实现时,团队可以临时拼接已有算子,也可以转向 Ascend C 或 TBE。前一种方式交付快,但计算图可能变长,性能回退也容易在模型放大后累积起来。
昇腾开发者博客把算子注册与模型迁移放在同一个技术主题下。对迁移项目来说,算子覆盖会直接影响计算图是否简洁、性能能否达到业务要求。
先做算子级性能剖析,比一开始就重写整张计算图更实际。把算子耗时、调用次数和内存占用列出来,热点清楚后再决定是否下沉。整张图直接改成 Ascend C,成本太高;只在兼容层反复调整 Batch Size 和并行参数,也可能掩盖真正的瓶颈。
OOM 不能只靠减 Batch Size
在已有 CUDA 工程里,团队通常积累了一套熟悉的排查方法:减小 Batch Size、调用 empty_cache()、检查显存峰值。迁到昇腾后,这些动作仍能用于快速排除问题,却不足以定位设备内存碎片、分配与释放周期,或者具体算子的越界访问。
遇到 OOM 或底层错误时,排查链路需要延伸到 CANN 日志和 Dump 结果。最好保留一组可复现输入,把代码版本、运行配置、错误代码和对应算子放在一起核对。否则,开发者很容易停留在最后一层 Python 报错上,反复重跑,却始终找不到触发问题的位置。
推理场景还要单独检查 KV Cache。除了总容量,内存布局、复用方式和边界对齐都会影响访问效率。设备内存看起来仍有余量,不代表 Token 生成速度一定稳定。这类问题靠“再加一点显存”很难解决,必须回到分配方式和算子实现上。
要不要写 Ascend C,先看热点
先留在兼容层。 如果当前吞吐和延迟已经满足业务目标,项目又强调交付速度,可以继续使用 torch_npu,配合 Tensor Parallelism 等并行策略完成优化。此时要锁定 CANN 版本并建立回归基线,不能默认一组调优参数在升级后仍然有效。
下沉关键算子。 如果多轮性能剖析都指向少数固定热点,且这些算子直接控制整体吞吐或延迟,就值得评估 Ascend C 或 TBE。Ascend C 采用接近 C++ 的编程方式,但开发者仍要理解 NPU 的存储层级和指令流水线。投入之前,应先确定可对比的性能基线、维护人员和回归范围。
重写算子不是迁移项目的固定动作。热点尚未定位时直接下沉,只会扩大排查范围;热点稳定、收益可测量,才适合进入原生算子开发。
采购价只占成本表的一行
算力迁移的账,至少要拆成三部分:硬件采购成本 + 迁移人力成本 + 性能差距对应的运行时间与能耗。如果团队长期依赖兼容层,还要在研发排期中单列 CANN 版本回归和算子维护。
对持续使用昇腾的团队来说,一套可复用的算子库,比为单个模型维护一次性分支更有价值。算子清单、版本兼容记录、性能基线和故障定位方法,也应该随项目一起沉淀下来。
昇腾社区公开的北京“淬火行动”伙伴能力提升培训为期三天,内容从硬件架构延伸到大模型。这个跨度很贴近迁移现场:框架接入只是开头,后面的工作会一路深入到工具链、内存和算子实现。
从 CUDA 到昇腾,验收标准应从“成功跑一次”扩展到“可以稳定复现、性能达标、问题能定位”。做到这一步,迁移才有复制价值。