第4章:NPU硬件架构详解
各位同学,今天我们来聊聊NPU的硬件架构。说实话,很多做算子映射的同学,最后卡住的地方往往不是算法本身,而是对硬件不够了解。我自己刚入行那会儿,写了个很漂亮的算子,结果在NPU上跑得比CPU还慢——后来才发现,是数据在存储层次里来回搬运,浪费了大量带宽。
所以这一章,我会把NPU的硬件架构掰开揉碎了讲。你想想看,只有知道硬件长什么样,才能写出真正高效的算子映射。
4.1 计算单元:NPU的“肌肉”
NPU的计算单元,说白了就是干活的。它主要分三类:MAC、SIMD和Vector。这三者各有分工,也各有脾气。
4.1.1 MAC(乘累加单元)
MAC是NPU里最基础的运算单元。它做的是乘法加累加,也就是 a * b + c 这个操作。深度学习里的卷积、全连接,本质上就是大量的MAC操作。
我个人习惯把MAC想象成“流水线上的工人”。一个MAC一次只能做一个乘加,但成千上万个MAC并行起来,吞吐量就非常可观了。
关键参数:
- MAC数量:决定了NPU的峰值算力。比如一个NPU有4096个MAC,那它一次就能做4096次乘加。
- 位宽:常见的有INT8、INT16、FP16、FP32。位宽越低,算力越高,但精度也越低。
我的经验: 做算子映射时,尽量让MAC的利用率接近100%。我曾经遇到一个项目,卷积算子的MAC利用率只有30%,后来发现是数据排布不对,导致MAC经常空等。调整了数据布局后,利用率直接飙到85%。
4.1.2 SIMD(单指令多数据)
SIMD,全称是Single Instruction Multiple Data。它跟MAC不一样,MAC是专门做乘加的,而SIMD能做更多种类的运算,比如加法、减法、比较、逻辑运算等。
你可以把SIMD想象成“一个教练带一群学生做同样的动作”。教练喊一声“蹲下”,所有学生同时蹲下。这就是SIMD的精髓——一条指令,操作多个数据。
在NPU里,SIMD通常用来处理激活函数、池化、归一化这类操作。这些操作计算量不大,但种类多,用MAC来做反而浪费。
注意: SIMD对数据对齐要求很高。如果数据没对齐,性能会断崖式下跌。我曾经调试过一个算子,性能死活上不去,最后发现是数据地址没按16字节对齐。嗯,这个问题花了我整整两天。
4.1.3 Vector(向量单元)
Vector单元,你可以理解成“加强版的SIMD”。它专门处理长向量运算,比如向量加法、向量点积、向量缩放等。
在NPU里,Vector单元通常有自己的寄存器文件,可以一次性加载整个向量,然后做流水线式的运算。它的优势在于:
- 数据重用性好:一次加载,多次使用
- 控制简单:不需要频繁的指令发射
- 适合长序列运算:比如RNN、LSTM里的向量操作
我个人觉得,Vector单元是NPU里最容易被忽视的“宝藏”。很多算子用MAC做效率不高,但用Vector做就非常合适。
4.2 存储层次:NPU的“记忆”
存储层次,说白了就是数据怎么存、怎么取。NPU的存储结构跟CPU不太一样,它更强调带宽和延迟的平衡。
4.2.1 L1 Buffer
L1 Buffer是离计算单元最近的存储。它的特点是:容量小(通常几十KB到几百KB),但速度极快(一个时钟周期就能访问)。
L1 Buffer通常用来存放当前计算需要的数据。比如做卷积时,会把输入特征图和权重先搬到L1 Buffer里,然后让MAC去读。
关键点: L1 Buffer的命中率直接影响算子的性能。如果数据不在L1里,就要去L2甚至Global Memory里取,那延迟就大了去了。
4.2.2 L2 Buffer
L2 Buffer是L1和Global Memory之间的桥梁。它的容量更大(几MB到几十MB),速度也还可以(几个时钟周期)。
L2 Buffer的作用是“缓存”。比如一个卷积层算完后,结果可以先放在L2里,下一个卷积层要用时,直接从L2取,不用再去Global Memory。
我的建议: 做算子映射时,尽量让数据在L1和L2之间流动,少去Global Memory。我曾经优化过一个模型,把数据从Global Memory搬到L2的次数减少了60%,整体性能提升了2倍。
4.2.3 Global Memory
Global Memory是NPU里最大的存储,通常有几十GB。但它也是最慢的,访问延迟可能达到几百个时钟周期。
Global Memory主要用来存放模型参数和中间结果。它跟CPU的DDR类似,但带宽更高(因为NPU需要处理大量数据)。
避坑指南: 千万不要频繁访问Global Memory。我曾经写过一个算子,每算一个元素就去Global Memory读一次数据,结果性能惨不忍睹。后来改成批量读取,性能直接翻了10倍。
4.3 数据通路:NPU的“血管”
数据通路,就是数据在NPU里怎么流动。它连接了计算单元和存储层次,决定了数据的传输效率。
NPU的数据通路通常有几种模式:
- 广播模式: 一个数据同时发给多个计算单元。适合做权重共享的场景。
- 收集模式: 多个计算单元的结果汇总到一个地方。适合做累加操作。
- 点对点模式: 数据从一个单元直接传到另一个单元。适合做流水线操作。
我个人觉得,数据通路的设计是NPU架构里最考验功力的地方。一个好的数据通路,能让数据“跑”起来,而不是“堵”在路上。
4.4 控制单元:NPU的“大脑”
控制单元负责指挥整个NPU的工作。它告诉计算单元做什么运算,告诉存储单元什么时候读写数据。
NPU的控制单元通常有两种设计思路:
- 集中式控制: 一个中央控制器统一指挥所有单元。优点是控制简单,缺点是灵活性差。
- 分布式控制: 每个单元有自己的控制器。优点是灵活性强,缺点是控制逻辑复杂。
现在的NPU大多采用混合模式。比如,计算单元用分布式控制,存储单元用集中式控制。这样既能保证灵活性,又能降低复杂度。
我的经验: 做算子映射时,要特别注意控制单元的指令调度。我曾经遇到一个算子,指令发射间隔太长,导致计算单元经常空等。后来调整了指令顺序,把计算和访存重叠起来,性能提升了30%。
4.5 知识体系总览
为了让你更直观地理解NPU硬件架构,我画了一张结构图。它展示了计算单元、存储层次、数据通路和控制单元之间的关系。
这张图里,控制单元是“大脑”,计算单元是“肌肉”,存储层次是“记忆”,数据通路是“血管”。四者协同工作,才能让NPU高效运转。
4.6 本章小结
这一章我们聊了NPU的硬件架构。说白了,就是搞清楚NPU里有什么、怎么用。我个人觉得,理解硬件架构是做好算子映射的前提。你想想看,如果连硬件长什么样都不知道,怎么可能写出高效的代码?
下一章,我们会深入聊聊算子映射的具体方法。到时候你会发现,很多技巧都是基于今天讲的硬件知识。
核心要点回顾:
- 计算单元:MAC做乘累加,SIMD做并行运算,Vector做长向量处理
- 存储层次:L1最快但最小,Global最慢但最大,L2居中
- 数据通路:决定了数据怎么流动,影响整体效率
- 控制单元:负责指挥调度,是NPU的“大脑”
想要更多资料,联系可可