CANN到底是什么?昇腾NPU上的“操作系统+发动机调校师“全拆解
昇腾CANN架构解析:从模型到NPU的全栈优化 CANN是昇腾NPU的核心软件栈,相当于GPU生态中的CUDA+cuDNN+TensorRT组合。文章通过汽车引擎的比喻,形象地解释了CANN的五层架构体系:最上层的AscendCL作为统一接口,中间的计算服务层提供现成算子库,核心的图引擎(GE)负责计算图优化,Runtime执行层管理硬件资源,底层驱动完成芯片交互。作者以PyTorch模型在NPU
CANN 到底是什么?
一句话:CANN 是昇腾 AI 硬件的软件栈,相当于 GPU 上的 CUDA + cuDNN + TensorRT 打包在一起,但比那个体系更复杂,因为它要管的不只是计算,还有图编译、算子调度、多框架适配这一整套东西。
如果还不明白,我打个比方:
你买了一辆赛车(昇腾 NPU 硬件)。这辆车引擎很强,但你不能直接往油箱里倒油就上路。你需要:
- 操作系统让车能启动、能响应你的操作
- 变速箱把引擎的动力合理分配到轮子上
- 调校师根据赛道特点调整引擎参数,让它跑最快
CANN 就是这三样东西的集合体。它不是某一个工具,而是一整套从模型到芯片的中间层软件体系。
昇腾 CANN 全称是昇腾异构计算架构(Compute Architecture for Neural Networks),注意不是什么编译器,也不是某个单一组件的名字。它是整个软件体系的总称,就像 Android 是一个操作系统体系,而不只是一个 system_server 进程。
CANN 和昇腾芯片的关系
昇腾芯片(比如 Ascend 910)是硬件,就像发动机。光有发动机跑不起来,你得有一套完整的系统把它驱动起来。
你的 PyTorch / MindSpore / TensorFlow 模型
↓ 框架适配层(Framework Adaptor)
CANN(中间层软件栈)
↓ 驱动 + Runtime
昇腾 NPU 硬件(达芬奇架构)
你在框架里写的 Python 代码,NPU 看不懂。CANN 干的事就是翻译 + 调度 + 优化,让你的模型能在 NPU 上跑起来,而且跑得快。
这里有一个容易混淆的点:很多人以为装了 CANN 就等于装了驱动。不对。CANN 是软件栈,驱动(driver)是它最底层的一部分,但 CANN 还包括编译器、运行时、算子库、工具链,这些跟驱动是两回事。你可以理解为:驱动是地基,CANN 是在地基上盖起来的整栋楼。
2025 年 8 月,CANN 已经全面开源了。55 个仓库,编译器、算子库、加速库、图引擎、运行时全部开放。这在国产 AI 软件栈里算是动作最大的一个,意味着你可以真正去看 GE 的源码、改 ops-transformer 的算子实现、给 catlass 提 PR。
CANN 五层架构:每层都在干啥
CANN 官方文档里把架构分成五层,从上到下依次是。别被层数吓到,我一层一层用大白话讲。
第一层:昇腾计算语言层(AscendCL)—— “对外营业的窗口”
这一层的核心是 AscendCL(Ascend Computing Language)。它是 CANN 对外暴露的编程接口,所有上层框架(PyTorch、MindSpore、TensorFlow)都是通过它来调用昇腾 NPU 的。
你可以把 AscendCL 想象成一个服务窗口。你想用 NPU 算东西?找这个窗口就行。不管你是做推理的、做训练的还是做预处理的,统一从这里进。它提供三类接口:
- 应用开发接口:做推理、预处理、单算子调用的
- 图开发接口:统一构图,支持多框架
- 算子开发接口:用 Ascend C 写自定义算子的入口
这一层还有个重要角色:Ascend C(注意中间有空格,不要写成 AscendC),这是算子编程语言。如果你想自己写一个 NPU 上跑的自定义算子,就用 Ascend C 来写。它类似 CUDA C 在 NVIDIA 生态里的地位,但语法和编程模型完全不同,是针对昇腾达芬奇架构专门设计的。用 Ascend C 写的算子可以直接编译成 NPU 能执行的二进制。
第二层:昇腾计算服务层 —— “工具柜”
这一层放的是各种现成的算子和调优工具。你不需要什么都自己写,这里已经帮你准备好了:
- AOL 算子库:神经网络算子(NN)、基础线性代数(BLAS)、视觉预处理(DVPP)、AI 预处理(AIPP)、集合通信(HCCL)、融合算子,全部有现成的实现
- AOE 调优引擎:包括 OPAT(算子自动调优)、SGAT(子图自动调优)、GDAT(梯度自动调优)、AMCT(模型压缩工具),自动帮你把模型调到最优性能,不用手动试参数
- Framework Adaptor:让不同框架能无缝对接下面的编译和执行层,PyTorch 的
torch_npu插件就是通过这个适配层跟 CANN 打交道的
对应到开源仓库的话,ops-math、ops-nn、ops-transformer 这些算子库都属于这一层的产出物。ops-transformer 专门放大模型里的 FlashAttention、MoE、MC2 这类高级算子,是目前社区关注度最高的仓库之一,因为大模型推理的瓶颈基本都在这些算子上。
第三层:昇腾计算编译层 —— “AI模型的流水线调度员”
这是 CANN 最核心也最复杂的一层,主角是 GE(Graph Engine,图引擎)。
为什么需要图引擎?因为你写的 PyTorch 代码是一行行执行的(动态图),但 NPU 的架构更适合拿到一张完整的计算图,然后一次性规划怎么执行最高效(静态图执行)。
GE 干的事情就是:
- 把你的模型转换成计算图(Graph)
- 做图优化:算子融合(比如 Conv+BN+ReLU 合成一个)、内存复用、并行调度
- 把优化后的图交给下层去执行
- 处理控制流(if/else、循环)在静态图中的表达
我把 GE 比作流水线调度员。你给一堆原材料(模型代码),他负责安排哪道工序先做、哪些可以同时做、怎么减少中间库存(显存占用)。一个好的调度员能让整条流水线几乎不停顿,GE 做图优化也是这个目的。
这一层还有 ATC 工具(Ascend Tensor Compiler),它是一个命令行工具,把你训练好的模型(比如 .pb 或 .onnx 格式)转成昇腾 NPU 能直接跑的离线模型(.om 格式)。后面我会用一个具体场景演示这个过程。
另外还有 BiSheng 编译器,负责把算子粒度的代码编译成 NPU 达芬奇架构能执行的二进制指令。这块在开源仓库里对应的是 ge 和 metadef 两个仓库。
第四层:昇腾计算执行层 —— “芯片资源的管理员”
图编译好了,总得有人真正去驱动硬件执行吧?这就是 Runtime 运行时干的活。
Runtime 是真正跟 NPU 硬件打交道的层。它负责:
- 给模型分配显存(HBM 管理)
- 把算子加载到 NPU 上执行
- 管理 NPU 的计算单元(AI Core)、显存带宽这些资源
- 处理多任务并发(多个进程同时用 NPU)
- 处理 Host-Device 之间的数据搬运(CPU 内存 ↔ NPU 显存)
除了 Runtime,这一层还有几个重要组件:
- HCCL(Huawei Collective Communication Library):集合通信库,多卡并行训练时用它做 AllReduce、AllGather 之类的通信操作。这个在分布式训练里是关键路径,性能直接决定多卡扩展效率。
- DVPP(Digital Vision Pre-Processing):数字视觉预处理,在 NPU 上直接做图片解码和缩放,省得数据在 CPU 和 NPU 之间来回搬。
- AIPP(AI Pre-Processing):AI 预处理,图像增强、归一化这类操作,可以在推理之前离线做掉,减少在线计算量。
- Graph Executor:图执行器,拿到 GE 优化后的图,真正按拓扑顺序调度算子执行。
第五层:昇腾计算基础层 —— “地基”
这一层是最底层的驱动和系统服务,普通开发者基本不会直接碰到。包括芯片驱动(DRV)、资源管理(RMS/CMS/DMS)、虚拟内存管理(SVM/VM)、主机设备通信(HDC)、以及一堆底层 UTILITY。
你知道它的存在就行了。除非你要做 CANN 本身的开发,否则不需要深入这一层。
一个真实场景:跑一个 PyTorch 模型,CANN 在哪里?
说了这么多理论,来看一个具体的例子。假设你有一个 ResNet-50 的 PyTorch 模型,想在昇腾 NPU 上做推理。整个流程大概是这样的:
# 第一步:你的原始代码(PyTorch)
import torch
import torchvision
model = torchvision.models.resnet50(weights=None)
model = model.eval()
# 加载权重(这里省略了 weights 加载代码)
img = torch.randn(1, 3, 224, 224)
这只是纯 PyTorch 的代码。在 GPU 上,这段代码直接 model = model.cuda() 然后 img = img.cuda() 就能跑。在昇腾 NPU 上,你只需要加一行 import torch_npu,然后把 .cuda() 改成 .npu() 就行:
# 加上 torch_npu,直接就能用 NPU
import torch_npu
model = torchvision.models.resnet50(weights=None)
model = model.npu() # 搬到 NPU 上
model.eval()
img = torch.randn(1, 3, 224, 224).npu() # 数据也搬到 NPU 上
output = model(img)
看起来没多复杂。但实际上背后发生了一连串事情,每一件都有 CANN 的组件在参与:
1. import torch_npu —— Framework Adaptor 加载
这一行把昇腾适配层加载进来。它注册了 NPU 作为 PyTorch 的一个新后端(backend),这样你后面写 .npu() 的时候,PyTorch 知道该调哪套底层实现。
2. .npu() —— AscendCL + Runtime 接管
当你写 .npu() 的时候,torch_npu 插件开始工作。它通过 AscendCL(第一层)跟 CANN 建立连接,调用 Runtime(第四层)申请 NPU 设备资源,把模型的参数张量从 CPU 内存搬到 NPU 的 HBM 显存里。
3. 前向传播 —— GE 图引擎介入
PyTorch 默认是动态图的,一行行执行。但 GE 图引擎(第三层)更擅长处理静态图。所以 torch_npu 会在第一次执行时进行一次图捕获,把 forward() 里的计算转成 GE 能处理的计算图格式。这一步叫 Trace 或者 图导出。
4. GE 做图优化
GE 拿到计算图之后开始做优化:
- 把连续的 Conv+BN+ReLU 融合成一个算子(算子融合,减少内存读写次数)
- 把多个小矩阵乘法合并成一个大矩阵乘法(提高计算密度,充分利用 AI Core)
- 规划显存分配,尽量复用中间 buffer(减少显存峰值占用)
- 对达芬奇架构做针对性的指令排布优化
5. Runtime 执行
优化后的图中每个节点都是一个算子。这些算子要么来自第二层的 AOL 算子库(标准算子直接用现成的实现),要么需要 JIT 编译(自定义算子组合)。Runtime 拿到执行计划,开始调度:分配显存、加载算子到 NPU 的 AI Core 上、按拓扑顺序执行。
整个过程对你来说是透明的。你只写了 10 行不到的 Python,但 CANN 在背后干了上百件事。
另一个场景:ATC 工具转离线模型
如果你要做生产级部署,一般不会用上面的动态推理方式(因为每次启动都要重新做图捕获和优化,延迟高),而是先用 ATC 把模型转成离线的 .om 文件:
# 先把 PyTorch 模型转成 ONNX
python -c "
import torch
model = torchvision.models.resnet50(weights=None)
model.eval()
torch.onnx.export(model, torch.randn(1,3,224,224), 'resnet50.onnx', input_names=['input'], output_names=['output'])
"
# 用 ATC 转成昇腾能跑的离线模型
atc \
--model=resnet50.onnx \
--framework=5 \
--output=resnet50_npu \
--soc_version=Ascend910 \
--input_shape="actual_input_1:1,3,224,224" \
--input_format=NCHW
这条命令背后发生了什么:
- ATC 解析你的 ONNX 模型文件,构建计算图(基于
ge仓库里的图定义) - GE 引擎对图做优化(融合、常量折叠、布局调整、算子调度策略选择等)
- 选择最优的算子实现(同一个算子可能有多种实现,GE 根据输入形状、硬件版本选最快的)
- BiSheng 编译器把算子编译成 NPU 达芬奇架构的二进制指令
- 编译生成 .om 离线模型文件(包含所有算子的二进制 + 执行计划 + 显存分配方案)
- 这个 .om 文件可以直接用 AscendCL 的推理 API 加载执行,不需要再经过图编译阶段
为什么要这么做?因为离线模型把编译阶段的工作提前做完了,推理的时候直接加载执行,启动更快,延迟更低,更适合生产环境。很多做推理部署的团队,线上跑的都是 .om 文件,不是原始的 PyTorch 或 ONNX 模型。
CANN 开源仓库全景(55 个,怎么找自己需要的)
CANN 全面开源后,55 个仓库在 AtomGit 上都能看到。刚开始面对这么多仓库会懵,我按用途给你分个类,以后要找什么直接去对应分类里翻:
算子类仓库(你写模型会间接用到,也可以直接调用):
ops-transformer:Transformer 大模型算子库,FlashAttention、MoE、MC2 都在这。做大模型推理的必看。ops-nn:神经网络类基础算子,MatMul、激活函数、Softmax 这些。ops-math:数学类基础算子,conversion、random 类。ops-blas:线性代数基础算子库,高性能 GEMM 实现。opbase:算子基础组件/通用库,是所有算子仓库的基础依赖。
加速库与模板仓库(想榨干 NPU 性能就看这些):
ascend-transformer-boost(ATB):Transformer 加速库,封装了 ops-transformer 的算子,对外提供更高级的接口。catlass:昇腾算子模板库,类似 NVIDIA 的 CUTLASS,但针对达芬奇架构设计。
编译与运行时仓库(底层核心):
ge:图引擎,CANN 最核心的编译组件,值得深入读源码。runtime:运行时,管理 NPU 执行。hccl:集合通信库源码。
学习资源(新手必看):
cann-learning-hub:社区学习中心,有教程、博客、竞赛 skill。cann-samples:示例代码,各种场景都有。cann-recipes-infer:推理最佳实践,有大量可直接跑的例子。cann-recipes-train:训练最佳实践。
新手入门该从哪入手?
如果你刚接触昇腾生态,我的建议是这样的路径,不要一上来就啃源码:
第一步:先跑通一个模型
不要一上来就研究架构。装好 CANN 环境,用 PyTorch + torch_npu 跑通一个简单的推理或训练任务。感受一下整个流程走通是什么样子。cann-recipes-infer 仓库里有大量现成的例子,直接拿来改就能跑。建议从 ResNet-50 推理开始,因为这是最成熟的路径,踩坑最少。
第二步:理解 ATC 模型转换
学会用 ATC 把自己的模型转成 .om 文件,理解什么是计算图、什么是算子融合。这一步会让你对 CANN 的编译层有直观认识。你可以在转换的时候加 --log=info 参数,看 GE 做了哪些图优化,对理解 CANN 的工作方式帮助很大。
第三步:看一眼 GE 和 Runtime 是干什么的
不需要读源码,但要理解它们各自负责什么。GE 管"怎么编排计算图",Runtime 管"怎么把编排好的计划扔给硬件执行"。这两个概念搞懂了,后面遇到性能问题就知道往哪个方向查。比如推理延迟高,先看 GE 的图优化日志,看是不是有算子没融合;如果融合了还慢,再看 Runtime 的 profiling 数据,看是不是某个算子实现本身慢。
第四步:深入算子层面(进阶)
当你需要做性能调优或者开发自定义算子时,就需要了解 ops-* 算子库和 Ascend C 编程了。这是进阶内容,不急。建议先从改现有算子开始,比如给 ops-transformer 里的 FlashAttention 加一个参数,体会一下 Ascend C 的编程模型,再去写自己的算子。
总结
CANN 说复杂也复杂——五层架构、55 个开源仓库、几十种工具和接口。说简单也简单——它就是一套让 AI 模型能在昇腾 NPU 上高效运行的软件体系,核心就三件事:翻译(把框架代码转成 NPU 能懂的东西)、调度(GE 图引擎规划最优执行路径)、优化(算子融合、内存复用、指令排布)。
对于大多数开发者来说,你不需要精通每一层。你需要知道的是:CANN 在你的模型和 NPU 硬件之间做了翻译、调度和优化这三件事。理解了这个,再看具体的组件和工具,就不会迷失方向。
昇腾生态正在快速成熟,CANN 全面开源意味着社区力量可以参与到核心软件栈的建设中。不管你是做大模型训练、推理部署,还是算子开发,这套体系都有对应的工具和库可以用。AtomGit 上的 55 个仓库就是全部家当,遇到问题去翻对应仓库的 Issues 和 Discussions,社区响应速度比以前快多了。
本篇文章涉及的相关仓库:
鲲鹏昇腾开发者社区是面向全社会开放的“联接全球计算开发者,聚合华为+生态”的社区,内容涵盖鲲鹏、昇腾资源,帮助开发者快速获取所需的知识、经验、软件、工具、算力,支撑开发者易学、好用、成功,成为核心开发者。
更多推荐



所有评论(0)