Ascend C提供一组Matmul高阶API,方便用户快速实现Matmul矩阵乘法的运算操作。
Matmul的计算公式为:C = A * B + Bias,其示意图如下。
除Matmul的基本功能外,对Matmul的特性场景说明如下。您可以根据实际应用场景,选择性了解Matmul特性场景的内容。
Matmul Tiling常量化为在编译期期间获取常量化的Matmul Tiling参数并进行算子编译,从而减少Scalar计算开销,提升算子整体性能。具体为,在获取Matmul模板时,可以确定MatmulConfig的singleCore Shape(MatmulConfig中的singleCoreM/singleCoreN/singleCoreK)和Base Shape(MatmulConfig中的basicM/basicN/basicK)参数,或者只确定Base Shape参数;通过指定获取模板的接口中的singleCore Shape和Base Shape参数,或者只指定Base Shape参数,获取自定义模板;然后通过调用GetMatmulApiTiling接口,得到常量化的Matmul Tiling参数。
Sparse Matmul场景为稀疏矩阵计算场景,该场景支持B矩阵为4:2的稠密输入并进行矩阵乘计算,从而减少矩阵乘计算时的内存占用,提升性能。在计算执行前的数据准备阶段,自行完成B矩阵的稠密化(稠密过程参考稠密算法说明)。实现Matmul计算时,在Kernel侧将B矩阵的参数类型设置为SparseMatmulType类型,稠密化过程中生成的索引矩阵通过SetSparseIndex接口传入,另外在获取Tiling前需要通过SetSparse接口设置使能Sparse Matmul场景。
下文中提及的M轴方向,即为A矩阵纵向;K轴方向,即为A矩阵横向或B矩阵纵向;N轴方向,即为B矩阵横向;尾轴,即为矩阵最后一个维度。
实现Matmul矩阵乘运算的具体步骤如下:
创建Matmul对象的示例如下:
1 2 3 4 5 6 7 8 9 |
// 纯cube模式(只有矩阵计算)场景下,需要设置该代码宏,并且必须在#include "lib/matmul_intf.h"之前设置 // #define ASCENDC_CUBE_ONLY #include "lib/matmul_intf.h" typedef AscendC::MatmulType<AscendC::TPosition::GM, CubeFormat::ND, half> aType; typedef AscendC::MatmulType<AscendC::TPosition::GM, CubeFormat::ND, half> bType; typedef AscendC::MatmulType<AscendC::TPosition::GM, CubeFormat::ND, float> cType; typedef AscendC::MatmulType<AscendC::TPosition::GM, CubeFormat::ND, float> biasType; AscendC::Matmul<aType, bType, cType, biasType> mm; |
创建对象时需要传入A、B、C、Bias的参数类型信息, 类型信息通过MatmulType来定义,包括:内存逻辑位置、数据格式、数据类型。
1 2 3 4 5 6 7 8 9 |
template <AscendC::TPosition POSITION, CubeFormat FORMAT, typename TYPE, bool ISTRANS = false, LayoutMode LAYOUT = LayoutMode::NONE, bool IBSHARE = false> struct MatmulType { constexpr static AscendC::TPosition pos = POSITION; constexpr static CubeFormat format = FORMAT; using T = TYPE; constexpr static bool isTrans = ISTRANS; constexpr static LayoutMode layout = LAYOUT; constexpr static bool ibShare = IBSHARE; }; |
Sparse Matmul场景与上述不同的是,通过SparseMatmulType类型定义矩阵B的参数类型,参数类型信息包括:矩阵B的内存逻辑位置、索引矩阵的内存逻辑位置、数据格式、数据类型等。
1 2 |
// 通过SparseMatmulType定义矩阵B的参数类型信息 typedef AscendC::SparseMatmulType<AscendC::TPosition::GM, AscendC::TPosition::GM, CubeFormat::ND, half> bType; |
1 2 3 4 |
template <TPosition POSITION, TPosition INDEX_POSITION, CubeFormat FORMAT, typename TYPE, bool ISTRANS = false, LayoutMode LAYOUT = LayoutMode::NONE, bool IBSHARE = false> struct SparseMatmulType : public MatmulType<POSITION, FORMAT, TYPE, ISTRANS, LAYOUT, IBSHARE> { constexpr static TPosition indexPosition = INDEX_POSITION; }; |
参数 |
说明 |
---|---|
POSITION |
内存逻辑位置。 针对
注意,C矩阵设置为TPosition::CO1时,C矩阵的数据排布格式仅支持CubeFormat::NZ,C矩阵的数据类型仅支持float、int32_t。 针对
针对
|
FORMAT |
数据的物理排布格式,详细介绍请参考数据格式。 针对
针对
注意:针对 针对
注意: 针对 关于CubeFormat::NZ格式的A矩阵、B矩阵、C矩阵的对齐约束,请参考表4。 |
TYPE |
数据类型。
针对
针对
针对
注意:除B矩阵为int8_t数据类型外,A矩阵和B矩阵数据类型需要一致,具体数据类型组合关系请参考表2。 |
是否开启使能矩阵转置的功能。
默认为false不使能转置。 |
|
LAYOUT |
表征数据的排布。 NONE:默认值,表示不使用BatchMatmul;其他选项表示使用BatchMatmul。 NORMAL:BMNK的数据排布格式,具体可参考IterateBatch中对该数据排布的介绍。 BSNGD:原始BSH shape做reshape后的数据排布,具体可参考IterateBatch中对该数据排布的介绍。 SBNGD:原始SBH shape做reshape后的数据排布,具体可参考IterateBatch中对该数据排布的介绍。 BNGS1S2:一般为前两种数据排布进行矩阵乘的输出,S1S2数据连续存放,一个S1S2为一个batch的计算数据,具体可参考IterateBatch中对该数据排布的介绍。 |
IBSHARE |
是否使能IBShare(IntraBlock Share)。IBShare的功能是能够复用L1 Buffer上相同的A矩阵或B矩阵数据。当A矩阵和B矩阵同时使能IBShare时,表示L1 Buffer上的A矩阵和B矩阵同时复用,此时只支持Norm模板(该场景的参数使用样例请参考matmulABshare样例、使能IBShare样例)。 注意,A矩阵和B矩阵同时使能IBShare的场景,需要满足:
除A、B矩阵同时复用的场景外,与IBShare模板配合使用,使用IBShare模板的要求是复用的矩阵必须在L1 Buffer上全载,具体参数设置详见表2。 |
A矩阵 |
B矩阵 |
Bias |
C矩阵 |
支持平台 |
---|---|---|---|---|
float |
float |
float/half |
float |
|
half |
half |
float |
float |
|
half |
half |
half |
float |
|
int8_t |
int8_t |
int32_t |
int32_t/half |
|
int4b_t |
int4b_t |
int32_t |
int32_t/half |
|
bfloat16_t |
bfloat16_t |
float |
float |
|
bfloat16_t |
bfloat16_t |
half |
float |
|
half |
half |
float |
int8_t |
|
bfloat16_t |
bfloat16_t |
float |
int8_t |
|
int8_t |
int8_t |
int32_t |
int8_t |
|
half |
half |
float |
half |
|
half |
half |
half |
half |
|
bfloat16_t |
bfloat16_t |
float |
bfloat16_t |
|
half |
int8_t |
float |
float |
|
参数 |
说明 |
---|---|
POSITION |
内存逻辑位置。 B矩阵支持设置为TPosition::GM。 |
INDEX_POSITION |
索引矩阵内存逻辑位置。 仅支持设置为TPosition::GM。 |
CubeFormat |
数据的物理排布格式,详细介绍请参考数据格式。 |
TYPE |
B矩阵支持设置为int8_t。 |
ISTRANS |
是否开启使能矩阵转置的功能。 当前只支持取值为true,表示开启使能矩阵转置的功能。 |
LAYOUT |
表征数据的排布。支持的取值如下。 NONE:默认值,表示不使用BatchMatmul。 |
IBSHARE |
预留参数。 |
1
|
REGIST_MATMUL_OBJ(&pipe, GetSysWorkSpacePtr(), mm, &tiling); // 初始化matmul对象,参数含义请参考REGIST_MATMUL_OBJ章节 |
1 2 3 4 5 6 |
mm.SetTensorA(gm_a); // 设置左矩阵A mm.SetTensorB(gm_b); // 设置右矩阵B mm.SetBias(gm_bias); // 设置Bias // Atlas 推理系列产品AI Core上需要额外调用SetLocalWorkspace接口设置计算所需的UB空间 mm.SetLocalWorkspace(usedUbBufLen); |
1 2 3 4 |
// API接口内部会进行循环结束条件判断处理 while (mm.Iterate()) { mm.GetTensorC(gm_c); } |
1
|
mm.IterateAll(gm_c); |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
// 定义C矩阵的类型信息 typedef AscendC::MatmulType<AscendC::TPosition::CO1, CubeFormat::NZ, float> cType; // 创建Matmul对象 AscendC::Matmul<aType, bType, cType, biasType> mm; // 用户提前申请CO1的内存l0cTensor TQue<TPosition::CO1, 1> CO1_; // 128 * 1024为申请的CO1内存大小 GetTPipePtr()->InitBuffer(CO1_, 1, 128 * 1024); LocalTensor<L0cT> l0cTensor = CO1_.template AllocTensor<L0cT>(); // 将l0cTensor作为入参传入Iterate,矩阵乘结果输出到用户申请的l0cTensor上 mm.Iterate(false, l0cTensor); // 调用Fixpipe接口将CO1上的计算结果搬运到GM FixpipeParamsV220 params; params.nSize = nSize; params.mSize = mSize; params.srcStride = srcStride; params.dstStride = dstStride; CO1_.EnQue(l0cTensor); CO1_.template DeQue<L0cT>(); Fixpipe<cType, L0cT, CFG_ROW_MAJOR>(gm[dstOffset], l0cTensor, params); //释放CO1内存 CO1_.FreeTensor(l0cTensor); |
1
|
mm.End(); |
源/目的操作数 |
外轴 |
内轴 |
---|---|---|
A矩阵/B矩阵 |
16的倍数 |
C0_size的倍数 |
C矩阵 |
16的倍数 |
16的倍数 |
C矩阵(使能channel_split功能) |
16的倍数 |
C0_size的倍数 |
C矩阵(不使能channel_split功能) |
16的倍数 |
16的倍数 |
注1:half/bfloat16_t数据类型的C0_size为16,float数据类型的C0_size为8,int8_t数据类型的C0_size为32,int4b_t数据类型的C0_size为64。 注2:channel_split功能通过MatmulConfig中的isEnableChannelSplit参数配置,具体内容请参考MatmulConfig。 |
计算过程分为如下几步:
注意:stepM、baseM等参数的含义请参考Tiling参数。