第三章 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精度高但速度慢
- 校准图片的质量直接影响量化效果
下一章我们会讲如何用海思的工具链完成模型转换,以及转换过程中常见的坑。到时候我会分享一些实战中的调试技巧,保证让你少走弯路。
嗯,今天就到这里。有问题随时找我。