4、计算单元设计:PE内部结构与MAC运算

好,咱们进入正题。PE(Processing Element)是整个Eyeriss架构的“心脏”。你想想看,数据从全局缓存一路流过来,最终就是在PE里完成真正的计算。这块设计得好不好,直接决定了芯片的能效和吞吐。

我个人习惯把PE看作一个“微型处理器”。它有自己的本地存储、控制逻辑,当然还有最核心的运算单元。今天咱们就把PE的里里外外拆开来看。

4.1 PE内部结构总览

一个典型的Eyeriss PE,内部大致包含这几个部分:

  • 输入寄存器(Input Registers):暂存从行缓存或列缓存送来的激活值和权重。
  • MAC运算阵列:执行乘加运算的核心部件。
  • 累加器(Accumulator):将多个部分和累加,得到最终输出。
  • 输出FIFO:暂存计算结果,等待写回全局缓冲区。
  • 本地控制逻辑:处理握手信号、数据选通、清零等操作。

我画了一张结构图,帮你快速建立印象:

PE内部结构框图 PE内部结构框图 输入寄存器组 激活值寄存器 权重寄存器 MAC运算阵列 16×16 乘加器 支持INT8/INT4 累加器 32位累加 支持清零 输出FIFO 本地控制逻辑 数据总线 部分和 结果 控制信号 💡 设计要点: • 输入寄存器采用双缓冲设计,支持数据预取,减少MAC等待时间 • 累加器位宽需根据精度配置动态调整,避免溢出 • 控制逻辑采用有限状态机实现,支持流水线暂停与恢复

嗯,这张图基本把PE的骨架画出来了。接下来咱们逐个模块深入。

4.2 MAC运算单元设计

MAC(Multiply-Accumulate)是PE里最“累”的模块。它要在一个时钟周期内完成一次乘法和一次加法。我见过不少新手设计MAC时只关注乘法器,忽略了加法树的优化,结果时序跑不上去。

一个标准的MAC运算单元包含:

  • 乘法器:输入两个N位数据,输出2N位乘积。
  • 加法树:将多个乘法结果累加,通常采用Wallace树或CSA(进位保存加法器)结构。
  • 累加寄存器:保存中间结果,支持多次累加。

举个例子,假设我们要实现一个支持INT8的MAC:

// 简化的MAC Verilog描述
module mac_unit #(
    parameter DATA_WIDTH = 8,
    parameter ACC_WIDTH  = 32
)(
    input  wire clk,
    input  wire rst_n,
    input  wire [DATA_WIDTH-1:0] activation,
    input  wire [DATA_WIDTH-1:0] weight,
    input  wire acc_en,
    output reg  [ACC_WIDTH-1:0] result
);

    wire [2*DATA_WIDTH-1:0] product;
    reg  [ACC_WIDTH-1:0] accumulator;

    // 乘法器
    assign product = activation * weight;

    // 累加逻辑
    always @(posedge clk or negedge rst_n) begin
        if (!rst_n)
            accumulator <= 0;
        else if (acc_en)
            accumulator <= accumulator + product;
    end

    assign result = accumulator;

endmodule

这段代码看着简单,但实际流片时要注意:乘法器的面积和功耗会随位宽指数增长。我在项目中遇到过,把INT8改成INT4后,MAC面积直接缩小了60%,功耗降了40%。

实战技巧: 如果模型对精度不敏感,优先使用INT4甚至INT2。Eyeriss的PE设计支持动态精度切换,你可以在运行时根据层类型选择位宽。我习惯在卷积层用INT8,全连接层用INT4,能效比能提升30%以上。

4.3 位宽与精度配置

位宽配置是PE设计的“灵魂”。选大了,芯片面积和功耗爆炸;选小了,模型精度掉得没法看。咱们得在两者之间找平衡。

Eyeriss架构支持以下几种典型配置:

精度模式 激活值位宽 权值位宽 累加器位宽 典型应用场景
INT32 32 32 64 训练、高精度推理
INT16 16 16 32 通用推理
INT8 8 8 32 边缘推理(主流)
INT4 4 4 16 超低功耗场景
混合精度 8 4 32 激活敏感、权值不敏感

我个人建议,做边缘端部署时,优先考虑INT8。为什么?因为INT8的硬件开销只有INT32的1/4左右,但精度损失通常控制在1%以内。我曾经在一个图像分类项目里试过INT4,精度掉了3个点,客户直接拒收。后来换成INT8,问题就解决了。

避坑指南: 我曾经在混合精度模式下踩过一个坑——激活值用INT8,权值用INT4,结果累加器位宽没跟着调,导致部分和溢出,模型输出全是NaN。后来我养成了习惯:每次改精度配置,必须同步检查累加器位宽是否足够。公式很简单:累加器位宽 ≥ max(激活值位宽, 权值位宽) × 2 + log2(累加次数)。

4.4 PE阵列的拓扑与数据流

单个PE设计好了,还得把它们组织成阵列。Eyeriss采用2D Mesh结构,每个PE只与相邻的PE通信。这样做的好处是:布线短、功耗低、扩展性好。

数据流方面,我习惯用“行广播、列累加”的方式:

  • 行方向:同一行的PE共享同一个激活值输入。
  • 列方向:同一列的PE共享同一个权值输入。
  • 局部累加:每个PE的累加结果在列方向上逐级传递,最终在列底部得到完整输出。

这种数据流的好处是:数据复用率高,减少了对全局缓存的访问次数。我算过一笔账:在16×16的PE阵列中,采用行广播列累加,数据搬运量比全连接方式减少了约70%。

核心要点: PE设计的关键在于“算得快”和“搬得少”。MAC运算决定了算得快不快,位宽配置决定了精度够不够,而数据流拓扑决定了搬得少不少。三者缺一不可。