想象你经营一家中餐厅的后厨。按照传统流程,切菜师傅把土豆切成丝后,不能直接把半成品递给旁边的炒锅师傅——必须装进保鲜盒、放进冷库;等炒锅师傅要用时,再从冷库里取出来。一份酸辣土豆丝,中间要经历“放回冷库—取出—放回冷库—取出”好几轮。这些步骤不增加任何味道,却占了师傅们大半的力气和时间。 深度学习模型的计算也面临同样的窘境。GPU 上每执行一个算子,结果都要写回显存(相当于冷库),下一个算子再读回来;每调用一次算子,CPU 还要向 GPU 发一次“开工指令”。这两笔开销加起来,往往比计算本身还贵。XLA 编译器里的算子融合(Fusion),做的就是“去冷库化”——把相邻的多个算子合并成一个融合内核,让数据留在手边一口气算完。 这篇文章咱们就沿着“为什么要融合—怎么融合—融合带来什么—XLA 怎么实现—PyTorch 怎么用—真实案例效果”这条主线,把这个底层加速魔法彻底讲透。

岗位关联

掌握算子融合,等于掌握了 AI 编译器最核心的性能密码。无论是排查推理延迟、还是做部署优化,这个知识都能让你从“会用框架”进阶到“懂性能”。

目录
  1. 可视化演示
  2. 融合原理
  3. 融合策略
  4. 融合收益
  5. XLA实现
  6. PyTorch集成
  7. 优化案例
  8. AI 应用场景
  9. Python 演示
  10. 常见误区
  11. 面试题

可视化演示

三步展示XLA算子融合:多算子(Mul/Add/Act)合并为单一Fusion核、融合类型分类(elementwise/producer/reduction)、以及融合后访存减少与内核启动开销降低的性能收益。

本节配有交互动效(进入视口后自动加载,约 3KB)。

算子融合过程 Mul/Add/Act: 相邻算子 FUSE: 合并为单一核 中间值留寄存器/缓存,减少内存读写 降低kernel启动与访存开销。

融合原理

想象你经营一家中餐厅的后厨。按照传统流程,切菜师傅把土豆切成丝后,不能直接把半成品递给旁边的炒锅师傅——必须装进保鲜盒、放进冷库;等炒锅师傅要用时,再从冷库里取出来。一份酸辣土豆丝,中间要经历好几轮“放回冷库—取出”。这些步骤不增加任何味道,却占了师傅们大半的力气和时间。

深度学习模型的推理和训练也是如此。GPU 上执行一个算子,就像后厨的一道工序:算完的结果必须写回显存(相当于冷库),下一个算子再把它读回来。让人头疼的是,现代 GPU 的计算速度增长得飞快,显存带宽却远远跟不上——这就是学术界说的内存墙(Memory Wall)。很多算子其实几微秒就算完了,数据搬运反而花了几十微秒。工程师们用一个指标来衡量这种失衡——计算访存比(Arithmetic Intensity),即每个字节的数据搬运能支撑多少次计算;这个值越低,说明算子越是被“空跑搬运”拖累。

更隐蔽的开销来自内核启动(Kernel Launch)。每执行一个算子,CPU 都要向 GPU 发起一次“开工指令”,从下发到真正执行通常要消耗微秒级的时间。如果一个模型有几百个算子,光启动开销就相当可观。把单个算子的耗时拆开看:

Top=Tcompute+Tmemory+TlaunchT_{\text{op}} = T_{\text{compute}} + T_{\text{memory}} + T_{\text{launch}}

1. T_op 总耗时:一个算子从开始到结束的墙钟时间(Wall-clock Time),是我们在性能分析里直接观测到的值。

TopT_{\text{op}}

2. T_compute 纯计算:GPU 真正做数学运算(如矩阵乘、逐元素加法)耗费的时间。

TcomputeT_{\text{compute}}

3. T_memory 访存时间:数据从显存读入寄存器、以及把结果写回显存的时间,通常被内存墙放大。

TmemoryT_{\text{memory}}

4. T_launch 启动时间:CPU 向 GPU 下发内核指令、GPU 排队调度所消耗的时间。

TlaunchT_{\text{launch}}

所以算子融合的出发点很简单:既然“放回冷库再取出来”和“呼叫厨师”都这么贵,那能不能让一位厨师一口气把几道工序做完,把菜直接留在手边?这正是 XLA 要解决的第一个问题——找到那些适合“传递接力棒”的工序。

