第三章 NNIE基础概念:神经网络在硬件上的映射、Caffe模型与海思WK模型的区别、量化原理(INT8 vs FP16)

好,我们直接进入正题。这一章讲的是NNIE最核心的几个概念。说白了,就是搞清楚三件事:神经网络怎么在芯片上跑起来的、Caffe模型和海思的WK模型到底差在哪、以及量化到底是个什么魔法。

我在做第一个海思项目时,就是被这几个概念绕晕过。当时拿着一个训练好的Caffe模型,直接往板子上怼,结果跑出来的结果完全不对。后来才发现,原来中间还隔着一层WK模型。嗯,这坑我替你们踩过了。

3.1 神经网络在硬件上的映射

先聊聊神经网络怎么映射到硬件上。你想想看,我们平时在PC上跑神经网络,用的是GPU或者CPU。GPU有几千个核心,适合做并行计算。但海思的NNIE不一样,它是个专门的硬件加速器。

NNIE本质上是一个固定流水线的硬件模块。它把神经网络的计算拆成了几个固定的步骤:

  • 数据加载:从DDR把输入数据搬到NNIE内部SRAM
  • 卷积计算:这是最核心的部分,NNIE有专门的卷积计算阵列
  • 激活函数:ReLU、sigmoid这些,硬件直接支持
  • 池化:最大池化、平均池化,也是硬件实现
  • 数据写回:计算结果再写回DDR

我个人习惯把NNIE想象成一个超级流水线工厂。数据从一头进去,经过一道道工序,从另一头出来。每一道工序都是固定的,不能随便改。这就是为什么有些网络结构在NNIE上跑不了——因为硬件不支持。

关键点:NNIE不支持所有网络层。它只支持Conv、Pooling、ReLU、FC、Softmax这些常见层。像LSTM、自定义层这些,要么用CPU跑,要么就别想了。

我在项目中遇到过一个问题:一个网络里用了PReLU激活函数,结果NNIE直接报错。后来只能改成ReLU,精度掉了一点点,但总算能跑了。所以设计网络时,一定要先查NNIE支持的算子列表。

3.2 Caffe模型与海思WK模型的区别

这个问题,我估计很多人一开始都搞不清楚。Caffe模型是训练出来的,WK模型是部署用的。它们之间到底差在哪?

说白了,Caffe模型是浮点模型,WK模型是定点模型。Caffe模型里存的是float32的权重和偏置,WK模型里存的是int8的量化后的数据。

但区别不止这些。我列个表,你一看就明白:

对比项 Caffe模型 海思WK模型
数据格式 float32 int8(量化后)
存储结构 protobuf格式,包含网络结构和权重 二进制格式,只包含权重和量化参数
网络结构 明文可读,包含所有层定义 结构被固化,不可修改
部署方式 需要框架解析,不能直接跑 直接加载到NNIE,无需框架
文件大小 较大(float32) 较小(int8,约1/4)

你可能会问:为什么非要转成WK模型?直接拿Caffe模型跑不行吗?

答案很简单:NNIE只认识WK模型。它是个硬件加速器,不是通用处理器。它只能执行预先编译好的指令序列。WK模型就是那个编译好的指令序列。

我的建议:转换时一定要用海思提供的工具链,比如nnie_mapper。我曾经试过自己写脚本转换,结果踩了一堆坑。工具链虽然慢,但至少靠谱。

转换过程大致是这样的:

# 典型的转换命令
nnie_mapper \
  -c prototxt_file \        # Caffe的prototxt
  -w caffemodel_file \      # Caffe的caffemodel
  -o output_wk_file \       # 输出的WK文件
  -s 1 \                    # 量化方式,1表示INT8
  -i image_list.txt \       # 校准图片列表
  -n 100                    # 校准图片数量

嗯,这里要注意:校准图片很重要。我见过有人随便找了几张图做校准,结果量化后的模型精度掉了5个点。后来换了和训练集分布一致的校准图,精度只掉了0.5个点。所以校准图片一定要有代表性。

3.3 量化原理:INT8 vs FP16

量化,说白了就是把浮点数变成整数。为什么要这么做?因为整数运算比浮点运算快得多,而且占用的存储空间小。

海思NNIE支持两种量化方式:INT8和FP16。但说实话,NNIE主要用的是INT8。FP16更多是给CPU或者GPU用的。

3.3.1 INT8量化

INT8量化就是把float32的数值映射到[-128, 127]这个范围内。怎么映射?用一个缩放因子scale和一个零点zero_point。

公式很简单:

int8_value = round(float32_value / scale) + zero_point

反过来:

float32_value = (int8_value - zero_point) * scale

scale怎么确定?看数据的分布。比如你的权重都在[-1.0, 1.0]之间,那scale就是1.0/127 ≈ 0.00787。如果数据分布不均匀,比如大部分在[-0.1, 0.1]之间,但有几个值到了0.5,那scale就得按最大值来算,这样小值的精度就会损失。

我曾经踩过的坑:有一次量化一个检测模型,因为有个别权重值特别大,导致scale很大,大部分权重都被量化成了0。结果模型直接废了。后来我用了饱和量化,把那些异常值截断掉,才解决了问题。

3.3.2 FP16量化

FP16就是半精度浮点数。它用16位来表示一个浮点数,比float32少了一半的位数。但它的动态范围比INT8大得多。

FP16的格式:1位符号位,5位指数位,10位尾数位。而float32是1位符号位,8位指数位,23位尾数位。

FP16的好处是:精度损失小,几乎可以忽略。坏处是:存储空间只减少了一半,而且NNIE不支持FP16的硬件加速。所以FP16一般用在CPU上做推理。

对比项 INT8 FP16
存储大小 1字节 2字节
动态范围 有限(-128~127) 较大(约±65504)
精度损失 较大(约1%~5%) 很小(约0.1%)
硬件支持 NNIE原生支持 NNIE不支持,需CPU
推理速度 快(硬件加速) 慢(CPU模拟)

3.3.3 量化策略选择

我个人习惯这样选:

  • 对精度要求极高:用FP16,但只能在CPU上跑,速度慢
  • 对速度要求高:用INT8,NNIE硬件加速,速度快
  • 折中方案:先用INT8量化,如果精度掉得太多,再考虑混合精度

你想想看,在实际项目中,大部分场景都是速度优先。比如安防监控,需要实时处理25帧以上的视频流。这时候INT8就是唯一的选择。精度掉个1%~2%,人眼根本看不出来。

我的经验:量化后一定要做精度验证。拿1000张测试图片,对比量化前后的推理结果。如果mAP下降超过3%,就要考虑调整量化策略了。我一般会先检查校准图片的质量,再尝试不同的量化参数。

3.4 本章小结

好,这一章的内容就这些。总结一下:

  • NNIE是个固定流水线的硬件加速器,只支持特定算子
  • Caffe模型是浮点模型,WK模型是量化后的定点模型,两者不能混用
  • INT8量化速度快但精度有损失,FP16精度高但速度慢
  • 校准图片的质量直接影响量化效果

下一章我们会讲如何用海思的工具链完成模型转换,以及转换过程中常见的坑。到时候我会分享一些实战中的调试技巧,保证让你少走弯路。

嗯,今天就到这里。有问题随时找我。