简介
本节内容为使用基础API进行矩阵乘法的编程指导。使用基础API进行矩阵编程的功能支持的产品型号为:
- Atlas 推理系列产品
- Atlas 训练系列产品
编程范式
Cube编程范式把算子的实现流程分为5个基本任务:CopyIn,Split,Compute,Aggregate,CopyOut。CopyIn负责搬入操作,Split负责数据切分操作,Compute负责矩阵指令计算操作,Aggregate负责数据汇聚操作,CopyOut负责搬出操作。
图1 矩阵编程基本任务设计
具体任务之间的交互流程和流程图如下。
- Stage1:CopyIn任务。
- Stage2:Split任务。
- Stage3:Compute任务。
- Stage4:Aggregate任务。
- Stage5:CopyOut任务。
图2 矩阵编程Queue队列
开发流程
基于Ascend C方式实现矩阵算子的流程如下图所示。
图3 矩阵算子实现流程
- 算子分析:分析算子的数学表达式、输入、输出以及计算逻辑的实现,明确需要调用的Ascend C接口。
- 核函数定义:定义Ascend C算子入口函数。
- 根据矩阵编程范式实现算子类:完成核函数的内部实现,调用私有成员函数CopyIn、SplitA、SplitB、Compute、Aggregate、CopyOut完成矩阵算子的五级流水操作。
下文将以Matmul算子为例对上述步骤进行详细介绍,Matmul算子的代码框架如下,完整代码请参见实现样例。
#include "kernel_operator.h" // 根据编程范式实现算子类 class KernelMatmul { public: __aicore__ inline void Init(GM_ADDR a, GM_ADDR b, GM_ADDR c) { // ... } __aicore__ inline void Process() { CopyIn(); SplitA(); AscendC::LocalTensor<half> b1Local = inQueueB1.DeQue<half>(); AscendC::LocalTensor<half> a2Local = inQueueA2.DeQue<half>(); AscendC::LocalTensor<float> c2Local = outQueueCO2.AllocTensor<float>(); // split matrix b into 2 parts, [32, 16] and [32, 16] for (int i = 0; i < 2; ++i) { SplitB(b1Local, i); Compute(a2Local); Aggregate(c2Local, i); } inQueueB1.FreeTensor(b1Local); inQueueA2.FreeTensor(a2Local); outQueueCO2.EnQue<float>(c2Local); CopyOut(); } private: __aicore__ inline void CopyIn() { // ... } __aicore__ inline void SplitA() { // ... } __aicore__ inline void SplitB(const LocalTensor<half>& b1Local, const int bSplitIdx) { // ... } __aicore__ inline void Compute(const LocalTensor<half>& a2Local) { // ... } __aicore__ inline void Aggregate(const LocalTensor<float>& c2Local, const int bSplitIdx) { // ... } __aicore__ inline void CopyOut() { // ... } private: // ... }; //核函数定义 extern "C" __global__ __aicore__ void matmul_custom(GM_ADDR a, GM_ADDR b, GM_ADDR c) { KernelMatmul op; op.Init(a, b, c); op.Process(); }
父主题: 矩阵编程(基础API)