融合策略

厨师长拿到今天的菜单,开始排兵布阵。有的工序之间关系紧密——前一道刚出锅、后一道马上要用,比如“焯水”和“爆炒”,那就让同一位师傅趁热完成;有的工序天生适合“边洗边切边扔”——洗菜时顺手把烂叶扔掉,只留下能用的部分;还有的工序规矩地排成流水线,可以串成一条长线。

XLA 的融合策略也遵循类似的直觉。最经典的是生产者-消费者融合:当一个算子的输出恰好是下一个算子的输入(而且这个输出没有被其他算子使用)时,就把它们合并成一个内核,中间结果直接留在寄存器或片上缓存里,不再写回显存。这就像切好的菜直接递给炒锅师傅,冷库完全被跳过了。

另一种重要的是 reductions 融合:某些算子会把数据沿某个维度“约减”掉一大块,比如求和、求最大值。融合时把“先算出全部结果、再约减”变成“边算边约减”,只把最终的小结果写回显存,中间的大块数据根本不需要落地。此外还有循环融合,把多个逐元素算子(如 Add、Mul、激活函数)打包成一个对数据只遍历一次的循环。无论哪种策略,XLA 最终都会用启发式规则做决策,核心判据就是“计算访存比”:

AI=WQ=总浮点运算量总显存数据访问量AI = \frac{W}{Q} = \frac{\text{总浮点运算量}}{\text{总显存数据访问量}}

1. W 总运算量:整个算子簇需要完成的浮点运算次数(FLOPs),是融合后内核的“体力活”总量。

WW

2. Q 总访存量:从显存读入加上写出的总字节数,是融合后内核的“搬运活”总量。

QQ

3. AI 算术强度:两者的比值,代表每字节搬运能支撑多少次计算,是判断“该不该融合”的标尺。

AI=WQAI = \frac{W}{Q}

厨师长不需要管每一根葱怎么切,只需要判断“这道菜值不值得趁热做”“洗完的菜要不要保留全部”。XLA 也一样:启发式规则扫过整张计算图,把值得合并的算子簇圈出来,再交给后端的代码生成器去“掌勺”。

融合收益

客人最直观的感受是上菜变快了。以前一道菜要经过六位师傅、六次冷库存取、六次吆喝开工;现在一位全能师傅一气呵成,冷库几乎没派上用场。出餐时间缩短,餐厅在同一时段能接待的客人自然更多——用行话说,就是“吞吐量上去了”。

把收益量化:假设一条计算链有 n 个算子,未融合时要启动 n 个内核,产生 n-1 份中间结果,每份中间结果都要经历一次“写回显存 + 再读入”的往返。融合成一个内核后,这些开销几乎全部消失。

融合到底能省多少时间?可以用这个式子估算:

Tsaved=(n−1)×Tlaunch+∑i=1n−1Qintermediate,iBmemT_{\text{saved}} = (n-1) \times T_{\text{launch}} + \sum_{i=1}^{n-1} \frac{Q_{\text{intermediate},i}}{B_{\text{mem}}}

其中 $Q_{\text{intermediate},i}$ 是第 i 份中间结果的体积,$B_{\text{mem}}$ 是显存带宽。前半部分省下的是内核启动次数,后半部分省下的是中间结果搬运时间。

1. 启动节省:n 个算子合成 1 个内核,启动次数从 n 次直接降到 1 次。

(n−1)×Tlaunch(n-1) \times T_{\text{launch}}

2. 访存节省:每一份中间结果都免掉一次“写显存 + 读显存”的往返,除以带宽即节省的时间。

∑i=1n−1Qintermediate,iBmem\sum_{i=1}^{n-1} \frac{Q_{\text{intermediate},i}}{B_{\text{mem}}}

3. 总节省时间:把启动开销与访存开销两部分相加,就是融合带来的真实加速。

Tsaved=启动节省+访存节省T_{\text{saved}} = \text{启动节省} + \text{访存节省}

更妙的是,这种加速是“免费午餐”——厨师并没有多花力气,只是少走了冤枉路。在真实 GPU 上,逐元素算子链(比如 add→relu→mul)融合后访存量常常能下降 50%~90%,内核数量从几十个降到几个,GPU 利用率显著提升,端到端推理延迟随之下降。这正是融合成为 XLA 核心优化手段的原因。

XLA实现

