Edge AI NPU基础:NPU架构特点、常见NPU产品与算子执行模型

在Edge AI设备上部署深度学习模型时,NPU(Neural Processing Unit,神经网络处理单元)已成为承担推理计算的核心硬件。与GPU或CPU不同,NPU针对卷积、矩阵乘、激活函数等算子做了深度定制,以极低的功耗换取更高的算力密度。理解NPU的架构特点、主流产品形态以及算子执行模型,是后续设计算子分派策略与CPU fallback机制的前提。本章将从硬件结构、产品对比、执行流水线三个维度展开,帮助读者建立对Edge AI NPU的系统认知。

NPU硬件架构 算子执行模型 分派与Fallback MAC阵列 激活/池化 片上SRAM DMA引擎 指令调度器(静态/动态) 权重预取 数据重排 图解析 → 算子序列 算子映射(NPU/CPU) 内存规划(tensor布局) 指令生成(firmware) 硬件同步执行 算子特性分析 NPU支持度查询 性能预估(延迟/功耗) 分派决策(NPU/CPU) CPU fallback触发 算力密度高、功耗低 静态图优先、动态控制流弱 异构调度、保底正确性 Edge AI NPU:以MAC阵列为核心,通过专用指令流完成张量计算,异构分派决定性能上限

上图展示了NPU在Edge AI系统中的核心地位:左侧为硬件架构的基本组成,中间为算子从图到硬件的执行路径,右侧为分派与fallback的决策逻辑。三者共同构成了NPU算子执行的主干链路。

2.1 NPU架构核心特点

2.1.1 计算单元:MAC阵列与数据流设计

NPU最核心的计算资源是MAC(Multiply-Accumulate)阵列,由大量乘加单元组成,通常以16×16、32×32等二维阵列形式排布。每个MAC单元在一个时钟周期内完成一次乘法和一次加法,因此NPU的算力峰值直接由MAC数量与主频决定。例如,瑞芯微RK3588的NPU拥有3个核心,每个核心包含约256个MAC,总算力达到6 TOPS(INT8)。

MAC阵列的数据流设计决定了算子的执行效率。常见的三种数据流包括:

  • 权重固定(Weight Stationary):权重数据驻留在片上寄存器中,输入特征图流经阵列。适用于卷积核较小的算子,减少权重搬运。
  • 输入固定(Input Stationary):输入特征图驻留,权重流经阵列。适用于全连接层或1×1卷积。
  • 输出固定(Output Stationary):部分和(partial sum)驻留在阵列内,减少中间结果的写回。适用于需要大量累加的深度卷积。

实际NPU产品通常混合使用多种数据流,并根据算子形状动态切换。例如,地平线征程5的BPU(Brain Processing Unit)采用可重构数据流架构,能够根据卷积的stride、kernel size自动调整数据复用策略。

2.1.2 存储层次与带宽瓶颈

NPU的存储层次直接影响算子的执行效率。典型层次包括:

  • 寄存器文件(Register File):容量最小(KB级),访问延迟1-2周期,用于暂存操作数。
  • 片上SRAM(也称Local Buffer或TCM):容量在几百KB到几MB之间,是数据复用的主战场。例如寒武纪MLU220的片上SRAM为4MB。
  • 外部DDR:容量大(GB级),但访问延迟高达数百周期,带宽有限。

算子执行时,数据从DDR搬运到SRAM,再从SRAM送入MAC阵列。若数据复用率低,DDR带宽将成为瓶颈。因此,NPU编译器会进行数据分块(tiling)和重排(layout transform),尽量让数据在片上多轮复用。

经验提示:在评估NPU性能时,不能只看TOPS算力,还要关注片上SRAM大小和DDR带宽。例如,某NPU标称4 TOPS,但若SRAM仅512KB,运行大分辨率模型时频繁搬运数据,实际吞吐可能只有峰值的30%-50%。

2.1.3 指令集与可编程性

