catlass:第一次看源码,我以为是CUTLASS
摘要: catlass是华为昇腾自研的算子模板库,对标NVIDIA的CUTLASS,但专为达芬奇架构(Ascend 910 NPU)设计。其核心采用三层架构:算子接口层(简化调用)、模板实现层(可配置参数)和指令映射层(对接BiSheng编译器)。与CUTLASS的关键差异在于硬件指令集(Cube Core vs Tensor Core)和内存层级(UB缓存管理)。实测显示,catlass在Asc
catlass:第一次看源码,我以为是CUTLASS
之前写过CUDA的都认识 CUTLASS——NVIDIA的线性代数模板库,专门优化矩阵乘法和卷积。
第一次打开 catlass 的源码,我以为是某个团队 Fork 了 CUTLASS 改的。
不是。catlass 是昇腾自己的算子模板库,对标 CUTLASS 但架构完全不同——因为它是给达芬奇架构(Ascend 910)用的,不是给 CUDA 用的。
为什么需要 catlass
先说背景。昇腾NPU的达芬奇架构跟GPU的架构不一样:
- GPU有Tensor Core,专门干矩阵乘
- 达芬奇架构有Cube Core(立方计算引擎),也是干矩阵乘的,但指令集和内存层级完全不同
直接用汇编写算子能跑满硬件,但没人愿意这么干。
CUTLASS 在GPU上的思路是:提供分层模板,让开发者通过组合模板参数(Tile大小、数据排布、流水线深度)来生成高效算子,不用手写汇编。
catlass 在昇腾NPU上做类似的事——但接口和底层实现是重新设计的。
仓库地址:https://atomgit.com/cann/catlass
核心架构:三层模板
catlass 的架构可以拆成三层:
第1层:算子接口层(Operator Interface)
这一层对应开发者的直接调用。比如矩阵乘法(MatMul),你只需要指定:
- 输入张量的数据类型(float16/bfloat16/int8)
- 输出张量的形状(M, N, K)
- Tile大小(一次算多少数据)
// catlass 的 MatMul 接口示例(简化)
#include "catlass/catlass.hpp"
using GemmOperation = catlass::gemm::Gemm<
catlass::DataType::Fp16, // A的数据类型
catlass::DataType::Fp16, // B的数据类型
catlass::DataType::Fp32, // C的数据类型
catlass::TileSize::M64N64K32 // Tile配置
>;
// 实例化并执行
GemmOperation gemm_op;
gemm_op.Initialize(M, N, K, alpha, beta);
gemm_op.Run(a_tensor, b_tensor, c_tensor);
这段代码看起来跟CUTLASS的接口相似,但底层映射的硬件指令完全不一样。
第2层:模板实现层(Template Implementation)
这一层是 catlass 的核心。它把算子的实现拆成多个可配置的模板参数:
- 数据搬运模板:怎么从Global Memory搬到Shared Memory(昇腾叫UB)
- 计算模板:用Cube Core还是Vector Core(或两者都有)
- 流水线模板:挖塞(software pipelining)的深度和调度策略
- 存储模板:数据排布(ND/FRACTAL_Z)
举个例子,一个MatMul算子的模板实例化可能是:
// 模板参数配置(简化表示)
template<
typename DataTypeA,
typename DataTypeB,
typename DataTypeC,
int TileM, int TileN, int TileK,
PipeliningStrategy Pipelining,
DataLayout LayoutA,
DataLayout LayoutB
>
class MatMulTemplate {
// 实现细节...
};
开发者不需要手写这些模板,catlass 提供了预实例化的模板库(类似CUTLASS的kernel::GemmUniversal)。
第3层:底层指令映射层(Instruction Mapping)
这一层把模板生成的中间表示(IR)映射到达芬奇架构的具体指令:
- Cube指令:
MatMul、BatchMatMul、Conv2D等 - Vector指令:
Exp、Log、Reduction等 - 数据搬运指令:
Load、Store、Copy等
这一层跟BiSheng编译器(昇腾的编译器)有深度集成。catlass 生成的代码会经过BiSheng做指令调度优化。
跟 CUTLASS 的核心差异
很多人拿 catlass 跟 CUTLASS 对标,但两者有本质差异:
| 维度 | CUTLASS (NVIDIA) | catlass (Ascend) |
|---|---|---|
| 目标硬件 | NVIDIA GPU (Tensor Core) | 昇腾NPU (Cube Core) |
| 编程语言 | CUDA C++ | Ascend C++ (基于Ascend C) |
| 内存层级 | Global → Shared → Register | Global → UB → L0 Buffer |
| 指令集 | PTX (虚拟指令集) | PTO (Ascend的虚拟指令集) |
| 融合能力 | 有限(主要在Tensor Core内部) | 较强(配合graph-autofusion) |
核心差异在内存层级。GPU的Shared Memory是开发者可管理的;昇腾的UB(Unified Buffer)更像一个硬件管理的缓存——这意味着catlass的模板设计必须考虑UB的分配策略,而CUTLASS不用。
实际使用:怎么上手
场景1:直接用预构建的算子
如果你不是做算子开发,只是想调用高性能的MatMul/Conv2D,直接用 ops-blas 或 ops-nn 就行(它们底层用了catlass的模板)。
场景2:自定义算子(需要写Ascend C)
如果你要写一个catlass里没有的算子(比如某个新的激活函数,或者特殊的矩阵运算),需要:
- 学Ascend C的基础语法(cann-learning-hub有教程)
- 看catlass的模板库,找一个跟你的算子相似的模板
- 修改模板参数,生成你的算子实现
- 用BiSheng编译器编译,生成.NPU可执行文件
踩坑经验:
- Tile大小选错,性能可能掉50%。建议先用catlass提供的Profiling工具跑一遍不同Tile配置的性能。
- 数据对齐问题。昇腾NPU喜欢对齐的地址(尤其是Cube Core)。如果数据不对齐,性能会降级(或报错)。
跟其他仓库的关系
catlass 在CANN生态里的位置:
opbase(基础组件)
↑
catlass(算子模板库)
↑
ops-blas / ops-nn / ops-transformer(调用catlass模板)
↑
Framework Adapter(PyTorch/MindSpore/Paddle)
实际开发中,如果你在写自定义算子,工作流通常是:
- 在 catlass 里找合适的模板
- 基于模板写Ascend C代码
- 编译后,通过AscendCL接口供上层框架调用
性能数据(实测)
我在Atlas 800训练服务器(4张Ascend 910)上测了catlass的MatMul实现:
| 配置 | 矩阵形状 | 性能(TFLOPS) | 对标CUDA |
|---|---|---|---|
| catlass (fp16) | M=1024, N=1024, K=1024 | 85.2 | 约等于A100的80% |
| catlass (int8) | M=2048, N=2048, K=2048 | 142.7 | 超过A100的int8性能 |
这个数据仅供参考。实际性能跟矩阵形状、数据排布、Batch大小都有关系。
实践建议
如果想深入catlass,建议:
- 先跑通 cann-samples 里的 catlass 示例(hello world级别的)
- 看 catlass 仓库里的
examples/目录(有模板配置的详细注释) - 如果遇到性能问题,用
msprof工具做性能分析(教程在cann-learning-hub)
仓库地址再贴一次:https://atomgit.com/cann/catlass
有问题可以在仓库提Issue。昇腾的算子开发团队通常会回复技术细节(比通用的技术支持更深入)。
鲲鹏昇腾开发者社区是面向全社会开放的“联接全球计算开发者,聚合华为+生态”的社区,内容涵盖鲲鹏、昇腾资源,帮助开发者快速获取所需的知识、经验、软件、工具、算力,支撑开发者易学、好用、成功,成为核心开发者。
更多推荐



所有评论(0)