如果说上面的策略是“厨师长的经验”,那 XLA 就是把经验变成了一套自动化后厨管理系统。你不需要告诉它“这道菜要趁热加工”,只要把原料丢进系统,它自己会读菜谱、排工序、合并操作,最后端出一盘热菜。

XLA 的编译对象是一张计算图,叫做 HLO 图,图中的每个节点就是一个算子。系统里有一个专门的融合 pass(一个优化步骤),在图上做一遍深度遍历,把符合策略的相邻算子标记为同一个融合簇,再交给后端的代码生成器(GPU 后端通常生成 CUDA 内核)。

融合决策本身是一个权衡问题。一个融合内核会把多个算子的逻辑全部写进同一个 kernel,中间值要尽量留在寄存器里,因此非常依赖寄存器数量和共享内存容量。启发式判定的通用形式可以写成:

Fuse(A,B)  ⟺  Rfused<Rlimit  ∧  Qunfused−QfusedQunfused>δ\text{Fuse}(A, B) \iff R_{\text{fused}} < R_{\text{limit}} \;\wedge\; \frac{Q_{\text{unfused}} - Q_{\text{fused}}}{Q_{\text{unfused}}} > \delta

1. 资源约束:融合后内核需要占用的寄存器数量 R_fused,必须低于当前硬件给出的上限 R_limit。

Rfused<RlimitR_{\text{fused}} < R_{\text{limit}}

2. 访存收益:融合前后访存量之差,占未融合访存量的比例,必须大于阈值 δ 才有融合价值。

Qunfused−QfusedQunfused>δ\frac{Q_{\text{unfused}} - Q_{\text{fused}}}{Q_{\text{unfused}}} > \delta

3. 组合判定:两个条件必须同时满足,系统才执行融合操作。

Fuse(A,B)  ⟺  条件1∧条件2\text{Fuse}(A, B) \iff \text{条件1} \wedge \text{条件2}

这套系统还配了“监控摄像头”:XLA 提供 HLO 转储、图形可视化等调试选项,工程师可以直观地看到哪些算子被合并了、哪些没有、为什么没有;配合性能分析工具统计内核数量和访存量,就能验证融合到底带来了多少收益。整条链路高度自动化,这也是它成为生产级编译器的重要原因。

PyTorch集成

普通食客不需要进后厨点菜——他们在前台下单,后厨系统自动把订单分解成一道道工序。PyTorch 用户就是食客,写下模型、调用一次接口,编译栈自动把 Python 层面的算子翻译成高效的 GPU 内核。

PyTorch 2.0 引入的 torch.compile 是当前最主流的入口。它内部由三大部分组成:Dynamo 负责“捕获计算图”——把 Python 代码的执行轨迹还原成一张静态图;AOTAutograd 负责把反向传播也展开成图;最后交给后端编译器生成内核。默认后端是 Inductor(基于 Triton),但在 PyTorch/XLA 这类框架中,图会直接转换成 HLO 交给 XLA 编译,从而完整享受算子融合。

无论是 Inductor 的 Triton 融合还是 XLA 的 HLO Fusion,思想同源。用一个加速比公式概括编译带来的收益:

Speedup=TeagerTcompiled=∑i=1nTop,i∑j=1mTfused,j,m≪n\text{Speedup} = \frac{T_{\text{eager}}}{T_{\text{compiled}}} = \frac{\sum_{i=1}^{n} T_{\text{op},i}}{\sum_{j=1}^{m} T_{\text{fused},j}}, \quad m \ll n

1. Eager 总耗时:未编译时每个算子单独执行,总耗时是所有算子耗时的累加。

∑i=1nTop,i\sum_{i=1}^{n} T_{\text{op},i}

2. 编译后总耗时:融合内核逐一执行,内核数量 m 远小于算子数量 n。

∑j=1mTfused,j\sum_{j=1}^{m} T_{\text{fused},j}

3. 加速比:两者相除,衡量整体性能提升的倍数。

Speedup=TeagerTcompiled\text{Speedup} = \frac{T_{\text{eager}}}{T_{\text{compiled}}}

对用户来说,这就像点餐后不用关心后厨怎么安排——torch.compile(model) 一行代码,编译器自动完成图捕获、融合、代码生成。同一套模型,Eager 模式逐个算子跑、编译模式融合后跑,基准测试一对比,融合的威力立刻可见。

优化案例

再好的理论也要拿招牌菜验证。Transformer 就是 AI 界的招牌菜,几乎每家大模型餐厅都在做。这道菜工序极多:多头注意力、Softmax、层归一化、MLP……每一道工序之间都藏着大量“冷库往返”。