NPU的指令集通常分为两类:

  • 专用指令:如CONV、POOL、ACTIVATE、ELEMENTWISE等,直接映射到硬件单元,执行效率高。
  • 通用指令:如MOVE、JUMP、SYNC等,用于数据搬运、流程控制和同步。

大多数Edge NPU采用静态调度方式,即编译器在编译期生成完整的指令序列,硬件按序执行。这种方式功耗低、确定性高,但对动态形状(如循环、条件分支)支持较差。少数NPU(如寒武纪MLU)支持动态指令,允许运行时插入新指令,但会增加硬件复杂度。

2.2 常见NPU产品对比

目前Edge AI领域主流的NPU产品包括瑞芯微(Rockchip)、地平线(Horizon Robotics)、寒武纪(Cambricon)等。下表从算力、功耗、算子支持、开发工具链等维度进行对比:

维度 瑞芯微 RK3588 NPU 地平线 征程5 BPU 寒武纪 MLU220
算力(INT8) 6 TOPS 128 TOPS(征程5旗舰) 8 TOPS(MLU220-M.2)
典型功耗 3-5W(NPU部分) 30W(整板) 8-12W(整卡)
片上SRAM 约1MB 约10MB 4MB
算子支持 Conv/BN/ReLU/Add/Concat等常见算子 支持自定义算子扩展(通过BPU指令集) 支持TensorFlow/PyTorch算子子集
开发工具链 RKNN-Toolkit 地平线OpenExplorer(OE) 寒武纪CNToolkit
动态形状支持 有限,需固定shape 支持动态batch,但动态分辨率受限 支持动态shape,但性能下降明显
CPU fallback机制 RKNN支持混合模式,部分算子自动切到CPU OE支持算子级fallback配置 CNToolkit支持手动指定CPU执行

2.2.1 瑞芯微RK3588 NPU

RK3588是瑞芯微旗舰SoC,内置3核NPU,总算力6 TOPS。其NPU采用多核异构设计,三个核心可以独立工作,也可以协同处理一个大模型。RKNN-Toolkit支持从ONNX、Caffe、TensorFlow等格式转换模型,并提供量化工具(INT8/INT16)。

实际使用中,RK3588 NPU对3×3卷积、ReLU、Add等算子支持良好,但对某些特殊算子(如TopK、NonMaxSuppression)支持不佳,需要切到CPU执行。RKNN运行时提供了自动fallback机制,但开发者也可以手动指定某些算子强制在CPU上运行。

2.2.2 地平线征程5 BPU

征程5的BPU采用伯努利架构,专为自动驾驶场景设计,算力高达128 TOPS。其特点是支持动态shape和稀疏计算,对Transformer类模型也有优化。地平线OpenExplorer工具链提供了丰富的性能分析工具,可以查看每个算子在BPU上的执行时间、DDR带宽占用等。

征程5的BPU指令集相对开放,允许高级用户编写自定义算子(通过C-like语言描述),但门槛较高。对于不支持的算子,OE会自动生成CPU代码,但开发者需要关注CPU与BPU之间的数据同步开销。

2.2.3 寒武纪MLU220

MLU220是寒武纪面向边缘计算的产品,采用MLUv02架构,支持INT8/INT16/FP16等多种精度。其特色是灵活的可编程性,支持动态shape和运行时编译,适合需要频繁改变输入尺寸的场景(如视频流分析)。

寒武纪CNToolkit提供了较为完善的调试工具,可以逐算子查看执行结果,便于定位精度问题。但MLU220的功耗相对较高,在低功耗设备上需要仔细评估散热设计。

风险提示:NPU产品迭代速度快,算子支持列表经常更新。在项目选型时,务必以当前版本工具链实际支持的算子为准,不要仅参考芯片手册。建议在开发早期就运行目标模型,验证所有算子的兼容性。

2.3 NPU算子执行模型

2.3.1 从计算图到NPU指令

