第二章:神经网络加速器(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的核心要素分成了三层:计算单元、数据流、微架构。下面又延伸出关键指标、设计权衡和常见陷阱。你想想看,任何一个NPU设计,都逃不出这个框架。
警告: 别以为看懂这张图就万事大吉了。实际调优时,你会发现每个模块之间都有耦合。比如你改了数据流,PE阵列的利用率就会变,Global Buffer的带宽需求也会变。牵一发而动全身。
好了,这一章的内容就到这里。NPU的基础打牢了,后面我们才能聊怎么调优、怎么榨干每一分算力。
公众号:蓝海资料掘金营,微信deep3321