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阵列中的流动方式。你可以直观地看到,每种数据流固定的是什么、流动的是什么。

四种数据流架构对比 输入固定 (IS) PE本地存:输入 流动:权重→ 流动:输出→ PE PE 输入固定不动 权重固定 (WS) PE本地存:权重 流动:输入→ 流动:输出→ PE PE 权重固定不动 输出固定 (OS) PE本地存:输出 流动:输入→ 流动:权重→ PE PE 输出固定不动 行固定 (RS) PE处理一行数据 行内数据流动 相邻PE共享数据 PE PE 行数据固定 数据流选择建议 • 能效优先 → 行固定(但开发成本高) • 面积优先 → 权重固定(控制简单) • 稀疏场景 → 输出固定(跳过无效计算) • 第一层卷积 → 输入固定(输入复用率高) 注:实际项目中常混合使用多种数据流,不同层用不同策略

3.8 怎么选?我的实战经验

说了这么多,到底怎么选?我个人的经验是,没有银弹。你得根据你的目标场景来定。

如果你做的是云端训练加速器,模型大、batch size大,我建议用权重固定。因为权重可以一次性加载,然后跟多个输入做计算,吞吐量高。

如果你做的是边缘端推理加速器,模型小、能效比要求高,行固定或者输出固定更合适。行固定能效比高,但开发周期长;输出固定实现简单,适合快速出产品。

如果你做的是稀疏加速器,别犹豫,直接上输出固定。我做过一个对比实验,在80%稀疏度的模型上,输出固定比权重固定快了将近5倍。原因很简单——跳过无效计算带来的收益,远大于数据流动的开销。

最后提醒一句:不管你选哪种数据流,一定要在RTL设计之前,先做数据流建模和性能仿真。我见过太多团队,架构选型拍脑袋,结果流片回来发现性能差了一大截。数据流建模花不了多少时间,但能帮你省下几个月的返工时间。


公众号:蓝海资料掘金营,微信deep3321