1. 为什么选择昇腾

在 AI 芯片百花齐放的今天,昇腾(Ascend)凭借其独特的达芬奇架构和全栈软件生态,正在成为国产 AI 计算的重要力量。无论你是学生、开发者还是企业工程师,掌握昇腾开发都能为你的技术栈增添极具竞争力的筹码。

本文将从零开始,带你完成昇腾开发环境的搭建,并一步步实现你的第一个推理程序。全程使用真实可运行的代码,让你在动手实践中真正掌握昇腾开发的核心流程。

2. 昇腾技术栈全景

在开始动手之前,我们先梳理一下昇腾的软件生态,这能帮助你在后续开发中快速定位问题。

层级组件作用
硬件层Atlas 系列、昇腾 310/910提供 AI 算力
驱动层NPU 驱动、固件管理硬件资源
运行时CANN(华为异构计算架构)提供算子库、图引擎、运行时
开发框架MindSpore、PyTorch(适配)编写模型代码
应用层MindX、ModelZoo快速部署推理服务

其中 CANN(Compute Architecture for Neural Networks) 是昇腾软件栈的核心,它向上支持主流 AI 框架,向下屏蔽硬件差异,是每个昇腾开发者必须掌握的基础。

3. 环境搭建实战

3.1 硬件与系统要求

  • 昇腾 310/910 推理卡,或 Atlas 200/300/500 开发套件
  • Ubuntu 18.04/20.04 x86_64 或 ARM64 架构
  • 至少 8GB 内存,50GB 可用磁盘空间

3.2 安装 CANN 工具包

首先,从昇腾社区下载对应版本的 CANN 工具包,然后执行安装:

# 以 root 用户执行
chmod +x Ascend-cann-toolkit_*.run
./Ascend-cann-toolkit_*.run --install

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

安装完成后,验证环境是否正常:

npu-smi info

如果能看到 NPU 芯片信息,说明驱动和固件安装成功。

3.3 安装 MindSpore

MindSpore 是昇腾原生支持的 AI 框架,安装非常简单:

pip install mindspore==2.2.0

验证 MindSpore 是否能调用昇腾 NPU:

import mindspore as ms
from mindspore import context

context.set_context(device_target="Ascend")
print("MindSpore 版本:", ms.__version__)
print("昇腾 NPU 环境就绪!")

4. 第一个推理程序

环境准备好之后,我们来写一个完整的图像分类推理程序。这里使用 MindSpore 内置的 ResNet50 模型和 ImageNet 数据集。

4.1 准备模型与数据

from mindspore import nn
from mindspore.train import Model
from mindspore.common.initializer import Normal
from mindspore.dataset import vision, transforms
from mindspore.dataset.transforms import Compose

# 加载预训练模型
from mindspore import load_checkpoint, load_param_into_net
from mindspore.nn import ResNet50

# 初始化网络
network = ResNet50()

# 从本地 checkpoint 文件加载预训练权重
checkpoint_path = "./resnet50.ckpt"  # 本地 checkpoint 文件路径

# 读取 checkpoint 文件中的权重参数
param_dict = load_checkpoint(checkpoint_path)

# 将权重参数加载到网络中
load_param_into_net(network, param_dict)

print("预训练权重加载完成!")

4.2 数据预处理

# 定义图像预处理流程
def create_dataset(data_path, batch_size=32):
    # 图像缩放、裁剪、归一化
    trans = Compose([
        vision.Resize(256),
        vision.CenterCrop(224),
        vision.ToTensor(),
        vision.Normalize(mean=[0.485, 0.456, 0.406],
                        std=[0.229, 0.224, 0.225])
    ])
    
    # 创建数据集
    dataset = vision.ImageFolderDataset(data_path, transform=trans)
    dataset = dataset.batch(batch_size)
    return dataset

4.3 执行推理

import numpy as np
from mindspore import Tensor