以 Attention 融合为例,Q、K、V 三个线性投影本来是三次独立的矩阵乘法,每次都要把结果写回显存。融合后,可以把三个投影拼成一个大矩阵,一次矩阵乘法同时算出 Q、K、V,省掉两次内核启动和两次中间结果落地。更极致的做法参考 FlashAttention 的思路:把 QK^T 和 PV 的计算放进片上缓存,Softmax 的中间矩阵根本不落显存。

Attention 融合前后的访存量差异,可以用一个式子说明:

Qunfused=QQK+QS+QPV,Qfused=QQK+QPVQ_{\text{unfused}} = Q_{QK} + Q_{S} + Q_{PV}, \qquad Q_{\text{fused}} = Q_{QK} + Q_{PV}

其中 $Q_S$ 是 Softmax 的注意力分数矩阵(大小为序列长度的平方)。序列越长,$Q_S$ 越大,不落显存的收益就越夸张。

1. 未融合访存量:QK 矩阵乘的结果、Softmax 分数矩阵、PV 矩阵乘的结果全部要写显存。

Qunfused=QQK+QS+QPVQ_{\text{unfused}} = Q_{QK} + Q_{S} + Q_{PV}

2. 融合后访存量:Softmax 分数矩阵 S 留在片上不再写回显存,只剩两个矩阵乘的读写。

Qfused=QQK+QPVQ_{\text{fused}} = Q_{QK} + Q_{PV}

3. 节省幅度:节省的部分正是规模为序列长度平方的 S 矩阵。

Qsaved=QS=O(N2)Q_{\text{saved}} = Q_{S} = O(N^{2})

Transformer 之外,MLP 融合也是重灾区。把“线性层 + GELU + Dropout”这些逐元素算子揉进相邻的矩阵乘内核后,一个 Decoder Layer 的内核数量往往能减少一半以上。放到整张网上看,融合后模型吞吐量提升 30%~50% 是常见结果——冷库没人去了,菜自然上得快。

---

AI 应用场景

大模型推理服务优化

阶段:推理部署与性能优化

解决的问题:LLM 逐 token 生成时,Decoder 每一层有大量内核启动和中间结果往返,传统逐算子执行让 GPU 大部分时间在搬运数据,延迟居高不下。

具体案例:使用 TensorRT-LLM 或 vLLM 部署 Llama-2-7B 时,将 QKV 投影融合、MLP 融合、RMSNorm 与逐元素乘融合,单 token 生成延迟可降低约 30%~50%,吞吐量接近翻倍。这些工具背后的融合思路,正是 XLA 算子融合理念的工程化落地。

PyTorch 编译栈一键加速

阶段:模型编译优化

解决的问题:手写 CUDA 内核门槛高、周期长,普通工程师无法为每个模型单独做融合优化。

具体案例:HuggingFace 上的 BERT 模型部署前调用 torch.compile(model),Dynamo 捕获计算图后由后端完成 GELU 与 Bias 等算子的融合,p50 推理延迟下降 20%~40%,业务代码零改动。若走 PyTorch/XLA 路径,图会被转换成 HLO 由 XLA 完成融合,效果同样显著。

自定义融合算子开发

阶段:算子开发与性能调优

解决的问题:标准算子库缺少特定组合的融合内核(如 LayerNorm + Residual + Activation),逐算子执行成为热点瓶颈。

具体案例:AI 编译器工程师在 XLA 中通过自定义调用(Custom Call)注册融合 kernel,或参考 XLA 的融合模式用 CUDA 手写“多语句内核”,让中间值留在寄存器而不写回显存。这类优化在自动驾驶、推荐系统等低延迟场景中收益巨大。

Python 演示