NPU执行算子的过程可以抽象为以下步骤:

  1. 图解析:将深度学习模型(如ONNX、Caffe)解析为计算图,每个节点代表一个算子。
  2. 算子映射:将每个算子映射到NPU支持的指令或CPU执行。这一步是分派策略的核心。
  3. 内存规划:为每个tensor分配地址,确定数据在SRAM和DDR之间的摆放位置。通常采用内存池技术,复用中间结果的内存。
  4. 指令生成:将算子转换为NPU指令序列,包括数据搬运指令、计算指令、同步指令。
  5. 硬件执行:NPU固件(firmware)加载指令并执行,通过中断或轮询方式通知CPU完成状态。

以RKNN为例,RKNN-Toolkit在编译模型时,会生成一个.rknn文件,其中包含指令序列和权重数据。运行时,RKNN API将.rknn文件加载到NPU,并触发执行。

2.3.2 算子执行的数据流

单个算子在NPU上的执行过程遵循“搬运-计算-写回”的流水线模式:

// 伪代码描述NPU执行一个卷积算子
1. DMA从DDR加载输入特征图到SRAM (input_buffer)
2. DMA从DDR加载权重到SRAM (weight_buffer)
3. 启动MAC阵列计算,输出部分和到output_buffer
4. 若需要,执行激活函数(ReLU等)在output_buffer上
5. DMA将output_buffer写回DDR
6. 发出中断,通知CPU算子完成

为了提高效率,NPU通常采用流水线并行:当第N个算子正在计算时,第N+1个算子的数据搬运已经启动。这种重叠执行可以隐藏DDR访问延迟,但需要编译器精心安排指令顺序。

2.3.3 算子分派与CPU fallback的触发条件

在实际推理中,并非所有算子都能在NPU上高效执行。以下情况会触发CPU fallback:

  • 算子不支持:NPU指令集中没有对应的指令,如TopK、Gather等动态索引操作。
  • shape不匹配:某些NPU要求输入shape是固定倍数(如16的倍数),若实际shape不满足,则无法执行。
  • 精度要求:NPU通常以INT8为主,若模型需要FP16或FP32精度,且NPU不支持,则必须用CPU。
  • 性能考量:某些小算子(如Add、Reshape)在NPU上执行的开销(指令调度、数据搬运)可能大于CPU直接计算,此时应选择CPU。
关键原则:分派策略的目标不是“尽可能把所有算子放到NPU”,而是“让整体延迟最低、功耗最小”。有时将少量算子放到CPU,反而能减少NPU与CPU之间的同步开销,提升端到端性能。

2.4 案例拆解:RK3588上YOLOv5s的算子分派与fallback

下面通过一个实际案例,展示NPU算子分派与CPU fallback的设计过程。

2.4.1 背景与目标

某智能摄像头项目采用RK3588平台,部署YOLOv5s目标检测模型。模型输入640×640×3,输出为3个尺度的检测结果。项目要求端到端延迟小于50ms,功耗低于5W(NPU+CPU)。

2.4.2 初始现象

使用RKNN-Toolkit默认配置转换模型后,在NPU上运行,实测延迟为68ms,超出目标。进一步分析发现,模型中的NonMaxSuppression(NMS)算子在NPU上执行时间长达22ms,且NPU的NMS实现仅支持单类别,导致需要多次调用。

2.4.3 分析过程

通过RKNN-Toolkit的性能分析工具,获取每个算子的执行时间:

算子名称           NPU时间(ms)   CPU时间(ms)  备注
Conv_0            3.2          -           3x3, stride=2
Conv_1            2.8          -           3x3, stride=2
...
Conv_52           1.9          -           1x1, 输出256通道
Sigmoid_0         0.8          -           激活
Add_0             0.3          -           残差连接
...
NMS_0             22.0         -           NPU实现,单类别
Reshape_0         -            0.1         CPU执行
Transpose_0       -            0.2         CPU执行

