人工智能深度学习算子库CANNAscend【免费下载链接】asc-devkit本项目是CANN 推出的昇腾AI处理器专用的算子程序开发语言原生支持C和C标准规范主要由类库和语言扩展层构成提供多层级API满足多维场景算子开发诉求。项目地址https://gitcode.com/cann/asc-devkit点击查看免费下载本指南以 CANN asc-devkit 开源仓库中的「矩阵编程高阶API」系列文档为骨架系统讲解基于 Ascend C 高阶 API 实现矩阵乘法Matmul算子的完整路径先建立矩阵乘的计算模型、存储逻辑位置与数据流、ND/NZ 数据格式与 Tiling 切分等基础知识再按 Host 侧 Tiling 生成与 Kernel 侧算子实现两大环节给出可直接运行的代码范式最后逐项梳理多核切分、异步处理、量化/反量化、稀疏矩阵乘、MxMatmul、Batch Matmul 等特性场景的适用条件、约束与调用示例。读完本文你将能够独立完成一个 Matmul 算子的 tiling 生成、核函数编写、编译运行与结果验证并具备按业务需求选择并组合高阶 API 特性模板的能力。一、矩阵乘法基础公式、逻辑位置与数据流1.1 计算模型Matmul 的计算公式为C A * B biasA、B 为源操作数A 为左矩阵形状为[M, K]B 为右矩阵形状为[K, N]C 为目的操作数存放矩阵乘结果形状为[M, N]bias 为矩阵乘偏置形状为[1, N]对 A*B 结果矩阵的每一行都采用同一 bias 进行偏置。该公式及矩阵形状定义完整记录在基础知识中是后续所有高阶 API 配置SetOrgShape、SetShape与地址偏移计算的出发点。Matmul矩阵乘示意图1.2 存储逻辑位置矩阵乘数据流依赖一组存储“逻辑位置”其与物理存储的映射关系详见逻辑位置和物理存储的映射关系。常用位置及语义如下逻辑位置用途类比A1 / B1 / C1存放整块 A、B、Bias 矩阵CPU 多级缓存中的二级缓存A2 / B2 / C2存放切分后的小块 A、B、BiasCPU 多级缓存中的一级缓存CO1存放小块结果 C 矩阵Cube OutCO2存放整块结果 C 矩阵Cube OutVECCALC计算需要临时变量时使用—1.3 矩阵乘法数据流矩阵乘法数据流描述输入输出在各存储位置间的流向为简化描述通常不列出 biasA 矩阵输入位置可以是 GM 或 VECOUT。数据流为GM-A2、GM-A1-A2、VECOUT-A1-A2。由于 A1 空间比 A2 更大大批量数据先搬入 A1 缓存、执行 Cube 计算前再从 A1 搬入 A2可减少计算前的等待、提升性能仅在搬入数据量较少的场景才可能使用GM-A2直达流。B 矩阵同样支持GM-B2、GM-B1-B2、VECOUT-B1-B2大批量数据优先走 B1 缓存路径。计算与输出完成A2*B2CO1计算后CO1-CO2汇聚再从 CO2 输出到 GM 或 VECINCO2-GM/CO2-VECIN。矩阵乘法数据流示意图二、数据格式ND 与 NZMatmul 主要涉及两种分形格式ND普通格式N 维张量数据按行连续排布NZ为满足 AI Core 中 Cube 计算单元高性能计算需要引入的特殊格式。ND 到 NZ 的变换过程为(..., N, H, W) -pad- (..., N, H1*H0, W1*W0) -reshape- (..., N, H1, H0, W1, W0) -transpose- (..., N, W1, H1, H0, W0)即(W, H)大小的矩阵被分为(H1*W1)个分形按列优先排布形如 N 字形每个分形内部含(H0*W0)个元素按行优先排布形如 z 字形因此称为 NZ大 N 小 Z格式。其余数据格式如 ND_ALIGN可参考数据排布格式。以分形格式 2*2、4*4 矩阵为例ND1,4,4与 NZ1,2,2,2,2在内存中的排布差异为ND: 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 NZ: 0, 1, 4, 5, 8, 9, 12, 13, 2, 3, 6, 7, 10, 11, 14, 15三、数据分块Tiling多核切分与核内切分3.1 多核切分为实现多核并行需要将矩阵数据切分到不同核上处理A 矩阵沿 M 轴切分为多份singleCoreM单核处理SingleCoreM * K大小数据B 矩阵沿 N 轴切分为多份singleCoreN单核处理K * SingleCoreN大小数据C 矩阵由SingleCoreM * K的 A 分块与K * SingleCoreN的 B 分块相乘得到SingleCoreM * SingleCoreN的单核输出。例如 8 个核参与计算、A 沿 M 轴分 4 块、B 沿 N 轴分 2 块时单核只处理一个分块。此外当 K 轴较大时还可以沿 K 轴切分为多份singleCoreK详细案例见Matmul高阶API开启多核切K。3.2 核内切分大多数情况下 Local Memory 无法完整容纳算子输入输出需要“搬一部分、算一部分、搬出去”的核内切分A 矩阵沿 M 轴切分为多份baseM份数即 mIter沿 K 轴切分为多份baseKB 矩阵沿 N 轴切分为多份baseN份数即 nIter沿 K 轴切分为多份baseKC 矩阵中baseM*baseN分块由baseM*baseK与baseK*baseN分块乘积累加得到例如 6 个基本块a*ab*bc*cd*de*ef*f的累加。3.3 常用 Tiling 参数除基本块形状 baseM/baseN/baseK 外还有几个关键参数iterateOrder一次 Iterate 迭代计算[baseM, baseN]大小的 C 分片Iterate 完成后 Matmul 自动偏移下一次输出位置。0表示先沿 M 轴偏移再沿 N 轴偏移1表示先沿 N 轴再沿 M 轴偏移。depthA1 / depthB1L1 BufferA1/B1中矩阵片分别全载到 L0A BufferA2/L0B BufferB2的份数即 A1 切片含baseM*baseK块的个数、B1 切片含baseN*baseK块的个数。stepM / stepN左/右矩阵在 L1 Buffer 中缓存的 M/N 方向上 baseM/baseN 的倍数。stepKa / stepKb左/右矩阵在 L1 Buffer 中缓存的 K 方向上 baseK 的倍数。四、算子实现Host 侧 Tiling 与 Kernel 侧计算Ascend C 将上述切分、搬运与计算算法封装为一组 Matmul 高阶 API。开发者 Host 侧调用 API 自动获取 Tiling 参数Kernel 侧初始化时传入通过几个简单 API 即可完成矩阵乘。完整样例见 matmul_advanced_api 样例其中 matmul_advanced_api.asc 为完整实现。矩阵编程流程示意图4.1 Host 侧自动获取 Tiling 参数关键步骤共 6 步① 创建 Tiling 对象。传入硬件平台信息创建 PlatformAscendC 对象再创建 Tiling 对象auto ascendcPlatform platform_ascendc::PlatformAscendCManager::GetInstance(); matmul_tiling::MultiCoreMatmulTiling tilingApi(*ascendcPlatform);② 设置核数及 A、B 的内存逻辑位置、格式和数据类型tilingApi.SetDim(ascendcPlatform-GetCoreNumAic()); tilingApi.SetAType(AscendC::TPosition::GM, CubeFormat::ND, matmul_tiling::DataType::DT_FLOAT16, false); tilingApi.SetBType(AscendC::TPosition::GM, CubeFormat::ND, matmul_tiling::DataType::DT_FLOAT16, false); tilingApi.SetCType(AscendC::TPosition::GM, CubeFormat::ND, matmul_tiling::DataType::DT_FLOAT);③ 设置矩阵 shape 信息tilingApi.SetOrgShape(M, N, K); // 设置原始完整的形状M、N、K tilingApi.SetShape(M, N, K);④ 设置可用空间大小。设置 Matmul 可用的 L1 Buffer/L0C Buffer/UB 空间大小-1表示使用 AI 处理器对应 Buffer 的默认大小tilingApi.SetBufferSpace(-1, -1, -1);⑤ 获取 Tiling 参数int64_t res tilingApi.GetTiling(tilingData); if (res -1) { std::cout gen tiling failed std::endl; }⑥ 序列化保存等操作uint32_t tcubeTilingSize tilingData.GetDataSize(); tilingData.SaveToBuffer(tilingBuf, tcubeTilingSize);以仓库样例为例M512, N512, K128A/B 为 half、ND 格式C 为 float、ND 格式SetDim(2)后 GetTiling 会在 2 个 Cube 核约束内生成实际使用核数usedCoreNum并将 M512 均分给 2 个核得到singleCoreM256、singleCoreN512、singleCoreK128。4.2 Kernel 侧矩阵乘运算① 创建 Matmul 对象。纯 Cube 模式只有矩阵计算建议定义ASCENDC_CUBE_ONLY宏避免额外性能开销默认为 MIX 模式矩阵计算矢量计算使用ASCENDC_CUBE_ONLY时必须用ASCEND_IS_AIC/ASCEND_IS_AIV宏隔离 Cube 与 Vector 代码详见融合算子编程typedef AscendC::MatmulTypeAscendC::TPosition::GM, CubeFormat::ND, half aType; typedef AscendC::MatmulTypeAscendC::TPosition::GM, CubeFormat::ND, half bType; typedef AscendC::MatmulTypeAscendC::TPosition::GM, CubeFormat::ND, float cType; AscendC::MatmulaType, bType, cType mm;MatmulType定义 A、B、C 的类型信息内存逻辑位置、数据格式、数据类型需与 Host 侧 SetAType/SetBType/SetCType 保持一致。② 初始化操作。Matmul 高阶 API 内部需要使用系统 workspace开发者需自行申请REGIST_MATMUL_OBJ(pipe, GetSysWorkSpacePtr(), mm, tiling); // 初始化workspace 空间由框架申请管理系统 workspace 大小通过 GetLibApiWorkSpaceSize 获取size_t userWorkspaceSize 0; size_t systemWorkspaceSize static_castsize_t(ascendcPlatform.GetLibApiWorkSpaceSize()); size_t workspaceSize userWorkspaceSize systemWorkspaceSize;③ 设置原始矩阵 shape 及当前核使用的 A、B。多核场景需根据切分方向为每个核设置矩阵起始地址。样例沿 M 轴切分 A 和 CSetOrgShape需在SetTensorA/SetTensorB之前调用A 按[M, Ka]连续存放当前核偏移为GetBlockIdx() * tiling.singleCoreM * tiling.KaB 不切分所有核从bGlobal[0]读取完整 B 矩阵参与 K 轴累加。第二个参数false表示矩阵不转置mm.SetOrgShape(tiling.M, tiling.N, tiling.Ka, tiling.Kb); mm.SetTensorA(aGlobal[GetBlockIdx() * tiling.singleCoreM * tiling.Ka], false); mm.SetTensorB(bGlobal[0], false);④ 完成矩阵乘操作两种方式Iterate while 循环可自行控制迭代次数方式灵活while (mm.Iterate()) { mm.GetTensorC(cGlobal[GetBlockIdx() * tiling.singleCoreM * tiling.N]); }IterateAll无需循环迭代使用简单mm.IterateAll(cGlobal[GetBlockIdx() * tiling.singleCoreM * tiling.N]);C 矩阵按[M, N]连续存放当前核写回偏移为GetBlockIdx() * tiling.singleCoreM * tiling.N。⑤ 结束操作mm.End();调用End可结束当前 Matmul 对象的使用并释放内部计算资源避免多个 Matmul 对象之间的资源冲突。4.3 编译运行与结果验证在样例根目录执行source ${install_path}/cann/set_env.sh # 配置环境变量 mkdir -p build cd build cmake -DCMAKE_ASC_ARCHITECTURESdav-2201 ..; make -j; # 编译默认npu模式 python3 ../scripts/gen_data.py # 生成测试输入数据 ./demo # 执行样例 python3 ../scripts/verify_result.py output/output.bin output/golden.bin # 验证结果编译选项CMAKE_ASC_RUN_MODE可选npu默认或simNPU 仿真CMAKE_ASC_ARCHITECTURES可选dav-2201Atlas A2/A3 系列或dav-3510Ascend 950PR950DT 系列。执行成功后输出test pass!。详细说明见样例 README.md。五、Shape 信息与 Format 格式的设置5.1 Shape 体系Tiling 与运行时涉及四层 Shape 概念orgShapeM、N、K原始完整形状singleCoreShapesingleCoreM、singleCoreN、singleCoreK单核分配到的形状singleShapesingleM、singleN、singleK实际参与 Matmul 计算的 shape单核时透传给 singleCore 系列baseShapebaseM、baseN、baseK核内基本块。Kernel 运行时修改 Shape 的方式SetTail、SetSingleShape 运行时修改 singleCoreM/N/K其中处理尾块用 SetTailMatmul 复用多个 Matmul 计算复用一个对象场景用 SetSingleShapeSetOrgShape 运行时修改 M、N、K用于 Matmul 复用场景。单核 Tiling 设置SetOrgShape必选设置 M/N/K、SetShape非必选设置 singleM/N/K、SetFixSplit非必选设置 baseM/N/K。多核 Tiling 额外支持SetSingleShape设置 singleCoreM/N/K与SetSingleRange设置 singleCoreM/N/K 的范围。各接口详见 Matmul_Tiling。5.2 Format 格式创建 Matmul 对象时A、B、C 支持三种 CubeFormatCubeFormat::ND、CubeFormat::NZ见本文第二节CubeFormat::ND_ALIGN用于 N 方向非 32 字节对齐的矩阵乘详见数据排布格式。六、Matmul 特性场景全景除基础计算能力外高阶 API 还提供一系列适用于不同场景的处理能力完整特性表见 Matmul特性介绍。以下按场景类别展开。6.1 多核对齐 / 非对齐切分多核对齐切分文档M 能被 singleCoreM 整除、N 能被 singleCoreN 整除、K 能被 singleCoreK 整除时沿 M/N/K 轴切分实现多核并行。不切 K 轴时单核处理singleCoreM*K与K*singleCoreN分块切 K 轴时单核处理singleCoreM*singleCoreK与singleCoreK*singleCoreNC 分块由多个核上并行算得的乘积累加。多核 Tiling 需构造MultiCoreMatmulTiling并用SetDim设置 Matmul 可用的核数仅多核场景设置用于计算 tiling 参数SetSimdNumBlocks设置整个算子实际加载的核数是必须设置的。关键代码auto ascendcPlatform platform_ascendc::PlatformAscendCManager::GetInstance(); matmul_tiling::MultiCoreMatmulTiling cubeTiling(*ascendcPlatform); cubeTiling.SetDim(ascendcPlatform.GetCoreNumAic()); cubeTiling.SetAType(matmul_tiling::TPosition::GM, matmul_tiling::CubeFormat::ND, matmul_tiling::DataType::DT_FLOAT16); cubeTiling.SetBType(matmul_tiling::TPosition::GM, matmul_tiling::CubeFormat::ND, matmul_tiling::DataType::DT_FLOAT16); cubeTiling.SetCType(matmul_tiling::TPosition::GM, matmul_tiling::CubeFormat::ND, matmul_tiling::DataType::DT_FLOAT); cubeTiling.SetBiasType(matmul_tiling::TPosition::GM, matmul_tiling::CubeFormat::ND, matmul_tiling::DataType::DT_FLOAT); cubeTiling.SetOrgShape(M, N, K); cubeTiling.SetShape(M, N, K); cubeTiling.EnableBias(isBias); optiling::TCubeTiling tilingData; int ret cubeTiling.GetTiling(tilingData); // ret -1 时表示生成失败完整样例多核切 M/N 样例、多核切 K 样例。多核非对齐切分文档M/N/K 无法整除 singleCoreM/N/K 时产生尾块。需在不改变原有 tiling 的前提下调用SetTail重新设置本次计算的 singleCoreM/N/K并按 tailM/tailN/tailK 搬运计算。SetTail必须在Iterate/IterateAll之前调用int tailM tiling.M - mCoreIndex * tiling.singleCoreM; tailM tailM tiling.singleCoreM ? tailM : tiling.singleCoreM; int tailN tiling.N - nCoreIndex * tiling.singleCoreN; tailN tailN tiling.singleCoreN ? tailN : tiling.singleCoreN; if (tailM tiling.singleCoreM || tailN tiling.singleCoreN) { matmulObj.SetTail(tailM, tailN); }完整样例见 matmul_multi_core_unaligned。6.2 异步场景处理异步场景 说明Iterate 与 IterateAll 在 MIX 场景下支持同步/异步两种模式纯 Cube 场景仅支持同步模式。Iterate GetTensorC 异步通过模板参数Iteratefalse()开启。调用 Iterate 后无需立即 GetTensorC 等待搬运完成可先执行其他操作需要结果时再获取。异步需用SetWorkspace设置临时空间物理地址 singleCoreM*singleCoreN大小的 C 空间缓存 Iterate 结果且SetWorkspace必须在 Iterate 之前调用mm.SetWorkspace(workspace, size); // workspace为临时空间物理地址size为singleCoreM*singleCoreN的C大小 mm.template Iteratefalse(); // …… 执行其他操作 auto mIter Ceil(singleCoreM, baseM); auto nIter Ceil(singleCoreN, baseN); for (int i 0; i mIter * nIter ; i) { mm.GetTensorCfalse(gm_c); }约束传入的 C 地址空间不小于baseM*baseN支持只输出到 UBVECIN、只输出到 GM、同时输出到 GM 和 UB 三种方式其中取到 UB 时数据格式仅支持 NZ取到 GM 时支持 ND 或 NZ。IterateAll 异步IterateAllfalse(...)后可用 WaitIterateAll 等待完成约束为传入 C 地址空间不小于singleCoreM*singleCoreN且仅支持连续输出至 GM。完整样例见 matmul_fused、matmul_async_iterate、matmul_async_iterate_all。6.3 矩阵乘输出的量化 / 反量化量化/反量化场景Matmul 支持将结果从 L0C BufferCO1搬出到 GM 时执行量化或反量化。量化场景A、B 为 half 或 bfloat16_t输出 C 为 int8_t搬出时量化反量化场景A、B 为 int8_t 或 int4b_t、输出 C 为 half或 A、B、C 均为 int8_t 时搬出时反量化。两种模式Tiling 侧用 SetDequantType 设置模式Tiling 侧接口Kernel 侧接口同一系数PER_TENSORshape 为 [1]SetDequantType(DequantType::SCALAR)SetQuantScalar(gmScalar)向量PER_CHANNELshape 为 [n]SetDequantType(DequantType::TENSOR)SetQuantVector(gmTensor)支持的数据类型组合含平台范围及约束详见原文表 2。关键约束SetQuantScalar/SetQuantVector 必须在 Iterate/IterateAll 之前调用Kernel 侧与 Tiling 侧的量化模式必须一致。Kernel 侧同一系数模式示例REGIST_MATMUL_OBJ(pipe, GetSysWorkSpacePtr(), mm, tiling); float tmp 0.1; // 输出gm时会乘以0.1 uint64_t ans static_castuint64_t(*reinterpret_castint32_t*(tmp)); // 浮点值量化系数转换为uint64_t类型设置 mm.SetQuantScalar(ans); mm.SetTensorA(gm_a); mm.SetTensorB(gm_b); mm.SetBias(gm_bias); mm.IterateAll(gm_c);完整样例见 matmul_quant。6.4 矩阵乘输出的 Channel 拆分ChannelSplit 场景当 C 矩阵为 NZ 格式、float 类型时默认每个分形为 16*16ChannelSplit 将每个分形切分为 16*8使内轴 32 字节对齐1 个 float 为 4 字节内轴数据量与一条 NPU 矢量计算指令处理的数据单元一致便于后续计算。默认不启用需通过 MatmulConfig 的isEnableChannelSplittrue开启。开启需满足C 为 CubeFormat::NZ、float 类型、内存逻辑位置为 GM且 L0C BufferCO1数据类型为 floatconstexpr static MatmulConfigMode configMode MatmulConfigMode::CONFIG_NORM; constexpr static MatmulFuncParams funcParamsChannelSplit{ false, false, false, false, 0, IterateOrder::ORDER_M, ScheduleType::INNER_PRODUCT, true, false, false, false, true/*isEnableChannelSplit*/ }; constexpr static MatmulConfig MM_CFG GetMMConfigconfigMode(funcParamsChannelSplit); MatmulA_TYPE, B_TYPE, C_TYPE, BIAS_TYPE, MM_CFG mm;完整样例见 matmul_channelsplit_output。6.5 矩阵向量乘GEMVGEMV 场景M1、形状为 (1, K) 的左矩阵 A 与 (K, N) 的 B 相乘。通过将 A 数据格式配置为CubeFormat::VECTOR开启 GEMV 模式A 从 A1 搬入 A2 时1*K 向量被当作 16*16 矩阵一次完成分形搬运搬运数据量更少、性能更好未开启时 M 方向按非对齐场景处理需对齐 32 字节、搬运 K/16 次。约束原始输入形状 M 必须等于 1左矩阵 A 不支持转置GM 上的左矩阵数据需 16 字节对齐。Tiling 侧与 Kernel 侧关键代码// Tiling设置A矩阵格式为CubeFormat::VECTOR tiling.SetAType(matmul_tiling::TPosition::GM, matmul_tiling::CubeFormat::VECTOR, matmul_tiling::DataType::DT_FLOAT16); // KernelMatmulType模板参数A_TYPE的格式为CubeFormat::VECTOR using A_TYPE AscendC::MatmulTypeAscendC::TPosition::GM, CubeFormat::VECTOR, half; using B_TYPE AscendC::MatmulTypeAscendC::TPosition::GM, CubeFormat::ND, half; using C_TYPE AscendC::MatmulTypeAscendC::TPosition::GM, CubeFormat::ND, float; AscendC::MatmulA_TYPE, B_TYPE, C_TYPE, BIAS_TYPE mm;完整样例见 matmul_format_gemv。6.6 4:2 稀疏矩阵乘Sparse Matmul4:2 稀疏矩阵乘输入 A、B 为稀疏矩阵B 中每 4 个元素至少 2 个为零。用户需先对 B 进行 4:2 稠密化每 4 个元素过滤 2 个零元素稠密算法见 MmadWithSparse生成稠密化 B 矩阵和索引矩阵 index。索引矩阵数据类型为 int2加载前需拼接为 int8且在一个 int8 地址中按逆序排布如索引矩阵1 2 0 1 0 2 1 0在地址中排布为1 0 2 1 0 1 2 0。实现流程Host 侧通过SetSparse(true)设置场景Kernel 侧用SparseMatmulType定义 B 矩阵参数类型含 B 矩阵与索引矩阵的内存逻辑位置、格式、数据类型用SetSparseIndex传入索引矩阵Matmul API 内部根据索引矩阵从 A 矩阵每 4 个元素中选择 2 个对应位置元素参与计算using B_TYPE AscendC::SparseMatmulTypeAscendC::TPosition::GM, AscendC::TPosition::GM, CubeFormat::ND, BType, true; AscendC::MatmulA_TYPE, B_TYPE, C_TYPE, BIAS_TYPE, CFG_MDL mm; mm.SetTensorA(gm_a); mm.SetTensorB(gm_b); mm.SetSparseIndex(gm_index); // 传入稠密化过程中生成的索引矩阵 mm.SetBias(gm_bias); while (mm.Iterate()) { mm.GetTensorC(gm_c); }SparseMatmulType参数约束POSITIONB 矩阵仅支持 GMINDEX_POSITION索引矩阵仅支持 GMCubeFormat 支持 ND/NZTYPE 仅支持 int8_tISTRANS 仅支持 true开启转置LAYOUT 仅支持LAYOUT::NONEIBSHARE 仅支持 false。该场景仅支持 MDL 模板下的纯 Cube 模式索引矩阵只支持 int8 类型和 NZ 格式M/K/N 任一值不能为 0。完整样例见 matmul_sparse。6.7 TSCM 输入的矩阵乘TSCM 输入场景TSCM 表示 L1 Buffer 空间对应的逻辑内存开发者可自行管理 TSCM缓存一份数据并在不同场景中灵活配置为 A、B 或 Bias。该场景下 Matmul 直接使用传入的 TSCM 地址不进行 GM 到 TSCM 的搬入适合自定义非连续搬入、搬入数据预处理等需求可通过自定义管理 TSCM 灵活配置 MTE2 流水、实现跨 Matmul 对象的全局 DoubleBuffer。约束设置为 TSCM 输入的矩阵必须在 TSCM 中全载。调用示例TQueTPosition::A1, 1 scm; // 队列逻辑位置A1队列深度为1 pipe-InitBuffer(scm, 1, tiling.M * tiling.Ka * sizeof(A_T)); MatmulA_TYPE, B_TYPE, C_TYPE, BIAS_TYPE mm1; // A_TYPE的TPosition为TSCMB_TYPE的TPosition为GM REGIST_MATMUL_OBJ(pipe, GetSysWorkSpacePtr(), mm1); mm1.Init(tiling); auto scmTensor scm.AllocTensorA_T(); DataCopy(scmTensor, gm_a, tiling.M * tiling.Ka); scm.EnQue(scmTensor); LocalTensorA_T scmLocal scm.DeQueA_T(); mm1.SetTensorA(scmLocal); mm1.SetTensorB(gm_b); mm1.SetBias(gm_bias); mm1.IterateAll(gm_c); scm.FreeTensor(scmLocal);完整样例见 matmul_tscm。6.8 矩阵乘输出的 N 方向对齐ND_ALIGNND_ALIGN 输出当 N 方向非 32 字节对齐时如 M16, K16, N14 的 half 矩阵乘配置 C 为 ND_ALIGN 格式后Matmul API 会在 C 矩阵 N 方向通过添加无效数据填充确保按 N 方向 32 字节对齐输出。约束为 C 申请的 Buffer 空间为 N 向上 32 字节对齐后的空间大小。Tiling 侧SetCType设置格式为CubeFormat::ND_ALIGNKernel 侧模板参数 cType 同步设置tiling.SetCType(matmul_tiling::TPosition::GM, matmul_tiling::CubeFormat::ND_ALIGN, matmul_tiling::DataType::DT_FLOAT); typedef AscendC::MatmulTypeAscendC::TPosition::GM, CubeFormat::ND_ALIGN, float cType;完整样例见 matmul_format_nd_align。6.9 单次矩阵乘局部输出Partial OutputPartial Output默认一次 Iterate 会在 K 方向做一次或多次基本块计算并累加后输出开启 Partial Output 后调用 Iterate 不做 K 轴累加、只做单次基本块计算用户通过 GetTensorC 获取单片数据后自行累加。典型场景先获取单次基本块数据进行反量化再累加。约束仅支持 MDL 模板获取结果仅支持 Iterate GetTensorC 的连续写模式不支持非连续写与 IterateAll不支持带 Bias 的 Matmul。调用示例constexpr static MatmulConfigMode configMode MatmulConfigMode::CONFIG_MDL; constexpr static MatmulFuncParams funcParams { false, false, false, false, 0, IterateOrder::UNDEF, ScheduleType::INNER_PRODUCT, true, true, true /* isPartialOutput */ }; constexpr static MatmulConfig CFG_PARTIAL GetMMConfigconfigMode(funcParams); MatmulA_TYPE, B_TYPE, C_TYPE, BIAS_TYPE, CFG_PARTIAL mm; mm.SetTensorA(gmA, isTransposeA); mm.SetTensorB(gmB, isTransposeB); while (mm.Iterate()) { mm.GetTensorC(tmpGmC[dstOffset], false, true); dstOffset baseM * baseN; // 其他操作 }完整样例见 matmul_partial_output。6.10 AIC 和 AIV 独立运行机制双主模式双主模式在分离模式下区别于 MIX 模式通过消息机制驱动 AIC 运行双主模式下 AIC 与 AIV 独立运行代码、不依赖消息驱动可提高 Matmul 性能。默认不开启通过 MatmulConfig 的enableMixDualMaster参数开启。约束仅支持 Norm 模板和 MDL 模板Kernel 类型为 MIX且 AIC 核数:AIV 核数为 1:1或 1:2 且 A/B 同时开启 IBSHARE同一算子内所有 Matmul 对象该参数取值必须一致A/B/Bias 仅支持 GM 输入结果仅支持 IterateAll 输出到 GlobalTensor。调用示例constexpr static MatmulConfig MM_CFG GetNormalConfig(false, false, false, BatchMode::BATCH_LESS_THAN_L1, true, IterateOrder::ORDER_M, ScheduleType::OUTER_PRODUCT, false, true/*enableMixDualMaster*/); MatmulA_TYPE, B_TYPE, C_TYPE, BIAS_TYPE, MM_CFG mm;完整样例见 matmul_mixdualmaster。6.11 MxMatmul 场景微缩放格式矩阵乘MxMatmul 场景微缩放MicroscalingMX格式浮点数可在低位宽下保持稳健的 AI 训练和推理精度。MX 格式由共享缩放因子 X位宽 w、私有元素 Pi位宽 d、块大小 k 三部分构成每个包含 k 个元素的块可用 (wk*d) 位编码。当前支持 MXFP8fp8_e5m2_t / fp8_e4m3fn_td8k32缩放因子 fp8_e8m0_t 位宽 8与 MXFP4fp4x2_e1m2_t / fp4x2_e2m1_td4k32等类型。MxMatmul 计算带有量化系数C (scaleA ⊗ A) * (scaleB ⊗ B) Bias其中 ⊗ 为广播乘法K 方向每 32 个元素共享一个量化因子。A 形状为 [M, K]scaleA 为 [M, K/32]B 为 [K, N]scaleB 为 [K/32, N]。Host 侧需调用SetScaleAType/SetScaleBType设置量化系数矩阵调用SetMadType(MatrixMadType::MXMODE)设置 MxMatmul 场景Kernel 侧用MatmulTypeWithScale定义 A/B 参数类型并通过模板参数MatmulWithScalePolicy开启 MxMatmul 模板策略using A_TYPE AscendC::MatmulTypeWithScaleAscendC::TPosition::GM, AscendC::TPosition::GM, CubeFormat::ND, fp8_e5m2_t, isTransposeA; using B_TYPE AscendC::MatmulTypeWithScaleAscendC::TPosition::GM, AscendC::TPosition::GM, CubeFormat::ND, fp8_e5m2_t, isTransposeB; AscendC::MatmulA_TYPE, B_TYPE, C_TYPE, BIAS_TYPE, CFG_MDL, MatmulCallBackFuncnullptr, nullptr, nullptr, AscendC::Impl::Detail::MatmulWithScalePolicy mm; mm.SetTensorA(gm_a, isTransposeA); mm.SetTensorB(gm_b, isTransposeB); mm.SetTensorScaleA(gm_scaleA, isTransposeScaleA); mm.SetTensorScaleB(gm_scaleB, isTransposeScaleB); mm.SetBias(gm_bias); while (mm.Iterate()) { mm.GetTensorC(gm_c); }MatmulTypeWithScale模板参数POSITION、SCALE_POSITION、FORMAT、TYPE、ISTRANS、SRCPOS、SCALE_FORMAT、SCALE_ISTRANS、SCALE_SRCPOS的取值与约束见原文表 3要点包括A/B 及 scale 矩阵位置可选 GM/VECOUT/TSCMTSCM 时格式仅支持 NZA 的 FORMAT 可含 VECTOR配合 GEMV当 scaleA/scaleB 以 ND 格式输入时API 内部格式转换需占用 UB 临时空间需用SetLocalWorkspace配置大小按原文公式计算。完整样例见 matmul_mx、matmul_mx_ub_tscm_nz、matmul_mx_scale_cache。七、Batch Matmul批量处理与 Bias 复用7.1 Batch Matmul 基础功能Batch Matmul 通过 IterateBatch 一次计算出多个singleCoreM*singleCoreN大小的 C 矩阵。当单次 Matmul 输入 shape 较小时搬运开销占整体耗时比例大批量处理可有效提升带宽利用率。支持 4 种 LayoutBSNGD、SBNGD、BNGS1S2、NORMALBMNK 排布。NORMAL 排布下一次 IterateBatch 可同时算出 mat_c1..mat_c4 mat_ai*mat_bi。约束要点仅支持 Norm 模板BSNGD/SBNGD/BNGS1S2 格式要求多 Batch 数据总和小于 L1 BufferNORMAL 无此限制但需通过 MatmulConfig 配置 batchModeBSNGD/SBNGD 输入输出仅支持 NDBNGS1S2/NORMAL 支持 ND/NZ不支持量化/反量化异步模式不支持 IterateBatch 搬移到 UB开启双主模式时不支持 Batch MatmulA/B 支持 half/float/bfloat16_t/int8_t不支持 int4b_t。NORMAL 格式调用示例Tiling 侧用 SetBatchInfoForNormal 设置 M/N/K 轴信息与 BatchNumconstexpr int32_t BATCH_NUM 3; tiling-SetBatchInfoForNormal(BATCH_NUM, BATCH_NUM, M, N, K); // 设置矩阵排布 // Kernel侧 typedef AscendC::MatmulType AscendC::TPosition::GM, CubeFormat::ND, half, false, LayoutMode::NORMAL aType; typedef AscendC::MatmulType AscendC::TPosition::GM, CubeFormat::ND, half, true, LayoutMode::NORMAL bType; typedef AscendC::MatmulType AscendC::TPosition::GM, CubeFormat::ND, float, false, LayoutMode::NORMAL cType; constexpr MatmulConfig MM_CFG GetNormalConfig(false, false, false, BatchMode::BATCH_LESS_THAN_L1); AscendC::MatmulaType, bType, cType, biasType, MM_CFG mm; mm.SetTensorA(gm_a); mm.SetTensorB(gm_b); mm.SetBias(gm_bias); mm.IterateBatch(gm_c, batchA, batchB, false); // 左矩阵每次计算batchA个MK数据右矩阵每次计算batchB个KN数据 mm.End();完整样例见 batch_matmul。7.2 Batch Matmul 复用 Bias 矩阵Batch Matmul 复用 BiasBatch Matmul 默认 Bias 输入包含 Batch 轴大小为 Batch*N当每个 Batch 使用相同 Bias 时将 MatmulConfig 的isBiasBatch参数置为 false只需输入一个不带 Batch 轴的1*singleCoreNBias 矩阵。约束A/B/C 均为 NORMAL Layout 时batchMode 不能设为 SINGLE_LARGE_THAN_L1单 Batch 的 A/B 数据总和不得超过 L1 Buffer 大小constexpr MatmulConfigMode configMode MatmulConfigMode::CONFIG_NORM; constexpr MatmulBatchParams batchParams { false, BatchMode::BATCH_LESS_THAN_L1, false /* isBiasBatch */ }; constexpr MatmulConfig CFG_MM GetMMConfigconfigMode(batchParams); AscendC::MatmulA_TYPE, B_TYPE, C_TYPE, BIAS_TYPE, CFG_MM mm; mm.SetTensorA(gm_a); mm.SetTensorB(gm_b); mm.SetBias(gm_bias); // 矩阵大小为1 * singleCoreN mm.IterateBatch(gm_c, batchA, batchB, false); mm.End();完整样例见 batch_matmul_bias_reuse。八、特性组合与模板选择速览特性场景核心开启方式模板/模式限制多核对齐/非对齐切分MultiCoreMatmulTiling SetDim / SetTail纯 Cube 或 MIX异步处理Iteratefalse / IterateAllfalse SetWorkspace / WaitIterateAll仅 MIX 支持异步量化/反量化SetDequantType SetQuantScalar / SetQuantVector数据类型组合受限ChannelSplitMatmulConfig.isEnableChannelSplittrueC 为 NZ、float、GMGEMVA 格式设为 CubeFormat::VECTORM 必须为 1A 不转置4:2 稀疏SetSparse(true) SparseMatmulType SetSparseIndex仅 MDL 模板纯 CubeTSCM 输入MatmulType 位置设为 TSCMTSCM 矩阵需全载ND_ALIGN 输出C 格式设为 CubeFormat::ND_ALIGNBuffer 空间需按 32 字节对齐Partial OutputMatmulConfig.isPartialOutputtrue仅 MDL 模板不支持 Bias双主模式MatmulConfig.enableMixDualMastertrueNorm/MDLMIX 核数比例 1:1 或 1:2MxMatmulSetMadType(MXMODE) MatmulTypeWithScale MatmulWithScalePolicyNorm/MDL类型组合受限Batch MatmulIterateBatch SetBatchInfoForNormal仅 Norm 模板4 种 LayoutBatch 复用 BiasMatmulConfig.isBiasBatchfalseNORMAL 下 batchMode 受限各场景的详细约束与完整样例链接均可在对应特性文档及Matmul特性介绍中继续查阅。高阶 API 的接口级定义SetTensorA/SetTensorB/SetBias/Iterate/IterateAll/SetTail 等可在 SIMD-API 的 cube_compute 模块中按名称检索其底层实现位于仓库 impl/adv_api/detail/matmul 目录如 matmul_impl.h、matmul_config_impl.hTiling 侧实现位于 impl/adv_api/tiling/matmul有兴趣的读者可结合源码进一步印证各特性的内部调度逻辑。赞分享人工智能深度学习算子库CANNAscend【免费下载链接】asc-devkit本项目是CANN 推出的昇腾AI处理器专用的算子程序开发语言原生支持C和C标准规范主要由类库和语言扩展层构成提供多层级API满足多维场景算子开发诉求。项目地址https://gitcode.com/cann/asc-devkit点击查看免费下载相关推荐Ascend C 高阶 API 矩阵乘实战用 Matmul API 在 asc-devkit 中实现 C A * B BiasAscend C 高阶 API 矩阵乘实战用 Matmul API 在 asc devkit 中实现 C A B Bias 本文以 asc devki人工智能深度学习算子库CANNAscendasc-devkit 静态 Tensor 编程实战基于基础 Matmul API 实现多核矩阵乘Matmul样例全解析asc devkit 静态 Tensor 编程实战基于基础 Matmul API 实现多核矩阵乘Matmul样例全解析 本篇文章以 asc devkit人工智能深度学习算子库CANNAscendasc-devkit AOT 编译优化实战基于 Matmul 高阶 API 的 Tiling 常量特化与运行时分发asc devkit AOT 编译优化实战基于 Matmul 高阶 API 的 Tiling 常量特化与运行时分发 AOTAhead of Time编译优人工智能深度学习算子库CANNAscend上一篇终极配置指南如何深度调优mpv播放器性能下一篇探索React Image Gallery构建高效图片画廊的利器创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考