def infer_single_image(network, image_path):
    """对单张图片执行推理"""
    # 读取并预处理图片
    image = vision.Decode()(image_path)
    image = vision.Resize(256)(image)
    image = vision.CenterCrop(224)(image)
    image = vision.ToTensor()(image)
    image = vision.Normalize(mean=[0.485, 0.456, 0.406],
                            std=[0.229, 0.224, 0.225])(image)
    
    # 增加 batch 维度
    image = image.expand_dims(0)
    
    # 执行推理
    network.set_train(False)
    output = network(Tensor(image))
    
    # 获取预测结果
    pred = np.argmax(output.asnumpy(), axis=1)
    return pred[0]

# 调用推理
result = infer_single_image(network, "cat.jpg")
print("预测类别 ID:", result)

5. 性能优化技巧

昇腾 NPU 的性能潜力巨大,但需要正确的使用方式才能充分发挥。以下是几个关键优化点:

5.1 使用混合精度

from mindspore import amp

# 开启混合精度训练/推理
network = amp.auto_mixed_precision(network, 'O3')

混合精度可以将 FP32 计算转为 FP16,在昇腾 NPU 上通常能获得 2-3 倍 的加速。

5.2 合理设置 Batch Size

# 根据 NPU 显存大小调整 batch size
batch_size = 64  # 8GB 显存推荐值

5.3 使用静态图模式

from mindspore import context

# 切换到静态图模式,减少动态图开销
context.set_context(mode=context.GRAPH_MODE)

6. 常见问题排查

6.1 驱动安装失败

# 检查内核版本
uname -r

# 查看驱动日志
dmesg | grep npu

6.2 显存不足

# 查看 NPU 显存使用情况
npu-smi info

# 清理残留进程
kill -9 $(ps aux | grep python | awk '{print $2}')

6.3 算子不支持

当遇到算子不支持时,可以:

  1. 检查 CANN 版本是否过旧,升级到最新版
  2. 使用 MindSpore 的算子替换功能
  3. 在昇腾社区提交算子需求

7. 推理部署实战

下面是 MindX 推理引擎的部署架构图,展示了从客户端请求到 NPU 硬件执行推理的完整调用链路:

硬件层

运行时层

服务层

客户端层

HTTP POST /infer
(JSON 请求)

调用推理接口

下发计算图

执行算子

返回推理结果

回传输出张量

封装响应

HTTP 响应
(JSON 结果)

HTTP 客户端
(Python / Java / C++)

mxServer
(RESTful 推理服务)

MindX 推理引擎
(模型加载 / 请求调度)

CANN 运行时
(算子库 / 图引擎)

昇腾 NPU
(310 / 910)

前面我们完成了模型推理,但实际生产环境中,我们需要将模型部署为可对外提供服务的推理引擎。昇腾生态提供了 MindX 推理引擎,它封装了模型转换、服务启动、请求处理等完整流程,让开发者可以快速将模型上线。

7.1 模型转换

MindX 推理引擎使用 .om(Offline Model)格式的模型文件。我们需要先将 MindSpore 的 checkpoint 权重转换为 ONNX,再通过 ATC(Ascend Tensor Compiler)工具转换为昇腾专用的 .om 模型。

# 第一步:将 MindSpore checkpoint 导出为 ONNX 格式
python export_onnx.py

# 第二步:使用 ATC 工具将 ONNX 转换为昇腾 .om 模型
atc --model=resnet50.onnx \
    --framework=5 \
    --output=resnet50 \
    --soc_version=Ascend310 \
    --input_shape="input:1,3,224,224" \
    --output_type=FP32

其中 export_onnx.py 脚本内容如下:

import mindspore as ms
from mindspore import Tensor, export
from mindspore.nn import ResNet50
from mindspore import load_checkpoint, load_param_into_net

# 初始化网络并加载预训练权重
network = ResNet50()
param_dict = load_checkpoint("./resnet50.ckpt")
load_param_into_net(network, param_dict)
network.set_train(False)

# 构造一个虚拟输入,用于导出模型
dummy_input = Tensor(ms.numpy.ones((1, 3, 224, 224), ms.float32))

# 导出为 ONNX 格式
export(network, dummy_input, file_name="resnet50", file_format="ONNX")
print("ONNX 模型导出完成!")

转换完成后,会在当前目录生成 resnet50.om 文件,这就是 MindX 推理引擎可以直接加载的模型文件。

7.2 启动推理服务

MindX 推理引擎提供了 mxVisionmxModel 两种部署方式。这里我们使用 mxVision 快速启动一个推理服务:

