深入理解华为 CANN 中的 Broadcast 算子实现:从底层机制到工程化落地

深入理解华为 CANN 中的 Broadcast 算子实现:从底层机制到工程化落地

在深度学习算子开发的世界里,Broadcast 是一个看似简单,却在底层实现上极富挑战性的概念。对用户而言,Broadcast 只是让两个 shape 不一致的张量也能 "自然相加";但对于算子开发者而言,它涉及 数据扩维策略、对齐约束、核内 Tiling 切分、UB 缓冲区布局以及对硬件特性的深度理解

本文将以 Add 算子中的 Broadcast 场景为例,系统讲解 CANN 框架下 Broadcast 机制的设计方式、Tiling 切分策略以及设备侧核函数的完整处理流程。希望通过本文,读者不仅能理解 "怎么做",更能理解 "为什么这样做"。


1. 为什么 Broadcast 在 CANN 算子中如此关键?

在深度学习模型中,Add、Mul、Sub 等基础操作经常用于对不同 shape 的张量执行计算。例如:

  • 一个 shape 为 (32, 8) 的张量与
  • 一个 shape 为 (32, 1) 的张量相加

框架层面可以轻松处理这种计算,但设备侧算子却不能直接使用不一致的 shape 进行核函数执行。

Broadcast 的核心功能是------
将较小维度的数据在某一个轴上扩展,使其与较大维度保持一致,从而支持逐元素计算。

然而,这看似简单的处理在底层却涉及多维问题:

  • 如何理解广播轴、扩展系数(coef)?
  • 扩张后的数据在 Unified Buffer 中如何排布?
  • GM(Global Memory) 中的读取地址如何对齐?
  • 多核 Tiling 后,每个核应处理哪些广播后的数据块?

这一切构成了本文的核心内容。


2. Broadcast 的判定条件与扩展特性

在 CANN 的 Ascend C 编程中,只有满足特定模式的数据才能执行硬件 Broadcast:

  • 两个输入的维度数量必须一致;
  • 仅允许其中一个维度不同;
  • 且较小维度必须为 1。

例如:

输入 shape
x (32, 8)
y (32, 1)

第二个输入在 axis=1 上为 1,因此能够进行广播,广播系数为:

复制代码
coef = 8 / 1 = 8

此外,硬件要求输入地址需要 32 字节对齐 ,这对 GM 的读写方式也带来额外限制,因此开发者往往需要使用 DataCopyPad 来规避越界地址或未对齐的问题。


3. Tiling:Broadcast 场景的核心设计挑战

3.1 添加 Broadcast 所需的 Tiling 描述信息

在普通 Add 算子中,我们只需描述输入长度与 tile 切分信息。而当 Broadcast 参与设计时,Tiling 结构体需要额外记录:

  • xLen / yLen:两个输入的总长度
  • axis:需要进行 Broadcast 的轴
  • coef:广播扩展倍数

示例结构:

cpp 复制代码
struct AddCustomTilingData {
    uint32_t xLen;
    uint32_t yLen;
    uint32_t coef;
    uint32_t axis;
    ...
};

coef 的作用极其关键,它决定了 kernel 中访问 y 数据的方式、扩展后的 shape 计算方式,以及 UB 内的排布方式。


4. Tiling 切分策略:以 "shorterAxisLen" 为核心

为了减少冗余计算、提升多核并行效率,切分逻辑采用以下关键设计:

4.1 以较小维度长度 shorterAxisLen 作为主切分依据

设:

复制代码
shorterAxisLen = min(xLen, yLen)
totalLength    = max(xLen, yLen)

因为较短的维度在 Broadcast 后真正的有效数据仍然只有 shorterAxisLen,在 Tiling 时应以 shorterAxisLen 进行分核。

广播后真实处理的数据长度为:

复制代码
processed_length = shorterAxisLen * coef

这也是各核通常搬入的 GM 数据量。


5. UB 内数据块长度计算:对齐 coef 与 BUFFER_NUM

Unified Buffer 的利用效率直接影响核函数性能,因此必须对 tileLength 做齐整处理。

核心对齐策略如下:

复制代码
ubBlockAligned =
    if UB_BLOCK_NUM * alignNum / (coef * BUFFER_NUM) * (coef * BUFFER_NUM) == 0:
        UB_BLOCK_NUM
    else:
        UB_BLOCK_NUM * alignNum / (coef * BUFFER_NUM) * (coef * BUFFER_NUM)

这句看似复杂,其背后逻辑十分明确:

👉 为了确保 UB 中的 Y 数据广播后能整齐地与 X 对应,UB 块长度必须同时满足:

  • coef 的倍数(广播需要 repeated coef 次)
  • BUFFER_NUM 的倍数(流水线分组要求)
  • UB_BLOCK_NUM 的基准大小(硬件限制)

这体现了 CANN 算子设计中最重要的一点:

