专栏算法工具链onnx模型量化掉点以及hb_onnxruntime使用对齐问题

onnx模型量化掉点以及hb_onnxruntime使用对齐问题

已解决
lvjj2023-04-13
85
8
1.芯片型号:X3派
2.天工开物开发包OpenExplorer版本

hbdk version 3.39.2

horizon_nn version 0.14.9

hb_mapper version 1.11.2

3.问题定位:模型转换
4.问题具体描述:量化模型精度下降的很厉害,以及关于**_original_float_model.onnx 的使用问题对齐

您好,这里再模型量化转换当中遇到了一些问题:

onnx原始模型测评进度再一个角度回归的问题上下降了10多个点,(精度的评定按照小于10°的误差为tp,算所有结果的accuracy),从原始模型的97%下降到83%

分类分支下降了3个点。

掉点为bin模型上板测量的结果。

一下sigmoid为角度向量的回归分支,conv为分类分支,网络的预处理为cv.imread,之后resize 128,128 , /256

从模型量化loge当中看量化结果应该挺正常的才对

2023-04-13 03:45:23,527 INFO The quantify model output:

======================================================

Node Cosine Similarity L1 Distance L2 Distance Chebyshev Distance

-------------------------------------------------------------------------------------------

Conv_97 0.999954 0.056883 0.027743 0.134689

Sigmoid_101 1.000000 0.001775 0.001278 0.004256

然后开始查找预处理操作可能出现的错误,

然后分别使用

*_quant_model.onnx

*_original_float_model.onnx

用于量化网络的一个pc上的模拟验证和预处理操作是否有误的判断。

这里俩个模型和bin文件的测试结果比较接近(但是quant_model.onnx和bin文件的结果还是有一定差异的不知道是否算正常)

定位可能是量化数据处理和量化预处理设置有问题。

