Matmul 多核对齐切分完整指南:从切分策略到核数配置
发布时间:2026/8/21 17:52:20 作者:尧图编辑部 阅读量:1,286

Matmul 多核对齐切分完整指南从切分策略到核数配置【免费下载链接】asc-devkit本项目是CANN 推出的昇腾AI处理器专用的算子程序开发语言原生支持C和C标准规范主要由类库和语言扩展层构成提供多层级API满足多维场景算子开发诉求。项目地址: https://gitcode.com/cann/asc-devkitCANN asc-devkit 面向昇腾 AI 处理器的算子开发其 Matmul 高阶 API 提供了MultiCoreMatmulTiling这一多核矩阵乘 Tiling 对象用于把大矩阵合理地分配到多个核上并行计算。这篇文章将带大家弄清多核对齐切分的两种策略、Tiling 参数的含义以及SetDim与SetBlockDim的正确用法最后给出可直接套用的代码模板。为什么多核场景必须做矩阵切分单核处理的性能瓶颈一次完整的矩阵乘C(M,N) A(M,K) × B(K,N)需要 M×N×K 量级的乘加运算。在单核上顺序执行时核内存储空间有限、计算单元空闲率偏高数据量一大就很容易成为整个算子的性能短板。因此要提升计算效率最直接的手段就是让多个核同时参与计算。多核并行的核心思路多核并行的前提是把大矩阵切成若干独立的分块每个核只处理属于自己的那部分数据。切分后的每个分块大小即单核负载会被记录到 Tiling 参数中例如SingleCoreM、SingleCoreN、SingleCoreK。这些参数是设备侧 Kernel 拿到多少数据、按什么尺寸搬移和计算的依据也是多核场景与单核场景在 Tiling 阶段的本质区别。两种主流切分策略拆解按照是否切分 K 轴多核对齐切分分为两种策略。不同策略决定了分块在核间的分布方式也直接影响累加逻辑的写法。不切分 K 轴沿 M、N 轴分块这种策略只切 M、N 两个维度K 维度保持完整具体划分如下A 矩阵沿 M 轴切分得到若干份大小为SingleCoreM × K的分块B 矩阵沿 N 轴切分得到若干份大小为K × SingleCoreN的分块C 矩阵单核上由SingleCoreM × K的 A 分块与K × SingleCoreN的 B 分块相乘直接得到SingleCoreM × SingleCoreN的 C 分块。举例来说若有 8 个核参与计算把 A 沿 M 轴切成 4 块、B 沿 N 轴切成 2 块就得到 4×2 的核间网格。每个核只需要加载自己那一份 A 分块和 B 分块例如某个核仅处理绿色标记的数据其输出就是对应位置SingleCoreM × SingleCoreN的 C 分块。切分 K 轴M、N、K 三轴联合分块当单核的存储放不下完整 K 维数据或者希望进一步提高并行度时可以对三个轴同时切分A 矩阵沿 M 轴切成SingleCoreM沿 K 轴切成SingleCoreK单核处理SingleCoreM × SingleCoreK的数据B 矩阵沿 K 轴切成SingleCoreK沿 N 轴切成SingleCoreN单核处理SingleCoreK × SingleCoreN的数据C 矩阵每个 C 分块不再由一次乘法得到而是A1×B1 A2×B2 A3×B3这样的累加结果。以切分成 3 份 K 块为例C 矩阵中的某个 R 块需要通过 A1×B1、A2×B2、A3×B3 三组乘积累加得到。这三组乘法互相独立恰好可以分配到不同的核上并行执行之后再把部分和累加回 C 分块。两种策略如何选择如果 K 维相对较小、单核放得下整段 K 数据优先选择不切 K 轴的方案累加逻辑简单、代码更易维护如果 K 很大或核数很多、需要更大并行度则选择三轴切分方案。需要留意的是切 K 轴会引入跨核的部分和累加通常需要额外的同步或归约处理。关键参数与核数设置规则Tiling 参数的含义SingleCoreM、SingleCoreN、SingleCoreK是切分结果的直接体现分别表示单核上处理的 M、N、K 维度尺寸。host 侧通过调用MultiCoreMatmulTiling的接口自动计算并获取这些参数无需手动推算。它们会随算子的输入形状、可用核数自动调整属于“声明形状后自动算好”的参数。SetDim 与 SetBlockDim 的分工多核 Tiling 中有一个容易混淆的点SetDim与SetBlockDim各自负责什么。SetDim设置 Matmul 计算可用的核数仅在多核场景下使用用于驱动 Tiling 参数的计算即告诉 Tiling 对象“有多少核可以参与矩阵乘”SetBlockDim设置整个算子计算所用核数即实际会被加载执行的核数这个值是必须设置的规则与numBlocks的说明一致。在纯 Cube 模式只有矩阵计算下典型做法是先用SetDim把当前 AI 处理器上可用的 Cube 核数传入再通过GetTiling得到 Matmul 实际使用的核数该值会小于等于可用的核数。随后用户按实际使用的核数配置SetBlockDim。若算子还包含矢量计算MIX 模式核数设置规则会更复杂需要参考 MIX 场景核数设置规则单独处理。需要注意的约束本场景没有额外限制条件只要遵循上述设置顺序即可先构造 Tiling 对象并设置维度与类型再设置核数最后获取 Tiling 参数。注意GetTiling的返回值用于判断是否成功返回 -1 表示 Tiling 生成失败。调用示例与关键步骤解读以纯 Cube 模式的浮点矩阵乘为例下面这段代码展示了多核 Tiling 的完整调用流程可以分为三步理解。第一步构造多核 Tiling 对象首先根据 SoC 版本获取平台实例并以此构造MultiCoreMatmulTiling对象。与单核场景不同多核必须使用该类而不是普通 Tiling 对象否则无法获取多核相关的切分参数。// 构造多核Tiling对象 auto ascendcPlatform platform_ascendc::PlatformAscendCManager::GetInstance(socVersion); matmul_tiling::MultiCoreMatmulTiling cubeTiling(*ascendcPlatform); // 仅包含Cube计算的算子设置可参与矩阵乘运算的核数为当前AI处理器上的Cube核数 cubeTiling.SetDim(ascendcPlatform.GetCoreNumAic());这里通过GetCoreNumAic()拿到当前 AI 处理器上的 Cube 核数并传给SetDim相当于告诉 Tiling 对象“最多可以用这么多核”。第二步声明矩阵类型与形状接着分别声明 A、B、C 三个矩阵以及偏置在全局内存中的位置、格式与数据类型并传入原始的 M、N、K 形状。是否需要偏置由EnableBias控制。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);第三步获取 Tiling 参数最后把结果写入TCubeTiling结构体并检查返回值。拿到 tilingData 后后续即可据此为设备侧 Kernel 计算地址偏移、循环边界等运行时信息。optiling::TCubeTiling tilingData; // 获取Tiling参数 int ret cubeTiling.GetTiling(tilingData); // if ret -1, gen tiling failed小结多核对齐切分的本质是把大矩阵按 M、N、K 三个维度切分到多个核上并行计算。不切 K 轴时逻辑简单、适合 K 较小的场景切 K 轴时并行度更高但需要处理跨核的部分和累加。在实际编码中牢记三点即可少走弯路多核场景务必使用MultiCoreMatmulTilingSetDim决定“最多可用多少核”SetBlockDim决定“实际加载多少核”后者必须设置最后用GetTiling的返回值确认 Tiling 是否生成成功。【免费下载链接】asc-devkit本项目是CANN 推出的昇腾AI处理器专用的算子程序开发语言原生支持C和C标准规范主要由类库和语言扩展层构成提供多层级API满足多维场景算子开发诉求。项目地址: https://gitcode.com/cann/asc-devkit创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考