Skip to content

国产 GPU/NPU 适配实战:从 CUDA 迁移到异构加速 ​

摘要: 国产算力(昇腾、寒武纪、沐曦、天数等)已进入真实生产集群,但"把 CUDA 代码迁过去"不是换个编译器那么简单:生态、算子、显存管理、性能特征全不同。本文给出一条可落地的迁移路线:盘点 CUDA 依赖 → 选迁移路径 → 算子映射 → 性能验收 → 双栈共存。

0. 实验目标 ​

  • 盘点应用对 CUDA 的真实依赖(决定迁移路径)
  • 掌握三条迁移路线:框架层迁移 / 算子重写 / 双栈共存
  • 了解昇腾(Ascend)与寒武纪(Cambricon)的适配要点
  • 建立性能验收标准:正确性 + 精度 + 性能回退容忍度

1. 先盘点:你的应用到底依赖 CUDA 什么 ​

bash
# 盘点工具链依赖:源码里出现的关键 CUDA 符号
grep -rE "cudaMalloc|cudaMemcpy|cublas|nccl|torch.cuda|numba.cuda" --include="*.py" --include="*.cu" --include="*.cpp" . | head -20

# 检查运行环境动态库依赖
ldd /path/to/your_binary | grep -iE "cuda|cudnn|cublas|nccl"

逐段拆解:

  • 依赖分四类:框架 API(torch.cuda,最易迁)、CUDA runtime API(cudaMalloc 等,中等)、库调用(cuBLAS/cuDNN/NCCL,由新栈提供)、手写 kernel(.cu/.pyx,最难)。
  • 结论先行:80% 的应用卡在"框架 API + 库调用"层——走框架层迁移即可,只有深度学习内核研究者才需要动 .cu。

2. 三条迁移路线 ​

路线做法成本适用
A. 框架层迁移PyTorch 模型 + torch_npu/torch_mlu 等适配层低(改 device 与少量 API)绝大多数训练/推理应用
B. 算子重写Triton/CANN/MLU 自定义算子替代手写 CUDA中高有自研 kernel 的热点模型
C. 双栈共存CUDA 与国产卡分池共存,按负载路由中迁移过渡期、容灾

原理讲解:

  • 路线 A 的核心:适配层把 torch.cuda 映射到国产卡运行时(昇腾叫 CANN,寒武纪叫 CNToolkit),并补齐 torch.compile/AMP/NCCL 对应物(HCCL/CNCL 通信库)。多数模型只需改 device="cuda" → 适配层暴露的设备名。
  • 路线 C(过渡期标配):CUDA 池跑存量业务,国产池跑新业务/备份,Slurm/K8s 用分区或标签路由(详见本知识库 Slurm 异构调度 与 K8s GPU 调度 篇)。

3. 昇腾适配要点(示例) ​

bash
# 安装 CANN + torch_npu
pip install torch_npu
export ASCEND_HOME=/usr/local/Ascend/ascend-toolkit

# 代码改动示例:torch.cuda → 昇腾设备
import torch
import torch_npu                      # 注册 npu 设备

device = "npu:0"                      # 原 "cuda:0"
model = model.to(device)
x = x.to(device)

工程启示(昇腾):

  • torch_npu 提供 npu:0 设备,但并非所有算子都有 NPU 实现——遇到不支持的算子会报错或回退 CPU,性能会掉。先跑 torch_npu 的算子支持清单核对。
  • 混合精度:昇腾支持 FP16/BF16,AMP 路径与 CUDA 类似;通信库是 HCCL(对应 NCCL),DDP 代码几乎不动。
  • 推理部署:MindSpore/MindIE 是昇腾生态的另一条路径(框架层二选一)。

4. 寒武纪适配要点(示例) ​

bash
# CNToolkit + torch_mlu
pip install torch_mlu
export LD_LIBRARY_PATH=$CNTOOLKIT_HOME/lib64:$LD_LIBRARY_PATH

# 代码改动示例
import torch_mlu                      # 注册 mlu 设备
device = "mlu:0"                      # 寒武纪 MLU 设备

工程启示(寒武纪):

  • MLU 的算子覆盖与性能特征和 NVIDIA 有差异:小算子场景 MLU 相对吃亏,大 GEMM/卷积类算子接近——迁移后先跑算力画像(算子级 profile),别拿整体 benchmark 猜。
  • 通信库是 CNCL;torch.compile 支持程度需按版本核对(Triton 后端适配成熟度不一)。

5. 性能验收:迁移成功的标准 ​

bash
# 验收三步:正确性 → 精度 → 性能
# 1) 正确性:同一输入,NVIDIA 与国产卡输出对齐
python compare_outputs.py --ref cuda --test npu --tolerance 1e-3

# 2) 精度:训练收敛曲线对比(loss 曲线形状一致)
# 3) 性能:同 batch 同模型,对比 step 耗时与吞吐
python bench.py --device npu --batch 32

验收标准建议:

项标准
输出正确性与 CUDA 结果 diff < 1e-3(FP32)/ 同量级(AMP)
训练收敛loss 曲线趋势一致,最终精度差 < 1%
性能达 CUDA 基线 60-90%(按场景;算子画像决定)
稳定性长跑 72h 无 OOM/挂死

关键认知:迁移的验收不是"跑通"而是"可对比"。性能回退要量化到算子级——知道掉在哪、为什么掉(算子覆盖/显存带宽/通信库),才有优化抓手。

6. 工程启示汇总 ​

  1. 先盘点再动手:80% 应用走框架层迁移(路线 A),别一上来写算子。
  2. 适配层是核心:torch_npu/torch_mlu 把 torch.cuda 映射到国产运行时,多数代码只改 device。
  3. 算子覆盖是第一个坑:跑官方支持清单,不支持的算子回退 CPU 会掉性能。
  4. 通信库对位:NCCL→HCCL(昇腾)/CNCL(寒武纪),DDP 代码基本不动。
  5. 算力画像再下结论:整体 benchmark 猜不出问题,算子级 profile 才知道掉在哪。
  6. 双栈共存过渡:CUDA 与国产卡分池,按负载路由,逐步切换。
  7. 验收量化:正确性/精度/性能/稳定性四项,性能回退量化到算子级。

7. 延伸阅读 ​

AI-HPC 智算超算专家 · Contact: openaihpc@gmail.com