CATLASS GMM_sliceM_perToken_Dequant

原型设计

名称/Name 类型/Class 数据类型/Dtype 维度/Dims 格式/Format 描述/Description
matA inTensor int8 [m, k] ND 左矩阵
matB inTensor int8 [groupCount, n, k] ND 右矩阵,支持转置
groupList inTensor int [groupCount] ND m轴方向分组大小,累加和列表
scale inTensor bf16 [groupCount, n] ND perChannel量化系数
perTokenScale inTensor bf16 [m] ND perToken量化系数
matD outTensor bf16 [m, n] ND 输出矩阵

样例实现

CATLASS GMM_sliceM_perToken_Dequant样例算子是基于CATLASS Gemm Api实现的亲和昇腾AtlasA2硬件的GMM算子,算子的结构可以分为以下几部分

Example组装

构造输入

组装blockMmad

组装blockEpilogue

组装和执行kernel

// Prepare FFTS address
    uint64_t fftsAddr{0};
    uint32_t fftsLen{0};
    RT_CHECK(rtGetC2cCtrlAddr(&fftsAddr, &fftsLen));
    ...
    matmulOp(stream, aicCoreNum, fftsAddr);

精度校验和空间释放

Kernel实现

Kernel主要结构体和函数

AIC流程

  • 初始化BlockScheduler和BlockMmad,代码
  • 初始化GlobalTensor:gmA/groupList/gmC,代码
  • 获取当前AIC序号coreIdx、AIC总数coreNum,代码
  • 初始化计算参数:A矩阵在GM上地址偏移gmGroupOffsetA、B矩阵在GM上地址偏移gmGroupOffsetB、workspace上的输出数据排布layoutC、WORKSPACE_STAGES操作对应stageId和stageUsed、当前group起始AIC序号startCoreIdx,代码
  • group循环,代码
    • 计算当前group的M,代码
    • 判断是否使能A矩阵L2Cache绕过,代码
    • 计算当前核在当前group基本块中的起始idx,代码
    • 当前group中、当前核的基本块循环,代码
      • blockMmad所需入参计算,代码
      • 根据是否为异步方案调用不同blockMmad,代码,当前样例为异步方案,callback需要传入blockMmad内安排调用
      • 更新stageId,代码
    • 更新gmGroupOffsetA、gmGroupOffsetB、startCoreIdx,代码
  • 异步方案blockMmad完成遗留的计算,代码

AIV计算流程与AIC一致,在调用blockMmad()处改为调用blockEpilogue(),并在kernel代码内做核间同步,不需要将callBack传入处改为调用blockEpilogue内

基本块分核方案

  • group内对[currentM, N]按照[L1TileShape::M, L1TileShape::N]切基本块分核
  • group间连续分核,达成不同AIC的负载均衡
  • 相关变量:
    • groupIdx:当前group序号
    • coreLoops:当前group的block数
    • startCoreIdx:起始block的aic序号(当前group内)
    • startLoopIdx:当前核的起始block序号(当前group内)
    • loopIdx:当前核需要处理的block序号(当前group内)
  • 示例:

Workspace方案

当前workspaceStages=2的配置下,使用基本块双缓冲,每个AIC分配两个基本块大小的Workspace。对于任意shape的输入,申请Workspace大小固定。

static size_t GetWorkspaceSize(const Arguments &args)
{
    size_t lenWorkspace = static_cast<size_t>(L1TileShape::M) * L1TileShape::N *
        args.aicCoreNum * WORKSPACE_STAGES;
    size_t sizeWorkspace = lenWorkspace * sizeof(uint32_t);
    return sizeWorkspace;
}

(库上还有一种方案为申请完整的 promblemShape.m * promblemShape.n 的Workspace,在小shape场景可以节约Workspace,参考

AIC/AIV核间同步方案

AIC上对于单个block的Mmad可以拆分为L1Tile搬入、L1Tile计算、L0C搬出三个动作,由于blockMmad有preload预载和async异步的特性,operator()<AscendC::AIC>内调用blockMmad()时,仅完成当前block的L1Tile搬入和大部分L1Tile计算,而剩余的L1Tile计算和L0C搬出会在下次调用blockMmad()时执行。所以需要将AIC/AIV核间同步相关的callBack入参传入blockMmad(),由blockMmad()内决定调用时机。

单个AIC和分配的两个AIV在处理GM上的一个个block的流程图如下:

BlockMmad实现

待完善

BlockEpilogue实现

待完善