2. 神经网络基础

神经网络模型本质上是由一系列计算算子(Operator)组成的计算图。在CPU或GPU上,这些算子以指令流的形式执行;而在NPU(神经网络处理单元)中,算子需要被映射到专用的硬件计算单元、数据通路和片上存储结构上。理解每个核心算子的数学本质及其在硬件中的映射逻辑,是进行NPU架构设计、算子优化和模型部署的基石。本章将逐一剖析卷积、全连接、激活函数和池化这四类基础算子,并深入探讨它们在典型NPU(如Arm Ethos-U系列及自研加速器)中的硬件实现方式。

NPU 核心算子硬件映射总览 输入特征图 IFM (H×W×C) DDR / SRAM 卷积 / 池化引擎 MAC 阵列 / 累加器 池化窗口逻辑 行缓冲 (Line Buffer) 权重缓冲 (Weight Buffer) 激活函数单元 ReLU / Sigmoid / Tanh 查找表 (LUT) / 硬件计算 全连接引擎 向量-矩阵乘法 复用 MAC 阵列 权重矩阵加载 偏置加法 输出特征图 OFM (H'×W'×M) DDR / SRAM 控制总线 (Control Bus) — 指令解码 / 数据流调度 / 同步 存储层级:寄存器文件 → 片上SRAM (TCM) → 二级缓存 (L2) → 外部DDR 数据复用策略:行缓冲、权重驻留、输出累积 图例: 特征图存储 计算引擎 激活/非线性 全连接/矩阵 数据流向

上图展示了NPU内部处理神经网络算子的宏观数据流。输入特征图从存储单元加载,经过卷积/池化引擎、激活函数单元和全连接引擎的流水线处理,最终将结果写回存储。控制总线负责协调各单元的时序与数据搬运。这张图是理解后续各算子硬件映射细节的总体框架。

2.1 卷积算子:计算核心与硬件加速原理

2.1.1 核心原理:滑窗乘累加

卷积是CNN中最主要的计算密集型算子。其数学本质是使用一个可学习的卷积核(Kernel)在输入特征图(IFM)上滑动,对窗口内的元素进行乘累加(MAC)运算,并加上偏置(Bias),最终得到输出特征图(OFM)上的一个像素点。对于多通道输入,卷积核的深度必须与输入通道数一致,每个输出通道对应一组独立的卷积核。

从计算角度看,一次标准的3×3卷积,对于每个输出像素,需要执行 K_h × K_w × C_in 次乘累加操作。假设输入特征图尺寸为 H×W×C_in,输出通道数为 C_out,则总的计算量约为 H×W×C_out×K_h×K_w×C_in。这种高密度的乘累加操作非常适合用硬件并行化实现。

2.1.2 硬件映射:MAC阵列与数据复用

在NPU中,卷积算子并非逐像素循环执行,而是通过空间并行和流水线技术大幅提升效率。核心硬件单元是MAC(乘累加)阵列,也称为脉动阵列或并行计算单元。

  • MAC阵列结构:一个典型的NPU会集成数十至数百个MAC单元。例如,Ethos-U55中配置了128个MAC,而更高性能的加速器可能拥有上千个MAC。这些MAC单元按二维网格排列,每个单元在单个时钟周期内完成一次乘法与一次加法。
  • 输入数据复用:卷积窗口在滑动时,相邻窗口之间存在大量重叠数据。NPU通过行缓冲(Line Buffer)机制,在片上缓存输入特征图的若干行数据,使得同一份输入数据可以被多个卷积窗口复用,从而大幅减少对DDR的访问次数。
  • 权重驻留:卷积核权重在推理过程中是固定不变的。NPU会将当前层所需的全部权重预先加载到片上权重缓冲(Weight Buffer)中。在计算过程中,权重数据从片上缓冲读取,避免了重复从外部存储加载的开销。
  • 输出累积:对于多通道输入,MAC阵列的累加器会持续累积同一输出像素在不同输入通道上的部分和,直到所有通道计算完毕,再一次性写入输出特征图。

关键设计权衡:MAC阵列的规模直接决定了NPU的峰值算力,但更大的阵列意味着更大的芯片面积和功耗。设计者需要在算力、面积、功耗之间寻找平衡。例如,对于资源受限的嵌入式NPU(如Ethos-U55),通常采用较小的MAC阵列(128个)配合高频运行;而面向数据中心的加速器则采用大规模阵列(如4096个MAC)并配合复杂的片上网络。

2.1.3 案例拆解:3×3卷积在Ethos-U55上的执行流程

