在对模型进行转化的过程中,会存在模型测试精度的下降。那么,究竟是哪个环节造成了精度的的降低呢?
采用什么方式可以快速的定位精度降低的点,以及快速调整,对非量化模型做对比呢?本文就是参照官方给出的内容,对这部分进行汇总。
本篇博客参考文档:
- 瑞芯微官方B站教程:RKNN模型精度优化指南
- RKNN SDK和官方文档下载:ROC-RK3588S-PC NPU使用
如果您觉得本篇文章对你有帮助,欢迎点赞 👍,让更多人看到,这是对我继续写下去的鼓励。本系列文章都不会收费,如果能再点击下方的红包打赏,给博主来一杯咖啡,那就太好了。💪
一、精度排查流程
下面这张图是来自于上面提供的视频的,强烈建议先去看看这个视频,配合着下面的图,更易于理解。
二、模型精度优化
模拟器精度排查,遵循两个“正确的前提”:
- 模拟器结果的正确是板端模型推理正确的前提;
- “fp16 模型” 的结果正确同样是“ 量化模型” 精度正确的前提
根据两个前提,“量化模型” 精度问题排查顺序:
-
需要在使用
rknn
的build
接口时, 将do_quantization
参数设置为False
, 即可以将原始模型转换为“fp16 模型”
。如果“fp16 模型”
输出结果错误, 则需进行以下排查:rknn
的 config 这个接口里:mean_values / std_values、input_size_list、inputs / outputs
rknn
的inference
这个接口里:inputs 和 data_format
。python 环境下,图像数据都是通过cv2.imread
读取的,图像格式为BGR
,大部分的caffe
模型不用改;其他的一般输入为RGB
,需要cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
将图像数据转为 RGB, 才可以传给rknn
的inference
接口进行推理。- 通过
cv2.imread
读取的图像数据的layout 为 NHWC
, 因为data_format
的默认值为NHWC
, 因此不需要设置data_format
参数;而如果模型的输入数据不是通过cv2.imread
读取,此时用户就必须清楚知道输入数据的 layout 并设置正确的 data_format 参数,如果是图像数据,也要保证其 RGB 顺序与模型的输入 RGB 顺序一致
-
在经过“ fp16 模型” 的精度验证后, 排除了“ fp16 模型” 的错误可能, 就可以对模型进行量化, 并进一步对“ 量化模型” 进行精度分析。 如果在“量化模型” 遇到精度问题,将主要从以下几个方面进行排查:
quantized_dtype
量化类型的选择,Toolkit2-1.3.0,默认值为asymmetric_quantized-8
,asymmetric_quantized-16
目前版本暂不支持。16-bit
量化和非量化(float16)
的运算性能差异不大,因此建议选择fp16
(rknn 的 build 接 口 的do_quantization
设 为False
)的运算方式来代替16-bit量化;quant_img_RGB2BGR
,一般用于caffe 模型;dataset
,rknn 的 build 接口的量化校正集配置。 如果选择了和实际部署场景不大一致的校正集,则可能会出现精度下降的问题, 或者校正集的数量过多或过少都会影响精度( 一般选择 50~200张)quantized_algorithm
quantized_method
optimization_level
更多内容,参考文档 NPU使用 Rockchip_User_Guide_RKNN_Toolkit2_CN-1.3.0.pdf
第46页
2.1、精度分析工具
注意:
- 该接口只能在
build
或hybrid_quantization_step2
之后调用; load
原始模型应该为非量化的模型, 否则会调用失败
# Build model
print('--> Building model')
ret = rknn.build(do_quantization=QUANTIZE_ON, dataset=DATASET) # DATASET来自于训练集,或验证集
if ret != 0:
print('Build model failed!')
exit(ret)
print('done')
# Accuracy analysis
print('--> Accuracy analysis')
Ret = rknn.accuracy_analysis(inputs=['./data/0000010_20200929_F_045Y57.jpeg'],
target='rk3588')
if ret != 0:
print('Accuracy analysis failed!')
exit(ret)
print('done')
rknn.build
是为了构建 RKNN
模型,rknn.accuracy_analysis
目的是对比fp32
和quant
后,前后两种数据之间的量化误差。所以,原始的模型,作为参照物,应该使用非量化的模型。
terminal
打印内容( 一般认为余弦相似度低于 0.99 存在少许不一致, 低于 0.98 几乎可以认为该层结果就是错误的):
--> Accuracy analysis
Analysing : 100%|████████████████████████████████████████████████| 295/295 [00:00<00:00, 320.01it/s]
Preparing : 100%|████████████████████████████████████████████████| 295/295 [00:01<00:00, 209.50it/s]
AccuracyAnalysising : 100%|███████████████████████████████████████| 295/295 [01:40<00:00, 3.91it/s]
I target set by user is: rk3588
I Starting ntp or adb, target is RK3588
I Start adb...
I Connect to Device success!
I NPUTransfer: Starting NPU Transfer Client, Transfer version 2.1.0 (b5861e7@2020-11-23T11:50:36)
D NPUTransfer: Transfer spec = local:transfer_proxy
D NPUTransfer: Transfer interface successfully opened, fd = 3
D RKNNAPI: ==============================================
D RKNNAPI: RKNN VERSION:
D RKNNAPI: API: 1.3.0 (121b661 build: 2022-04-29 11:07:20)(null)
D RKNNAPI: DRV: rknn_server: 1.3.0 (121b661 build: 2022-04-29 11:11:57)
D RKNNAPI: DRV: rknnrt: 1.3.0 (c193be371@2022-05-04T20:16:22)
D RKNNAPI: ==============================================
D NPUTransfer: Transfer client closed, fd = 3
adbd is already running as root
/data/dumps/: 897 files pulled. 35.7 MB/s (1749757536 bytes in 46.729s)
Save Tensors to txt: 100%|████████████████████████████████████████| 299/299 [00:34<00:00, 8.73it/s]
Calculate Distance: 100%|█████████████████████████████████████████| 296/296 [02:11<00:00, 4.17it/s]
# quant_error: calculate the quantize errors.
# entire: errors between 'golden' and 'simulator'.
# per_layer: compare to 'entire', the input of each layer is come from 'golden'
# runtime_error: calculate the runtime errors.
# simu_err: errors between 'simulator' and 'runtime'.
# golden_err: errors between 'golden' and 'runtime'.
layer_name quant_error runtime_error
entire per_layer simu_err golden_err
--------------------------------------------------------
images 1.000000 1.000000 1.000000 1.000000
254 1.000000 1.000000 1.000000 1.000000
256 1.000000 1.000000 0.999999 0.999999
257 0.999999 1.000000 0.999990 0.999991
259 1.000000 1.000000 0.999993 0.999993
260 1.000000 1.000000 0.999994 0.999994
262 1.000000 1.000000 0.999995 0.999995
263 1.000000 1.000000 0.999994 0.999994
265 1.000000 1.000000 0.999993 0.999993
266 1.000000 1.000000 0.999994 0.999995
268 0.999999 1.000000 0.999994 0.999994
269 1.000000 1.000000 0.999997 0.999998
2.2、检查数据输入
2.3、检查rknn.config配置参数和量化方法
2.4、量化配置参数精度对比
FP32也叫做 float32
,两种叫法是完全一样的,全称是Single-precision floating-point
(单精度浮点数)FP16也叫做 float16
,两种叫法是完全一样的,全称是Half-precision floating-point
(半精度浮点数),
注意:
toolkit2-1.3.0
下,量化默认就是int8
,不支持float16
(目前最高版本是1.5.0, 2023.07.04发布,同样不支持float16);- 不启用量化
do_quantization=False
,就是fp16
精度; rknn.config
中quantized_algorithm、、quantized_method、optimization_level
目前都是使用的默认值,这个也可以进行修改,用处是提高精度。
2.5、混合量化
也可以设定proposal
,会自动选择可能需要混合量化的层,如下设定:
三、QAT(Quantization Aware Training,量化感知训练)
如果混合量化后的精度,还是不够,或者运行性能不足,可以采用量化感知的方式,得到一个量化后的模型。再将这个模型转换成RKNN模型。
量化感知训练(Quantization Aware Training)是在模型中插入伪量化模块(fake_quant
module)模拟量化模型在推理过程中进行的舍入(rounding)和钳位(clamping)操作,从而在训练过程中提高模型对量化效应的适应能力,获得更高的量化模型精度 。在这个过程中,所有计算(包括模型正反向传播计算和伪量化节点计算)都是以浮点计算实现的,在训练完成后才量化为真正的int8模型。
Pytorch官方从1.3版本开始提供量化感知训练API,只需修改少量代码即可实现量化感知训练。
四、总结
在上一篇RKNN的文章中,对量化与非量化的模型进行了占用内存和效率的对比,发现非量化的模型,占用内存更多和推理时间更长。
但是,非量化的结果,会比量化的精度降低更少。而对于由于量化降低的模型精度,可以参照本篇文章,一一排查,确认降低精度的点。
可以知道:
1.在3588的toolkit2-1.3.0
下,量化默认就是int8,不支持float16
,但是,非量化下,是可以到fp16
的;(目前最高版本是1.5.0, 2023.07.04
发布,同样不支持float16
)
2.rknn.config
中quantized_algorithm、quantized_method、optimization_level
目前都是使用的默认值,这个也可以进行修改,用处是提高精度
2种方式可以改:
- 使用非量化的模型,这样就是fp16的版本,在非量化下,
build
后的模型accuracy_analysis
准确度分析,能做到0.9999
,与onnx版本基本一致,采用非量化rknn模型与预测,与本地pytorch
做对比; - 调整配置
config
内的quantized_algorithm、quantized_method、optimization_level
参数
本篇只是做一个记录,对于实践测试发现的问题,也会在这里进行记录。如果你也关注这个问题,欢迎收藏、点赞。