PaddleClas icon indicating copy to clipboard operation
PaddleClas copied to clipboard

PaddleClas MultiLabels模型导出的onnx模型推理有BUG

Open xddun opened this issue 1 year ago • 21 comments

MultiLabels模型导出的onnx模型推理 与 paddle模型相差非常大。

1 代码:PaddleClas develop分支 2 环境:docker images paddlepaddle/paddle:2.1.0-gpu-cuda11.2-cudnn8

下面是我操作的过程:

导出到paddle推理模型

python3 tools/export_model.py -c ./ppcls/configs/quick_start/professional/MobileNetV1_multilabel_intent_eval.yaml -o Arch.pretrained="./output/k1000_focal_2/MobileNetV2/latest" image

安装必要的包

python -m pip install -i https://pypi.tuna.tsinghua.edu.cn/simple --upgrade pip pip config set global.index-url https://pypi.tuna.tsinghua.edu.cn/simple pip install paddle2onnx onnx onnx-simplifier onnxruntime-gpu image

导出到onnx

paddle2onnx --model_dir inference/ --model_filename inference.pdmodel --params_filename inference.pdiparams --save_file focal2.onnx --opset_version 10 --enable_dev_version True --enable_onnx_checker True

对于同一张图片输入,paddle的输出是: image

但是onnx的输出是: image

我做的是130类的多标签分类器,两者输出的数值相差很大,经过sigmod之后标签概率大小排序,最大的是同样的,但是数值上明显差别很大。

btw,官方的例子https://github.com/PaddlePaddle/PaddleClas/blob/release/2.4/docs/en/quick_start/quick_start_multilabel_classification_en.md里面,使用NUS-WIDE-SCENE做多标签任务,最后的模型导出到onnx依旧会遇到这个问题。

是我操作不对,还是有解决办法,希望尽快给一个答复。不行的话,我想我在下一周将转到使用pytorch来完成我的工作。

xddun avatar Jul 30 '22 03:07 xddun

onnx推理代码:

        import onnxruntime as ort
        session = ort.InferenceSession(r'model/focal2.onnx', providers=['CUDAExecutionProvider'])  # 加载模型
        outputs = session.run(None, {'x': img})  # 调用模型

xddun avatar Jul 30 '22 03:07 xddun

在paddle那里的图 贴错了,我再贴一些今天测试的结果: 对于同一张图输入,paddle模型输出后sigmod是(最大的两个数值是0.10090836, 0.96171629): image

而onnx模型里面带了sigmod,输出就是想要的数值(最大的两个数值是0.00439452, 0.98361409): image

想不出来是哪里出了问题,是paddle转onnx之后精度差这么多吗?

xddun avatar Jul 30 '22 05:07 xddun

今天有了新的对比发现,把图片保存为bin后利用不同模型处理多标签任务,看输出的最大值判定模型推理是否相同,我发现: (1)运行onnx的结果最大数值是 0.96299744 (2)运行paddleclas自带的推理的功能(/deploy/python/predict_cls.py)的结果最大数值是 0.9629971。 万分位以上的差别都是可以接受的,所以我觉得paddle2onnx还是OK的。 (3)运行paddleclas自带的infer推理(tools/infer.py)的结果最大数值是0.94861。那么问题就出在paddle的动态模型转到paddle的推理模型上。

我在paddlecls的项目里也提一下这个问题,希望能得到解决。

xddun avatar Aug 01 '22 03:08 xddun

您好,麻烦提供一下paddle的inference model和onnx的model,我们定位一下

cuicheng01 avatar Aug 01 '22 03:08 cuicheng01

你好,我把文件传百度云了,他们都是一一对应的: 链接:https://pan.baidu.com/s/1sscJwEJVflt06I-5fPNKBg?pwd=y9v3 提取码:y9v3

image

xddun avatar Aug 01 '22 05:08 xddun

这个issues里还有一些其他描述,如有需要可以查看:https://github.com/PaddlePaddle/Paddle2ONNX/issues/832

xddun avatar Aug 01 '22 05:08 xddun

是否有新进展呢?我提一下yaml配置:

# global configs
Global:
  checkpoints: null
#  pretrained_model: ./output/intent3/MobileNetV2/latest
  pretrained_model: null
#  output_dir: ./output/intent4/
  output_dir: ./output/local/
  device: cpu
  save_interval: 1
  eval_during_train: True
  eval_interval: 1
  epochs: 20
  print_batch_step: 10
  use_visualdl: False
  # used for static mode and model export
  image_shape: [ 3, 224, 224 ]
  save_inference_dir: ./inference
  use_multilabel: True
# model architecture
Arch:
  name: MobileNetV2
  class_num: 130
  pretrained: True

# loss function config for traing/eval process
Loss:
  Train:
    - MultiLabelLoss:
        weight: 1.0
  Eval:
    - MultiLabelLoss:
        weight: 1.0


Optimizer:
  name: Momentum
  momentum: 0.9
  lr:
    name: Cosine
    learning_rate: 0.001
  regularizer:
    name: 'L2'
    coeff: 0.00004


