3、NPU硬件架构概览:典型NPU的运算单元、存储层次、数据通路、指令集特征

NPU(Neural Processing Unit)并非通用处理器的替代品,而是面向神经网络计算中“高并行、高复用、高吞吐”特征的专用加速引擎。理解NPU硬件架构,是进行指令调度优化、编译器后端设计以及性能分析的前提。本章从运算单元、存储层次、数据通路和指令集四个维度,拆解典型NPU(如华为达芬奇、寒武纪MLU、Google TPU)的共性设计,并揭示这些硬件特征如何约束编译器的调度策略。

典型NPU硬件架构与数据流 计算阵列 (MAC/脉动阵列) 16x16 ~ 128x128 PE INT8/FP16/BF16 向量/激活单元 ReLU/池化/归一化 标量/控制单元 地址生成/循环控制 外部存储 (DDR/HBM) 容量大, 带宽有限 ~100GB/s - 2TB/s 片上SRAM (统一缓冲/共享内存) 容量: 256KB - 8MB 多bank交叉访问 寄存器/缓冲 PE局部寄存器 向量寄存器堆 数据 中间结果 DMA加载 DMA/直连 写回 指令流水线: 取指 → 译码 → 发射 → 执行 → 写回 支持多级流水、乱序发射(部分)、同步/异步执行 控制信号 图例: 数据流 DMA/存储访问 控制流 编译器调度目标: 最大化数据复用、最小化bank冲突、隐藏DMA延迟、平衡各单元负载

上图展示了典型NPU的宏观数据流。编译器需要理解这些硬件模块的物理约束,才能生成高效的指令序列。下面逐一深入剖析。

3.1 运算单元:从MAC阵列到异构计算核

核心原理:NPU的算力主要来自大规模乘累加(MAC)阵列。与CPU的SIMD(单指令多数据)不同,NPU的MAC阵列通常以脉动阵列(Systolic Array)或二维网格(2D Mesh)形式组织。每个处理单元(PE)包含一个乘法器和一个累加器,相邻PE间有直接的数据通路,数据在阵列中“流动”而非反复从寄存器读取。

判断方法:查看芯片手册中的PE数量、数据位宽和时钟频率,即可估算峰值算力。例如,某NPU有64x64=4096个PE,每个PE每周期完成一次INT8乘法累加,主频1GHz,则峰值算力为4096 GOPS(每秒十亿次运算)。但实际有效算力受限于数据供给和存储带宽。

运算单元类型典型配置适用算子编译器关注点
MAC阵列(脉动)16x16 ~ 128x128 PE卷积、全连接、矩阵乘数据复用方向、PE间数据传递模式
向量单元128~512通道激活函数、池化、归一化向量长度对齐、内存对齐
标量单元1~4核地址计算、循环控制、分支循环展开、指令调度
专用单元转置、Softmax、TopK特殊算子加速算子融合、硬件指令映射

案例拆解:以卷积层为例,输入特征图尺寸为112x112x64,卷积核3x3x64x128。编译器需要将卷积循环映射到MAC阵列。一种常见策略是:将输出通道128拆分为2批,每批64个输出通道映射到64列PE;将输入通道64拆分为4批,每批16个输入通道在时间上循环。这样,每个PE负责一个输出通道和一个输入通道的乘累加,数据在行方向传递输入像素,在列方向传递权重。

调度要点:脉动阵列中,数据从左上角流入,经过多个PE后从右下角流出。编译器必须确保数据到达每个PE的时间与计算周期精确匹配,否则会产生气泡(流水线停顿)。这要求编译器在指令调度时精确计算数据产生和消费的周期数。

3.2 存储层次:容量、带宽与延迟的权衡

核心原理:NPU的存储层次通常分为三级:外部存储(DDR/HBM)、片上SRAM(统一缓冲或共享内存)、寄存器/缓冲。片上SRAM是编译器调度的主战场,其容量有限(通常256KB~8MB),但带宽极高(可达数十TB/s)。编译器必须通过数据分块(Tiling)、数据复用(Data Reuse)和双缓冲(Double Buffering)来最大化片上数据利用率。

操作流程:编译器进行存储层次优化的典型步骤:

  1. 循环分块:将大维度的循环(如输入通道、输出通道、空间尺寸)切分为适合片上SRAM容量的小块。
  2. 数据布局转换:将NHWC(通道在后)转换为NCHW(通道在前)或自定义布局,以匹配MAC阵列的数据访问模式。
  3. 双缓冲调度:将DMA传输与计算重叠,即当前块计算时,预取下一块数据到另一块SRAM区域。
  4. bank冲突避免:分析SRAM的bank划分,调整数据存储地址,避免多个PE同时访问同一bank导致冲突。

案例拆解:假设片上SRAM为1MB,需要计算一个卷积层,输入特征图大小为56x56x256(约3.2MB),权重为3x3x256x512(约1.2MB)。显然无法一次性载入。编译器将输入通道256拆分为4块(每块64通道),输出通道512拆分为8块(每块64通道)。每次计算一个64x64的输出块,需要输入数据56x56x64(约200KB)和权重3x3x64x64(约36KB),加上输出缓冲,总占用约300KB,可放入SRAM。调度顺序为:先遍历输出通道块,再遍历输入通道块,确保权重复用。

