4、NPU架构基础:神经网络计算模式与数据流
神经网络加速器(NPU)的本质,是将深度学习算法中高度重复的乘加运算(MAC)与数据搬运操作,映射到专用的硬件流水线上。理解NPU架构,首先需要拆解神经网络的基本计算原语(卷积、全连接、激活、池化),再掌握这些原语在硬件中如何组织成高效的数据流。本章将建立从算法算子到硬件微架构的映射思维,为后续RTL设计打下基础。
4.1 核心计算模式:从算法到硬件原语
4.1.1 卷积运算的硬件本质
卷积层在NPU中并非直接实现滑窗,而是转化为矩阵乘加操作。对于输出特征图上的每个点,硬件需要完成输入通道维度的乘累加。以3×3卷积、输入通道C=64、输出通道K=64为例,单个输出像素需要 3×3×64 = 576 次乘加。RTL设计的关键在于:数据复用。权重在多个输出位置被复用,输入激活在多个输出通道被复用。因此,硬件架构通常采用权重固定(Weight Stationary)或输出固定(Output Stationary)的数据流策略,以减少片外DRAM访问。
- 并行度(Parallelism):通常以 MAC 阵列大小表示,如 16×16、32×32。RTL设计需权衡面积与吞吐率。
- 位宽(Bit-width):INT8 是主流,但混合精度(INT4/FP16)需要可配置的乘法器。
- 累加器位宽:为防止溢出,累加器通常比输入位宽宽 4-8 位(如 INT32)。
4.1.2 全连接层与矩阵乘法单元
全连接层本质是矩阵向量乘(GEMV)或矩阵矩阵乘(GEMM)。在NPU中,全连接层通常复用卷积的计算阵列,只是将卷积核大小设为1×1,或者直接调用专用的矩阵乘法单元。RTL实现时,需要关注权重矩阵的加载方式——是逐行加载还是分块加载,这直接影响DMA(Direct Memory Access)控制器的设计复杂度。
4.1.3 激活函数与池化的硬件实现
激活函数(ReLU、Sigmoid、Tanh)在硬件中通常使用查找表(LUT)或分段线性逼近实现。ReLU 只需比较器,而 Sigmoid 需要更复杂的逻辑。池化层(最大池化/平均池化)则相对简单,主要涉及数据选择与加法树。在RTL设计中,这些算子通常被集成在计算阵列的输出端,形成算子融合,减少中间数据的搬移。
| 计算模式 | 硬件映射单元 | 关键RTL组件 | 数据复用策略 |
|---|---|---|---|
| 卷积 (3×3) | 脉动阵列 / 乘法器树 | MAC单元、移位寄存器、累加器 | 权重广播、输入行缓存 |
| 全连接 | 矩阵乘法单元 | 乘加阵列、权重Buffer | 权重分块加载 |
| 激活 (ReLU) | ALU / LUT | 比较器、多路选择器 | 流水线直通 |
| 池化 (Max) | 比较树 | 比较器、寄存器链 | 窗口滑动复用 |
4.2 NPU数据流架构:从存储到计算的搬运
4.2.1 经典数据流范式
NPU的数据流决定了数据在存储层级间的移动方式。主流架构分为三类:
- 权重静止(Weight Stationary):权重从片上SRAM加载后保持不变,输入激活流经计算阵列。适合权重较大的网络,减少权重搬运。
- 输入静止(Input Stationary):输入激活驻留在寄存器中,权重流经阵列。适合激活图较小的场景。
- 输出静止(Output Stationary):部分和(PSUM)在累加器中保持,直到计算完成。减少了累加器的读写次数,是当前NPU最常用的策略。
在RTL设计中,选择数据流直接影响片上存储(SRAM)的容量划分和NoC(片上网络)的带宽设计。例如,输出静止架构需要较大的累加器阵列,但可以显著降低DRAM的写回压力。
4.2.2 计算单元与存储层次
一个典型的NPU计算单元包含:MAC阵列、激活Buffer、权重Buffer、累加器(PSUM)。数据流路径为:外部DDR → DMA → 片上SRAM(全局Buffer) → 局部Buffer → MAC阵列 → PSUM → 激活/池化 → 写回SRAM。RTL设计者需要关注带宽匹配:如果MAC阵列每周期需要消费 1024 个INT8数据,那么片上SRAM必须提供至少 1024B/cycle 的读取带宽。
4.3 案例拆解:一个8×8 MAC阵列的卷积数据流设计
4.3.1 场景与约束
假设我们要设计一个用于边缘设备的NPU子模块,输入为 32×32×16 的特征图,卷积核为 3×3×16×16,输出为 32×32×16。硬件约束:MAC阵列为 8×8(即64个MAC单元),片上SRAM容量为 256KB,时钟频率 500MHz。
4.3.2 初始目标与瓶颈分析
目标:完成一次卷积计算的总周期数最小化。初始方案:直接按输出通道循环,每次计算一个输出通道的所有像素。但这样会导致输入激活从DRAM重复加载 16 次,带宽不足。
4.3.3 优化操作步骤
- 循环分块(Tiling):将输出通道分为两组(每组8通道),输入通道也分为两组。这样,每次加载 16×16×8 的输入块和 3×3×8×8 的权重块,可重复利用数据。
- 双缓冲(Double Buffering):在DMA搬运下一块数据时,当前块正在计算,隐藏搬运延迟。
- 脉动阵列映射:将8×8 MAC阵列设计为脉动结构,权重预加载到每个PE的寄存器中,输入激活从左侧流入,部分和在下方累加。
4.3.4 结果对比与复盘
| 方案 | DRAM访问量 | 计算周期数 | MAC利用率 |
|---|---|---|---|
| 朴素循环 | 约 1.2 MB | 约 1,048,576 周期 | 约 25% |
| 分块+双缓冲 | 约 0.4 MB | 约 524,288 周期 | 约 68% |
复盘经验:性能提升的关键在于数据复用。通过分块,输入激活的加载次数从16次降为4次。RTL实现时,需注意地址生成器的复杂度,它需要支持多维循环的地址跳变。
4.4 常见误区与设计总结
4.4.1 误区一:盲目增加MAC阵列规模
增加MAC数量并不总能提升性能。如果片上存储带宽不足,MAC阵列会处于“饥饿”状态。RTL设计应首先确保数据供给速率 ≥ 计算消耗速率。
4.4.2 误区二:忽略累加器溢出
在INT8计算中,16个通道的累加结果可能超过INT16范围。设计时必须使用INT32累加器,并在输出前进行截断或饱和处理。否则,会出现严重的精度损失。
4.4.3 误区三:控制逻辑与数据路径耦合过紧
将地址计算、状态机与MAC阵列的流水线耦合在一起,会导致时序收敛困难。建议采用解耦设计:控制模块通过简单的握手信号(valid/ready)与数据路径通信,数据路径内部采用深度流水线。
generate 语句参数化MAC阵列的尺寸。例如:genvar i, j; generate for (i=0; i<8; i=i+1) begin : mac_row ... end endgenerate。这便于后续扩展或缩减阵列规模。
4.4.4 总结复盘
本章节的核心在于理解算法到硬件的映射。在RTL设计实战中,建议遵循以下流程:
- 第一步:分析网络模型,提取计算量与数据量。
- 第二步:确定数据流范式(推荐输出静止)。
- 第三步:划分存储层次,计算所需带宽。
- 第四步:编写参数化的MAC阵列与地址生成器RTL。
- 第五步:通过仿真验证MAC利用率与功耗。
下一阶段,我们将深入MAC阵列内部的微架构设计,包括乘法器选择(基于LUT或DSP48)、流水线级数平衡以及低功耗技术(如操作数隔离、门控时钟)。