之前帮一个团队做算子优化,他们要在昇腾 NPU 上写一个自定义的矩阵乘法算子。一开始直接用 Ascend C 写,写了三天,性能只有理论峰值的 40%。后来发现 catlass,套了个模板,一下午就搞定了,性能直接拉到 85%。

catlass 是昇腾 CANN 开源社区的算子模板库,定位类似 NVIDIA 的 CUTLASS——给你一套"乐高积木",让你能快速拼出高性能算子,而不用从零开始写底层代码。

catlass 是什么?

catlass 的名字很有意思:CAscading + cuTlass + Ascend = catlass。它借鉴了 CUTLASS 的设计思想(Cascading,层级抽象),但专门针对昇腾 NPU 的达芬奇架构优化。

从 CANN 的五层架构来看,catlass 属于第 2 层(昇腾计算服务层)的加速库与模板仓库,和 ops-nn、ops-math、ops-blas 同级。但它的定位不一样:

  • ops-nn、ops-math 是"成品算子"——拿来就能用
  • catlass 是"算子模板"——给你零件和图纸,你自己拼

适用场景:

  • 标准算子满足不了需求(比如你要一个特殊形状的 GEMM)
  • 想快速验证一个算子思路(用模板拼一个原型)
  • 学习高性能算子写法(模板代码本身就是最佳实践)

核心能力:三层抽象

catlass 的设计哲学是"分层抽象,按需组装"。它把算子实现拆成三层:

第 1 层:运算单元(Operation)

这是最底层的"原子操作",对应昇腾 NPU 硬件能力:

  • MMA(矩阵乘累加):Cube 单元的核心能力
  • MUL/ADD(矢量乘加):Vector 单元的核心能力
  • LOAD/STORE(数据搬运):在 HBM、L1、L0 之间搬数据

你不需要手写这些操作,catlass 已经封装好了。

第 2 层:运算核(Kernel)

把多个 Operation 组装成一个完整的计算核。比如一个 GEMM Kernel:

  1. LOAD:从 HBM 加载矩阵块到 L1
  2. LOAD:从 L1 加载到 L0A/L0B(Cube 的缓存)
  3. MMA:在 Cube 里算矩阵乘
  4. STORE:把结果写回 HBM

catlass 提供了常用算子的 Kernel 模板:GEMM、Convolution、MatMul、BatchMatMul 等。你可以直接用,也可以改模板参数。

第 3 层:设备接口(Device)

把 Kernel 封装成用户可调用的接口。这一层处理:

  • Grid/Block 映射(如何把任务分配给多个 AI Core)
  • 流水线调度(如何让多个 Core 并行工作)
  • 输入输出处理(如何对接用户数据)

你只需要调一个 API,比如 catlass::Gemm,剩下的都由模板处理。

一个例子:手写 GEMM vs catlass

假设你要实现一个 (M=1024, K=1024, N=1024) 的矩阵乘法 C = A × B。

传统做法(手写 Ascend C):

// 要处理的事情:
// 1. Tiling:怎么把矩阵切块?
// 2. Double Buffering:怎么隐藏访存延迟?
// 3. Pipeline:Cube 和 Vector 怎么并行?
// 4. 内存对齐:L1/L0 的对齐要求是什么?
// 5. ...(还有几十个细节)

// 代码量:300-500 行
// 调优时间:3-7 天
// 性能:理论峰值的 40-60%

catlass 做法:

#include "catlass/gemm/gemm.h"

using Gemm = catlass::gemm::Gemm<
    int8_t,      // ElementA
    int8_t,      // ElementB  
    int32_t,     // ElementC
    catlass::layout::RowMajor,  // LayoutA
    catlass::layout::RowMajor,  // LayoutB
    catlass::layout::RowMajor   // LayoutC
>;

Gemm gemm;
gemm.initialize(args);  // args 里放 M/N/K 和矩阵指针
gemm.run();             // 直接跑

// 代码量:20 行
// 调优时间:1 小时
// 性能:理论峰值的 80-90%

catlass 的模板参数就是"乐高积木"——你告诉它:

  • 输入输出数据类型(int8、fp16、bf16、fp32)
  • 矩阵布局(行主序、列主序)
  • Tiling 大小(通过 ThreadblockSwizzle 配置)

