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 干的事情就是:

  1. 把你的模型转换成计算图(Graph)
  2. 做图优化:算子融合(比如 Conv+BN+ReLU 合成一个)、内存复用、并行调度
  3. 把优化后的图交给下层去执行
  4. 处理控制流(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

这条命令背后发生了什么:

  1. ATC 解析你的 ONNX 模型文件,构建计算图(基于 ge 仓库里的图定义)
  2. GE 引擎对图做优化(融合、常量折叠、布局调整、算子调度策略选择等)
  3. 选择最优的算子实现(同一个算子可能有多种实现,GE 根据输入形状、硬件版本选最快的)
  4. BiSheng 编译器把算子编译成 NPU 达芬奇架构的二进制指令
  5. 编译生成 .om 离线模型文件(包含所有算子的二进制 + 执行计划 + 显存分配方案)
  6. 这个 .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,社区响应速度比以前快多了。

本篇文章涉及的相关仓库:

Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