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指令MatMulBatchMatMulConv2D
  • Vector指令ExpLogReduction
  • 数据搬运指令LoadStoreCopy

这一层跟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-blasops-nn 就行(它们底层用了catlass的模板)。

场景2:自定义算子(需要写Ascend C)

如果你要写一个catlass里没有的算子(比如某个新的激活函数,或者特殊的矩阵运算),需要:

  1. 学Ascend C的基础语法(cann-learning-hub有教程)
  2. 看catlass的模板库,找一个跟你的算子相似的模板
  3. 修改模板参数,生成你的算子实现
  4. 用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)

实际开发中,如果你在写自定义算子,工作流通常是:

  1. 在 catlass 里找合适的模板
  2. 基于模板写Ascend C代码
  3. 编译后,通过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,建议:

  1. 先跑通 cann-samples 里的 catlass 示例(hello world级别的)
  2. 看 catlass 仓库里的 examples/ 目录(有模板配置的详细注释)
  3. 如果遇到性能问题,用 msprof 工具做性能分析(教程在cann-learning-hub)

仓库地址再贴一次:https://atomgit.com/cann/catlass

有问题可以在仓库提Issue。昇腾的算子开发团队通常会回复技术细节(比通用的技术支持更深入)。


Logo

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

更多推荐