Ascend C提供一组Matmul高阶API,方便用户快速实现Matmul矩阵乘法的运算操作。
Matmul的计算公式为:C = A * B + Bias,其示意图如下。
下文中提及的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; }; |
|
参数 |
说明 |
|---|---|
|
POSITION |
内存逻辑位置。 针对
针对
注意,C矩阵设置为TPosition::CO1时,C矩阵的数据排布格式仅支持CubeFormat::NZ,C矩阵的数据类型仅支持float、int32_t。 针对
针对
|
|
FORMAT |
数据的物理排布格式,详细介绍请参考数据格式。 针对
针对
针对
注意:针对 针对
注意: 针对 关于CubeFormat::NZ格式的A矩阵、B矩阵、C矩阵的对齐约束,请参考表3。 |
|
TYPE |
数据类型。
针对
针对
针对
针对
注意:除B矩阵为int8_t数据类型外,A矩阵和B矩阵数据类型需要一致,具体数据类型组合关系请参考表2。A矩阵和B矩阵为int4b_t数据类型时,矩阵内轴的数据个数必须为偶数。例如,A矩阵为int4b_t数据类型且不转置时,singleCoreK必须是偶数。 |
|
是否开启支持矩阵转置的功能。
注意,由于L1 Buffer上的矩阵数据有分形对齐的约束,A、B矩阵转置和不转置时所需的L1空间可能不相同,在开启支持矩阵转置功能时,必须保证按照Matmul Tiling参数申请的L1空间不超过L1 Buffer的规格,判断方式为(depthA1*Ceil(baseM/c0Size)*baseK + depthB1*Ceil(baseN/c0Size)*baseK) * db * sizeoof(dtype) < L1Size,db表示L1是否开启double buffer,取值1(不开启double buffer)或2(开启double buffer),其余参数的含义请参考表1。 |
|
|
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矩阵数据,复用的矩阵必须在L1 Buffer上全载。A矩阵和B矩阵仅有一个使能IBShare的场景,与IBShare模板配合使用,具体参数设置详见表2。 注意,A矩阵和B矩阵同时使能IBShare的场景,表示L1 Buffer上的A矩阵和B矩阵同时复用,需要满足:
该参数使用样例请参考MatmulABshare样例、使能IBShare样例。 |
|
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 |
|
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 27 28 29 |
// 定义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); // L0cT为C矩阵的数据类型。 // A矩阵数据类型是int8_t或int4b_t时,C矩阵的数据类型是int32_t。 // A矩阵数据类型是half、float或bfloat16_t时,C矩阵的数据类型是float。 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的倍数 |
float/int32_t:16的倍数 half/bfloat16_t/int8_t:C0_size的倍数 |
|
注1:float/int32_t数据类型的C0_size为8,half/bfloat16_t数据类型的C0_size为16,int8_t数据类型的C0_size为32,int4b_t数据类型的C0_size为64。 注2:channel_split功能通过MatmulConfig中的isEnableChannelSplit参数配置,具体内容请参考MatmulConfig。 |
||
计算过程分为如下几步:
注意:stepM、baseM等参数的含义请参考Tiling参数。