脉动阵列原理:经典Google TPU架构分析
脉动阵列,说白了就是让数据像心跳一样,在计算单元之间有节奏地流动。我第一次接触这个概念是在2017年,当时Google的TPU刚出来,我熬夜读完后拍了一下大腿——这玩意儿太巧妙了。
你想想看,传统的卷积计算,数据要反复从内存里搬进搬出。功耗都花在搬运上了,真正算的时间反而少。脉动阵列解决的就是这个问题——让计算单元排成阵列,数据流过去,顺便就把活干了。
什么是脉动阵列?
脉动阵列的核心思想很简单:多个处理单元(PE)排列成网格状,每个PE只和相邻的PE通信。数据像血液一样,从一个PE流到下一个PE,每个PE在数据经过时完成一部分计算。
我个人习惯把脉动阵列比作工厂流水线。原材料(输入数据)从一端进来,每个工位(PE)做一点加工,最后成品(计算结果)从另一端出来。流水线上的工人不用到处跑,材料自己送上门。
脉动阵列的三大优势:
- 局部通信:每个PE只和邻居通信,没有全局连线,布线简单
- 高吞吐量:数据流水线式处理,每个时钟周期都能出结果
- 低功耗:减少数据搬运,大部分功耗花在计算上
我在项目中遇到过一个问题:刚开始设计脉动阵列时,总觉得PE越多越好。结果128x128的阵列做出来,面积大得吓人,功耗也压不住。后来才明白,阵列大小要和片内带宽匹配,否则喂不饱计算单元,白白浪费面积。
Google TPU的脉动阵列架构
Google TPU v1用的是256x256的脉动阵列,总共65536个MAC单元。这个数字我记得很清楚,因为当时我们团队讨论了很久——为什么是256不是128?
原因其实很简单:TPU v1主要做推理,权重是固定的。256x256的阵列可以在一个时钟周期内完成256个输入和256个权重的乘加运算,正好匹配当时的内存带宽。
TPU的脉动阵列有几个关键设计点:
- 权重固定(Weight Stationary):权重预先加载到PE中,输入数据流过阵列
- 16位整数运算:推理场景下精度够用,面积和功耗比浮点小很多
- 累加器在PE内部:每个PE有自己的累加寄存器,减少数据搬移
避坑指南:我曾经在设计时忽略了PE内部的累加器位宽。默认用了16位,结果跑某些大模型时累加溢出,结果全错。后来改成32位累加器才解决问题。记住:累加器位宽一定要比乘法器位宽大,至少大一倍。
三种数据流模式详解
脉动阵列的数据流模式,说白了就是决定"谁不动,谁动"。我把它分成三种:
1. 权重固定(Weight Stationary)
这是TPU v1用的模式。权重预先加载到每个PE中,然后输入数据从左到右流过阵列,部分和从上到下累加。
工作流程:
- 先把权重矩阵加载到PE阵列中,每个PE存一个权重值
- 输入数据从阵列左侧进入,逐列向右移动
- 每个PE将输入数据乘以本地权重,结果累加到部分和中
- 部分和从上往下传递,最终在底部得到完整结果
这种模式的好处是权重不用反复加载,适合推理场景。我在做AI加速器时,90%的推理场景都用的权重固定模式。
2. 输入固定(Input Stationary)
输入数据固定在PE中,权重数据流过阵列。这种模式适合训练场景,因为训练时权重更新频繁。
工作流程:
- 输入数据预先加载到PE阵列中
- 权重数据从阵列上方进入,逐行向下移动
- 每个PE将输入数据乘以流过的权重,结果累加
- 部分和在PE内部累加,最终读出
我记得有一次做训练加速器,用了输入固定模式。结果发现一个问题:输入数据量太大,加载一次要花很多时钟周期。后来改用数据复用技术,同一个输入数据被多个权重复用,效率提升了不少。
3. 输出固定(Output Stationary)
输出结果固定在PE中,输入和权重都流动。这种模式适合输出通道数很多的场景。
工作流程:
- 每个PE负责计算一个输出像素点
- 输入数据和权重数据分别从左侧和上方流入
- PE内部累加所有乘加结果,直到计算完成
- 结果直接从PE读出,不需要额外累加
注意:输出固定模式虽然减少了累加器的数据搬移,但PE利用率可能不高。我曾经在一个项目中用了输出固定模式,结果因为输入数据复用率低,很多PE在空转。后来改成混合模式才解决问题。
三种模式的对比
| 特性 | 权重固定 | 输入固定 | 输出固定 |
|---|---|---|---|
| 适用场景 | 推理 | 训练 | 输出通道多 |
| 数据复用 | 权重复用 | 输入复用 | 部分和复用 |
| PE利用率 | 高 | 中等 | 低 |
| 控制复杂度 | 低 | 中等 | 高 |
| 典型芯片 | TPU v1 | 某些训练加速器 | 较少使用 |
你可能会问:到底选哪种模式?我的经验是:没有银弹。推理场景首选权重固定,训练场景考虑输入固定,输出固定模式除非有特殊需求,否则不建议单独使用。
脉动阵列的硬件实现要点
嗯,这里要注意几个关键点:
- PE设计:每个PE包含一个乘法器、一个累加器和少量寄存器。面积要小,频率要高
- 数据通路:相邻PE之间的连线要尽量短,减少延迟
- 控制逻辑:用简单的状态机控制数据流动,不要搞复杂
- 边界处理:阵列边缘的数据输入输出要设计好,避免瓶颈
我曾经犯过一个低级错误:PE之间的数据通路用了全局布线,结果频率死活上不去。后来改成局部布线,频率直接从500MHz飙到1GHz。记住:脉动阵列的精髓就是局部性,别自己破坏它。
SVG架构图:脉动阵列数据流
实际项目中的选择建议
说了这么多理论,到底怎么选?我给出几条实战建议:
- 推理芯片:无脑选权重固定。权重不变,加载一次用到底,效率最高
- 训练芯片:考虑输入固定或混合模式。权重频繁更新,固定权重反而成了负担
- 边缘设备:优先考虑面积和功耗。小阵列+权重固定,256x256太大就用64x64
- 高性能计算:大阵列+数据复用。我见过512x512的阵列,但带宽必须跟上
我的经验:如果你刚开始设计脉动阵列,先从权重固定模式入手。它最简单,也最容易调通。等跑通了基础功能,再考虑其他模式。我曾经一上来就想做混合模式,结果调试了三个月还没搞定,后来老老实实从权重固定开始,两周就出了第一版。
脉动阵列不是银弹,但它确实是目前卷积加速器最主流的设计方案。理解了这三种数据流模式,你就掌握了脉动阵列的核心。剩下的就是根据具体场景做权衡和优化了。
可可精品资料库