第二章:NPU架构基础——核心组件、数据流与指令集
大家好,我是你们的讲师。今天咱们聊聊NPU的骨架——它的核心架构。说实话,很多同学一开始觉得NPU就是个“大号乘法器”,这么理解也没错,但真正用起来,里面的门道可不少。
我在做嵌入式AI加速的时候,最早接触的是CPU跑模型,后来换成GPU,再后来才真正上手NPU。每次切换,都像重新学一门手艺。但NPU给我的感觉最特别——它不像CPU那样“万能”,也不像GPU那样“暴力”,它更像一个为AI量身定制的“专用工厂”。
2.1 核心组件:MAC阵列、缓存、控制器
NPU的核心,说白了就三样东西:MAC阵列、缓存系统、控制器。这三者缺一不可,配合好了,性能才能拉满。
2.1.1 MAC阵列——算力的心脏
MAC阵列,全称是乘累加阵列。它负责做矩阵乘法,这是神经网络最核心的操作。你想想看,一个卷积层,本质上就是一堆乘法和加法。MAC阵列就是专门干这个的。
我习惯把MAC阵列比作“算力工厂里的流水线工人”。每个MAC单元能同时做一个乘法和一个加法。成千上万个MAC单元排成阵列,就能并行处理海量数据。
关键参数:
- MAC数量:直接决定峰值算力。比如一个256 MAC的NPU,理论算力就是256 × 频率。
- 数据位宽:常见的有INT8、INT4、FP16。位宽越小,算力越高,但精度会下降。
- 阵列拓扑:有1D、2D、脉动阵列等。2D阵列最常用,数据复用效率高。
我在项目中遇到过一个问题:某款NPU标称4TOPS算力,但跑我的模型死活达不到。后来一查,原来是MAC阵列利用率只有30%。为什么?因为数据搬运跟不上。这就引出了第二个核心组件——缓存。
2.1.2 缓存系统——数据的中转站
NPU的缓存和CPU的缓存不太一样。CPU缓存主要为了降低延迟,而NPU缓存更注重数据复用和带宽匹配。
典型的NPU缓存分三级:
| 缓存级别 | 容量 | 作用 |
|---|---|---|
| L1(本地缓存) | 几十KB | 每个MAC单元独享,存当前计算块的输入 |
| L2(共享缓存) | 几百KB到几MB | 多个MAC单元共享,存中间特征图 |
| L3(全局缓存) | 几MB到几十MB | 存权重和整个特征图,连接外部DDR |
嗯,这里要注意:缓存大小和MAC数量要匹配。我曾经见过一个设计,MAC阵列很大,但L1缓存太小,导致MAC单元经常“饿着肚子”等数据。利用率直接掉到20%以下。这就是典型的“算力虚胖”。
我的经验:选NPU时,别光看TOPS。看看缓存大小和带宽。一个合理的比例是:每1TOPS算力,至少配1MB L2缓存和10GB/s带宽。否则,算力再高也是摆设。
2.1.3 控制器——指挥调度的大脑
控制器负责指挥整个NPU的工作。它要干的事包括:
- 指令译码:把CPU发来的指令翻译成NPU能懂的微操作
- 数据流调度:决定什么时候从DDR搬数据到缓存,什么时候启动MAC阵列
- 同步控制:协调多个MAC单元、多个计算层之间的依赖关系
- 功耗管理:动态调整频率和电压,省电
控制器的设计难度,其实比MAC阵列还大。因为MAC阵列是“体力活”,控制器是“脑力活”。一个好的控制器,能让MAC阵列利用率达到90%以上;差的控制器,可能连50%都跑不到。
2.2 数据流架构——数据怎么“流”起来
数据流架构,说白了就是数据在NPU内部怎么移动。这直接决定了计算效率。常见的架构有三种:
2.2.1 权重固定(Weight Stationary)
权重数据固定在MAC单元里,输入数据流进来。适合权重复用度高的场景,比如全连接层。
优点:权重不用反复搬运,省带宽。
缺点:输入数据要广播到所有MAC单元,广播网络压力大。
2.2.2 输入固定(Input Stationary)
输入数据固定在MAC单元里,权重数据流进来。适合输入复用度高的场景,比如卷积层。
优点:输入数据不用反复搬运。
缺点:权重需要频繁更新,对权重带宽要求高。
2.2.3 输出固定(Output Stationary)
部分和结果固定在MAC单元里,输入和权重都流进来。适合需要累加的场景,比如深度卷积。
优点:减少中间结果的搬运。
缺点:控制逻辑复杂。
实际项目中怎么选?
我个人的习惯是:看模型结构。如果模型里卷积层多,用输入固定;如果全连接层多,用权重固定。但大多数现代NPU都支持动态切换,根据当前层自动选择最优数据流。这需要控制器足够聪明。
2.3 指令集特点——NPU的“语言”
NPU的指令集和CPU的指令集完全不同。CPU指令集强调通用性,而NPU指令集强调向量化和张量化。
2.3.1 向量指令
一条指令就能完成一组数据的相同操作。比如:
VADD v0, v1, v2 // 向量加法:v0 = v1 + v2
VMUL v3, v4, v5 // 向量乘法:v3 = v4 * v5
VMM v6, v7, v8 // 矩阵乘法:v6 = v7 * v8
你看,一条VMM指令,背后就是成千上万个MAC单元在同时工作。这就是NPU高效的原因。
2.3.2 张量指令
更高层次的抽象,一条指令完成整个张量运算。比如:
CONV2D dst, src, weight, stride, padding // 二维卷积
POOL2D dst, src, kernel, stride // 池化
ACTIVATE dst, src, relu // 激活函数
这些指令,CPU要拆成成百上千条微指令才能完成。NPU一条搞定。
2.3.3 特殊指令
NPU还有一些特殊指令,专门优化某些操作:
- DMA指令:控制数据在DDR和缓存之间搬运,不占用MAC单元
- 同步指令:等待某个计算任务完成,保证数据依赖正确
- 量化指令:在INT8和FP32之间转换,省带宽
- 稀疏指令:跳过值为0的权重或输入,节省计算量
避坑指南:我曾经在某个NPU上踩过坑——它的指令集不支持非对称量化。我花了两周时间手动实现,结果性能还不如CPU。后来换了一款支持非对称量化的NPU,速度直接翻了5倍。所以,选NPU时,一定要看指令集是否支持你需要的量化方式。
2.4 小结
NPU架构的核心,就是MAC阵列做计算,缓存做数据中转,控制器做调度。数据流架构决定了数据怎么移动,指令集决定了我们怎么编程。
说实话,这些概念听起来有点抽象。但等你真正上手调优的时候,就会发现:理解架构,是性能优化的第一步。下一章,我会带大家实际写一个NPU的驱动程序,看看这些组件是怎么协同工作的。
嗯,今天就到这里。有问题随时问我。