检查配置感觉没有啥问题,于是按照makertbin的执行方式做了一个 1层卷积的网络输入输出完全相等的
用来验证量化工程当中的预处理设置问题,onnx模型本身是bgr输入,bin模型希望设置为nv12输入,所以这里给生成的**_original_float_model.onnx的时候,输入为yuv444_128格式(参考了用户手册当中的 input_type_r对应中间类型表格)应该得到得到正确的预处理的bgr的结果。结果做去归一化 确实也回到了bgr图片的值(np.allclose判断输入输出相似度,1个像素值误差我们就认为预处理本身是没有问题的)
那在预处理确认无误之后,按照用户文档的说法_original_float_model.onnx模型应该就只加了一个预处理,这里我也查看了源模型的weight和_original_float_model的weight ,也是完全一致的。(下图这个三到五的对齐应该也是因为input_type_r在pc上用中间类型表达没有办法完全做到绝对一致,但像上面的实验以及足够验证它是正确的了
于是这里去掉了量化当中的makertbin环节的预处理操作,所有的操作都放到网络外面完成,也就是input_type_rt 设置为'featuremap',input_type_train: 'featuremap',我理解这个时候得到的_original_float_model.onnx就应该和原始onnx输入数据也是完全等价。

这里出现了:

在同为HB_ONNXRuntime作为后端的时候,_original_float_model.onnx 和原始onnx喂同样的数据的时候,结果完全一致 ,但是开源onnxruntime 的测试结果不一致。

于是,以上过程当中有三个问题不太理解:

1.HB_ONNXRuntime可以调用原始的onnx文件进行推理吗(得到的结果和自己环境的onnxruntime结果不一致)?
2.**_original_float_model.onnx 是否除了预处理步骤,以后的算子完全等价onnx文件本身?

3.bin文件和quant_model.onnx结果存在一定误差是否合理?

如果有其他需要提供表述的log和模型或者测试图像,这边都可以提供的,感谢答疑

算法工具链
评论2
0/1000
  • 颜值即正义
    Lv.2

    逐个回答一下你的问题哈

    关于问题1HB_ONNXRuntime可以推理自己刚导出的onnx,也可以推理模型转换中间产物:original_float_model.onnx、optimized_float_model.onnx、quantized_model.onnx,它的推理结果和自己环境的onnxruntime是一致的,只是onnxruntime只能推理自己刚导出的onnx,关于如何推理,建议参考社区文章:https://developer.horizon.ai/forumDetail/71036815603174578。
    关于问题2original_float_model.onnx只是在模型首部插入了预处理节点,建议将归一化、图像格式转换在yaml中配置,该部分解读,可以看这篇社区文章:https://developer.horizon.ai/forumDetail/118363912788935513。
    关于问题3:bin和quantized.onnx存在一点误差是正常的,但这个误差很小,可以使用hb_verifier/hb_model_verifier来进行一致性验证,也可以参考问题1中的链接。

    此外,建议您使用最新版OE2.5.2来进行转换哈,获取链接如下:https://developer.horizon.ai/forumDetail/136488103547258769

    2023-04-13
    0
    6
    • lvjj回复颜值即正义:

      感谢回复,不过在使用上问题一这里还是有一些问题:

      这里图中demo为hb_onnxruntime调用原始模型,demo_1为个人环境通过onnxruntime调用模型,共同使用input.npy作为输入数据,前后都完全没有预处理和后处理,我的理解是这里得到的结果应该是一样的才对,但是结果无法对上,这边稍后会用新版本的工具进行量化测试

      2023-04-13
      0
    • 颜值即正义回复lvjj:

      float32的数据,在demo中,需要使用sess.run_feature()哈,后期我们会出一个关于这块的社区文章,专门介绍一下这个

      2023-04-13
      0
    • lvjj回复颜值即正义:
      你好,在float32数据下,再预处理什么都不做的 feature 作为输入的模型转换当中,demo 使用sess.run_feature 跑出来的结果与个人环境的onnxruntime的结果完全一致,这里对齐了。回到nv12转bgr 的模型,使用original_float_model.onnx 使用yuv444_128数据作为输入的时候,结果没有对齐,差异如下,结果为上述sigmoid层的输出对比,是否再可以接受范围之内?

      下面是makebin 的yaml文件操作其中的数据输入设置

      model_parameters:
      onnx_model: '../car_angle_test/model_weight/car_angle_cls_model_20230406.onnx'
      march: "bernoulli2"
      working_dir: 'model_output
      output_model_file_prefix: 'car_angle_cls_model_20230406'
      input_parameters:
      input_name: ""
      input_type_rt: 'nv12'
      input_type_train: 'bgr'
      input_layout_train: 'NCHW'
      input_shape: ''
      norm_type: 'data_scale'
      mean_value: ''
      scale_value: 0.00390625

      这个转换得到的float_orginal_model.onnx 调用手段如下

      def infer_transformers(input_layout="NCHW"):
      transformers = [
      ResizeTransformer(target_size=(128,128)),
      BGR2NV12Transformer(data_format="HWC"),
      NV12ToYUV444Transformer((128, 128),
      yuv444_output_layout=input_layout[1:]),
          ]
      return transformers

      其中yuv444 减少128的操作放在 input_offset当中,操作如下

      outputs = self.sess.run(self.output_names, feed_dict, input_offset=128)
      用yuv444_128的数据测试original_float_model.onnx掉点了10个点,想问一下该怎么调查这个误差的原因
      2023-04-16
      0
    • 颜值即正义回复lvjj:

      您好,您配置的板端输入是nv12,给original_model就应该是nv12哈。

      如果您实在不放心,建议您先尝试将板端输入与训练输入都使用一样的数据,熟悉之后,再尝试使用nv12的板端数据。

      2023-04-17
      0
    • lvjj回复颜值即正义:
      抱歉这里不太理解为什么板端输入是nv12的时候,original_float_model.onnx为啥是nv12呢,这里先对齐一下说法哈,板端模型是指bin模型,然后根据用户手册当中的 转换内部过程解读 相当于original_float_model.onnx相较于训练原始模型onnx多了一个input_type_rt*到bgr的预处理。然后bin模型是完整做了nv12到bgr的预处理融合到模型当中。一下是转换内部过程解读的部分节选
      我是根据这个对应表格来判断我再使用original_float_model.onnx的时候应该使用nv12对应的中间类型来使用yuv444_128的数据作为输入的。(即使我想输入nv12数据长度也对应不上)。

      然后由于无论是bin模型文件还是original_float_model.onnx模型文件,他们输入和原始模型同样的数据应该都是结果没有办法对齐的把,他们不是给模型增加了预处理模块吗?感谢答疑

      2023-04-17
      0
    • 颜值即正义回复lvjj:
      嗯嗯,您的理解是没问题的哈,板端时nv12的时候,original_model确实应该处理到nv12的中间类型,也就是yuv444_128,这里的减去128通过配置onnx模型推理API的input_offset参数实现。

      关于在模型中加了预处理模块,从您的yaml配置看,主要是scale的影响,请问你的0.00390625是满足下面公式的计算嘛?


      还有就是,做了归一化,外面的数据处理时,别重复了哈。

      实在不放心,建议先尝试将板端输入与训练输入都使用bgr,都不要配置scale参数,熟悉之后,再尝试使用nv12和scale,用来提升性能。

      2023-04-17
      0
  • 颜值即正义
    Lv.2
    2023-04-24
    0
    0