以Arm Ethos-U55为例,其硬件架构针对3×3卷积进行了深度优化。假设输入特征图为 64×64×16,输出通道为16,卷积核为3×3。

  1. 权重预加载:16个输出通道的3×3×16权重(共2304个权重值)被加载到权重缓冲中。
  2. 输入行缓冲:NPU从SRAM中读取输入特征图的前3行数据(64×16×3 = 3072个值),存入行缓冲。
  3. 滑动窗口计算:MAC阵列在单个周期内并行计算多个输出像素。Ethos-U55的128个MAC可以同时处理多个输出通道的部分和。
  4. 累加与激活:完成一个3×3窗口的乘累加后,结果送入累加器。若启用了ReLU激活,则在累加器输出端直接进行截断和比较操作。
  5. 行滑动:行缓冲滑动一个像素,重复步骤3-4,直到完成整行计算,然后加载下一行数据。

通过这种流水线设计,Ethos-U55在200MHz主频下可实现约25.6 GOPS的算力,而功耗仅为几十毫瓦,非常适合物联网设备。

常见误区:初学者常认为NPU的MAC阵列越大越好。实际上,如果片上存储带宽不足,再大的MAC阵列也会因“数据饥饿”而空转。因此,NPU设计必须同时考虑计算能力与数据供给能力(即“算力-带宽比”)。在评估NPU性能时,不能只看峰值算力,还要关注其在实际模型上的“有效算力利用率”。

2.2 全连接层:向量矩阵乘法与权重驻留

2.2.1 核心原理:特征变换

全连接层(Fully Connected Layer)将输入特征向量与权重矩阵相乘,并加上偏置,实现特征空间到样本标记空间的映射。其数学表达式为 y = Wx + b,其中 x 为输入向量(长度 N),W 为权重矩阵(尺寸 M×N),y 为输出向量(长度 M)。

全连接层通常出现在CNN的分类头或MLP(多层感知机)中。虽然其计算密度不如卷积层,但参数量往往非常庞大,容易成为模型大小的瓶颈。

2.2.2 硬件映射:复用MAC阵列

在NPU中,全连接层通常不单独设计专用硬件,而是复用卷积层的MAC阵列。这是因为全连接层可以视为一种特殊的卷积:当卷积核尺寸与输入特征图尺寸完全一致时,卷积操作就退化为全连接操作。

  • 矩阵分块:当权重矩阵过大无法一次性装入片上缓冲时,NPU会将矩阵分块处理。例如,将 M×N 的权重矩阵按行或列切分为多个子块,依次加载并计算部分和,最后在累加器中合并。
  • 权重预加载与驻留:全连接层的权重复用率极高(每个权重仅使用一次),因此NPU会尽量将权重驻留在片上。对于嵌入式NPU,如果权重超过片上存储容量,则必须采用“流式”加载方式,即边加载边计算。
  • 向量并行:MAC阵列的每一行可以同时处理多个输入特征,实现向量并行。例如,一个128-MAC的阵列可以同时计算128个输出神经元的加权和。

优化技巧:在部署模型到NPU时,如果全连接层权重过大,可以考虑使用“矩阵分解”技术(如SVD分解)将大矩阵拆分为两个小矩阵的乘积,从而减少参数量和计算量。但需注意,分解后的精度损失需要评估。

2.2.3 实战场景:分类头在NPU上的部署

假设一个图像分类模型,最后两层为全连接层:第一层输入1024维,输出512维;第二层输入512维,输出10维(类别数)。在NPU上部署时,编译器会将这两层转换为等效的1×1卷积操作。NPU的MAC阵列会先计算第一层,将中间结果暂存于片上SRAM,然后立即计算第二层。由于中间结果较小(512个值),可以完全驻留在片上,避免了DDR访问。

这种“算子融合”策略是NPU编译器的重要优化手段。通过将全连接层与相邻的激活函数、池化层融合,可以减少数据搬运次数,提升整体推理效率。

2.3 激活函数:非线性变换的硬件实现

2.3.1 核心原理:引入非线性

激活函数为神经网络引入非线性表达能力。没有激活函数,多层网络将退化为单层线性变换。常见的激活函数包括ReLU、Leaky ReLU、Sigmoid、Tanh等。在量化模型中,激活函数通常采用定点或查找表(LUT)方式实现。

2.3.2 硬件映射:LUT与专用计算单元

NPU对激活函数的硬件实现主要有两种方式:

实现方式 适用函数 硬件资源 精度 延迟
查找表(LUT) Sigmoid、Tanh、GELU等复杂函数 片上SRAM存储预计算值 取决于表大小(如256或1024项) 1-2个周期
硬件计算单元 ReLU、Leaky ReLU、Clip 比较器、多路选择器、移位器 精确 1个周期
  • ReLU的硬件实现:ReLU函数 max(0, x) 在硬件中仅需一个比较器和一个多路选择器。当输入为有符号定点数时,只需检查符号位即可决定输出是0还是原值。因此,ReLU几乎不消耗额外硬件资源,通常被“免费”集成在MAC阵列的输出端。
  • LUT实现复杂函数:对于Sigmoid等复杂函数,NPU会在片上SRAM中预存一张查找表。输入值经过量化后作为表索引,直接读出对应的输出值。表的大小决定了精度,例如256项的表可以提供约8位精度。为了提升精度,可以采用“分段线性插值”技术,即存储若干段线性函数的系数,计算时先查表找到所在段,再进行一次乘加运算。

