NPU架构基础:核心架构、脉动阵列、数据流与片上存储
好,咱们今天聊聊NPU的架构基础。说实话,很多人一上来就盯着算力看,觉得TOPS越高越好。但我在项目里吃过亏,发现真正决定NPU能不能打的关键,其实是架构设计。你想想看,一个设计糟糕的NPU,就算堆了再多的MAC单元,实际跑起来也可能被带宽卡死。
NPU核心架构:从宏观到微观
NPU的核心架构,说白了就是怎么把矩阵运算这件事做到极致。我个人习惯把NPU架构分成三个层次来看:
- 计算阵列层:这是最核心的部分,由大量的乘加单元(MAC)组成。我见过最夸张的设计,一个芯片里塞了上万甚至几十万个MAC。
- 数据流控制层:负责决定数据怎么喂给计算阵列。嗯,这里要注意,数据流的设计直接决定了计算效率。
- 存储层次层:包括片上存储和外部存储接口。我曾经在一个项目里,因为片上存储设计太小,导致频繁搬运数据,功耗直接翻倍。
这三个层次必须协同工作。举个例子,你计算阵列再快,如果数据流控制层调度不好,或者存储层次跟不上,那整体性能就会大打折扣。这就像一条流水线,任何一个环节卡住,整条线都得停。
脉动阵列:NPU的“心脏”
脉动阵列(Systolic Array)是NPU里最经典的计算结构。为什么叫“脉动”?因为它像心脏一样,数据有节奏地“泵”进阵列里,每个计算单元只做简单的乘加操作,然后把结果传递给下一个单元。
核心思想:数据复用 + 局部通信。每个MAC只和邻居通信,避免了全局互联的复杂性和高功耗。
我记得第一次在项目里用脉动阵列时,犯了个低级错误——我把权重和输入数据都从同一个方向灌进去。结果呢?数据冲突,计算效率只有理论值的30%。后来我才意识到,脉动阵列的数据流方向是有讲究的。
常见的脉动阵列数据流模式有三种:
| 数据流模式 | 权重流动 | 输入特征流动 | 部分和流动 |
|---|---|---|---|
| 权重固定(Weight Stationary) | 固定不动 | 行方向流动 | 列方向累加 |
| 输入固定(Input Stationary) | 行方向流动 | 固定不动 | 列方向累加 |
| 输出固定(Output Stationary) | 行方向流动 | 列方向流动 | 固定不动 |
我个人最常用的是权重固定模式。为什么?因为权重在推理过程中是不变的,把它固定在片上,可以最大化复用。我曾经在一个语音识别芯片里,用权重固定模式把带宽需求降低了4倍。
避坑指南:我曾经在设计脉动阵列大小时,一味追求大尺寸,结果发现小尺寸的矩阵运算效率极低。后来我加了“分块”机制,把大矩阵切成小块,再映射到脉动阵列上。嗯,这个技巧很实用。
数据流:决定效率的关键
数据流设计,说白了就是决定“谁在什么时候去哪儿”。我见过太多团队,计算阵列设计得很漂亮,但数据流一塌糊涂,最终性能惨不忍睹。
数据流的核心问题有三个:
- 数据复用:如何让同一个数据被多次使用,减少从外部存储搬运的次数。
- 数据对齐:如何让数据在正确的时间到达正确的计算单元。
- 数据调度:如何安排数据的读写顺序,避免流水线停顿。
举个例子,卷积操作中,同一个输入特征图会被多个卷积核复用。如果你设计的数据流能把这个复用做到极致,那带宽需求就能大幅降低。我做过一个对比实验:优化数据流后,同样的硬件,性能提升了2.3倍。
注意:数据流设计没有银弹。不同的网络结构、不同的计算模式,需要不同的数据流策略。我曾经在一个项目里,把图像分类网络的数据流直接套用到目标检测网络上,结果性能反而下降了。所以,一定要根据实际场景来设计。
片上存储:NPU的“粮仓”
片上存储(On-Chip Memory)是NPU架构里最容易忽视但又最关键的部分。你想想看,计算阵列再快,如果数据喂不进去,那就是白搭。
片上存储通常分为几个层次:
- 寄存器文件(Register File):最靠近计算单元,容量最小,速度最快。一般用来存当前计算需要的权重和输入。
- 共享内存(Shared Memory):多个计算单元共享,容量中等。我习惯用它来存中间结果。
- 全局缓冲区(Global Buffer):容量最大,但访问延迟也最高。一般用来缓存从外部DDR搬来的数据。
这里有个关键点:片上存储的大小和带宽,直接决定了NPU的“计算密度”。我曾经算过一笔账:一个128x128的脉动阵列,如果片上存储只有256KB,那每秒钟需要从外部搬运的数据量高达几十GB。这个带宽,很多芯片根本扛不住。
经验之谈:我建议片上存储至少能容纳一次卷积操作的所有输入和权重。这样,计算过程中就不需要频繁访问外部存储,功耗和延迟都能大幅降低。
另外,片上存储的带宽设计也很重要。我见过一个设计,片上存储容量很大,但带宽只有64位。结果呢?计算阵列大部分时间都在等数据,利用率不到50%。所以,存储带宽要和计算阵列的吞吐量匹配。
总结:架构设计的三个核心原则
好了,讲了这么多,我总结一下NPU架构设计的三个核心原则:
- 计算与存储平衡:不要只堆算力,要确保存储带宽能跟上。我曾经见过一个芯片,算力标称100TOPS,但实际跑起来只有30TOPS,就是因为存储带宽不够。
- 数据流优先:先想清楚数据怎么流动,再设计计算阵列。数据流设计好了,性能自然就上去了。
- 复用最大化:无论是权重复用还是输入复用,都要做到极致。每减少一次数据搬运,都是在省功耗、提性能。
嗯,这些原则说起来简单,但真正落地的时候,你会发现每个项目都有自己的坑。我建议你在设计NPU架构时,先从数据流和存储入手,再考虑计算阵列。这样,你的设计会更扎实,也更不容易翻车。