python47 行
"""算子融合效果对比: Eager 模式 vs torch.compile 编译模式"""import timeimport torch  def build_mlp():    """一个典型 MLP 块: Linear -> GELU -> Linear -> GELU"""    return torch.nn.Sequential(        torch.nn.Linear(256, 256),        torch.nn.GELU(),        torch.nn.Linear(256, 256),        torch.nn.GELU(),    )  def bench(model, x, iters=50):    """预热后返回平均耗时(毫秒)"""    with torch.no_grad():        for _ in range(5):          # 预热: 触发编译与缓存            model(x)        if x.is_cuda:            torch.cuda.synchronize()        t0 = time.perf_counter()        for _ in range(iters):            model(x)        if x.is_cuda:            torch.cuda.synchronize()    return (time.perf_counter() - t0) / iters * 1000  def main():    dev = "cuda" if torch.cuda.is_available() else "cpu"    x = torch.randn(2048, 256, device=dev)     eager = build_mlp().to(dev).eval()    compiled = torch.compile(build_mlp().to(dev).eval())     te = bench(eager, x)    tc = bench(compiled, x)     print(f"Eager    : {te:.3f} ms")    print(f"Compiled : {tc:.3f} ms")    print(f"Speedup  : {te / tc:.2f}x (得益于算子融合)")  if __name__ == "__main__":    main()
目的:同一模型分别用 Eager 模式与 torch.compile(融合编译)运行,量化对比延时差异,直观展示算子融合的加速效果。
  1. torch.nn.Sequential(...)定义 4 个连续算子的 MLP 链,正是一串适合融合的“工序链”。
  2. build_mlp().to(dev).eval()把模型搬到 GPU(或 CPU)并切到推理模式,保证计时公平。
  3. torch.compile(build_mlp().to(dev).eval())一行开启编译模式,后端自动做图捕获与算子融合。
  4. bench(eager, x)` / `bench(compiled, x)同一套预热+计时逻辑分别测量两种模式,避免编译延迟污染结果。
  5. torch.cuda.synchronize()阻塞等待 GPU 执行完毕,保证计时不包含异步排队的误差。
  6. te / tcEager 耗时除以编译耗时,得到融合带来的加速比,通常大于 1。

常见误区

误区我一直以为算子融合是把两个算子的数学计算合并简化了,所以模型推理变快是因为浮点运算变少了。

正解融合几乎不减少浮点运算量(FLOPs),它省的是“搬运”和“呼叫”成本——中间结果不再写回显存、内核启动次数减少。就像后厨把“切完放冷库再取出”省掉了,但切菜本身的功夫一点没少。融合后计算时间占比可能不变甚至略升,端到端时间却大幅下降。

为何常见:人们习惯用“合并=简化”的直觉理解,忽略了 GPU 上访存往往比算数更贵这一硬件事实。

误区既然融合能提速,那把能合并的算子全塞进一个大内核,效果肯定最好?

正解融合内核要把所有中间值放进寄存器或共享内存,融合过多会导致寄存器溢出、GPU 占用率(Occupancy)下降,并行度反而变差;编译时间也会暴涨。XLA 的启发式规则正是为了避免“过度融合”,在访存收益与资源压力之间取平衡。后厨硬把十道菜挤在一口锅里,只会手忙脚乱。

为何常见:只看到了融合省掉的访存成本,没看到 GPU 硬件资源的有限性。

误区PyTorch 2.0 的 torch.compile 底层就是 XLA,所以我用 torch.compile 就是在用 XLA 做融合。

正解torch.compile 默认后端是 Inductor(生成 Triton 内核),与 XLA 是不同的编译器;但这套编译思想(图捕获、算子融合)与 XLA 一脉相承。若想真正用上 XLA,需要走 PyTorch/XLA 或 PJRT 插件路径,把图转换成 HLO。两者都能融合加速,但实现栈并不相同。

为何常见:两者都能融合、都能加速,表象相似,容易混淆底层实现细节。

误区编译器的融合判断只要看算子依赖关系,关系允许就融合,不需要关心硬件。

正解融合决策强烈依赖硬件特性:寄存器文件大小、共享内存容量、带宽比都会影响“融合后是否真的更快”。同一个图在 A100 上适合融合,在资源更小的卡上可能适得其反。所以 XLA 的启发式规则会读取目标硬件参数做权衡。

为何常见:把编译优化抽象成纯数学问题,忽略了编译器的本质目标就是适配具体硬件。

面试题

Q1. 算子融合最主要的优化目标是?

单选题 · easy

  • A.降低浮点运算次数
  • B.减少访存与启动开销← 正确答案
  • C.减小模型参数量
  • D.提升数据计算精度

答案:B。融合把多个算子合成一个内核,省掉的是中间结果写回显存(访存)与 CPU 反复下发内核(启动)的开销,而不是减少 FLOPs。就像后厨省掉的是“放回冷库再取出”的往返,而不是切菜本身。

Q2. 下列哪项最能描述“内存墙”问题?

