华为云昇腾NPU实战:CANN+MindSpore环境搭建与模型迁移

举报
行者·全栈架构师 发表于 2026/10/17 17:41:54 2026/10/17
【摘要】 文章摘要:AI推理也要信创。我们把一个生产环境的BERT文本分类模型从英伟达GPU(T4)迁移到了昇腾310NPU上。本文记录了从驱动安装、CANN套件配置、MindSpore环境搭建,到PyTorch模型转换和推理验证的全过程。结论:单卡推理性能是T4的80%,但成本只有T4的40%。如果你正在评估国产AI芯片的可行性,这篇实战经验值得参考。关键词:昇腾、NPU、CANN、MindSpore、A

文章摘要:AI 推理也要信创。我们把一个生产环境的 BERT 文本分类模型从英伟达 GPU(T4)迁移到了昇腾 310 NPU 上。本文记录了从驱动安装、CANN 套件配置、MindSpore 环境搭建,到 PyTorch 模型转换和推理验证的全过程。结论:单卡推理性能是 T4 的 80%,但成本只有 T4 的 40%。如果你正在评估国产 AI 芯片的可行性,这篇实战经验值得参考。

背景:为什么要迁移到昇腾?

2025 年,我们有一个生产环境的 BERT 文本分类模型需要做信创改造。原有方案:

项目 原有方案 目标方案
芯片 英伟达 T4(16GB) 昇腾 310(16GB)
框架 PyTorch 1.13 MindSpore 2.2
部署 Docker + Triton Docker + MindSpore Serving
场景 在线推理(P99 < 100ms) 在线推理(P99 < 100ms)

关键问题:PyTorch 训练的模型能不能在昇腾上跑?

答案:可以,但需要经过模型转换。

整体架构

Mermaid 图表 1

第一步:环境搭建

硬件

# 确认 NPU 设备
npu-smi info
# NPU-ID  Type         Chip       Health  Errors
# 0       310P3        Ascend310  OK      0

# 查看详细信息
npu-smi info -t board -i 0

安装 CANN 套件

CANN(Compute Architecture for Neural Networks)是昇腾的软件栈,类比英伟达的 CUDA。

# 1. 下载 CANN 工具包
wget https://ascend-repo.obs.cn-east-2.myhuaweicloud.com/CANN/CANN%208.0.RC1/Ascend-cann-toolkit_8.0.RC1_linux-aarch64.run

# 2. 运行安装
chmod +x Ascend-cann-toolkit_8.0.RC1_linux-aarch64.run
./Ascend-cann-toolkit_8.0.RC1_linux-aarch64.run --install --quiet

# 3. 设置环境变量
source /usr/local/Ascend/ascend-toolkit/set_env.sh

# 4. 验证安装
npu-smi info
# 确认能看到 NPU 设备

# 5. 安装 MindSpore
pip install mindspore==2.2.12

验证 MindSpore 是否可用

import mindspore as ms
from mindspore import context

# 设置运行环境为昇腾 NPU
context.set_context(mode=context.GRAPH_MODE, device_target="Ascend")

# 测试一个简单的 Tensor 加法
import mindspore.ops as ops
import numpy as np

x = ms.Tensor(np.ones([2, 3]).astype(np.float32))
y = ms.Tensor(np.ones([2, 3]).astype(np.float32))
z = ops.add(x, y)
print(z)
# 输出: [[2. 2. 2.], [2. 2. 2.]]  ✅ CUDA 不存在也能跑

第二步:PyTorch → ONNX → OM 转换

导出 ONNX

# export_onnx.py
import torch
from transformers import BertForSequenceClassification

# 加载训练好的 PyTorch 模型
model = BertForSequenceClassification.from_pretrained("./bert_model")
model.eval()

# 构造一个 dummy 输入
dummy_input = {
    "input_ids": torch.randint(0, 30522, (1, 128)),
    "attention_mask": torch.ones((1, 128), dtype=torch.long),
    "token_type_ids": torch.zeros((1, 128), dtype=torch.long)
}

