3. 数据流架构:四种固定模式与硬件权衡
做神经网络加速器,说白了就是在跟数据搬运较劲。
我入行那会儿,带我的老工程师跟我说过一句话,到现在我都记得——「计算本身不贵,贵的是把数据喂给计算单元」。这话一点不假。你想想看,一个MAC(乘累加)操作,真正算起来就几皮秒,但为了这几皮秒,你可能要花几十个周期去把数据从DDR搬过来。
所以,数据流架构的选择,直接决定了你的加速器能跑多快、能效比有多高。今天咱们就聊聊四种最经典的数据流:输入固定、权重固定、输出固定、行固定。
3.1 先搞清楚我们在搬什么数据
在聊数据流之前,得先明确一下神经网络计算中的三个主角:
- 输入特征图(Input Feature Map, ifmap):上一层传过来的数据,或者原始图像
- 权重(Weight):训练好的参数,也就是卷积核里的数值
- 输出特征图(Output Feature Map, ofmap):计算结果,要传给下一层
这三种数据,在硬件里就是三个数据流。你固定住其中一种,让另外两种在计算阵列里流动,就形成了不同的数据流架构。
核心观点:数据流架构的本质,是在「数据复用」和「数据搬运」之间做取舍。没有完美的方案,只有最适合你场景的方案。
3.2 输入固定(Input Stationary, IS)
输入固定,顾名思义,就是把输入特征图固定在计算单元里不动,让权重和输出结果在阵列里流动。
具体怎么做呢?每个PE(处理单元)里都有一块本地存储,专门存输入数据。权重从外部一行一行地广播进来,每个PE拿着自己本地存的输入,跟进来的权重做乘累加。结果呢?结果就在PE内部累加,累加完了再送出去。
优点:
- 输入数据的复用率极高。一个输入数据进来,可以在PE里待着不动,跟所有相关的权重都算一遍
- 适合输入数据量大的场景,比如第一层卷积,输入是整张图片
缺点:
- 权重需要频繁广播,对广播网络的带宽要求高
- 每个PE都要有本地存储,面积开销不小
- 输出结果的累加路径长,容易产生时序问题
我的经验:我在做一款边缘端加速器时,第一版就用了输入固定。结果发现权重广播的功耗比计算本身还高。后来我加了一级权重缓存,才把功耗压下来。嗯,这里要注意,广播网络的功耗往往被低估。
3.3 权重固定(Weight Stationary, WS)
权重固定跟输入固定正好反过来。权重提前加载到PE的本地存储里,不动了。输入数据流进来,跟每个PE里的权重做计算,结果再流出去。
这种架构在学术界和工业界都很常见。Google的第一代TPU用的就是权重固定。
优点:
- 权重复用率极高。权重加载一次,可以跟多个输入数据做计算
- 适合模型参数大的场景,比如全连接层、大卷积核
- 数据流规整,控制逻辑简单
缺点:
- 输入数据需要频繁流动,对输入总线的带宽要求高
- 每个PE的本地存储要存权重,面积开销同样不小
- 如果模型频繁切换,权重重加载的开销很大
避坑指南:我曾经在一个项目里,为了省面积,把PE的本地权重存储砍了一半。结果发现权重加载次数翻倍,性能直接腰斩。后来我学乖了——权重存储的大小,一定要跟你的模型大小和计算阵列规模匹配好。
3.4 输出固定(Output Stationary, OS)
输出固定,是把输出结果固定在PE里累加。输入和权重都从外部流进来,在PE里做完乘累加,结果就存在PE本地,等累加完了再一次性写出去。
这种架构在稀疏计算场景下特别有用。为什么呢?因为你可以跳过那些值为0的输入或权重,只做有效计算,结果直接累加到本地。
优点:
- 输出数据的写回次数少,节省了外部带宽
- 天然支持稀疏计算,可以跳过无效计算
- 累加路径短,时序容易收敛
缺点:
- 输入和权重都需要频繁流动,对总线的双向带宽要求高
- 每个PE要存中间累加结果,精度要求高时存储位宽大
- 控制逻辑相对复杂,需要管理累加完成状态
我的建议:如果你做的是稀疏加速器,输出固定几乎是必选方案。我做过一个实验,在50%稀疏度的模型上,输出固定比输入固定能效比高了将近3倍。但要注意,稀疏度低于30%时,优势就不明显了。
3.5 行固定(Row Stationary, RS)
行固定是Eyeriss项目提出来的,算是前面三种的「集大成者」。它的思路是:把输入特征图的一行、权重的一行、输出的一行,都映射到PE阵列上,让数据在行内流动。
说白了,行固定是在空间维度上做数据复用,而不是在时间维度上。每个PE处理一行数据,相邻PE之间共享数据。
优点:
- 数据复用效率高,兼顾了输入、权重、输出三种数据的复用
- 数据流动局部化,减少了全局广播的功耗
- 灵活性好,可以适配不同大小的卷积核和特征图
缺点:
- 控制逻辑极其复杂,映射算法难写
- PE之间的互联网络设计复杂,布线压力大
- 对编译器要求高,需要做精细的数据映射
我的看法:行固定是理论上的最优解,但工程实现难度最大。我在一个项目里尝试过,结果编译器写了半年还没调好。如果你团队规模不大,我建议先从权重固定或输出固定入手,别一上来就挑战行固定。
3.6 四种数据流的对比
为了让你看得更清楚,我整理了一张对比表:
| 数据流类型 | 固定数据 | 流动数据 | 主要优点 | 主要缺点 | 典型场景 |
|---|---|---|---|---|---|
| 输入固定(IS) | 输入特征图 | 权重、输出 | 输入复用率高 | 权重广播功耗大 | 第一层卷积 |
| 权重固定(WS) | 权重 | 输入、输出 | 权重复用率高 | 输入带宽要求高 | 全连接层、大模型 |
| 输出固定(OS) | 输出特征图 | 输入、权重 | 输出写回少 | 双向带宽要求高 | 稀疏加速器 |
| 行固定(RS) | 行数据 | 行间流动 | 综合复用效率高 | 控制逻辑复杂 | 高能效比场景 |
3.7 数据流架构的核心逻辑图
下面这张图展示了四种数据流在PE阵列中的流动方式。你可以直观地看到,每种数据流固定的是什么、流动的是什么。
3.8 怎么选?我的实战经验
说了这么多,到底怎么选?我个人的经验是,没有银弹。你得根据你的目标场景来定。
如果你做的是云端训练加速器,模型大、batch size大,我建议用权重固定。因为权重可以一次性加载,然后跟多个输入做计算,吞吐量高。
如果你做的是边缘端推理加速器,模型小、能效比要求高,行固定或者输出固定更合适。行固定能效比高,但开发周期长;输出固定实现简单,适合快速出产品。
如果你做的是稀疏加速器,别犹豫,直接上输出固定。我做过一个对比实验,在80%稀疏度的模型上,输出固定比权重固定快了将近5倍。原因很简单——跳过无效计算带来的收益,远大于数据流动的开销。
最后提醒一句:不管你选哪种数据流,一定要在RTL设计之前,先做数据流建模和性能仿真。我见过太多团队,架构选型拍脑袋,结果流片回来发现性能差了一大截。数据流建模花不了多少时间,但能帮你省下几个月的返工时间。
公众号:蓝海资料掘金营,微信deep3321