所有 tiled 数据必须"形状可用、对齐可控、排布合理"。


6. 核函数(Device Side)的实现流程详解

核函数执行阶段主要包含三项关键任务:

  • 确定 GM 输入指针(长输入与短输入)
  • 初始化 UB Buffer
  • 根据 coef 处理对齐后的数据搬入与广播计算

6.1 初始化:选择需要广播的输入

cpp 复制代码
if (tiling.xLen > tiling.yLen) {
    longerInputPtr = x;
    shorterInputPtr = y;
} else {
    longerInputPtr = y;
    shorterInputPtr = x;
}
this->coef = tiling.coef;

其中 shorterInputPtr 指向需要进行广播的张量。

6.2 GM Buffer 设置:根据核编号偏移

由于不同核处理不同 tile,需要根据 blockIdx 计算偏移,并对 shorterInputPtr 应用:

复制代码
offset / coef

以确保访问的是未 broadcast 的数据。

6.3 CopyIn:DataCopyPad 保证 32 字节对齐

因为 broadcast 后数据跨度变化,导致 GM 地址不一定对齐,因此引入 DataCopyPad:

cpp 复制代码
AscendC::DataCopyPad<dataType>(xLocal, xGm[offset], copyParams, padParams);
AscendC::DataCopyPad<dataType>(yLocal, yGm[offset / coef], copyParams, padParams);

这保证了:

  • 地址未对齐也可安全访问
  • UB 数据填充完整

7. Compute:Broadcast + Add 的核心实现

7.1 计算广播前后 shape

对于长度 tileLength:

复制代码
srcShape = { tileLength / coef, 1 }
dstShape = { tileLength / coef, coef }

示意:

输入 yLocal 广播后 broadcastTmp
32 x 1 32 x coef

7.2 调用硬件 Broadcast API

cpp 复制代码
AscendC::BroadCast<dataType, 2, 1>(broadcastTmpTensor, yLocal, dstShape, srcShape);

该 API 是硬件级广播,具有极高吞吐效率。

7.3 Add 计算(伪代码)

cpp 复制代码
zLocal = xLocal + broadcastTmpTensor;

实现中通常使用 VectorAdd 或 Add DSL 指令完成。


8. CopyOut:仍然需要 DataCopyPad

由于 tile 的最后一块可能不是对齐长度,需要使用 Pad 写回:

cpp 复制代码
AscendC::DataCopyPad<dataType>(zGm[offset], zLocal, copyParams);

确保 GM 写回始终合法。


9. 总结:Broadcast 场景下 Add 算子的工程化价值

Broadcast 是许多高层操作的基础,一旦底层实现合理,可以极大提升算子执行效率。

本文总结 Broadcast 场景中最关键的设计点:

★算子设计思路

  • 以较小轴长度为切分基础(shorterAxisLen)
  • coef 是所有计算的核心倍数参数

★内存访问

  • GM 地址必须满足 32 字节对齐,因此 DataCopyPad 必不可少
  • broadcast 后数据块必须与 coef × BUFFER_NUM 对齐

★多核并行

  • former/tail 切分策略提升核间负载均衡
  • tileLength/lastTileLength 区分尾块

★计算部分

  • 使用 AscendC::BroadCast API 完成硬件级扩张
  • Add 计算在 UB 中即可完成,减少 GM 访问

训练营简介

2025年昇腾CANN训练营第二季,基于CANN开源开放全场景,推出0基础入门系列、码力全开特辑、开发者案例等专题课程,助力不同阶段开发者快速提升算子开发技能。获得Ascend C算子中级认证,即可领取精美证书,完成社区任务更有机会赢取华为手机,平板、开发板等大奖。

报名链接:https://www.hiascend.com/developer/activities/cann20252#cann-camp-2502-intro

相关推荐
向哆哆5 小时前
深入解析华为CANN Matmul算子:从数据流到高性能实现
算子·昇腾·cann
S***q1925 小时前
HarmonyOS应用沙盒机制
华为·harmonyos
向哆哆8 小时前
深入理解华为CANN静态Tensor编程范式:极致性能的算子开发之道
华为·算子·昇腾·cann
9***Y4812 小时前
HarmonyOS在智能车载中的导航系统
华为·harmonyos
晚霞的不甘13 小时前
CANN:华为全栈AI计算框架的深度解析(终极扩展版 · 完整篇)
人工智能·华为
不爱吃糖的程序媛17 小时前
华为 CANN:昇腾 AI 的异构计算架构核心与开源生态解析
人工智能·华为·架构
1***Q78417 小时前
HarmonyOS在智能汽车中的V2X通信
华为·汽车·harmonyos
p***c94917 小时前
HarmonyOS应用分发
华为·harmonyos
4***149020 小时前
HarmonyOS在智能电视中的语音交互
华为·harmonyos·智能电视