一、卷积加速器概述:从软件算法到硬件加速的思维转变
各位同学好,我是你们这堂课的主讲人。做了十几年芯片架构,我最大的感触就是——软件和硬件工程师看卷积的方式,完全是两个世界。
软件工程师眼里,卷积就是几层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 卷积的数据流特征
卷积的数据流,说白了就是三个维度:
- 输入通道维度(C)——每个输出像素需要累加所有输入通道的卷积结果。
- 空间维度(H×W)——卷积核在特征图上滑动。
- 输出通道维度(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 数据复用
数据复用是解决带宽瓶颈的终极武器。卷积里有三种复用机会:
- 输入复用——同一个输入像素被多个卷积核用到。比如3×3卷积,步长1,一个输入像素最多被9个输出像素共享。
- 权重复用——同一个卷积核在空间位置上反复使用。比如一个3×3的核,要在整个特征图上滑动,每个位置都用同一组权重。
- 部分和复用——同一个输出像素的累加结果,在不同输入通道之间复用。
这三种复用,你至少要抓住两种,加速器才能跑得起来。我见过最极端的案例——一个做视频处理的芯片,通过巧妙的输入复用设计,把外部带宽需求从256GB/s降到了32GB/s,省了8倍!
1.5 知识体系总览
说了这么多,我画了一张图,帮你把这一章的核心逻辑串起来。你看完应该能明白,卷积加速器设计到底在解决什么问题。
这张图把这一章的核心逻辑串起来了。你看,卷积加速器设计,本质上就是在计算强度、带宽瓶颈和数据复用这三个维度上找平衡。你抓住了数据复用这个“牛鼻子”,计算强度和带宽问题就迎刃而解了。
好了,第一章就讲到这里。记住一句话:做卷积加速器,先别急着写代码,先把数据流想清楚。数据流想明白了,后面的事情就顺了。
可可精品资料库