单选题 · easy

  • A.显存容量不太够用
  • B.算力增速远超带宽← 正确答案
  • C.内存价格比较贵
  • D.显存无法方便扩容

答案:B。内存墙指 GPU 算力增长远快于显存带宽增长,导致数据搬运速度跟不上计算速度,很多算子被访存卡住——“算得快但搬得慢”。容量和价格是另一个维度的工程问题,与“墙”的本义无关。

Q3. 哪种融合策略专门处理“把生成中间结果的算子和消费它的算子合并”?

单选题 · mid

  • A.约减类算子融合
  • B.生产者消费者融合← 正确答案
  • C.循环逐点融合方案
  • D.数据布局融合方案

答案:B。生产者-消费者融合的核心是“趁热加工”:一个算子的输出恰好是下一个算子的输入,中间结果直接留在寄存器里,不再写回显存。reductions 融合侧重约减中间维度,循环融合侧重逐元素算子打包。

Q4. 一条链路有 n 个算子,融合成一个内核后,最多减少几次内核启动?

单选题 · mid

  • A.恰好为 n 次
  • B.最多 n-1 次← 正确答案
  • C.约等于 n/2 次
  • D.几乎等于 0 次

答案:B。n 个算子原本各启动一次内核,共 n 次;融合成一个内核后只剩 1 次启动,减少 n-1 次。这对应公式 $T_{\text{saved}}$ 中的 $(n-1) \times T_{\text{launch}}$ 项,融合链越长节省越多。

Q5. 算术强度(Arithmetic Intensity)表示什么?

单选题 · mid

  • A.单位时间的浮点运算量
  • B.每字节访存对应的运算量← 正确答案
  • C.模型精度与速度之比
  • D.内核启动时间占总比

答案:B。算术强度 = 总浮点运算量 ÷ 总显存访问字节数,衡量“每搬运一个字节能换多少次计算”。AI 越高说明计算越密集,越值得融合;AI 越低说明算子在“空跑搬运”。

Q6. 关于 XLA 的启发式融合决策,下列说法正确的是?

单选题 · hard

  • A.融合总是越彻底越好
  • B.融合决策只看访存节省
  • C.需权衡访存与寄存器压力← 正确答案
  • D.融合与硬件特征无关

答案:C。XLA 的融合判定公式要求同时满足“寄存器资源不超限”和“访存削减超过阈值”两个条件。过度融合会让寄存器溢出、占用率下降,反而降低性能,所以必须在访存收益与资源压力之间取平衡。

Q7. 为什么过度融合可能导致 GPU 性能下降?

单选题 · hard

  • A.编译器会直接报错
  • B.寄存器压力降低占用率← 正确答案
  • C.GPU 温度显著升高
  • D.数据精度发生丢失

答案:B。融合内核要把大量中间值放进寄存器,融合过多导致寄存器压力过大,GPU 能同时驻留的线程块变少,占用率下降,并行度不足反而拖慢执行。这就像后厨把太多工序挤在一口锅里,厨师反而施展不开。

Q8. 算子融合可以降低哪些开销?

多选题 · easy

  • A.内核启动时间← 正确答案
  • B.显存往返读写← 正确答案
  • C.模型参数规模
  • D.数据标注成本

答案:AB。融合消除的是内核启动次数和中间结果的显存往返,这两项正是 GPU 上最昂贵的开销。参数规模和标注成本属于模型与数据层面的问题,编译优化无法触及。

Q9. 以下哪些属于 XLA 支持的融合类型?

多选题 · mid

  • A.生产者消费者融合← 正确答案
  • B.约减类算子融合← 正确答案
  • C.梯度反向传播更新
  • D.分布式数据并行

答案:AB。XLA 支持生产者-消费者融合、reductions 融合、循环融合等策略。反向传播是训练算法,数据并行是分布式策略,它们属于训练与系统层面的概念,不是编译器的融合分类。

Q10. 关于 Attention 的算子融合实践,下列说法正确的有?

多选题 · extreme

  • A.QKV 投影融合为一次矩阵乘← 正确答案
  • B.softmax 中间矩阵不落显存← 正确答案
  • C.融合后精度必然降低
  • D.融合后内核数量必定减少← 正确答案

答案:ABD。QKV 三个投影可拼成一个大矩阵一次性算完;FlashAttention 式融合让 Softmax 分数矩阵留在片上缓存不写回显存;融合减少内核启动次数。但融合不改变浮点运算顺序与精度,精度降低并非必然结果。