核心概念:处理单元(PE)的结构,本地寄存器与累加器,数据在阵列中的流动方式

好,我们正式开始拆解脉动阵列的“细胞”——处理单元(PE)。

很多人一上来就盯着整个阵列看,觉得眼花缭乱。我的建议是:先搞懂一个 PE 怎么工作,剩下的就是复制粘贴。说白了,脉动阵列就是一堆长得一模一样的 PE,按某种规则连在一起。

PE 的内部结构:一个微型计算站

每个 PE 本质上是一个小型的、可配置的计算单元。它不像 CPU 那样什么都能干,但干一件事特别快——乘加运算(MAC)。

我早期做过一个图像滤波的加速器,当时图省事,直接用 DSP 硬核搭。后来发现,对于固定模式的卷积,用 PE 阵列做,面积和功耗都能省下一大截。嗯,这就是专用加速器的魅力。

一个典型的 PE 内部包含以下几个关键部件:

  • 乘法器:执行输入数据与权重的乘法。
  • 加法器/累加器:将乘法结果与之前的部分和相加。
  • 本地寄存器组:用于暂存权重、输入数据或中间结果。
  • 控制逻辑:管理数据流动和操作时序。

核心要点:PE 的设计哲学是“小而专”。它不需要通用处理器的复杂指令集,只需要在每一个时钟周期内,稳定地完成一次乘加操作,并把结果传递给下一个 PE。

本地寄存器与累加器:PE 的“手”和“账本”

这两个部件是 PE 的灵魂。很多人搞混它们的作用,我在这里仔细说一下。

本地寄存器:数据暂存站

每个 PE 内部都有几个小容量的寄存器。它们用来干什么?

  • 保存权重:权重通常提前加载到 PE 里,计算过程中不再改变。这叫“权重固定”。
  • 缓存输入数据:从上游 PE 流过来的数据,先存一下,等乘法器准备好了再喂给它。
  • 暂存中间结果:部分和在累加之前,可能需要在寄存器里待一个周期。

我曾经遇到过一个 bug,因为寄存器深度不够,导致数据在 PE 间传递时丢失了一个周期。查了两天才发现,是设计时低估了数据路径上的延迟。所以,寄存器数量的设计,一定要留有余量。

累加器:结果的“账本”

累加器是一个带反馈的寄存器。它的工作流程很简单:

  1. 乘法器算出当前结果:data_in × weight
  2. 累加器读出上一次保存的部分和。
  3. 加法器把两者相加:partial_sum_old + (data_in × weight)
  4. 新结果写回累加器。

这个过程会重复多次,直到一个计算窗口结束。最后,累加器里的值就是最终结果,然后被送出 PE。

小技巧:在 RTL 设计里,累加器通常用“寄存器 + 加法器”的组合实现。注意清零信号的时机,搞错了整个卷积结果都会偏移。

数据在阵列中的流动方式:三种经典模式

数据怎么在 PE 之间跑,决定了阵列的效率和灵活性。我把它归纳为三种基本模式。

流动模式 数据方向 典型应用 特点
输入数据流动 从左到右 FIR 滤波器 权重固定,数据依次流过每个 PE
权重流动 从上到下 矩阵乘法 输入数据固定,权重在 PE 间传递
双向流动 数据与权重交叉 卷积神经网络 数据从左到右,权重从上到下,部分和对角线传递

你想想看,为什么会有这么多模式?因为不同的算法,数据复用方式不一样。比如 FIR 滤波器,输入数据是串行流,权重是固定的系数,那就让数据流动起来,每个 PE 算一个抽头。

而矩阵乘法,我们通常让一个矩阵的行数据固定,另一个矩阵的列权重流动。这样能最大化数据复用,减少访存次数。

避坑指南:我曾经在一个项目里,为了省事,所有 PE 都用了同一种数据流动模式。结果发现,对于某些稀疏矩阵,效率反而下降了。后来我加了一个模式选择寄存器,让软件可以根据算法动态配置。这个改动,让芯片的通用性提升了不少。

一个 PE 的完整工作周期

我们用一个具体的例子,把上面说的串起来。假设一个 PE 要完成 4 次乘加,计算 y = w1*x1 + w2*x2 + w3*x3 + w4*x4。

时钟周期 1: 加载 w1 到本地寄存器,x1 从左侧 PE 流入
时钟周期 2: 执行 x1 * w1,结果存入累加器 (acc = x1*w1)
时钟周期 3: 加载 w2,x2 流入,执行 x2 * w2,累加 (acc = x1*w1 + x2*w2)
时钟周期 4: 加载 w3,x3 流入,执行 x3 * w3,累加
时钟周期 5: 加载 w4,x4 流入,执行 x4 * w4,累加 (acc = 最终结果)
时钟周期 6: 将累加器结果输出到右侧 PE,同时累加器清零

你看,每个周期 PE 都在干活。没有空泡,没有等待。这就是脉动阵列名字的由来——数据像血液一样,在每个“细胞”间有节奏地流动。

SVG 图:PE 内部结构与数据流动

下面这张图展示了一个 PE 的内部结构,以及数据在三个相邻 PE 间的流动方向。你可以看到,输入数据从左向右传递,权重从上向下广播,部分和则在对角线方向累加。

PE 内部结构与数据流动示意 PE 1 乘法器 累加器 本地寄存器 (权重/数据) PE 2 乘法器 累加器 本地寄存器 (权重/数据) PE 3 乘法器 累加器 本地寄存器 (权重/数据) 数据 数据 权重 权重 权重 部分和 部分和 图例说明: • 蓝色箭头:输入数据从左向右流动,每个 PE 处理一个数据点。 • 绿色箭头:权重从上向下广播,所有 PE 可以同时接收新权重。 • 橙色箭头:部分和沿对角线方向传递,最终在最后一个 PE 输出完整结果。 • 每个 PE 内部:乘法器 → 累加器 → 本地寄存器,构成一个完整的 MAC 单元。

这张图里,我特意把三种数据流用不同颜色标出来了。你看,数据从左到右,权重从上到下,部分和斜着走。三者互不干扰,在每一个 PE 里完成一次“相遇”。

嗯,这就是脉动阵列最优雅的地方——数据流动的节奏,就是计算的节奏。你不需要复杂的调度,只要保证数据按时到达,结果自然就出来了。