一、卷积加速器概述:从软件算法到硬件加速的思维转变

各位同学好,我是你们这堂课的主讲人。做了十几年芯片架构,我最大的感触就是——软件和硬件工程师看卷积的方式,完全是两个世界。

软件工程师眼里,卷积就是几层for循环,数据哗哗往里灌,结果就出来了。但到了我们硬件这边,事情就没那么简单了。你想想看,一个3×3的卷积核,在软件里就是9次乘加,但在硬件里,这9次操作背后牵涉到数据怎么搬、怎么存、怎么复用、怎么流水……稍不留神,性能就崩了。

所以这一章,我们先从思维上转个弯。说白了,就是让你学会用硬件的眼光去看卷积。

1.1 卷积运算的数学本质

先回顾一下卷积的数学定义。别怕,我不跟你扯太深,咱们就讲点实在的。

二维卷积的公式长这样:

O[i][j] = Σ_m Σ_n I[i+m][j+n] × K[m][n]

其中I是输入特征图,K是卷积核,O是输出特征图。m和n遍历卷积核的尺寸,比如3×3就是m从0到2,n从0到2。

嗯,这里要注意——这个公式看起来简单,但它隐含了一个非常重要的特征:数据复用。同一个输入像素,会被多个输出像素用到。我举个例子,一个3×3的卷积核,步长为1,那么输入特征图中间的一个像素,最多会被9个不同的输出像素用到。这就是我们做硬件加速的底气所在。

核心观点:卷积的本质是滑动窗口内的加权求和。窗口滑动过程中,相邻窗口之间有大量重叠数据。这个重叠,就是硬件加速的“金矿”。

1.2 从软件到硬件的思维转变

我个人习惯把这种转变总结成三个“不要想”:

  • 不要想“循环”——软件里三层for循环很自然,但硬件里循环就是状态机,就是控制逻辑,就是面积和功耗。我们要想的是“数据流”。
  • 不要想“数组”——软件里一个二维数组随手就定义了,但硬件里数组就是SRAM,就是寄存器阵列,就是布线资源。我们要想的是“存储层次”。
  • 不要想“顺序执行”——软件里一条指令一条指令跑,但硬件里我们要的是“流水并行”。一个时钟周期内,最好所有计算单元都在干活。

我在项目中遇到过一位软件转硬件的同事,他一开始写卷积加速器,直接照着软件代码翻译成Verilog。结果呢?面积大得离谱,频率还上不去。后来我帮他重新梳理了数据流,把循环展开成流水线,性能直接翻了4倍。这就是思维转变的力量。

1.3 卷积的数据流特征

卷积的数据流,说白了就是三个维度:

  1. 输入通道维度(C)——每个输出像素需要累加所有输入通道的卷积结果。
  2. 空间维度(H×W)——卷积核在特征图上滑动。
  3. 输出通道维度(K)——每个输出通道对应一组不同的卷积核。

这三个维度交织在一起,就形成了不同的数据流方式。我简单列一下常见的几种:

数据流方式 核心思路 适用场景
权重固定(Weight Stationary) 卷积核数据留在计算单元内,输入数据流过来 权重复用度高,适合小batch
输入固定(Input Stationary) 输入数据留在计算单元内,权重流过来 输入复用度高,适合大batch
输出固定(Output Stationary) 部分和留在计算单元内,不断累加 减少写回带宽,适合深度网络

你可能会问,哪种最好?说实话,没有的好坏。我在做一款AI芯片的时候,不同层用了不同的数据流方式。比如前面几层通道数少,我用权重固定;后面几层通道数多,我换成输出固定。灵活搭配才是王道。

1.4 加速器设计的核心挑战

好了,前面铺垫了这么多,现在咱们聊聊真正的难点。做卷积加速器,你绕不开这三个坎:

1.4.1 计算强度

计算强度,就是每字节数据能做多少次运算。公式很简单:

计算强度 = 运算量(OPs) / 数据访问量(Bytes)

为什么这个指标重要?因为如果计算强度太低,你的加速器就会变成“数据搬运工”——计算单元闲着没事干,总线却忙得要死。我见过一个团队做的加速器,理论算力有2TOPS,实际跑起来只有200GOPS,就是因为计算强度没算好,数据供不上。

我的经验:设计初期先算一下目标网络的计算强度,然后对比你的硬件平台能提供的带宽。如果计算强度小于带宽/算力比,那就要考虑增加数据复用了。我曾经在一个项目里,通过调整tile size,把计算强度从0.8提到了2.3,性能直接翻倍。

1.4.2 带宽瓶颈

带宽瓶颈,说白了就是“路太窄,车太多”。卷积加速器需要同时搬运输入特征图、权重和输出特征图,这三路数据抢带宽,很容易打架。

我常用的解决思路有几种:

  • 数据压缩——比如用稀疏编码,把零值跳过去。我在一个语音识别芯片上试过,带宽需求直接降了40%。
  • 片上缓存分层——L1给计算阵列用,L2给数据重排用,L3跟DDR打交道。每一层各司其职。
  • 双缓冲(Double Buffering)——一组缓存给计算单元用,另一组在后台加载数据,交替工作,隐藏搬运延迟。

避坑指南:我曾经在一个项目里,为了省面积,把片上缓存砍了一半。结果呢?数据搬运次数翻倍,功耗反而上去了。所以缓存大小不是越小越好,要算总账——搬运数据的功耗往往比存储数据的功耗大得多。

1.4.3 数据复用

数据复用是解决带宽瓶颈的终极武器。卷积里有三种复用机会:

  1. 输入复用——同一个输入像素被多个卷积核用到。比如3×3卷积,步长1,一个输入像素最多被9个输出像素共享。
  2. 权重复用——同一个卷积核在空间位置上反复使用。比如一个3×3的核,要在整个特征图上滑动,每个位置都用同一组权重。
  3. 部分和复用——同一个输出像素的累加结果,在不同输入通道之间复用。

这三种复用,你至少要抓住两种,加速器才能跑得起来。我见过最极端的案例——一个做视频处理的芯片,通过巧妙的输入复用设计,把外部带宽需求从256GB/s降到了32GB/s,省了8倍!

1.5 知识体系总览

说了这么多,我画了一张图,帮你把这一章的核心逻辑串起来。你看完应该能明白,卷积加速器设计到底在解决什么问题。

卷积加速器设计核心知识体系 卷积加速器 计算强度 带宽瓶颈 数据复用 OPs / Bytes Tile Size调整 数据压缩 缓存分层 输入复用 权重复用 部分和复用 思维转变:循环 → 数据流 数据流:权重固定 / 输入固定 / 输出固定 核心逻辑:理解卷积的数据复用特征 → 突破计算强度和带宽瓶颈

这张图把这一章的核心逻辑串起来了。你看,卷积加速器设计,本质上就是在计算强度、带宽瓶颈和数据复用这三个维度上找平衡。你抓住了数据复用这个“牛鼻子”,计算强度和带宽问题就迎刃而解了。

好了,第一章就讲到这里。记住一句话:做卷积加速器,先别急着写代码,先把数据流想清楚。数据流想明白了,后面的事情就顺了。

可可精品资料库