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画了一张图,方便大家理解:

典型NPU架构框图 片外DRAM 容量大,带宽低 DMA 全局Buffer (SRAM) 容量中等,带宽高 数据分发 本地Buffer MAC阵列 16x16 = 256 MAC 控制单元 指令调度 图例: 存储 计算 控制 控制信号

这个架构图里,数据从DRAM通过DMA搬到全局Buffer,再分发到本地Buffer,最后喂给MAC阵列。控制单元负责调度这一切。

我个人的习惯是,在设计NPU时,先画数据流图,再画控制流图。数据流决定了性能上限,控制流决定了能不能达到这个上限。

五、实际项目中的经验

最后分享一个我踩过的坑。有一次做NPU设计,我们把MAC阵列做到了32x32,觉得算力肯定够了。结果跑ResNet-50时,发现利用率只有40%。

为什么?因为数据复用没做好。权重和输入数据都在争带宽,MAC阵列经常饿着肚子等数据。

后来我们做了两件事:

  1. 增加了本地Buffer的大小,让每个MAC能缓存更多数据
  2. 优化了数据流调度,让权重和输入数据错峰传输

利用率从40%提升到了85%。嗯,这就是架构设计的魅力——不是堆硬件,而是让硬件高效运转。

总结一下:NPU架构的核心就三件事——MAC阵列怎么排、数据怎么流、存储怎么配。这三件事想清楚了,NPU就成功了一大半。

专注资料整理