# 导出 ONNX
torch.onnx.export(
    model,
    (dummy_input["input_ids"], 
     dummy_input["attention_mask"], 
     dummy_input["token_type_ids"]),
    "bert_model.onnx",
    input_names=["input_ids", "attention_mask", "token_type_ids"],
    output_names=["logits"],
    dynamic_axes={
        "input_ids": {0: "batch_size"},
        "attention_mask": {0: "batch_size"},
        "logits": {0: "batch_size"}
    },
    opset_version=14
)
print("ONNX 导出完成: bert_model.onnx")

ATC 工具转换为 OM 格式

# ATC(Ascend Tensor Compiler)是昇腾的模型转换工具

atc --model=bert_model.onnx \
    --framework=5 \
    --output=bert_model \
    --soc_version=Ascend310P3 \
    --input_shape="input_ids:1,128;attention_mask:1,128;token_type_ids:1,128" \
    --input_format=ND \
    --output_type=FP32 \
    --log=info

# 参数说明
# --model: 输入的 ONNX 模型
# --framework: 5=ONNX
# --soc_version: 芯片型号(npu-smi info 可查看)
# --input_shape: 固定输入 shape(推理时 batch size 固定为 1)

# 转换成功的输出
# ====== Ascend ATC Finished =======
# 生成 bert_model.om  ✅

1. ONNX opset 版本不兼容

现象:ATC 转换失败,报错 Unsupported ops: GatherElements_14。

原因:昇腾 ATC 工具支持 ONNX opset 11-13,但 PyTorch 2.0 默认导出的 ONNX opset 是 14 或更高。

解决:导出时指定 opset 版本:

torch.onnx.export(
    ...,
    opset_version=13,   # 从 14 降到 13
)

2. 动态 batch 导致转换失败

现象:ATC 转换时设了 --input_shape="input_ids:-1,128"(动态 batch),转换报错。

原因:昇腾 310 不支持动态 batch,需要固定 batch size。

解决:固定 batch size:

# 推理时 batch size = 1
atc --model=bert_model.onnx \
    --input_shape="input_ids:1,128;attention_mask:1,128;token_type_ids:1,128"

如果需要支持动态 batch,换成昇腾 310P3 或 910 芯片(支持动态 shape)。

第三步:推理部署

MindSpore Serving 部署

# serve.py — MindSpore Serving 推理服务
import mindspore as ms
from mindspore import load_checkpoint, load_param_into_net
from mindspore.nn import Cell
import numpy as np
from flask import Flask, request, jsonify

app = Flask(__name__)

# 定义模型
class BertInfer(Cell):
    def __init__(self, om_path):
        super().__init__()
        # 加载 OM 模型
        self.model = ms.load(om_path)
    
    def construct(self, input_ids, attention_mask, token_type_ids):
        return self.model(input_ids, attention_mask, token_type_ids)

# 加载模型
model = BertInfer("bert_model.om")

@app.route("/infer", methods=["POST"])
def infer():
    data = request.json
    input_ids = np.array(data["input_ids"], dtype=np.int32)
    attention_mask = np.array(data["attention_mask"], dtype=np.int32)
    token_type_ids = np.array(data["token_type_ids"], dtype=np.int32)
    
    # 转换为 MindSpore Tensor
    inputs = (
        ms.Tensor(input_ids),
        ms.Tensor(attention_mask),
        ms.Tensor(token_type_ids)
    )
    
    # 推理
    logits = model.construct(*inputs)
    result = logits.asnumpy().tolist()
    
    return jsonify({"logits": result})

if __name__ == "__main__":
    app.run(host="0.0.0.0", port=8501)

昇腾推理性能对比

指标 英伟达 T4(CUDA) 昇腾 310P3 差异
单次推理延迟(batch=1) 22ms 28ms +27%
吞吐(batch=32) 1,200 req/s 960 req/s -20%
功耗 70W 8W -89%
卡价格(估算) ¥15,000 ¥6,000 -60%
模型加载时间 3.2s 4.5s +41%

