AsendC:matmul A1->A2,B1->B2搬运优化

AsendC:A1->A2,B1->B2搬运优化

目前matmul A1->A2,B1->B2的搬运,均使用loadData的load2d接口来进行搬运。如下图的搬运流程。需要将A1中zN格式数据,搬运到A2中变成zZ格式的数据。
图1 A1->A2搬运的示例,数据类型为fp16。分形大小为16x16

图1 A1->A2搬运的示例,数据类型为fp16,分形大小为16x16。

使用load2d指令搬运需要再M方向循环搬运。这样搬运会让内核scalar占比过高。后述介绍如何使用load3d接口来进行数据搬运。

for (uint32_t i = 0; i < M / 16; i++)
{
    AscendC::LoadData(
        dstTensor[i * K * 16],
        srcTensor[i * 16 * 16],
        AscendC::LoadData2dParams(
            0,
            static_cast<uint16_t>(K / 16),
            M / 16,
            0,
            0,
            false,
            0));
}

load3d接口介绍

load3的接口的介绍可查看loadData接口介绍load3d可将卷积的输入数据,映射为矩阵乘法的形式。当然可完成矩阵乘法的数据搬运。
load3d指令需要设置寄存器,可通过SetFMatrix API设置。SetFMatrix介绍
SetFMatrix函数原型。

__aicore__ inline void SetFmatrix(uint16_t l1H, uint16_t l1W, const uint8_t padList[4], const FmatrixMode& fmatrixMode);

注意:

  1. 矩阵乘法计算时,需要将l1H设置为1。
  2. FmatrixMode 有FMATRIX_LEFT和FMATRIX_RIGHT两种。和load3d中的fMatrixCtrl对应。FMATRIX_LEFT对应fMatrixCtrl=0,FMATRIX_RIGHT对应fMatrixCtrl=1。原因:AsendC将load3d多余的参数放置在寄存器中,并给予了两套寄存器。分别给A1->A2,B1->B2使用。设置寄存器通常比较耗时,并且都为重复操作。在最开始设置,可减少寄存器开销。

下面介绍在矩阵乘法搬运中的四种情况。

情况一

将A1上zN的数据,转换为A2 zZ的数据。不需要转置矩阵。
在这里插入图片描述

uint8_t padList[4] = {0, 0, 0, 0};
AscendC::SetFmatrix(
	1, // l1H 
	M, // l1W
	padList,
	AscendC::FmatrixMode::FMATRIX_LEFT
); // 设置一次即可,最好不要多次设置
static constexpr AscendC::IsResetLoad3dConfig config = {false, false}; // 防止重复设置SetFmatrix
AscendC::LoadData3DParamsV2<Element> loadDataParams;
loadDataParams.L1H=1;
loadDataParams.L1W=M; // 矩阵在A1的M
loadDataParams.kExtension = K; // A2上K方向的大小
loadDataParams.mExtension = M; // A2上M方向的大小
loadDataParams.kStartPt = 0; // 从L1开始读取的位置在L1W,L1H的坐标
loadDataParams.mStartPt = 0; // 从L1开始读取的位置在L1W,L1H的坐标
loadDataParams.strideW = 1; // 默认为1
loadDataParams.strideH = 1;
loadDataParams.filterW = 1;
loadDataParams.filterH = 1;
loadDataParams.dilationFilterW = 1;
loadDataParams.dilationFilterH = 1;
loadDataParams.filterSizeW = 0;
loadDataParams.filterSizeH = 0;
loadDataParams.enTranspose = 0; // A1->A2中是否将整个矩阵转置,包含分形间和分型内都转置。B1->B2中默认分形转置。该选项不启用。
loadDataParams.fMatrixCtrl = 0; // 使用FMATRIX_LEFT还是使用FMATRIX_RIGHT,=0使用FMATRIX_LEFT,=1使用FMATRIX_RIGHT。
loadDataParams.channelSize = K; // 矩阵在A1的K

AscendC::LoadData<Element,config>(
    A2Tensor,
    A1Tensor,
    loadDataParams
);