常见误区:初学者常认为SRAM容量越大越好,但实际上,更大的SRAM意味着更高的成本和功耗。编译器优化的目标是在有限容量下实现最高的数据复用率。另一个误区是忽略DMA传输的启动开销,频繁的小块传输会严重降低效率,应尽量合并为大的连续传输。

3.3 数据通路:DMA、总线与同步机制

核心原理:数据通路连接存储层次和运算单元,包括DMA控制器、总线矩阵和同步机制。DMA负责在外部存储和片上SRAM之间搬运数据,不占用计算单元。总线矩阵提供多个主设备(如DMA、计算单元)访问多个从设备(如SRAM bank)的交叉连接。同步机制(如栅栏指令、信号量)确保数据依赖关系正确。

判断方法:分析数据通路瓶颈时,关注三个指标:DMA带宽、总线冲突概率、同步开销。DMA带宽通常远低于片上SRAM带宽,因此编译器应尽量减少DMA传输次数,增大单次传输长度。总线冲突发生在多个PE同时访问同一SRAM bank时,可通过地址交错(Interleaving)缓解。

数据通路组件典型带宽/延迟编译器优化策略
DMA (DDR→SRAM)10~100 GB/s, 延迟~1μs大块传输、双缓冲、突发模式
总线矩阵 (SRAM访问)1~10 TB/s, 延迟~5nsbank划分、地址对齐、访问模式调整
PE间直连每周期1~2字数据流方向匹配、减少中间结果写回
同步机制栅栏延迟~20ns减少同步点、批量同步

案例拆解:某NPU的DMA支持二维搬运(2D DMA),可一次搬运一个矩形区域。编译器利用此特性,将输入特征图的多个通道打包为连续内存块,一次DMA传输完成多通道数据加载。例如,将4个通道的同一空间区域合并为一个2D传输,传输效率提升4倍。同时,编译器在计算当前数据块时,提前发出下一块的DMA请求,实现计算与传输重叠。

经验提醒:在编写编译器调度策略时,务必为DMA预留足够的SRAM空间(通常为总容量的10%~20%),否则双缓冲无法实现。另外,同步指令的开销不可忽视,在循环体内应尽量减少同步点,可将多个计算任务合并后统一同步。

3.4 指令集特征:VLIW、显式并行与硬件控制

核心原理:NPU指令集与CPU的复杂指令集(CISC)或精简指令集(RISC)有本质区别。NPU通常采用VLIW(超长指令字)或显式并行指令计算(EPIC)风格,一条指令可同时控制多个功能单元。指令集设计强调“显式”而非“隐式”:编译器负责找出并行性,硬件只负责执行,不进行动态调度。

操作流程:理解NPU指令集的关键步骤:

  1. 识别指令类型:通常包括计算指令(矩阵乘、向量运算)、数据搬运指令(DMA)、控制指令(循环、跳转)、同步指令(栅栏)。
  2. 分析指令编码:每条指令包含操作码、目标地址、源地址、立即数等字段,VLIW指令还包含多个子操作槽。
  3. 理解执行模型:NPU多为静态调度,即指令顺序由编译器决定,硬件按序发射。部分NPU支持简单的乱序完成,但编译器仍需保证数据依赖。
  4. 掌握特殊指令:如矩阵乘指令(MMA)、张量指令、压缩/解压缩指令等,这些指令可大幅减少指令数。

案例拆解:以某NPU的矩阵乘指令为例,一条指令可完成16x16x16的矩阵乘累加。编译器将大矩阵分解为多个16x16块,每个块对应一条指令。假设计算两个256x256矩阵的乘法,需要(256/16)^3 = 4096条MMA指令。编译器还需插入DMA指令加载数据、同步指令确保数据就绪。通过循环展开和指令重排,可隐藏DMA延迟,提高指令流水线利用率。

调度策略总结:NPU指令调度的核心是“三对齐”:数据对齐(地址、大小)、计算对齐(PE映射、向量长度)、时间对齐(DMA与计算重叠、同步点放置)。编译器需在指令级并行(ILP)和数据级并行(DLP)之间找到平衡。

常见误区与复盘:一个典型误区是认为指令数越少性能越好。实际上,指令数少但数据依赖强可能导致流水线停顿。例如,两条MMA指令若存在数据依赖(第二条使用第一条的结果),则必须等待。编译器应通过改变计算顺序(如分块矩阵乘中的累加顺序)来打破依赖链。另一个误区是忽略指令发射宽度限制,VLIW指令中每个槽位只能发射特定类型的操作,编译器需合理分配槽位,避免资源冲突。

总结而言,NPU硬件架构的每个细节都直接影响编译器设计。运算单元决定了计算映射方式,存储层次决定了数据调度策略,数据通路决定了同步和传输优化,指令集则提供了编译器可用的调度原语。只有深入理解这四者的协同关系,才能编写出高效、稳定的AI编译器后端。