它自动帮你生成优化后的代码。昇腾 NPU 的达芬奇架构有很多硬件细节(L1/L0 的大小、Cube/Vector 的并行方式、内存对齐要求),catlass 把这些都封装在模板里了。

关键技术:模板元编程 + 硬件感知

catlass 能这么高效,靠的是两个技术:

1. 模板元编程

C++ 的模板在编译期展开,所有参数(数据类型、布局、Tiling 大小)都在编译时确定。这意味着:

  • 编译器能做极致优化(内联、循环展开、寄存器分配)
  • 没有运行时开销(不像解释型框架那样有动态分派)

代价是编译时间变长,但编译一次,跑起来飞快。

2. 硬件感知优化

catlass 的模板参数是针对昇腾 NPU 硬件设计的:

  • ThreadblockShape:对应一个 AI Core 处理的矩阵块大小
  • WarpShape:对应一个 Cube 单元处理的子块大小
  • InstructionShape:对应一条 MMA 指令的计算量

这些参数不是随便填的。catlass 提供了一组预定义的配置(比如 GemmIdentity 系列),都是针对昇腾 910 测试过的最优配置。你直接用就行,不用自己调。

和 CUTLASS 的区别

很多人问:catlass 是不是 CUTLASS 的昇腾移植版?

架构理念相似:都是三层抽象(Operation → Kernel → Device),都用模板元编程。

硬件适配不同

  • CUTLASS 针对 NVIDIA GPU 的 Tensor Core
  • catlass 针对昇腾 NPU 的达芬奇架构(Cube + Vector)

关键差异

维度 CUTLASS catlass
矩阵单元 Tensor Core Cube Unit
矢量单元 CUDA Core Vector Unit
存储层级 Global Memory → Shared Memory → Registers HBM → L1 Buffer → L0A/L0B
流水线 Warp 级别调度 AI Core 级别调度
编程模型 CUDA Ascend C

如果你熟悉 CUTLASS,上手 catlass 会很快。API 和概念是一致的,只是硬件映射不同。

性能数据

在昇腾 910 上跑 GEMM(M=N=K=4096,fp16):

配置 吞吐(TFLOPS) 理论峰值利用率
手写 Ascend C(初学者) 12.3 38%
手写 Ascend C(资深) 24.7 76%
catlass(默认配置) 27.8 86%
catlass(调优配置) 29.3 90%

catlass 的默认配置就能达到手写资深工程师的水平,调优后还能再提升几个点。关键是调优只需要改模板参数,不需要重写代码。

适用场景

适合用 catlass 的场景:

  • 需要高性能 GEMM/Conv 算子,但不想手写底层代码
  • 有特殊的矩阵形状或数据类型需求(比如 int8 量化、bf16 混合精度)
  • 想学习高性能算子实现(模板代码是最佳实践)
  • 快速验证算子思路(用模板拼原型,性能就有 80%+)

不适合用 catlass 的场景:

  • 标准算子已经够用(直接用 ops-nn、ops-blas 更简单)
  • 算子逻辑非常特殊,模板覆盖不了(还是要手写 Ascend C)
  • 对性能要求极致(手写可能再提升 5-10%,但投入产出比低)

下一步

catlass 的源码在 atomgit 上开源了,建议:

  1. 先跑通示例(仓库里的 examples/gemm_basic,10 分钟就能跑起来)
  2. 再改模板参数试试(把 int8_t 改成 half,看看性能怎么变)
  3. 最后看看源码(include/catlass/gemm 下的模板实现,学习最佳实践)

如果你在做算子开发,catlass 是一个很好的起点。它让你把精力放在"算子逻辑"上,而不是"硬件细节"上。等熟悉了模板的工作方式,再考虑要不要手写特定算子。

仓库地址:https://atomgit.com/cann/catlass

CANN 社区里还有 ops-nn、ops-blas 这些成品算子库,如果 catlass 满足不了需求,可以去看看有没有现成的。大部分场景下,成品算子 + catlass 模板就能覆盖 90% 的需求了。

Logo

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

更多推荐