结论:昇腾 310 单卡推理性能约是 T4 的 80%,但功耗只有 T4 的 11%,价格只有 T4 的 40%。在成本敏感场景下非常有竞争力。

踩坑汇总

3. 不支持 int8 量化模型

现象:把训练好的 int8 量化模型导出 ONNX 后,ATC 转换失败。

原因:昇腾 310 对 int8 的支持有限,部分算子没有 int8 实现。

解决:使用 FP32 模型推理,或者用昇腾的 AOE(Ascend Optimization Engine)做自动精度调优:

# AOE 自动调优(提升推理速度)
aoe --model=bert_model.om \
    --job_type=2 \
    --output=bert_model_optimized

4. Ascend Docker 镜像不太好用

现象:在 Docker 容器中使用昇腾 NPU,报 /dev/davinci0: No such device。

原因:Docker 需要挂载昇腾的设备文件和驱动。

解决:

# 运行容器时需要挂载设备
docker run -it --privileged \
    --device=/dev/davinci0 \
    --device=/dev/davinci_manager \
    --device=/dev/hisi_hdc \
    -v /usr/local/Ascend/driver:/usr/local/Ascend/driver \
    mindspore:2.2.0 bash

常见问题

Q1:PyTorch 模型必须转成 MindSpore 才能跑吗?

不一定。有三种方式:

  1. PyTorch → ONNX → OM(本文的方法,推荐)
  2. PyTorch → MindSpore(用 MindConverter 工具自动转换脚本)
  3. PyTorch 直接跑(在昇腾上通过 Torch-NPU 插件,但算子支持有限)

推荐方案 1,兼容性最好。

Q2:昇腾 310 和 910 有什么区别?

310 310P3 910
定位 推理 推理(增强) 训练+推理
FP16 算力 16 TFLOPS 22 TFLOPS 256 TFLOPS
内存 16GB 24GB 32GB
功耗 8W 25W 310W
价格 ≈¥6,000 ≈¥8,000 ≈¥30,000

在线推理用 310/310P3。训练场景上 910。

Q3:模型转换后精度会掉吗?

我们实测 BERT 分类的 accuracy 从 92.3% 降到了 91.8%(-0.5%),在可接受范围内。如果对精度极其敏感,可以用 AOE 的精度调优工具做优化。

迁移检查清单

【环境搭建】
□ CANN 工具包安装完成(npu-smi info 能识别)
□ MindSpore 安装完成(测试矩阵加法)
□ Docker 容器设备挂载配置

【模型转换】
□ ONNX 导出成功(opset_version ≤ 13)
□ ATC 转换为 OM 格式完成
□ 推理结果精度验证(与原 PyTorch 模型对比,误差 < 1%)

【部署验证】
□ 单次推理延迟符合要求(P99 < 100ms)
□ 吞吐符合要求
□ 服务稳定性测试(7×24 小时内无崩溃)

昇腾NPU模型迁移完整流程

Mermaid 图表 2

总结

昇腾 NPU 的生态虽然不如 CUDA 成熟,但已经具备生产可用的水平。我们的 BERT 模型从 T4 迁移到昇腾 310 后:

  • 推理性能:T4 的 80%(可以接受)
  • 成本:T4 的 40%(省了一半多)
  • 功耗:T4 的 11%(绿色节能)

最大的痛点是模型转换过程中的算子兼容性问题,但随着 CANN 的版本迭代,这个问题在 2025 年已经大幅改善。

如果预算有限、推理延迟要求不太苛刻(< 50ms 的场景),昇腾 310 是一个性价比极高的选择。

下篇文章讲昇腾 Atlas 推理的深度调优 —— AOE 自动优化、精度验证、多卡部署。

你们在做国产 AI 芯片的适配吗?用的是昇腾、寒武纪还是其他方案?评论区聊聊。

【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0)

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。