# data loader for train and eval
DataLoader:
  Train:
    dataset:
      name: MultiLabelDataset
      image_root: /mnt/e/multilabels/
      cls_label_path: /mnt/e/multilabels/train_labels.txt
      transform_ops:
        - DecodeImage:
            to_rgb: True
            channel_first: False
        - ResizeImage:
            size: 224
        - RandFlipImage:
            flip_code: 1
        - NormalizeImage:
            scale: 1.0/255.0
            mean: [ 0.485, 0.456, 0.406 ]
            std: [ 0.229, 0.224, 0.225 ]
            order: ''

    sampler:
      name: DistributedBatchSampler
      batch_size: 4
      drop_last: False
      shuffle: True
    loader:
      num_workers: 20
      use_shared_memory: True

  Eval:
    dataset:
      name: MultiLabelDataset
      image_root: /mnt/e/multilabels/
      cls_label_path: /mnt/e/multilabels/val_labels.txt # 最小的,从训练集里面摘出来的
      #      cls_label_path: /ssd/xiedong/datasets/multilabel/eval_all.txt # 所有的
      #      cls_label_path: /ssd/xiedong/datasets/multilabel/eval_all2.txt # 除了训练集之外的
      transform_ops:
        - DecodeImage:
            to_rgb: True
            channel_first: False
        - ResizeImage:
            size: 224
        #        - CropImage:
        #            size: 224
        - NormalizeImage:
            scale: 1.0/255.0
            mean: [ 0.485, 0.456, 0.406 ]
            std: [ 0.229, 0.224, 0.225 ]
            order: ''
    sampler:
      name: DistributedBatchSampler
      batch_size: 256
      drop_last: False
      shuffle: False
    loader:
      num_workers: 20
      use_shared_memory: True

Infer:
  infer_imgs: /mnt/c/Users/dong.xie/Desktop/workcode/workplace/PaddleClas/deploy/images/fixed/104cartoon_scene000009.jpg
  batch_size: 10
  transforms:
    - DecodeImage:
        to_rgb: True
        channel_first: False
    - ResizeImage:
        size: 224
    #    - CropImage:
    #        size: 224
    - NormalizeImage:
        scale: 1.0/255.0
        mean: [ 0.485, 0.456, 0.406 ]
        std: [ 0.229, 0.224, 0.225 ]
        order: ''
    - ToCHWImage:
  PostProcess:
    name: MultiLabelTopk
    topk: 10
    class_id_map_file: None

Metric:
  Train:
    - AccuracyScore:
    - HammingDistance:
  Eval:
    - AccuracyScore:
    - HammingDistance:

xddun avatar Aug 02 '22 08:08 xddun

好的,我们会尽快查看

cuicheng01 avatar Aug 03 '22 06:08 cuicheng01

现在的问题是paddle的infer.py和paddle的inference推理没对上还是paddle的inference推理和onnx推理没对上呢?

cuicheng01 avatar Aug 03 '22 08:08 cuicheng01

是前者。 paddle的infer.py和paddle的inference推理没对上。

xddun avatar Aug 03 '22 08:08 xddun

我这边是可以对上的,你需要检验一下你打印的位置是否正确,是否都是只经过了一个sigmoid函数。

cuicheng01 avatar Aug 04 '22 08:08 cuicheng01

我试了一下,还是不行,我详细写一下我操作过程,看看哪里有问题。

我的local.yaml文件:

# global configs
Global:
  checkpoints: null
#  pretrained_model: ./output/intent3/MobileNetV2/latest
  pretrained_model: null
#  output_dir: ./output/intent4/
  output_dir: ./output/local/
  device: cpu
  save_interval: 1
  eval_during_train: True
  eval_interval: 1
  epochs: 20
  print_batch_step: 10
  use_visualdl: False
  # used for static mode and model export
  image_shape: [ 3, 224, 224 ]
  save_inference_dir: ./inference
  use_multilabel: True
# model architecture
Arch:
  name: MobileNetV2
  class_num: 130
  pretrained: True

# loss function config for traing/eval process
Loss:
  Train:
    - MultiLabelLoss:
        weight: 1.0
  Eval:
    - MultiLabelLoss:
        weight: 1.0


Optimizer:
  name: Momentum
  momentum: 0.9
  lr:
    name: Cosine
    learning_rate: 0.001
  regularizer:
    name: 'L2'
    coeff: 0.00004