import mxvision as mx

# 初始化推理上下文
context = mx.MXContext()
context.device_id = 0  # 指定使用的 NPU 设备

# 加载 .om 模型
model = mx.MXModel()
model.load_model("./resnet50.om")

# 创建推理会话
session = mx.MXSession(context, model)

# 设置输入输出
session.set_input_shape("input", [1, 3, 224, 224])
session.set_output_shape("output", [1, 1000])

print("MindX 推理服务已启动,等待客户端请求...")

启动后,服务会监听本地端口,等待客户端发送推理请求。你也可以使用 MindX 自带的 mxServer 工具以 RESTful 方式启动服务:

# 使用 mxServer 启动 RESTful 推理服务
mxServer --model=resnet50.om \
         --port=8080 \
         --device=0 \
         --batch_size=1

7.3 客户端调用

服务启动后,客户端可以通过 HTTP 请求调用推理接口。下面是一个完整的 Python 客户端示例:

import requests
import numpy as np
from PIL import Image
import io

# 服务地址
SERVER_URL = "http://127.0.0.1:8080"

def preprocess_image(image_path):
    """对图片进行预处理,与训练时的预处理保持一致"""
    img = Image.open(image_path).convert("RGB")
    img = img.resize((256, 256))
    img = img.crop((16, 16, 240, 240))  # CenterCrop 224x224
    img = np.array(img, dtype=np.float32) / 255.0
    
    # 归一化
    mean = np.array([0.485, 0.456, 0.406])
    std = np.array([0.229, 0.224, 0.225])
    img = (img - mean) / std
    
    # 调整维度为 NCHW
    img = np.transpose(img, (2, 0, 1))
    img = np.expand_dims(img, axis=0)
    return img

def infer(image_path):
    """发送推理请求并获取结果"""
    # 预处理图片
    input_data = preprocess_image(image_path)
    
    # 构造请求
    payload = {
        "input": input_data.tolist()
    }
    
    # 发送 POST 请求
    response = requests.post(f"{SERVER_URL}/infer", json=payload)
    
    if response.status_code == 200:
        result = response.json()
        pred_class = np.argmax(result["output"])
        confidence = np.max(result["output"])
        return pred_class, confidence
    else:
        raise RuntimeError(f"推理请求失败: {response.status_code}")

# 调用推理
pred_class, confidence = infer("cat.jpg")
print(f"预测类别 ID: {pred_class}")
print(f"置信度: {confidence:.4f}")

运行效果说明

  • 模型转换耗时约 1-2 分钟,转换完成后会输出 resnet50.om 文件;
  • 推理服务启动后,日志会显示 MindX 推理服务已启动,并监听指定端口;
  • 客户端调用时,单张图片推理延迟通常在 5-10ms 以内(昇腾 310 上),吞吐量可达 200+ 张/秒
  • 相比直接调用 MindSpore 推理,MindX 部署方式省去了模型加载和框架初始化开销,更适合生产环境的高并发场景。

8. 总结与进阶路线

通过本文的学习,你已经掌握了昇腾开发的核心流程:

  • 理解了昇腾软件栈的层次结构
  • 完成了 CANN 和 MindSpore 的环境搭建
  • 运行了第一个图像分类推理程序
  • 了解了性能优化的基本方法

接下来,你可以沿着以下路线继续深入:

  1. 模型迁移:将 PyTorch 模型迁移到昇腾平台
  2. 算子开发:使用 TBE 自定义算子
  3. 分布式训练:在多卡环境下训练大模型
  4. 推理部署:使用 MindX 快速部署推理服务

昇腾生态正在快速发展,社区资源也越来越丰富。建议你多关注昇腾社区的技术博客和示例代码,在实践中不断积累经验。如果在开发中遇到问题,欢迎在评论区留言交流,我们一起探讨解决方案。

Logo

鲲鹏昇腾开发者社区是面向全社会开放的“联接全球计算开发者,聚合华为+生态”的社区,内容涵盖鲲鹏、昇腾资源,帮助开发者快速获取所需的知识、经验、软件、工具、算力,支撑开发者易学、好用、成功,成为核心开发者。

更多推荐