1. 算子优化全景图

大家好,我是你们这趟算子优化之旅的向导。

说实话,每次带新人入门,我总会被问到同一个问题:「算子优化到底在优化什么?」

嗯,这个问题问得好。今天我们就从最底层开始,把算子优化的全景图彻底讲透。

1.1 什么是算子?

先说说算子的本质。

算子,说白了就是神经网络里的一个「计算单元」。你想想看,卷积、池化、全连接、激活函数……这些在模型里反复出现的操作,每一个都是一个算子。

我习惯把算子比作乐高积木。一个完整的模型,就是由这些积木搭起来的。积木本身的质量,直接决定了最终模型的性能。

核心定义:算子 = 输入数据 + 计算逻辑 + 输出数据。在硬件上,它对应着一组特定的指令序列。

举个例子,一个 3x3 的卷积算子,在 GPU 上执行时,会涉及:

  • 从显存加载输入特征图
  • 执行乘加运算(MAC)
  • 写回输出特征图

就这么简单?嗯,表面上看是的。但真正让算子变「重」的,是数据搬运和内存访问的开销。我在项目中遇到过,一个看似简单的算子,因为内存访问模式不对,性能直接掉了 5 倍。

1.2 推理吞吐的核心瓶颈

好了,知道了算子是什么,我们来看看推理吞吐的瓶颈到底在哪。

我个人经验里,90% 的性能问题都出在下面三个地方:

瓶颈类型 具体表现 影响程度
计算瓶颈 算力利用率低,MAC 单元空转 高
访存瓶颈 数据搬运慢,带宽吃满 极高
调度瓶颈 算子之间等待,流水线停顿 中

为什么会这样?

我举个例子你就明白了。假设你在做卷积,计算本身可能只需要 1 毫秒,但把数据从内存搬到计算单元,却花了 5 毫秒。你想想看,这 5 毫秒里,计算单元一直在干等。

避坑指南:我曾经在一个项目里,花了整整两周优化卷积的计算逻辑,结果性能只提升了 10%。后来一分析,发现 80% 的时间都花在数据搬运上。从那以后,我每次优化算子,第一件事就是看内存访问模式。

1.3 优化方法论总览

那么,面对这些瓶颈,我们该怎么下手?

我总结了一套「三板斧」的方法论,你可以直接拿来用:

  1. 计算优化:减少冗余计算,提高算力利用率。比如算子融合、循环展开、向量化。
  2. 访存优化:减少数据搬运,提高缓存命中率。比如数据重排、tiling(分块)、预取。
  3. 调度优化:让算子之间并行起来,减少等待。比如流水线、异步执行、算子并行。

这三板斧不是孤立的,它们经常需要组合使用。我个人的习惯是:先做访存优化,再做计算优化,最后搞调度。因为访存往往是最大的瓶颈,搞定它,收益最明显。

小技巧:刚开始做算子优化时,别急着上手改代码。先用 profiler 跑一遍,看看热点在哪。我见过太多人凭感觉优化,结果改了半天,优化的根本不是瓶颈。

知识体系总览

为了让你更直观地理解算子优化的全貌,我画了一张图:

算子优化全景图 算子定义 输入 → 计算 → 输出 核心瓶颈 计算 · 访存 · 调度 优化方法论 三板斧组合 计算瓶颈:算力利用率低 访存瓶颈:数据搬运慢 调度瓶颈:流水线停顿 计算优化:算子融合 访存优化:数据重排 调度优化:异步执行 核心原则:先访存,再计算,后调度 用 profiler 定位瓶颈,避免凭感觉优化

这张图把算子优化的核心逻辑串起来了。从算子定义出发,到识别瓶颈,再到应用方法论,每一步都有清晰的路径。

好了,这就是算子优化的全景图。说白了,就是搞清楚「你在优化什么」、「瓶颈在哪」、「怎么优化」这三个问题。