Edge AI NPU基础:NPU架构特点、常见NPU产品与算子执行模型
在Edge AI设备上部署深度学习模型时,NPU(Neural Processing Unit,神经网络处理单元)已成为承担推理计算的核心硬件。与GPU或CPU不同,NPU针对卷积、矩阵乘、激活函数等算子做了深度定制,以极低的功耗换取更高的算力密度。理解NPU的架构特点、主流产品形态以及算子执行模型,是后续设计算子分派策略与CPU fallback机制的前提。本章将从硬件结构、产品对比、执行流水线三个维度展开,帮助读者建立对Edge AI NPU的系统认知。
上图展示了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),尽量让数据在片上多轮复用。
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的功耗相对较高,在低功耗设备上需要仔细评估散热设计。
2.3 NPU算子执行模型
2.3.1 从计算图到NPU指令
NPU执行算子的过程可以抽象为以下步骤:
- 图解析:将深度学习模型(如ONNX、Caffe)解析为计算图,每个节点代表一个算子。
- 算子映射:将每个算子映射到NPU支持的指令或CPU执行。这一步是分派策略的核心。
- 内存规划:为每个tensor分配地址,确定数据在SRAM和DDR之间的摆放位置。通常采用内存池技术,复用中间结果的内存。
- 指令生成:将算子转换为NPU指令序列,包括数据搬运指令、计算指令、同步指令。
- 硬件执行: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。
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算子,采用以下策略:
- 算子分派调整:将NMS从NPU强制切换到CPU执行。虽然CPU执行NMS需要约15ms(基于RK3588的Cortex-A76核心),但比NPU的22ms更快,且释放了NPU资源。
- 算法优化:在CPU上使用快速NMS实现(如Fast NMS),通过向量化指令(NEON)将耗时降至9ms。
- 数据流优化:将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)是定位瓶颈、优化分派策略的必备工具。