量化感知:在NPU中,激活函数通常与量化操作紧密结合。例如,ReLU的输出会被限制在量化范围内(如0~255),这相当于一个“Clip”操作。编译器会将ReLU与后续的量化缩放因子合并,减少一次数据搬运。

2.3.3 案例拆解:Sigmoid的LUT实现

假设NPU采用8位量化,输入范围映射到[-4.0, 4.0]。为了在硬件上实现Sigmoid,设计者选择使用256项的LUT。具体步骤如下:

  1. 表生成:在编译阶段,工具链计算输入范围[-4.0, 4.0]内均匀分布的256个采样点的Sigmoid值,并量化为8位定点数,存入LUT。
  2. 索引计算:运行时,输入值 x 经过量化后得到一个8位整数 idx,该整数直接作为LUT的地址。
  3. 查表输出:LUT输出对应的Sigmoid近似值。由于输入是均匀量化的,输出精度在0.4%以内,满足大多数分类任务的精度要求。

这种LUT方案的优势在于实现简单、延迟固定,且不消耗乘法器资源。缺点是精度受表大小限制,且对于输入范围变化较大的情况需要重新生成表。

2.4 池化层:降采样与特征压缩

2.4.1 核心原理:局部统计

池化层对特征图进行下采样,降低空间分辨率,同时保留重要特征。最常见的池化操作是最大池化(Max Pooling)和平均池化(Average Pooling)。最大池化取窗口内最大值,平均池化取窗口内平均值。池化层没有可学习参数,计算量相对较小,但数据访问模式特殊。

2.4.2 硬件映射:数据流控制与窗口逻辑

池化层在NPU中的硬件映射相对简单,但需要精细的数据流控制:

  • 窗口滑动:与卷积类似,池化也需要在输入特征图上滑动窗口。NPU复用行缓冲机制,但池化窗口通常不重叠(步长等于窗口大小),因此数据复用率较低。
  • 最大池化实现:硬件中只需一组比较器。对于2×2最大池化,需要3个比较器找出4个值中的最大值。比较器可以复用MAC阵列中的加法器逻辑,但更常见的做法是设计独立的比较树。
  • 平均池化实现:平均池化需要加法器和移位器。对于2×2平均池化,先将4个值相加,再右移2位(除以4)。如果窗口大小不是2的幂次,则需要使用乘法器进行除法。
  • 与卷积融合:在NPU中,池化层经常与卷积层融合执行。例如,卷积层输出的特征图直接送入池化单元,无需写回DDR再读入。这种融合减少了数据搬运,提升了整体效率。

常见误区:池化层虽然计算量小,但数据访问量可能很大。例如,对于 112×112×64 的输入特征图,2×2最大池化需要读取约80万个数据。如果NPU的片上存储不足,频繁的DDR访问会成为性能瓶颈。因此,在设计NPU时,需要为池化层预留足够的数据带宽。

2.4.3 实战场景:池化与卷积的融合优化

在MobileNet等轻量级网络中,池化层通常紧跟在深度可分离卷积之后。NPU编译器会将池化操作“下沉”到卷积引擎内部。具体做法是:卷积引擎在完成一个输出像素的计算后,不立即写回存储,而是暂存在寄存器中。当同一池化窗口内的所有像素都计算完毕后,再执行池化操作并写回。这种方式将池化的数据访问完全隐藏在卷积的计算过程中,实现了“零开销”池化。

这种融合策略要求NPU的卷积引擎具备额外的寄存器空间和比较逻辑,但相比单独执行池化层,可以节省约30%的推理时间。

2.5 算子映射的总结与设计要点

下表总结了四类核心算子在NPU中的硬件映射要点:

算子类型 计算特征 硬件单元 关键优化策略 主要瓶颈
卷积 高密度乘累加 MAC阵列、行缓冲、权重缓冲 数据复用、权重驻留、输出累积 片上带宽、MAC利用率
全连接 向量矩阵乘法 复用MAC阵列 矩阵分块、权重流式加载 权重存储容量
激活函数 非线性变换 LUT、比较器、多路选择器 算子融合、量化合并 LUT精度
池化 局部统计 比较树、加法器、移位器 与卷积融合、窗口复用 数据访问带宽

在实际NPU设计中,算子映射并非孤立的,而是需要从整个计算图的角度进行全局优化。编译器负责将神经网络模型转换为NPU可执行的指令序列,并决定每个算子的数据布局、计算顺序和存储分配。硬件设计者则需要提供足够的灵活性和可编程性,以支持不同模型的映射需求。

设计复盘:在评估一个NPU架构时,建议从以下三个维度进行考量:算力利用率(实际吞吐量/峰值算力)、数据搬运效率(片上命中率、DDR访问次数)和算子覆盖度(能否高效支持目标模型中的所有算子)。一个优秀的NPU设计,应该在这三个维度上达到良好的平衡。