3、FINN核心架构:数据流架构、层折叠技术、SIMD与MVTU原理
好,咱们进入正题。这一章我打算聊聊FINN的核心架构。说实话,我第一次接触FINN时,也被它那套概念搞得有点晕。什么数据流、层折叠、SIMD、MVTU……一堆缩写。但等你真正搞懂了,会发现这些设计其实非常巧妙。
我个人习惯是,先理解大框架,再抠细节。所以咱们先从数据流架构说起。
3.1 数据流架构:不是冯·诺依曼那套
传统的CPU或者GPU,用的是冯·诺依曼架构。指令一条条取,数据一次次搬。说白了,就是“取指-译码-执行”那套循环。但FINN不一样,它用的是数据流架构。
什么叫数据流?就是数据一来,计算就自动触发。没有复杂的指令调度,没有乱序执行。每个计算单元就像一个小工坊,原料(数据)到了,就开始干活,干完活把结果传给下一个工坊。
我在项目中遇到过这样一个场景:用FINN部署一个3层的小CNN,输入是一张28x28的灰度图。如果用传统CPU,你得写循环、算地址、搬数据。但在FINN里,你只需要把网络结构描述清楚,数据就像流水一样,一层层往下流。延迟极低,吞吐量极高。
核心优势:数据流架构天然适合CNN这种计算密集型、数据依赖固定的任务。每一层的输出就是下一层的输入,中间不需要全局内存的频繁读写。
你想想看,在传统架构里,数据从内存搬到寄存器,再从寄存器搬到ALU,算完再搬回去。这一来一回,功耗和延迟都上去了。而数据流架构把计算单元和存储单元紧密耦合在一起,数据几乎不走远路。
3.2 层折叠技术:把深度变成宽度
好,数据流架构讲完了。但有个问题:如果网络很深,比如有50层,那是不是需要50个独立的硬件层?
嗯,理论上可以。但FPGA的资源是有限的。你不可能为了一个50层的网络,把整个芯片都铺满计算单元。这时候,层折叠技术就派上用场了。
层折叠,说白了就是时间换空间。把多个网络层映射到同一套硬件上,分时复用。比如你有5层卷积,但只设计了1个卷积硬件模块。数据先流过这个模块,算完第1层,结果存回BRAM,再喂给同一个模块算第2层……以此类推。
我记得有一次,客户要求在一个小芯片上部署一个8层的网络。如果不折叠,资源根本不够。我用了层折叠,把8层折叠成2个硬件阶段,每个阶段处理4层。虽然延迟增加了,但资源占用降到了原来的1/4。客户很满意。
我的经验:层折叠的折叠因子不是越大越好。折叠太多,控制逻辑会变复杂,而且BRAM的读写冲突也会增加。一般我建议折叠因子控制在2~8之间,具体要看你的网络结构和FPGA资源。
这里有个避坑指南:我曾经在一个项目里把折叠因子设成了16,结果控制逻辑的时序跑不过,最后不得不拆成两个阶段。所以,别贪心,适可而止。
3.3 SIMD:一条指令,多份数据
接下来聊聊SIMD。这个词大家应该不陌生,CPU里也有。但在FINN里,SIMD的用法有点不一样。
SIMD的全称是Single Instruction Multiple Data。意思就是,一条指令同时处理多份数据。在CNN里,这太合适了。你想啊,一个卷积核要跟输入图像的多个像素点做乘加运算。这些运算之间没有数据依赖,完全可以并行。
FINN里的SIMD,通常是在输出通道维度上做并行。比如你有32个输出通道,SIMD宽度设为4,那就一次并行计算4个通道的结果。这样,计算吞吐量直接翻了4倍。
为什么会这样?因为输出通道之间的计算是独立的。每个通道的卷积核不同,但输入数据是共享的。SIMD正好利用了这个特性。
我建议你在设计时,把SIMD宽度设成FPGA片上DSP单元数量的整数倍。这样资源利用率最高。比如你的芯片有220个DSP,SIMD宽度设成8,那就需要8个DSP做一组乘加,剩下的可以分配给其他任务。
注意:SIMD宽度不是越大越好。宽度越大,需要的输入数据带宽也越大。如果BRAM的读取速度跟不上,反而会拖慢整体性能。我曾经见过一个设计,SIMD宽度设成32,结果BRAM成了瓶颈,吞吐量反而下降了。所以,要平衡计算和存储。
3.4 MVTU:矩阵向量乘的专用引擎
最后,咱们聊聊MVTU。这个缩写看起来吓人,其实就是Matrix-Vector Multiply Unit,矩阵向量乘单元。
在CNN里,全连接层和卷积层(尤其是1x1卷积)本质上都是矩阵向量乘。MVTU就是专门干这个活的。
FINN里的MVTU,设计得非常精巧。它把权重矩阵存在片上BRAM里,输入向量从外部流进来,然后做乘加累加。输出又是一个向量,流到下一层。
我记得第一次看MVTU的代码时,觉得它就是个“大号的乘加器”。但后来发现,它的关键在于数据复用。权重矩阵是固定的,输入向量是变化的。MVTU会尽量复用权重,减少从外部读取权重的次数。
具体来说,MVTU内部有一个权重缓冲区。一次加载一批权重,然后跟多个输入向量做计算。这样,权重的读取次数就大大减少了。
这里有个表格,对比一下不同实现方式的性能:
| 实现方式 | 权重读取次数 | 计算吞吐量 | 资源占用 |
|---|---|---|---|
| 纯流式(无复用) | 高 | 低 | 低 |
| MVTU(带复用) | 中 | 高 | 中 |
| 全并行阵列 | 低 | 极高 | 极高 |
你看,MVTU在性能和资源之间取得了很好的平衡。这也是为什么FINN选择它作为核心计算单元的原因。
总结一下:数据流架构决定了计算的组织方式,层折叠解决了资源不足的问题,SIMD提升了并行度,MVTU则提供了高效的计算引擎。这四个概念,是理解FINN的基石。
嗯,这一章的内容就到这里。下一章我会讲如何在FINN里配置这些参数,以及如何根据你的网络结构做优化。到时候咱们再细聊。