# data loader for train and eval
DataLoader:
  Train:
    dataset:
      name: MultiLabelDataset
      image_root: /mnt/e/multilabels/
      cls_label_path: /mnt/e/multilabels/train_labels.txt
      transform_ops:
        - DecodeImage:
            to_rgb: True
            channel_first: False
        - ResizeImage:
            size: 224
        - RandFlipImage:
            flip_code: 1
        - NormalizeImage:
            scale: 1.0/255.0
            mean: [ 0.485, 0.456, 0.406 ]
            std: [ 0.229, 0.224, 0.225 ]
            order: ''

    sampler:
      name: DistributedBatchSampler
      batch_size: 4
      drop_last: False
      shuffle: True
    loader:
      num_workers: 20
      use_shared_memory: True

  Eval:
    dataset:
      name: MultiLabelDataset
      image_root: /mnt/e/multilabels/
      cls_label_path: /mnt/e/multilabels/val_labels.txt # 最小的,从训练集里面摘出来的
      #      cls_label_path: /ssd/xiedong/datasets/multilabel/eval_all.txt # 所有的
      #      cls_label_path: /ssd/xiedong/datasets/multilabel/eval_all2.txt # 除了训练集之外的
      transform_ops:
        - DecodeImage:
            to_rgb: True
            channel_first: False
        - ResizeImage:
            size: 224
        #        - CropImage:
        #            size: 224
        - NormalizeImage:
            scale: 1.0/255.0
            mean: [ 0.485, 0.456, 0.406 ]
            std: [ 0.229, 0.224, 0.225 ]
            order: ''
    sampler:
      name: DistributedBatchSampler
      batch_size: 256
      drop_last: False
      shuffle: False
    loader:
      num_workers: 20
      use_shared_memory: True

Infer:
  infer_imgs: /mnt/c/Users/dong.xie/Desktop/workcode/workplace/PaddleClas/deploy/images/fixed/104cartoon_scene000009.jpg
  batch_size: 10
  transforms:
    - DecodeImage:
        to_rgb: True
        channel_first: False
    - ResizeImage:
        size: 224
    #    - CropImage:
    #        size: 224
    - NormalizeImage:
        scale: 1.0/255.0
        mean: [ 0.485, 0.456, 0.406 ]
        std: [ 0.229, 0.224, 0.225 ]
        order: ''
    - ToCHWImage:
  PostProcess:
    name: MultiLabelTopk
    topk: 10
    class_id_map_file: None

Metric:
  Train:
    - AccuracyScore:
    - HammingDistance:
  Eval:
    - AccuracyScore:
    - HammingDistance:

我想进去infer.py的调试,这是给入的参数: image

我在infer函数中加的断点: image

image

此时batch_tensor就是那张图,装batch了,所以是(1,3,224,224).

image

out 变量就是模型输出的数值,此时还没经过sigmod,数值还是较大的:

image

此时我将执行这段代码:

import paddle.nn.functional as F

print("out的sigmod最大值", F.sigmoid(out).max())  # 0.96171629
import onnxruntime as ort

session = ort.InferenceSession(
    r'inference/inference.onnx')
outputs = session.run(None, {'x': batch_tensor.numpy()})
print("onnx", outputs[0].max())

可以看到out经过sigmod之后的最大值是0.96171629,而onnx输出的数值好像是经过sigmod的,所以直接求最大值,是0.9836141。

image

onnx的输出: image

而out变量经过sigmod的数值是: image

确实是对不齐啊~~

PS. 我倒挺希望得到的回复是我的onnx模型转换错了,因为从这个结果来看真的让人不理解。

xddun avatar Aug 04 '22 08:08 xddun

希望能像我这样操作一把试试,从而找到问题根源。

此外,还希望paddleclas在未来给出一些数据增强示例、训练在线可视化的一些东西。

xddun avatar Aug 04 '22 08:08 xddun

群里加我微信语音讨论下吧~

cuicheng01 avatar Aug 08 '22 10:08 cuicheng01

好的呀,已添加,叫Kevin。

xddun avatar Aug 08 '22 10:08 xddun

@cuicheng01 @xddun 你好,请问你的问题解决了吗?我在进行多标签分类任务的时候也遇到了这个bug,infer推理值和inference的推理值差异明显,如果解决了麻烦艾特我一下,需要知道该怎么解决这个bug

phoenixliu666 avatar Aug 21 '22 16:08 phoenixliu666

请问解决了吗,遇到同样的问题,infer正常,export_model进行推理就有问题,同样再转onnx也是有问题,问题出在export_model上,对输出作了归一化操作,实际是不能作这个归一化操作的。

chennankuan avatar Aug 25 '22 03:08 chennankuan

@phoenixliu666 @chennankuan

已经在微信给百度负责这块的人 @cuicheng01 提供了详细的过程文件和描述,这的确是一个很大的BUG,如果各位有在端侧执行推理的需求,可能需要耐心等待bug修复或者换一个框架了,bug修复后 @cuicheng01 应该会第一时间回复此条issues。

xddun avatar Aug 25 '22 03:08 xddun

问题的确出在export_model上,百度infer的模型导出到自身推理模型上出了问题。

xddun avatar Aug 25 '22 03:08 xddun

好的,多谢解答

phoenixliu666 avatar Aug 28 '22 15:08 phoenixliu666

这里有一些支持其他特性的时候导致的一个bug,中间某一个版本修复过,最新的又暴露出来了,最新的PR已修复,同时支持解析label名字。https://github.com/PaddlePaddle/PaddleClas/pull/2219

cuicheng01 avatar Aug 29 '22 06:08 cuicheng01

@xddun @phoenixliu666 解决没有 你们

YSYS101010000 avatar Feb 24 '23 08:02 YSYS101010000