Gemm
函数功能
根据输入的切分规则,将给定的两个输入张量做矩阵乘,输出至结果张量。将A和B两个输入矩阵乘法在一起,得到一个输出矩阵C。
函数原型
- 功能接口:1 2 template <typename dst_T, typename src0_T, typename src1_T> __aicore__ inline void Gemm(const LocalTensor<dst_T>& dstLocal, const LocalTensor<src0_T>& src0Local, const LocalTensor<src1_T>& src1Local, const uint32_t m, const uint32_t k, const uint32_t n, GemmTiling tilling, bool partialsum = true, int32_t initValue = 0) 
- 切分方案计算接口:1 2 template <typename T> __aicore__ inline GemmTiling GetGemmTiling(uint32_t m, uint32_t k, uint32_t n) 
参数说明
| 参数名称 | 类型 | 说明 | ||
|---|---|---|---|---|
| dstLocal | 输出 | 目的操作数。 Atlas 训练系列产品,支持的QuePosition为:CO1,CO2 Atlas推理系列产品AI Core,支持的QuePosition为:CO1,CO2 | ||
| src0Local | 输入 | 源操作数,QuePosition为A1。 | ||
| src1Local | 输入 | 源操作数,QuePosition为B1。 | ||
| m | 输入 | 左矩阵Src0Local有效Height,范围:[1, 4096]。 注意:m可以不是16的倍数。 | ||
| k | 输入 | 左矩阵Src0Local有效Width、右矩阵Src1Local有效Height。 
 注意:k可以不是16的倍数。 | ||
| n | 输入 | 右矩阵Src1Local有效Width,范围:[1, 4096]。 注意:n可以不是16的倍数。 | ||
| tilling | 输入 | 切分规则,类型为GemmTiling,结构体具体定义为: 
 参数说明请参考表3。 | ||
| partialsum | 输入 | 当dstLocal参数所在的QuePosition为CO2时,通过该参数控制计算结果是否搬出。 
 | ||
| initValue | 输入 | 表示dstLocal是否需要初始化。 
 | 
| src0Local.dtype | src1Local.dtype | dstLocal.dtype | 
|---|---|---|
| int8_t | int8_t | int32_t | 
| half | half | float | 
| half | half | half | 
| 参数名称 | 类型 | 说明 | ||
|---|---|---|---|---|
| blockSize | uint32_t | 固定值,恒为16,一个维度内存放的元素个数。 | ||
| loopMode | LoopMode | 遍历模式,结构体具体定义为: 
 | ||
| mNum | uint32_t | M轴等效数据长度参数值,范围:[1, 4096]。 | ||
| nNum | uint32_t | N轴等效数据长度参数值,范围:[1, 4096]。 | ||
| kNum | uint32_t | K轴等效数据长度参数值。 
 | ||
| roundM | uint32_t | M轴等效数据长度参数值且以blockSize为倍数向上取整,范围:[1, 4096] | ||
| roundN | uint32_t | N轴等效数据长度参数值且以blockSize为倍数向上取整,范围:[1, 4096] | ||
| roundK | uint32_t | K轴等效数据长度参数值且以c0Size为倍数向上取整。 
 | ||
