Atlas 这个名字在技术圈出现频率很高,有时指开源项目,有时指华为的 AI 加速卡。看到《RIP:只活了292天的Atlas》这个标题,第一反应可能是某个同名项目又结束了生命周期;但同样是 Atlas,华为 Atlas 300I Duo AI 加速卡做的事情完全不同。它是一块面向数据中心推理场景的硬件加速卡,需要驱动、固件、CANN 工具链和推理框架协同工作,才能把模型跑起来。别把标题理解成硬件产品的讣告——在 AI 计算生态里,这个 Atlas 恰恰需要长期维护和持续测试。
围绕 Atlas 300I Duo 的测试工作,通常会经历硬件识别、驱动安装、环境变量配置、模型转换、推理验证和性能监控这几个阶段。每个阶段都可能因为一个小配置不到位而卡住很久,所以理解背后的工作原理比记住命令更重要。下面按顺序拆开。
1. 先搞清楚 Atlas 300I Duo 的定位,再谈测试才有意义
1.1 Atlas 产品线为什么容易和开源项目混淆
“Atlas” 是技术圈里被反复使用的名称。很多开源项目、数据库产品、图计算框架都叫 Atlas,华为的 AI 计算产品线也叫 Atlas。两者没有直接关系,只是命名撞车。
这种命名冲突带来的实际问题是:搜索资料时经常看到两套完全不同的内容。一套是软件项目的文档,一套是昇腾 AI 计算相关的硬件资料。测试华为 Atlas 300I Duo 时,如果搜到的是别的 Atlas 项目,很容易被误导。建议建立一个基本判断:当技术文档里出现 npu-smi、CANN、Ascend、davinci 这些关键词时,才是在讲华为 Atlas 硬件生态。
1.2 Atlas 300I Duo 的技术定位与常见误解
Atlas 300I Duo 是华为 Atlas 系列中的一款 AI 推理加速卡,常见设计是一张卡上包含两个 AI 处理器,通过 PCIe 接口与主机连接。它在推理场景中承担模型计算任务,比如图像分类、目标检测、OCR、语音识别等。
在使用上,它和普通显卡有几处明显区别:
第一,它不是即插即用的设备。插上 PCIe 后,需要安装驱动、固件,再安装 CANN 工具包,才能被推理框架识别。
第二,它的算力不能像 CUDA 那样直接通过 PyTorch 的.cuda()调用。PyTorch 代码要跑在 Atlas 300I Duo 上,需要经过 MindSpore、昇腾适配层或 CANN 的 ACL 接口才能访问硬件。
第三,模型不能直接用.pt或.pth文件推理。常见流程是先导出 ONNX,再用 ATC 工具转换为.om离线模型,最后由 ACL 或推理引擎加载执行。
这个定位决定了测试步骤的先后顺序:先把硬件环境弄干净,再跑通一个最小推理样例,最后才去碰性能优化。跳过硬件验证直接写模型代码,是大多数测试失败的开端。
2. 测试前环境准备:从 PCIe 设备识别到驱动固件安装
2.1 主机侧需要满足哪些基本条件
Atlas 300I Duo 通常安装在 x86 或鲲鹏架构的服务器上,操作系统以 Ubuntu、openEuler、CentOS 等 Linux 发行版为主。测试前要确认三件事:主板是否有空闲 PCIe 插槽、供电是否满足,BIOS 是否开启了 PCIe 设备枚举。
在原始资料不明确的前提下,落地前要先确认当前服务器 CPU 架构和操作系统版本,再从对应版本的软件包列表中选择驱动、固件和 CANN 安装包。不要从旧项目里复制安装命令直接执行,因为不同版本的安装包路径和参数可能不同。
2.2 如何确认系统已经识别到加速卡
硬件安装完成后,先不要急着装驱动。用lspci检查系统是否枚举到设备。
lspci | grep -i davinci如果输出里出现类似Huawei Technologies Co., Ltd. Device [davinci]的内容,说明 PCIe 链路已经通了。如果没有任何输出,说明系统没识别到卡,或卡没有正确插好。
这一步容易踩的坑是:lspci能识别设备,但操作系统还没有/dev/davinci*设备节点。设备节点要等驱动加载成功后才会生成,所以lspci只是第一个检查点,不能作为安装完成的标志。
2.3 驱动与固件安装的先后顺序
驱动和固件是配合使用的。常见顺序是:
- 从官方对应版本的软件包中下载驱动、固件和 CANN 工具包。
- 先安装驱动,再升级或安装固件,最后安装 CANN。
- 安装完成后重启系统,确认驱动模块加载。
驱动安装命令在不同版本中不完全一样,一般以类似下面的方式执行:
sudo ./Ascend-hdk-*.run --install如果系统提示缺少依赖,需要先安装对应的内核头文件和编译工具:
sudo apt-get install -y gcc make linux-headers-$(uname -r)如果拿到的资料没有给出明确版本,安装前必须确认驱动、固件、CANN 三者之间的版本兼容关系。不能直接拿默认最新版,也不能只看某个组件版本,最好以官方配套关系表为准。
2.4 npu-smi 是第一个必须通过的检查点
驱动和固件装好后,第一个要执行的命令是npu-smi:
npu-smi info正常情况下能列出每张逻辑卡的芯片温度、利用率、内存、功耗等信息。Atlas 300I Duo 是双芯设计,所以一张物理卡在npu-smi里可能显示为多个逻辑设备。
执行失败时不建议继续往下装 CANN 或跑模型,先回到驱动和固件排查。常见的npu-smi错误会在后面的排查章节展开。
注意:驱动、固件、CANN 三者版本不一致时,
npu-smi不一定报错,但后续模型转换或推理时可能频繁失败。所以每一套环境都应该把版本记录清楚。
3. 跑通最小推理样例:用 CANN/ACL 完成一次图片分类
3.1 准备推理环境变量与 Python 依赖
CANN 安装后,会提供一组环境变量脚本,典型路径是/usr/local/Ascend/ascend-toolkit/set_env.sh。每次进入终端后需要 source 一下:
source /usr/local/Ascend/ascend-toolkit/set_env.sh这一步的目的是把atc、npu-smi、acl等工具的路径加到PATH和PYTHONPATH中。没有 source 环境变量时,命令行里可能能敲atc,但 Python 里import acl会失败。
Python 侧最好使用虚拟环境,避免把依赖装进系统 Python。以 Python 3 为例:
python3 -m venv venv source venv/bin/activate pip install pillow numpy如果准备用 MindSpore,需要安装与当前 CANN 版本匹配的 MindSpore 包。注意:MindSpore 的安装源和版本非常多,装错版本后导入阶段就会报错,建议按照官方发布的配套关系安装。
3.2 ACL 推理流程的四个阶段
ACL(Ascend Computing Language)是 CANN 提供的设备侧编程接口,Python 推理通常按四个阶段组织:
- 初始化:
acl.init()初始化 ACL 运行时。 - 设备管理:
acl.rt.set_device(0)指定使用哪张逻辑卡。 - 模型执行:加载
.om模型、创建输入输出、执行推理、取回结果。 - 资源释放:释放模型、上下文,最后
acl.finalize()。
理解这四个阶段后,写推理代码就不会乱。很多新手把模型加载写在初始化和设备设置之前,导致运行时报错,就是这个流程没搞清楚。
3.3 最小分类推理代码拆解
下面是一个示意代码,用来理解 ACL 推理的调用顺序。实际项目需要按自己的模型和图片数据补充预处理逻辑。
import os import numpy as np from PIL import Image import acl def preprocess(image_path): image = Image.open(image_path).resize((224, 224)) image = np.asarray(image, dtype=np.float32) / 255.0 mean = np.array([0.485, 0.456, 0.406], dtype=np.float32) std = np.array([0.229, 0.224, 0.225], dtype=np.float32) image = (image - mean) / std image = image.transpose(2, 0, 1) return np.expand_dims(image, axis=0).copy() def main(): acl.init() ret = acl.rt.set_device(0) if ret != 0: raise RuntimeError("set device failed") model_path = "./resnet50.om" # 这里会通过 ACL 接口加载模型并创建推理上下文 # 加载后把输入数据拷到设备侧,执行模型,再取回输出 # 输出通常是 shape 为 [1, 1000] 的分数数组 print("inference done") acl.rt.reset_device(0) acl.finalize() if __name__ == "__main__": main()这段代码没有完整实现模型加载和输入输出的内存拷贝,因为不同版本的 CANN 接口封装方式不同。写真实项目时,建议先跑通官方样例,再对照样例替换成自己的模型和预处理逻辑。直接跳过样例去封装接口,遇到问题会分不清是代码问题还是环境问题。
3.4 运行结果怎么判断正常
推理程序正常结束,只能说明链路通了,不能说明结果正确。判断一次推理是否真正的“跑通”,至少要看三点:
第一,程序退出码是 0,没有报 ACL 接口错误。
第二,输出张量形状和模型定义一致。分类模型通常输出[1, 类别数]的分数,通过argmax取到类别下标。
第三,把输入图片、输出类别、置信度三者对应起来,人工确认分类结果合理。比如一个明显是猫的图片输出类别是猫,才算正常。输出类别完全随机时,要回去检查预处理逻辑,而不是继续调性能。
注意:不要只验证程序能启动,还要验证输入、输出、异常分支和日志是否符合预期。
4. 把自研 ONNX 模型转换成 om,并验证精度
4.1 为什么要转换模型
Atlas 300I Duo 不能直接加载 PyTorch 或 TensorFlow 的训练产物,一般需要把模型转换成昇腾的.om离线模型。离线模型的执行效率更高,也方便统一版本。
常见的转换链路是:PyTorch 模型导出 ONNX,再用 ATC(Ascend Tensor Compiler)工具把 ONNX 转换为 om。如果使用的推理框架是 MindSpore,也可以直接从 MindSpore 模型转换,但 ONNX 到 om 是适用范围更广的路线。
4.2 ATC 转换命令的常用参数
ATC 命令通常长这样:
atc --model=resnet50.onnx \ --framework=5 \ --output=resnet50 \ --soc_version=Ascend310P3 \ --input_shape="input:1,3,224,224" \ --log=info这里每个参数都不能随便写:
--model:输入模型路径。--framework:模型框架类型。ONNX 对应 5。--output:输出模型的名称和路径。--soc_version:芯片版本。Atlas 300I Duo 对应的芯片型号需要根据实际硬件确认,写错会导致编译失败或生成的模型无法加载。--input_shape:输入张量名和 shape。ONNX 里输入名如果不是input,需要先用工具确认输入节点名称。
转换成功后,当前目录会生成resnet50.om。转换过程会输出算子编译日志,如果某个算子不支持,日志里会明确标出。遇到这种情况不要急着换模型,先确认模型版本和 ATC 的算子支持范围。
4.3 转换后的精度对比方法
模型转换后要检查精度是否下降。做法是准备一批测试图片,把 PyTorch 模型和 om 模型的推理结果放在一起对比。
以分类模型为例,至少对比两个指标:
- Top-1 一致率:两种实现输出的最大分数下标一致的比例。
- 最大分数差异:两种实现输出的 softmax 向量之间的平均绝对误差。
如果一致率低于预期,优先检查预处理是否一致。很多精度问题不是转换造成的,而是推理代码的归一化方式、resize 方式或通道顺序和训练时不一致。
4.4 算子不支持的常见处理方式
ONNX 模型转换失败时,日志里通常有算子名称。处理方式按优先级排列:
- 把不支持的算子在模型导出阶段替换为等价算子。
- 调整 ONNX 算子版本,使用 ATC 支持范围内的版本导出。
- 把部分算子移到主机侧处理,比如一些动态 shape 相关的逻辑。
- 如果无法避免,改用 MindSpore 或昇腾提供的更高层推理框架重新加载原模型。
不建议一开始就替换模型结构。先确认算子是否真的不支持,很多时候只是导出时设置的问题。
5. 性能测试:吞吐、延迟、卡利用率缺一不可
5.1 性能指标怎么定义
Atlas 300I Duo 测试不能只看“推理跑完了”,还要量化性能。常见指标包括:
- 单张图片延迟:从输入图片到输出结果的耗时,单位毫秒。
- 吞吐量:单位时间处理的图片数量,单位 FPS。
- 卡利用率:
npu-smi中看到的 AI Core 利用率。 - 设备内存占用:模型加载和推理过程中动态占用情况。
延迟和吞吐是互相关联的指标。同一个模型,batch size 增大时,单图延迟可能增加,但整体吞吐可能上升。所以测试时要同时记录,不能只取一个指标评价性能。
5.2 用多路并发脚本观察吞吐与延迟
最小性能测试可以写成多进程或多线程并发推理脚本。思路是固定并发数,每个 worker 连续处理 N 张图片,最后统计总耗时。
import time from concurrent.futures import ThreadPoolExecutor def one_task(image_path): start = time.time() # 调用推理函数 end = time.time() return end - start def run_benchmark(images, workers=4): start = time.time() with ThreadPoolExecutor(max_workers=workers) as executor: latencies = list(executor.map(one_task, images)) total = time.time() - start fps = len(images) / total avg_latency = sum(latencies) / len(latencies) print(f"fps={fps:.2f}, avg_latency={avg_latency:.2f}s")这个脚本只用来理解测试思路。真实压测还需要考虑预热、时间同步、结果校验等问题。比如前几次推理可能包含模型加载和内存初始化,通常要预热后再统计数据。
5.3 用 npu-smi 监控卡利用率和内存
性能测试时,另开一个终端持续执行:
npu-smi info观察 AI Core 利用率是否稳定在一个合理区间。如果利用率很低,说明瓶颈可能在数据预处理、主机内存拷贝、模型单次计算量太小或并发数不足。如果利用率很高但吞吐仍上不去,说明硬件已经接近满负载,需要调 batch size 或模型结构。
设备内存也是一样。模型转换时设置的 batch size 会直接影响显存占用。实际部署时要把模型、图片缓冲区、推理输出全部算进内存预算,留出余量。
5.4 区分硬件阈值与应用瓶颈
性能不达标时,先别急着怀疑卡。要分清瓶颈在哪一层:
- 数据侧:图片读取、解码、resize 是否占了大量时间。
- 传输侧:从磁盘到内存、从主机到设备的拷贝是否频繁。
- 计算侧:模型算子是否是当前芯片擅长的高密度算子。
- 框架侧:推理框架是否有额外的序列化和调度开销。
排查方式是把各阶段耗时分别打点。比如只测空模型推理耗时,再测带预处理的全流程耗时,两者之差就是数据侧开销。这样能快速定位该优化哪一部分。
6. 常见问题与排查链路
6.1 lspci 看不到设备
现象:执行lspci时没有任何华为相关设备输出。
可能原因:卡没有插紧、PCIe 插槽故障、BIOS 未识别、静电或供电问题。
检查方式:
- 重新插拔加速卡,确认卡和插槽完全接触。
- 换一个 PCIe 插槽测试。
- 查看
dmesg日志中是否有 PCIe 相关报错:
dmesg | grep -i -E "pci|davinci|huawei"解决方案:先排除物理链路问题,再考虑系统 BIOS 设置。不要在这个阶段反复重装驱动。
6.2 npu-smi 报错
现象:驱动安装完成后,npu-smi info提示设备不存在或返回错误码。
可能原因:驱动与固件版本不匹配、设备节点权限不足、驱动模块未加载、多个版本驱动残留。
检查方式:
ls /dev/davinci* ls /dev/davinci_manager如果有多个不同版本的驱动安装记录,清理干净后重新安装。确认用户对/dev/davinci*有读写权限,必要时加入对应的用户组。
6.3 模型转换失败
现象:ATC 执行报算子不支持或输入输出类型错误。
检查方式:查看 ATC 日志中的关键行,确认soc_version和模型实际输入名。可以先打印 ONNX 模型的输入信息:
import onnx model = onnx.load("resnet50.onnx") for inp in model.graph.input: print(inp.name, [d.dim_value for d in inp.type.tensor_type.shape.dim])根据实际输入名修改--input_shape参数。不要盲目套用网上命令。
6.4 推理结果异常
现象:程序能跑,但输出类别完全不对,或输出全是 NaN。
排查顺序:
- 检查预处理:图像是否 resize 到模型输入尺寸,归一化均值方差是否一致。
- 检查通道顺序:RGB 和 BGR 是否在转换过程中被弄反。
- 检查输入数据内存是否拷全:输入张量是否连续,数据拷贝长度是否足够。
- 检查模型是否是用 PyTorch 训练后再导出,导出前是否已经切换到 eval 模式。
6.5 容器内无法使用加速卡
现象:宿主机上推理正常,容器内npu-smi看不到设备。
原因一般是容器启动时没有传入设备节点,也没有使用昇腾容器运行时。
检查启动命令是否包含类似下面的参数:
--device /dev/davinci0 \ --device /dev/davinci_manager \ -v /usr/local/Ascend:/usr/local/Ascend如果是 Docker,建议确认是否已经配置 Ascend Docker Runtime,而不是简单挂载设备文件。容器内版本必须和宿主机驱动兼容,否则看不到设备或加载模型失败。
以下排查表可以贴在测试环境旁边:
| 现象 | 检查顺序 | 处理建议 |
|---|---|---|
| lspci 无设备 | 物理链路 -> 插槽 -> BIOS | 重新插拔或换槽 |
| npu-smi 报错 | 版本 -> 设备节点权限 -> 残留驱动 | 清理重装并核对版本 |
| ATC 转换失败 | 输入名 -> soc_version -> 算子 | 按日志定位并修正 |
| 结果 NaN | 预处理 -> 通道顺序 -> 模型状态 | 对照训练预处理逐项核对 |
| 容器无设备 | 挂载参数 -> runtime -> 版本 | 检查启动参数并安装对应 runtime |
7. 从学习环境走向生产环境:版本管理和部署清单
7.1 版本组合要记录成文档
Atlas 300I Duo 的环境不是“装一次就能永续使用”的。驱动、固件、CANN、推理框架之间互相约束,升级任何一个组件都可能影响其他部分。
建议在项目里维护一份环境信息文件,至少包含:
- 操作系统发行版和内核版本。
- 驱动版本和固件版本。
- CANN 版本和安装路径。
- 推理框架(MindSpore、PyTorch 适配版等)版本。
- 模型转换使用的 ATC 版本。
- 当前环境的
npu-smi info输出样例。
这样换新机器、升级组件、排查问题时,不用反复“猜版本”。
7.2 容器化部署注意事项
生产环境很多服务以容器方式运行。使用 Atlas 300I Duo 时,容器化不是简单把代码打进去就行,还需要处理:
- 设备挂载:把 davinci 设备和 davinci_manager 映射到容器。
- 环境变量:CANN 的 set_env.sh 要在容器启动时自动 source。
- 运行时:使用昇腾容器运行时,才能正确处理设备文件。
- 资源限制:容器内部对设备内存、队列数量的限制需要和任务负载匹配。
冷启动和模型加载时间也要考虑。如果服务需要快速扩容,预先加载模型到内存能缩短第一个请求的响应时间。
7.3 生产上线前检查清单
测试环境和生产环境之间的差距,往往就体现在这些细节里:
| 检查项 | 学习环境 | 生产环境 |
|---|---|---|
| 驱动安装 | 能跑通即可 | 记录版本并纳入变更管理 |
| 环境变量 | 手动 source | 开机或容器启动自动加载 |
| 模型转换 | 单模型验证 | 统一转换流水线,保留日志 |
| 推理结果 | 人工核对 | 自动断言输出 shape 和精度阈值 |
| 性能验证 | 单路测试 | 并发、压测、监控齐全 |
| 异常处理 | 打印异常 | 上报、告警、恢复流程 |
| 备份回滚 | 不关注 | 驱动和模型版本可回滚 |
| 安全权限 | 本机 root | 最小权限,限制设备访问 |
这张表不只是给 Atlas 300I Duo 用的,其他 AI 加速卡测试项目也可以参考。
7.4 后续可以扩展的方向
跑通 Atlas 300I Duo 推理后,可以继续研究:
- 使用 MindX SDK 或 ModelBox 封装推理服务,减少直接操作 ACL 的代码量。
- 把多个模型切成多个逻辑设备,提高单卡利用率。
- 在 Kubernetes 集群中管理带 AI 加速卡的节点,做推理服务的自动调度。
- 关注昇腾社区中针对具体模型的算子优化和动态 shape 支持情况。
从硬件识别到模型落地,Atlas 300I Duo 测试过程中最花时间的通常不是模型代码,而是环境版本、设备节点、算子支持和精度验证这些工程细节。把这些细节沉淀成文档和检查清单,后续不管是换机器还是换模型,都能少走很多弯路。