NPU架构基础:核心计算单元、数据流与存储层次
各位同学好,今天我们聊聊NPU的架构基础。说实话,NPU这个词这几年被炒得很热,但真正理解它内部怎么工作的,其实不多。我在做AI芯片设计之前,也踩过不少坑,今天就把这些经验分享给大家。
一、NPU的核心计算单元:MAC阵列
NPU最核心的东西,就是MAC阵列。MAC是Multiply-Accumulate的缩写,说白了就是乘加运算。你想想看,神经网络里90%以上的计算都是卷积和全连接,这些本质上就是一堆乘法和加法。
一个MAC单元长什么样?很简单:
// 一个MAC单元的逻辑
output = input_a * input_b + previous_result
但NPU里不是只有一个MAC,而是成千上万个。它们排成阵列,同时干活。我习惯把这个阵列叫做“计算网格”。
关键点:MAC阵列的规模直接决定了NPU的算力。比如一个16x16的阵列,就有256个MAC,每个时钟周期能完成256次乘加。
我在项目中遇到过一个问题:阵列太大,数据喂不饱。你想想看,256个MAC同时要数据,内存带宽跟不上,结果大部分时间都在等数据。这就是所谓的“内存墙”。
二、数据流:数据怎么在NPU里跑
数据流是NPU架构的灵魂。我见过很多团队,MAC阵列设计得很漂亮,但数据流没想清楚,最后性能一塌糊涂。
典型的数据流模式有三种:
- 权重固定流(Weight Stationary):权重数据留在MAC里不动,输入数据流过来。适合卷积层,因为权重复用率高。
- 输入固定流(Input Stationary):输入数据留在MAC里,权重流过来。适合全连接层。
- 输出固定流(Output Stationary):部分和结果留在MAC里,不断累加。适合深度卷积。
嗯,这里要注意:没有哪种模式是万能的。我建议根据你的应用场景来选。比如做图像识别的NPU,权重固定流就很好用。
我的经验:实际项目中,我们经常混合使用多种数据流。比如卷积层用权重固定,全连接层用输入固定。这样能最大化利用率。
三、存储层次:NPU的“记忆系统”
NPU的存储层次,说白了就是怎么让数据离计算单元更近。我刚开始做NPU时,总觉得内存越大越好,后来发现根本不是这么回事。
典型的NPU存储层次是这样的:
| 层级 | 容量 | 带宽 | 延迟 |
|---|---|---|---|
| 寄存器文件 | 几KB | 极高 | 1个周期 |
| 片上SRAM | 几MB | 高 | 几个周期 |
| 片外DRAM | 几GB | 低 | 几百个周期 |
你想想看,从DRAM读一次数据要几百个周期,而MAC计算只要1个周期。如果不做缓存,计算单元大部分时间都在等数据。
避坑指南:我曾经在一个项目里,把片上SRAM做得太小,结果数据频繁在DRAM和SRAM之间搬来搬去,功耗直接翻倍。后来我学乖了,先算好数据复用率,再定SRAM大小。
四、典型NPU架构分析
我们来看一个典型的NPU架构。我用SVG画了一张图,方便大家理解:
这个架构图里,数据从DRAM通过DMA搬到全局Buffer,再分发到本地Buffer,最后喂给MAC阵列。控制单元负责调度这一切。
我个人的习惯是,在设计NPU时,先画数据流图,再画控制流图。数据流决定了性能上限,控制流决定了能不能达到这个上限。
五、实际项目中的经验
最后分享一个我踩过的坑。有一次做NPU设计,我们把MAC阵列做到了32x32,觉得算力肯定够了。结果跑ResNet-50时,发现利用率只有40%。
为什么?因为数据复用没做好。权重和输入数据都在争带宽,MAC阵列经常饿着肚子等数据。
后来我们做了两件事:
- 增加了本地Buffer的大小,让每个MAC能缓存更多数据
- 优化了数据流调度,让权重和输入数据错峰传输
利用率从40%提升到了85%。嗯,这就是架构设计的魅力——不是堆硬件,而是让硬件高效运转。
总结一下:NPU架构的核心就三件事——MAC阵列怎么排、数据怎么流、存储怎么配。这三件事想清楚了,NPU就成功了一大半。