ops-reduce:ReduceMax 与 ReduceMean 的并行优化

Transformer 推理中 Reduce 类算子无处不在:LayerNorm 需要算 mean 和 var(ReduceMean + 方差),Softmax 需要算 max(ReduceMax)和 sum(ReduceSum),Attention 的归一化因子需要跨序列维度做归约。

ops-reduce 是 CANN 管理所有归约算子的仓库------ReduceMax、ReduceMin、ReduceMean、ReduceProd。它们共享同一个核心问题:计算量极小但搬运量极大。


为什么 Reduce 类算子容易成为瓶颈

以 ReduceMax 为例------在一个 [4096, 4096] 的 Tensor 上沿行方向找最大值:

  • 数据量:32MB
  • 计算量:4096×4095 = 16M 次比较
  • 计算/搬运比:约 0.5 FLOPs/byte

对比 GEMM 的 52.5 FLOPs/byte------Reduce 的瓶颈非常明显:时间主要花在从 DDR 读数据上,Vector Unit 的比较运算只需要几微秒。


ReduceMax 与 ReduceMean 的典型场景

ReduceMax------Attention 中的 Softmax。 Softmax 的第一步需要对 Score 矩阵的每一行找最大值,用于数值稳定性(减去最大值防止 exp 溢出)。这个 ReduceMax 在朴素 Attention 中需要对 32MB 的 Score 矩阵做一次完整扫描。

ReduceMean------LayerNorm。 LayerNorm 的第一步 mean = sum(x) / n 需要对输入 Tensor 做 ReduceSum 再除以 n。LLaMA 的每个 Decoder Block 做两次 LayerNorm------每次都要对隐藏层的 [B, n, d] Tensor 做 mean 和 var。


昇腾NPU如何做并行归约

ops-reduce 在 Vector Unit 上做并行归约。一个 Core 处理一部分数据,用 SIMD 指令同时比较多个元素:

cpp 复制代码
// 昇腾 Vector Unit 上的 ReduceMax Kernel(伪代码)
// 输入:x (GM 地址), n = 元素数
// 输出:max_value (GM 地址)

__vector__ void reduce_max_kernel(...) {
    float16 local_max = -FLT_MAX;
    
    // 每次处理 128 个元素
    for (int i = 0; i < n; i += 128) {
        float16 vec[128] = load_gm_to_local(x + i); // DDR→L1
        local_max = vec_max(local_max, vec);         // SIMD 比较
    }
    
    // 如果启动了多个 Core,做跨 Core 归约
    float16 global_max = warp_reduce_max(local_max);
    
    store_local_to_gm(global_max, max_value);        // L1→DDR
}

多 Core 场景中每个 Core 先算自己的局部最大值,然后通过一次跨 Core 的 reduce 操作合并为全局最大值。这个跨 Core reduce 在 Vector Unit 上用 warp_reduce_max 指令完成------比写 DDR 再读回来快两个数量级。


性能分析

在 Ascend 910 上对不同大小 Tensor 做 ReduceMax 的实测:

Tensor 形状 元素数 搬运量 延迟 带宽利用率
1024 1K 2KB 3μs 15%
1,4096 4K 8KB 5μs 28%
4096,4096 16M 32MB 85μs 72%
8,4096,4096 128M 256MB 610μs 78%

小 Tensor 的带宽利用率低是因为 DMA 启动开销占比大。大 Tensor 的利用率接近硬件上限。


Transformer 中的归约链路

LLaMA-7B 的两次 LayerNorm 的归约链路:

复制代码
输入 [B, n, d] → ReduceMean → (x - mean)² → ReduceMean → var
                       ↑                          ↑
                  一次归约                     一次归约
                  mean 缓存                    var 缓存

ops-reduce 在 LayerNorm 场景中的优化是:meanvar 的归约 Kernel 共享同一个 Tensor 的搬运------mean 归约时从 DDR 读一次 x,var 归约时复用 L1 上的 x 数据,不需要重新搬运。优化后归约的搬运量从 2 次减到 1 次。

ReduceMean 的融合执行

ReduceMean 可以跟下游算子融合。LayerNorm 的 (x - mean) / sqrt(var + eps) 中,ReduceMean 和后面的计算共享同一个 x 的搬运------x 搬入 L1 后先做 ReduceMean,mean 的结果留存在 L1 中,后续的 x - mean 和 ReduceVar 直接使用------x 不需要重新搬运。

融合后 LayerNorm 的总搬运量从 2 次降到 1 次。实测中 LLaMA-7B 的 LayerNorm 延迟从 12μs 降到 7μs。

性能分析表的补充

Ascend 910 上不同 Tensor 大小的 ReduceMean(axis=-1)性能:

Tensor 形状 元素数 延迟 瓶颈环节
1, 4096 4K 4μs DMA 启动
4, 4096, 4096 64M 210μs DDR 带宽
8, 4096, 4096 128M 395μs DDR 带宽
1, 4096, 4096 16M 56μs DDR 带宽

Batch 维度增加时延迟近线性增长------ops-reduce 在 Batch 维度上可以并行,每个 Batch 分给不同 Core 处理,Batch=8 时 4 个 Core 并行能把延迟从 395μs 降到 110μs。

参考仓库

ops-reduce 归约算子库

ops-math 数学算子库

相关推荐
vibecoding日记5 小时前
双非如何快速入职字节等大厂大模型?真实案例分析:推理优化和投机解码
算法·求职·大模型工程师
yszaygr21387 小时前
Verilog参数化游程编码RLE模块
算法
望易7 小时前
刚设计的大模型架构-双域耦合认知框架
算法·架构
复杂网络11 小时前
多个 Claude Code 与多个 Codex 协同工作:设计与实现方案
算法
HjhIron1 天前
面试常客:字符串算法从入门到进阶
算法·面试
吴佳浩1 天前
DeepSeek DSpark:Confidence-Scheduled Speculative Decoding 技术解析
人工智能·算法·deepseek
触底反弹1 天前
🧠 搞懂 Token,才算真正入门大模型——从分词原理到 Embedding 语义实战
javascript·人工智能·算法
vivo互联网技术1 天前
ICLR 2026 | 基于后验采样的图像恢复方法LearnIR:人脸去阴影、去雾
人工智能·算法·aigc
浮生望1 天前
JS字符串与回文算法:从包装类到双指针的面试进阶之路
javascript·算法