Convert ONNX to PyTorch: TypeError: Conv2d.__init__() missing 2 required positional arguments: 'in_channels' and 'out_channels'

I want to convert onnx model to pytorch.
But I get this error.

python script

import onnx
from onnx2pytorch import ConvertModel
import torch

def load_and_convert_model(onnx_model_path):
    onnx_model = onnx.load(onnx_model_path)

    pytorch_model = ConvertModel(onnx_model)
    return pytorch_model


def test_model(pytorch_model, input_shape=(1, 3, 224, 224)):
    dummy_input = torch.randn(input_shape)

    output = pytorch_model(dummy_input)
    print("Output Shape:", output.shape)
    print("Output Data:", output)

def main():
    onnx_model_path = "cls_model/inference.onnx"
    pytorch_model = load_and_convert_model(onnx_model_path)

    test_model(pytorch_model, input_shape=(1, 3, 224, 224))  
    test_model(pytorch_model, input_shape=(1, 3, 299, 299))  

if __name__ == "__main__":
    main()

error

$ python export_onnx2pytorch.py 
Traceback (most recent call last):
  File "/home/natalia/Documents/Workspace/convert_models/export_onnx2pytorch.py", line 31, in <module>
    main()
  File "/home/natalia/Documents/Workspace/convert_models/export_onnx2pytorch.py", line 24, in main
    pytorch_model = load_and_convert_model(onnx_model_path)
  File "/home/natalia/Documents/Workspace/convert_models/export_onnx2pytorch.py", line 10, in load_and_convert_model
    pytorch_model = ConvertModel(onnx_model)
  File "/home/natalia/Dev/Tools/conda/envs/convert/lib/python3.10/site-packages/onnx2pytorch/convert/model.py", line 122, in __init__
    for op_id, op_name, op in convert_operations(
  File "/home/natalia/Dev/Tools/conda/envs/convert/lib/python3.10/site-packages/onnx2pytorch/convert/operations.py", line 104, in convert_operations
    op = convert_layer(node, "Conv", params)
  File "/home/natalia/Dev/Tools/conda/envs/convert/lib/python3.10/site-packages/onnx2pytorch/convert/layer.py", line 80, in convert_layer
    layer = layer(**kwargs)
TypeError: Conv2d.__init__() missing 2 required positional arguments: 'in_channels' and 'out_channels'

versions

onnx                      1.17.0                   
onnx-tf                   1.10.0                   
onnx2pytorch              0.5.1                    
onnxruntime               1.20.1                   
torch                     2.0.1                    
torchvision               0.15.2

using neutron

MODEL PROPERTIES

format ONNX v7
version 0
imports ai.onnx v14
graph PaddlePaddle Graph 0

INPUTS
x name: x
tensor: float32[DynamicDimension.0,3,DynamicDimension.1,DynamicDimension.2]

OUTPUTS
softmax_0.tmp_0
name: softmax_0.tmp_0
tensor: float32[DynamicDimension.3,2]

I’m not deeply familiar with ONNX, but would this indicate the original model was written in PaddlePaddle? If so, do you know if their conv APIs differ as it seems the channel dimensions are missing?

Yes, I converted the PaddleOCR model to ONNX. The goal now is to convert the ONNX models to PyTorch.

PaddleOCR consists of three models: detection, classification, and recognition. I successfully converted all three to ONNX.

However, I am encountering issues with converting them to PyTorch.

I tested various ONNX versions and ensured the correct opset, following the documentation: ONNX Runtime Compatibility.

Despite these efforts, I am currently stuck. After the conversion, some dimensions appear to be missing, and I am unable to identify the cause of this issue.

For example, the classification model (cls):

inspect.py

import onnx

def inspect_onnx_model(model_path):
    onnx_model = onnx.load(model_path)
    for node in onnx_model.graph.node:
        if node.op_type == "Conv":
            print(f"Conv Node: {node.name}")
            print(f"  Inputs: {node.input}")
            print(f"  Outputs: {node.output}")
    print("Model inspection complete.")

inspect_onnx_model("model/cls_model/inference.onnx")
$ python inspect_onnx.py 
Conv Node: Conv.0
  Inputs: ['x', 'conv2d_0.w_0']
  Outputs: ['conv2d_53.tmp_0']
Conv Node: Conv.1
  Inputs: ['hardswish_0.tmp_0', 'conv2d_1.w_0']
  Outputs: ['conv2d_54.tmp_0']
Conv Node: Conv.2
  Inputs: ['relu_0.tmp_0', 'conv2d_2.w_0']
  Outputs: ['depthwise_conv2d_0.tmp_0']
Conv Node: Conv.3
  Inputs: ['pool2d_0.tmp_0', 'conv2d_3.w_0', 'conv2d_3.b_0']
  Outputs: ['conv2d_55.tmp_0']
Conv Node: Conv.4
  Inputs: ['relu_2.tmp_0', 'conv2d_4.w_0', 'conv2d_4.b_0']
  Outputs: ['conv2d_56.tmp_0']
Conv Node: Conv.5
  Inputs: ['Mul.1', 'conv2d_5.w_0']
  Outputs: ['conv2d_57.tmp_0']
Conv Node: Conv.6
  Inputs: ['batch_norm_3.tmp_3', 'conv2d_6.w_0']
  Outputs: ['conv2d_58.tmp_0']
Conv Node: Conv.7
  Inputs: ['relu_3.tmp_0', 'conv2d_7.w_0']
  Outputs: ['depthwise_conv2d_1.tmp_0']
Conv Node: Conv.8
  Inputs: ['relu_4.tmp_0', 'conv2d_8.w_0']
  Outputs: ['conv2d_59.tmp_0']
Conv Node: Conv.9
  Inputs: ['batch_norm_6.tmp_3', 'conv2d_9.w_0']
  Outputs: ['conv2d_60.tmp_0']
Conv Node: Conv.10
  Inputs: ['relu_5.tmp_0', 'conv2d_10.w_0']
  Outputs: ['depthwise_conv2d_2.tmp_0']
Conv Node: Conv.11
  Inputs: ['relu_6.tmp_0', 'conv2d_11.w_0']
  Outputs: ['conv2d_61.tmp_0']
Conv Node: Conv.12
  Inputs: ['Add.5', 'conv2d_12.w_0']
  Outputs: ['conv2d_62.tmp_0']
Conv Node: Conv.13
  Inputs: ['hardswish_1.tmp_0', 'conv2d_13.w_0']
  Outputs: ['depthwise_conv2d_3.tmp_0']
Conv Node: Conv.14
  Inputs: ['pool2d_1.tmp_0', 'conv2d_14.w_0', 'conv2d_14.b_0']
  Outputs: ['conv2d_63.tmp_0']
Conv Node: Conv.15
  Inputs: ['relu_7.tmp_0', 'conv2d_15.w_0', 'conv2d_15.b_0']
  Outputs: ['conv2d_64.tmp_0']
Conv Node: Conv.16
  Inputs: ['Mul.3', 'conv2d_16.w_0']
  Outputs: ['conv2d_65.tmp_0']
Conv Node: Conv.17
  Inputs: ['batch_norm_12.tmp_3', 'conv2d_17.w_0']
  Outputs: ['conv2d_66.tmp_0']
Conv Node: Conv.18
  Inputs: ['hardswish_3.tmp_0', 'conv2d_18.w_0']
  Outputs: ['depthwise_conv2d_4.tmp_0']
Conv Node: Conv.19
  Inputs: ['pool2d_2.tmp_0', 'conv2d_19.w_0', 'conv2d_19.b_0']
  Outputs: ['conv2d_67.tmp_0']
Conv Node: Conv.20
  Inputs: ['relu_8.tmp_0', 'conv2d_20.w_0', 'conv2d_20.b_0']
  Outputs: ['conv2d_68.tmp_0']
Conv Node: Conv.21
  Inputs: ['Mul.5', 'conv2d_21.w_0']
  Outputs: ['conv2d_69.tmp_0']
Conv Node: Conv.22
  Inputs: ['Add.15', 'conv2d_22.w_0']
  Outputs: ['conv2d_70.tmp_0']
Conv Node: Conv.23
  Inputs: ['hardswish_5.tmp_0', 'conv2d_23.w_0']
  Outputs: ['depthwise_conv2d_5.tmp_0']
Conv Node: Conv.24
  Inputs: ['pool2d_3.tmp_0', 'conv2d_24.w_0', 'conv2d_24.b_0']
  Outputs: ['conv2d_71.tmp_0']
Conv Node: Conv.25
  Inputs: ['relu_9.tmp_0', 'conv2d_25.w_0', 'conv2d_25.b_0']
  Outputs: ['conv2d_72.tmp_0']
Conv Node: Conv.26
  Inputs: ['Mul.7', 'conv2d_26.w_0']
  Outputs: ['conv2d_73.tmp_0']
Conv Node: Conv.27
  Inputs: ['Add.21', 'conv2d_27.w_0']
  Outputs: ['conv2d_74.tmp_0']
Conv Node: Conv.28
  Inputs: ['hardswish_7.tmp_0', 'conv2d_28.w_0']
  Outputs: ['depthwise_conv2d_6.tmp_0']
Conv Node: Conv.29
  Inputs: ['pool2d_4.tmp_0', 'conv2d_29.w_0', 'conv2d_29.b_0']
  Outputs: ['conv2d_75.tmp_0']
Conv Node: Conv.30
  Inputs: ['relu_10.tmp_0', 'conv2d_30.w_0', 'conv2d_30.b_0']
  Outputs: ['conv2d_76.tmp_0']
Conv Node: Conv.31
  Inputs: ['Mul.9', 'conv2d_31.w_0']
  Outputs: ['conv2d_77.tmp_0']
Conv Node: Conv.32
  Inputs: ['Add.27', 'conv2d_32.w_0']
  Outputs: ['conv2d_78.tmp_0']
Conv Node: Conv.33
  Inputs: ['hardswish_9.tmp_0', 'conv2d_33.w_0']
  Outputs: ['depthwise_conv2d_7.tmp_0']
Conv Node: Conv.34
  Inputs: ['pool2d_5.tmp_0', 'conv2d_34.w_0', 'conv2d_34.b_0']
  Outputs: ['conv2d_79.tmp_0']
Conv Node: Conv.35
  Inputs: ['relu_11.tmp_0', 'conv2d_35.w_0', 'conv2d_35.b_0']
  Outputs: ['conv2d_80.tmp_0']
Conv Node: Conv.36
  Inputs: ['Mul.11', 'conv2d_36.w_0']
  Outputs: ['conv2d_81.tmp_0']
Conv Node: Conv.37
  Inputs: ['Add.33', 'conv2d_37.w_0']
  Outputs: ['conv2d_82.tmp_0']
Conv Node: Conv.38
  Inputs: ['hardswish_11.tmp_0', 'conv2d_38.w_0']
  Outputs: ['depthwise_conv2d_8.tmp_0']
Conv Node: Conv.39
  Inputs: ['pool2d_6.tmp_0', 'conv2d_39.w_0', 'conv2d_39.b_0']
  Outputs: ['conv2d_83.tmp_0']
Conv Node: Conv.40
  Inputs: ['relu_12.tmp_0', 'conv2d_40.w_0', 'conv2d_40.b_0']
  Outputs: ['conv2d_84.tmp_0']
Conv Node: Conv.41
  Inputs: ['Mul.13', 'conv2d_41.w_0']
  Outputs: ['conv2d_85.tmp_0']
Conv Node: Conv.42
  Inputs: ['batch_norm_27.tmp_3', 'conv2d_42.w_0']
  Outputs: ['conv2d_86.tmp_0']
Conv Node: Conv.43
  Inputs: ['hardswish_13.tmp_0', 'conv2d_43.w_0']
  Outputs: ['depthwise_conv2d_9.tmp_0']
Conv Node: Conv.44
  Inputs: ['pool2d_7.tmp_0', 'conv2d_44.w_0', 'conv2d_44.b_0']
  Outputs: ['conv2d_87.tmp_0']
Conv Node: Conv.45
  Inputs: ['relu_13.tmp_0', 'conv2d_45.w_0', 'conv2d_45.b_0']
  Outputs: ['conv2d_88.tmp_0']
Conv Node: Conv.46
  Inputs: ['Mul.15', 'conv2d_46.w_0']
  Outputs: ['conv2d_89.tmp_0']
Conv Node: Conv.47
  Inputs: ['Add.43', 'conv2d_47.w_0']
  Outputs: ['conv2d_90.tmp_0']
Conv Node: Conv.48
  Inputs: ['hardswish_15.tmp_0', 'conv2d_48.w_0']
  Outputs: ['depthwise_conv2d_10.tmp_0']
Conv Node: Conv.49
  Inputs: ['pool2d_8.tmp_0', 'conv2d_49.w_0', 'conv2d_49.b_0']
  Outputs: ['conv2d_91.tmp_0']
Conv Node: Conv.50
  Inputs: ['relu_14.tmp_0', 'conv2d_50.w_0', 'conv2d_50.b_0']
  Outputs: ['conv2d_92.tmp_0']
Conv Node: Conv.51
  Inputs: ['Mul.17', 'conv2d_51.w_0']
  Outputs: ['conv2d_93.tmp_0']
Conv Node: Conv.52
  Inputs: ['Add.49', 'conv2d_52.w_0']
  Outputs: ['conv2d_94.tmp_0']

Model inspection complete.