| c0Size | uint32_t | 一个block的字节长度,范围:[16或者32]。 | ||
| dtypeSize | uint32_t | 传入的数据类型的字节长度,范围:[1, 2]。 | ||
| mBlockNum | uint32_t | M轴Block个数,mBlockNum = mNum / blockSize。 | ||
| nBlockNum | uint32_t | N轴Block个数,nBlockNum = nNum / blockSize。 | ||
| kBlockNum | uint32_t | K轴Block个数,kBlockNum = kNum / blockSize。 | ||
| mIterNum | uint32_t | 遍历维度数量,范围:[1, 4096]。 | ||
| nIterNum | uint32_t | 遍历维度数量,范围:[1, 4096]。 | ||
| kIterNum | uint32_t | 遍历维度数量,范围:[1, 4096]。 | ||
| mTileBlock | uint32_t | M轴切分块个数,范围:[1, 4096]。 | ||
| nTileBlock | uint32_t | N轴切分块个数,范围:[1, 4096]。 | ||
| kTileBlock | uint32_t | K轴切分块个数,范围:[1, 4096]。 | ||
| kTailBlock | uint32_t | K轴尾块个数,范围:[1, 4096]。 | ||
| mTailBlock | uint32_t | M轴尾块个数,范围:[1, 4096]。 | ||
| nTailBlock | uint32_t | N轴尾块个数,范围:[1, 4096]。 | ||
| kHasTail | bool | K轴是否存在尾块。 | ||
| mHasTail | bool | M轴是否存在尾块。 | ||
| nHasTail | bool | N轴是否存在尾块。 | ||
| kHasTailEle | bool | 是否存在尾块元素。 | ||
| kTailEle | uint32_t | K轴尾块元素,范围:[1, 4096]。 | 
支持的型号
Atlas 训练系列产品
Atlas推理系列产品AI Core
注意事项
- 参数m,k,n可以不是16对齐,但因硬件原因,操作数dstLocal,Src0Local和Src1Local的shape需满足对齐要求,即m方向,n方向要求向上16对齐,k方向根据操作数数据类型按16或32向上对齐。
- 操作数地址偏移对齐要求请参见通用约束。
调用示例
| 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 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 | #include "kernel_operator.h" class KernelCubeGEMM { public: __aicore__ inline KernelCubeGEMM() {} __aicore__ inline void Init(__gm__ uint8_t* fmGm, __gm__ uint8_t* weGm, __gm__ uint8_t* dstGm, uint32_t mInput, uint32_t kInput, uint32_t nInput, bool initVal, AscendC::LoopMode mode) { m = mInput; k = kInput; n = nInput; initValue = initVal; loopMode = mode; featureMapA1Size = m * k; weightA1Size = k * n; dstCO1Size = m * n; roundm = AscendC::DivCeil(m, 16) * 16; roundn = AscendC::DivCeil(n, 16) * 16; roundk = AscendC::DivCeil(k, c0Size) * c0Size; fmGlobal.SetGlobalBuffer((__gm__ half*)fmGm); weGlobal.SetGlobalBuffer((__gm__ half*)weGm); dstGlobal.SetGlobalBuffer((__gm__ float*)dstGm); pipe.InitBuffer(inQueueFmA1, 1, featureMapA1Size * sizeof(half)); pipe.InitBuffer(inQueueWeB1, 1, weightA1Size * sizeof(half)); pipe.InitBuffer(outQueueCO1, 1, dstCO1Size * sizeof(float)); pipe.InitBuffer(outQueueUB, 1, dstCO1Size * sizeof(float)); } __aicore__ inline void Process() { CopyIn(); Compute(); CopyUB(); CopyOut(); } private: __aicore__ inline void CopyIn() { AscendC::LocalTensor<half> featureMapA1 = inQueueFmA1.AllocTensor<half>(); AscendC::LocalTensor<half> weightB1 = inQueueWeB1.AllocTensor<half>(); AscendC::DataCopy(featureMapA1, fmGlobal, featureMapA1Size); AscendC::DataCopy(weightB1, weGlobal, weightA1Size); inQueueFmA1.EnQue(featureMapA1); inQueueWeB1.EnQue(weightB1); } __aicore__ inline void Compute() { AscendC::LocalTensor<half> featureMapA1 = inQueueFmA1.DeQue<half>(); AscendC::LocalTensor<half> weightB1 = inQueueWeB1.DeQue<half>(); AscendC::LocalTensor<float> dstCO1 = outQueueCO1.AllocTensor<float>(); AscendC::GemmTiling tilling = GetGemmTiling<half>(m, k, n); tilling.loopMode = loopMode; // 左矩阵形状为[m,k],右矩阵形状为[k,n],计算结果搬出至GM,目的矩阵无需初始化 AscendC::Gemm(dstCO1, featureMapA1, weightB1, m, k, n, tilling, false, initValue); outQueueCO1.EnQue<float>(dstCO1); inQueueFmA1.FreeTensor(featureMapA1); inQueueWeB1.FreeTensor(weightB1); } __aicore__ inline void CopyUB() { AscendC::LocalTensor<float> dstCO1 = outQueueCO1.DeQue<float>(); AscendC::LocalTensor<float> dstUB = outQueueUB.AllocTensor<float>(); AscendC::DataCopyParams dataCopyParams; dataCopyParams.blockCount = 1; dataCopyParams.blockLen = roundm * roundn * sizeof(float) / 1024; AscendC::DataCopyEnhancedParams enhancedParams; enhancedParams.blockMode = BlockMode::BLOCK_MODE_MATRIX; AscendC::DataCopy(dstUB, dstCO1, dataCopyParams, enhancedParams); outQueueUB.EnQue<float>(dstUB); outQueueCO1.FreeTensor(dstCO1); } __aicore__ inline void CopyOut() { AscendC::LocalTensor<float> dstUB = outQueueUB.DeQue<float>(); AscendC::DataCopy(dstGlobal, dstUB, roundm * roundn); outQueueUB.FreeTensor(dstUB); } private: AscendC::TPipe pipe; // feature map queue AscendC::TQue<AscendC::QuePosition::A1, 1> inQueueFmA1; // weight queue AscendC::TQue<AscendC::QuePosition::B1, 1> inQueueWeB1; // dst queue AscendC::TQue<AscendC::QuePosition::CO1, 1> outQueueCO1; AscendC::TQue<AscendC::QuePosition::VECOUT, 1> outQueueUB; AscendC::GlobalTensor<half> fmGlobal, weGlobal; AscendC::GlobalTensor<float> dstGlobal; uint16_t m; uint16_t k; uint16_t n; uint32_t roundm, roundk, roundn; uint32_t c0Size = 16; bool initValue = false; AscendC::LoopMode loopMode = AscendC::LoopMode::MODE_NM; uint32_t featureMapA1Size, weightA1Size, dstCO1Size; }; extern "C" __global__ __aicore__ void cube_gemm_simple_kernel(__gm__ uint8_t* fmGm, __gm__ uint8_t* weGm, __gm__ uint8_t* dstGm, uint32_t m, uint32_t k, uint32_t n, bool initValue, LoopMode mode) { KernelCubeGEMM op; // 上方示例结果入参为:m = 32, k = 64, n = 32, initValue = false, mode = LoopMode::MODE_NM op.Init(fmGm, weGm, dstGm, m, k, n, initValue, mode); op.Process(); } |