第二章:神经网络加速器(NPU)基础

各位同学,今天我们聊聊NPU的核心。说实话,很多人一上来就盯着算力看,什么多少TOPS、多少MAC,但真正决定加速器效率的,是它的“骨架”——计算单元和数据流。

我做了十几年芯片,见过太多“纸面算力很高,实际跑起来打对折”的案例。嗯,这章我们就把它拆开看看。

2.1 核心计算单元:MAC阵列与PE阵列

NPU最核心的活儿,就是做乘加运算。一个卷积层,说白了就是成千上万个“乘加”堆出来的。

MAC(乘加单元)是基本细胞。一个MAC做一次 a * b + c 的操作。你想想看,一个卷积核3x3,一次就要做9次乘加。一张224x224的图,几百个通道,这运算量有多大?

所以NPU不会只放一个MAC,而是放一堆——这就是MAC阵列。我习惯把它想象成一个“算力棋盘”,每个格子就是一个MAC。

PE(处理单元)则更复杂一些。一个PE通常包含多个MAC,外加本地寄存器、累加器,甚至小块的SRAM。PE阵列就是把这些PE排成矩阵,协同工作。

关键区别:

  • MAC:纯运算单元,只管乘加
  • PE:带“脑子”的运算单元,能管理数据流动

我在项目中遇到过一个问题:某款芯片的MAC利用率只有40%。查了半天,发现是数据搬运跟不上,MAC经常“饿着肚子”等数据。后来调整了PE阵列的局部存储,利用率直接拉到85%。

2.2 数据流架构:三种经典模式

数据怎么在PE阵列里流动?这决定了你的NPU是“猛虎”还是“病猫”。

业内公认有三种经典数据流:权重固定输出固定行固定。我一个个说。

2.2.1 权重固定(Weight Stationary)

把权重数据“钉”在PE里不动,让输入特征图和部分和在PE之间流动。

优点:权重复用率高,适合权重大的网络(比如早期VGG)。
缺点:输入特征图要广播,带宽压力大。

我曾经在一个边缘芯片上用过这种架构。当时模型权重很大,但输入分辨率不高。权重固定正好扬长避短,效果不错。

2.2.2 输出固定(Output Stationary)

把部分和“锁”在PE里,让权重和输入特征图流进来。

优点:减少部分和的读写,省功耗。
缺点:对PE的本地存储要求高。

嗯,这里要注意:输出固定特别适合深度可分离卷积。我有个项目做MobileNet加速,用输出固定比权重固定省了30%的功耗。

2.2.3 行固定(Row Stationary)

这是Eyeriss论文里提出的经典方案。把一行权重和一行输入特征图“固定”在PE里,沿着行方向滑动计算。

优点:平衡了权重复用和数据复用,灵活性高。
缺点:控制逻辑复杂。

我个人觉得,行固定是“万金油”方案。如果你不确定选哪种,先试试行固定。它虽然不是某个指标最优,但综合表现最稳。

数据流模式 固定对象 主要优点 主要缺点
权重固定 权重 权重复用高 输入带宽大
输出固定 部分和 省功耗 本地存储大
行固定 行数据 平衡灵活 控制复杂

2.3 典型NPU微架构拆解

光说概念不过瘾,我们拆一个典型的NPU看看。我以某款主流NPU为例(不点名,你懂的),它的内部大致长这样:

+------------------+     +------------------+
|   Global Buffer  | <--> |   PE Array       |
|   (SRAM, 2MB)    |     |   (16x16 = 256PE)|
+------------------+     +------------------+
        |                         |
        v                         v
+------------------+     +------------------+
|   Data Load/Store|     |   Accumulator    |
|   (DMA Engine)   |     |   (Post-Process) |
+------------------+     +------------------+
        |
        v
+------------------+
|   Activation     |
|   & Pooling Unit |
+------------------+

这个结构里,有几个关键点:

  • Global Buffer: 全局缓存,通常几百KB到几MB。它负责喂数据给PE阵列。我建议至少能放下一个卷积层的输入和权重,否则DMA会频繁搬运,效率暴跌。
  • PE Array: 16x16的阵列,256个PE。每个PE内部有4个MAC,所以总共1024个MAC。算力就是靠这个堆出来的。
  • Accumulator: 累加器模块。多个PE算完的部分和,在这里汇总。注意,累加器的位宽要够,否则精度会丢。
  • Activation & Pooling: 激活函数和池化。ReLU、Sigmoid这些,还有Max Pooling、Average Pooling,都在这里做。

避坑指南: 我曾经在设计Global Buffer时,只考虑了容量,没考虑带宽。结果PE阵列跑起来,Buffer的读写端口不够,数据堵在门口进不去。后来加了双端口SRAM,问题才解决。记住:带宽和容量一样重要。

2.4 知识体系总览

为了让你更直观地理解,我画了一张图。这张图把NPU的核心要素串起来了:

NPU核心知识体系 计算单元 MAC阵列 · PE阵列 数据流架构 权重固定 · 输出固定 · 行固定 微架构拆解 Global Buffer · PE Array 关键指标 算力(TOPS) · 利用率 设计权衡 面积 · 功耗 · 带宽 常见陷阱 数据饥饿 · 带宽瓶颈 核心思想 计算单元是肌肉,数据流是骨架,微架构是神经系统 三者协同,才能让NPU真正“跑起来”

这张图把NPU的核心要素分成了三层:计算单元、数据流、微架构。下面又延伸出关键指标、设计权衡和常见陷阱。你想想看,任何一个NPU设计,都逃不出这个框架。

警告: 别以为看懂这张图就万事大吉了。实际调优时,你会发现每个模块之间都有耦合。比如你改了数据流,PE阵列的利用率就会变,Global Buffer的带宽需求也会变。牵一发而动全身。

好了,这一章的内容就到这里。NPU的基础打牢了,后面我们才能聊怎么调优、怎么榨干每一分算力。


公众号:蓝海资料掘金营,微信deep3321