脉动阵列原理:经典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中,然后输入数据从左到右流过阵列,部分和从上到下累加。

工作流程:

  1. 先把权重矩阵加载到PE阵列中,每个PE存一个权重值
  2. 输入数据从阵列左侧进入,逐列向右移动
  3. 每个PE将输入数据乘以本地权重,结果累加到部分和中
  4. 部分和从上往下传递,最终在底部得到完整结果

这种模式的好处是权重不用反复加载,适合推理场景。我在做AI加速器时,90%的推理场景都用的权重固定模式。

2. 输入固定(Input Stationary)

输入数据固定在PE中,权重数据流过阵列。这种模式适合训练场景,因为训练时权重更新频繁。

工作流程:

  1. 输入数据预先加载到PE阵列中
  2. 权重数据从阵列上方进入,逐行向下移动
  3. 每个PE将输入数据乘以流过的权重,结果累加
  4. 部分和在PE内部累加,最终读出

我记得有一次做训练加速器,用了输入固定模式。结果发现一个问题:输入数据量太大,加载一次要花很多时钟周期。后来改用数据复用技术,同一个输入数据被多个权重复用,效率提升了不少。

3. 输出固定(Output Stationary)

输出结果固定在PE中,输入和权重都流动。这种模式适合输出通道数很多的场景。

工作流程:

  1. 每个PE负责计算一个输出像素点
  2. 输入数据和权重数据分别从左侧和上方流入
  3. PE内部累加所有乘加结果,直到计算完成
  4. 结果直接从PE读出,不需要额外累加

注意:输出固定模式虽然减少了累加器的数据搬移,但PE利用率可能不高。我曾经在一个项目中用了输出固定模式,结果因为输入数据复用率低,很多PE在空转。后来改成混合模式才解决问题。

三种模式的对比

特性 权重固定 输入固定 输出固定
适用场景 推理 训练 输出通道多
数据复用 权重复用 输入复用 部分和复用
PE利用率 高 中等 低
控制复杂度 低 中等 高
典型芯片 TPU v1 某些训练加速器 较少使用

你可能会问:到底选哪种模式?我的经验是:没有银弹。推理场景首选权重固定,训练场景考虑输入固定,输出固定模式除非有特殊需求,否则不建议单独使用。

脉动阵列的硬件实现要点

嗯,这里要注意几个关键点:

  • PE设计:每个PE包含一个乘法器、一个累加器和少量寄存器。面积要小,频率要高
  • 数据通路:相邻PE之间的连线要尽量短,减少延迟
  • 控制逻辑:用简单的状态机控制数据流动,不要搞复杂
  • 边界处理:阵列边缘的数据输入输出要设计好,避免瓶颈

我曾经犯过一个低级错误:PE之间的数据通路用了全局布线,结果频率死活上不去。后来改成局部布线,频率直接从500MHz飙到1GHz。记住:脉动阵列的精髓就是局部性,别自己破坏它。

SVG架构图:脉动阵列数据流

脉动阵列数据流模式示意图 权重固定 输入 W W W W W W 输出 输入固定 权重 I I I I I I 输出固定 输入 权重 O O O O O O 权重固定PE 输入固定PE 输出固定PE

实际项目中的选择建议

说了这么多理论,到底怎么选?我给出几条实战建议:

  • 推理芯片:无脑选权重固定。权重不变,加载一次用到底,效率最高
  • 训练芯片:考虑输入固定或混合模式。权重频繁更新,固定权重反而成了负担
  • 边缘设备:优先考虑面积和功耗。小阵列+权重固定,256x256太大就用64x64
  • 高性能计算:大阵列+数据复用。我见过512x512的阵列,但带宽必须跟上

我的经验:如果你刚开始设计脉动阵列,先从权重固定模式入手。它最简单,也最容易调通。等跑通了基础功能,再考虑其他模式。我曾经一上来就想做混合模式,结果调试了三个月还没搞定,后来老老实实从权重固定开始,两周就出了第一版。

脉动阵列不是银弹,但它确实是目前卷积加速器最主流的设计方案。理解了这三种数据流模式,你就掌握了脉动阵列的核心。剩下的就是根据具体场景做权衡和优化了。

可可精品资料库