从数据可见,NMS_0是主要瓶颈。此外,Reshape和Transpose在NPU上不支持,已自动fallback到CPU,但耗时很小。

2.4.4 优化方案

针对NMS算子,采用以下策略:

  1. 算子分派调整:将NMS从NPU强制切换到CPU执行。虽然CPU执行NMS需要约15ms(基于RK3588的Cortex-A76核心),但比NPU的22ms更快,且释放了NPU资源。
  2. 算法优化:在CPU上使用快速NMS实现(如Fast NMS),通过向量化指令(NEON)将耗时降至9ms。
  3. 数据流优化:将NMS的输入(候选框坐标和得分)直接从NPU输出缓冲区传递到CPU,避免额外的DDR拷贝。

2.4.5 结果对比

方案 NPU时间 CPU时间 端到端延迟 功耗
默认配置 60ms 8ms 68ms 4.8W
NMS切到CPU 38ms 15ms+8ms=23ms 61ms 4.5W
NMS切CPU+FastNMS 38ms 9ms+8ms=17ms 55ms 4.3W
进一步优化(算子融合) 35ms 9ms+6ms=15ms 50ms 4.1W

最终通过将NMS算子分派到CPU并优化算法,端到端延迟从68ms降至50ms,满足项目要求。同时,由于NPU负载降低,整体功耗也略有下降。

2.4.6 复盘与经验

  • 不要盲目信任NPU的算子实现:NPU上的NMS实现可能针对特定场景优化,但不一定适合所有模型。在部署前应逐一验证关键算子的性能。
  • CPU fallback不是“降级”而是“协同”:在本案例中,CPU承担了NMS这一复杂逻辑算子,NPU专注于卷积等计算密集型算子,两者协同达到最优。
  • 数据拷贝开销不可忽视:NPU与CPU之间的数据传递需要经过DDR,若频繁切换,会产生大量拷贝开销。应尽量将需要fallback的算子集中在同一区域,减少切换次数。

2.5 常见误区与总结

2.5.1 常见误区

  • 误区一:TOPS越高,NPU性能越好。TOPS只是峰值算力,实际性能受限于数据带宽、算子支持度、内存容量。例如,某NPU标称8 TOPS,但运行MobileNetV2时可能不如4 TOPS但SRAM更大的NPU。
  • 误区二:所有算子都应该在NPU上执行。对于元素级操作(如Add、Mul)或数据搬运操作(如Concat、Reshape),CPU可能更快,因为NPU需要额外的指令调度和数据搬运。
  • 误区三:忽略NPU的量化精度损失。INT8量化后,某些敏感层(如检测头的输出层)可能出现精度下降。此时应将这些层保留在CPU上以FP32计算,而不是强行量化。
  • 误区四:不关注工具链版本差异。NPU工具链更新频繁,新版本可能增加算子支持或优化性能。但升级工具链也可能引入新的问题,需要回归测试。

2.5.2 总结复盘

本章从NPU的硬件架构出发,分析了MAC阵列、存储层次、指令集等核心特点,对比了瑞芯微、地平线、寒武纪三家主流产品的差异,并详细阐述了算子从计算图到NPU指令的执行模型。关键要点如下:

  • NPU的性能不仅取决于算力,更取决于数据复用率、片上存储容量和指令调度效率。
  • 不同NPU产品的算子支持范围差异较大,开发前必须验证目标模型的算子兼容性。
  • 算子分派策略应基于实际性能数据,而非简单“能跑就上NPU”。CPU fallback是异构计算的重要组成部分,合理使用可以提升整体性能。
  • 工具链的性能分析功能(如RKNN-Toolkit的profiler)是定位瓶颈、优化分派策略的必备工具。
实践建议:在项目初期,建议建立一个“算子性能基线表”,记录每个算子在NPU和CPU上的执行时间、精度差异、内存占用。随着模型迭代,持续更新该表,为后续的分派决策提供数据支撑。