以情况一介绍一下为什么可以搬运完成。如下图所示:图片数据格式一般为(N,C,H,W),在A1上需要(N,C1,H,W,C0)其中C0为32字节,C1=C/C0。其中卷积窗口设置为1x1。其他参数默认。则矩阵乘法A1->A2可转换为下图形式。其中K=C、L1W=M、L1H=1。该形式可利用load3d完成。
在这里插入图片描述

情况二

A1上zN的数据,转换为A2上zZ的数据。
在这里插入图片描述

uint8_t padList[4] = {0, 0, 0, 0};
AscendC::SetFmatrix(1, K, padList, AscendC::FmatrixMode::FMATRIX_LEFT); // 设置一次即可,最好不要多次设置
static constexpr AscendC::IsResetLoad3dConfig config = {false, false}; // 防止重复设置SetFmatrix
AscendC::LoadData3DParamsV2<Element> loadDataParams;
loadDataParams.L1H=1;
loadDataParams.L1W=K;
loadDataParams.kExtension = M;
loadDataParams.mExtension = K;
loadDataParams.kStartPt = 0;
loadDataParams.mStartPt = 0;
loadDataParams.strideW = 1;
loadDataParams.strideH = 1;
loadDataParams.filterW = 1;
loadDataParams.filterH = 1;
loadDataParams.dilationFilterW = 1;
loadDataParams.dilationFilterH = 1;
loadDataParams.filterSizeW = 0;
loadDataParams.filterSizeH = 0;
loadDataParams.enTranspose = 1;
loadDataParams.fMatrixCtrl = 0;
loadDataParams.channelSize = M;

AscendC::LoadData<Element, config>(
    A2Tensor,
    A1Tensor,
    loadDataParams
);

情况三

B1上zN的数据,转换为B2上nZ的数据。不需要转置。(load3d指令无法实现,原因:B1->B2的数据搬运,分形必须转置)两者布局非常相似。如果A2上的N等于A1上的N可直接使用一条load2d指令搬运,因为无分形间数据布局变化。
在这里插入图片描述

AscendC::LoadData(
   B2Tensor,
   B1Tensor,
   AscendC::LoadData2dParams(
       0,
       static_cast<uint16_t>(N / 16 * K / 16),
       1,
       0,
       0,
       false,
       0)
   );

情况四

B1上zN的数据,转换为B2上nZ的数据。需要转置。可使用load3d指令实现。
在这里插入图片描述

uint8_t padList[4] = {0, 0, 0, 0};
AscendC::SetFmatrix(1, K, padList, AscendC::FmatrixMode::FMATRIX_RIGHT); // 设置一次即可,最好不要多次设置
static constexpr AscendC::IsResetLoad3dConfig config = {false, false}; // 防止重复设置SetFmatrix
AscendC::LoadData3DParamsV2<Element> loadDataParams;
loadDataParams.L1H=1;
loadDataParams.L1W=K;
loadDataParams.kExtension = N;
loadDataParams.mExtension = K;
loadDataParams.kStartPt = 0;
loadDataParams.mStartPt = 0;
loadDataParams.strideW = 1;
loadDataParams.strideH = 1;
loadDataParams.filterW = 1;
loadDataParams.filterH = 1;
loadDataParams.dilationFilterW = 1;
loadDataParams.dilationFilterH = 1;
loadDataParams.filterSizeW = 0;
loadDataParams.filterSizeH = 0;
loadDataParams.enTranspose = 1; // B1->B2的搬运中不起作用,默认分形转置
loadDataParams.fMatrixCtrl = 1; // 使用FMATRIX_LEFT还是使用FMATRIX_RIGHT,=0使用FMATRIX_LEFT,=1使用FMATRIX_RIGHT。
loadDataParams.channelSize = N;

AscendC::LoadData<Element>(
    B2Tensor,
    B1Tensor,
    loadDataParams
);

注意:

load3d指令执行A1->A2,B1->B2搬运,不一定比load2d指令搬运快,但load3d可减少大量的scalar操作。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值