PINTO0309 / onnx2tf

Self-Created Tools to convert ONNX files (NCHW) to TensorFlow/TFLite/Keras format (NHWC). The purpose of this tool is to solve the massive Transpose extrapolation problem in onnx-tensorflow (onnx-tf). I don't need a Star, but give me a pull request.

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

yolov8-seg output transpose (0,3,1,2)

ChenLiangChong opened this issue · comments

Issue Type

Feature Request, Others

OS

Linux

onnx2tf version number

1.16.2

onnx version number

1.12.0

onnxruntime version number

1.16.3

onnxsim (onnx_simplifier) version number

0.4.33

tensorflow version number

2.10.0

Download URL for ONNX

https://drive.google.com/file/d/1QWHtwhQleps0rpy3HDt-E27Rqoev0nr2/view?usp=sharing

Parameter Replacement JSON

onnx2tf -i "yolov8n-seg.onnx" -o "yolov8n-seg_saved_model" --verbosity info -oiqt -ioqd "uint8"

Description

  1. Deploying efficiently on the Android edge can save at least 200ms if this problem is solved.

  2. After model conversion, the output dimensions also change. If the output was originally 4-dimensional, it becomes (0,2,3,1). I believe this is due to applying a dimension transformation to the entire model. However, in Android, we cannot directly use methods like transpose as in Python, and other approaches are too time-consuming.

  3. I have already tried to find a way to add a transpose layer before the model's output in a similar conversion tool, but I cannot find the right place to make adjustments in this project.

  4. Solving this problem would greatly benefit deployment on the edge.

  5. I am using another conversion tool, https://github.com/MPolaris/onnx2tflite, and in my modified code in utils/builder.py line 88, I have added the following code.

    input_nodes = [tf_tensor[x.name] for x in model_graph.input]
    outputs_nodes = [tf_tensor[x.name] for x in model_graph.output]
//add transpose to get correct output
    transposed_outputs = [tf.transpose(node, perm=[0, 3, 1, 2]) for node in outputs_nodes]
    keras_model = keras.Model(inputs=input_nodes, outputs=transposed_outputs)
    keras_model.trainable = False

All you have to do is break up the model before the final layer, Transpose.

Read the README so thoroughly that it has holes in it.

https://github.com/PINTO0309/onnx2tf#2-run-test

image

# Split the model at the middle position for debugging
# Specify the output name of the OP
$ onnx2tf -i resnet18-v1-7.onnx -onimc resnetv15_stage2_conv1_fwd resnetv15_stage2_conv2_fwd

Hello, it seems like my previous response did not address my issue.

In the context of YOLOv8, the final output tensor shape is (1, 84, 8400) for my project. In YOLOv8-seg, the original output shape is (1, 116, 8400) and (1, 32, 160, 160).

The YOLOv8 official implementation also handles this special case in ultralytics/ultralytics/nn/autobackend.py, line 444.

            # TF segment fixes: export is reversed vs ONNX export and protos are transposed
            if len(y) == 2:  # segment with (det, proto) output order reversed
                if len(y[1].shape) != 4:
                    y = list(reversed(y))  # should be y = (1, 116, 8400), (1, 160, 160, 32)
                y[1] = np.transpose(y[1], (0, 3, 1, 2))  # should be y = (1, 116, 8400), (1, 32, 160, 160)
            y = [x if isinstance(x, np.ndarray) else x.numpy() for x in y]

In the model_zoo tflite provided by me, the shapes are (1, 116, 8400) and (1, 160, 160, 32), but in ONNX, it's (1, 116, 8400) and (1, 32, 160, 160). This means that the mask part is automatically transposed during conversion.

I am wondering if it's possible to add a transpose operation just before the last layer to handle this special case. When deploying, I want to output the original shapes (1, 116, 8400) and (1, 32, 160, 160) for efficiency. I have ten outputs for reg, cls, ms, and seg, respectively:

(1, 80, 80, 80) (1, 80, 40, 40) (1, 80, 20, 20)
(1, 1, 4, 6400) (1, 1, 4, 1600) (1, 1, 4, 400)
(1, 32, 80, 80) (1, 32, 40, 40) (1, 32, 20, 20)
(1, 32, 160, 160)

However, after converting to TFLite, the shapes become:

(1, 80, 80, 80) (1, 40, 40, 80) (1, 20, 20, 80)
(1, 6400, 4, 1) (1, 1600, 4, 1) (1, 400, 4, 1)
(1, 80, 80, 32) (1, 40, 40, 32) (1, 20, 20, 32)
(1, 160, 160, 32)

Hello, I have already attempted to extrapolate the Transpose operation to the back of the final layer.
However I encountered some problems, and the output of the onnx model compared to the TFLite output doesn't seem to indicate that the operation was successful.

螢幕快照 2023-12-04 11-04-12

螢幕快照 2023-12-04 11-09-10

I think the reg3 in onnx and Identity_4296 in tflite is the same output.
but i still got (1,1,4,400) and (1,4,400,1)

I suspect there might be an issue with how I wrote my JSON file. The JSON file I used is shown below.

{
  "format_version": 1,
  "operations": [
    {
      "op_name": "reg1",
      "param_target": "outputs",
      "param_name": "reg1",
      "post_process_transpose_perm": [0, 3, 2, 1]
    },
	    {
      "op_name": "cls1",
      "param_target": "outputs",
      "param_name": "cls1",
      "post_process_transpose_perm": [0, 3, 2, 1]
    },
	    {
      "op_name": "reg2",
      "param_target": "outputs",
      "param_name": "reg2",
      "post_process_transpose_perm": [0, 3, 2, 1]
    },
	    {
      "op_name": "cls2",
      "param_target": "outputs",
      "param_name": "cls2",
      "post_process_transpose_perm": [0, 3, 2, 1]
    },
	    {
      "op_name": "reg3",
      "param_target": "outputs",
      "param_name": "reg3",
      "post_process_transpose_perm": [0, 3, 2, 1]
    },
	    {
      "op_name": "cls3",
      "param_target": "outputs",
      "param_name": "cls3",
      "post_process_transpose_perm": [0, 3, 2, 1]
    },
	    {
      "op_name": "mc1",
      "param_target": "outputs",
      "param_name": "mc1",
      "post_process_transpose_perm": [0, 3, 2, 1]
    },
	    {
      "op_name": "mc2",
      "param_target": "outputs",
      "param_name": "mc2",
      "post_process_transpose_perm": [0, 3, 2, 1]
    },
		    {
      "op_name": "mc3",
	  "param_target": "outputs",
      "param_name": "mc3",
      "post_process_transpose_perm": [0, 3, 2, 1]
    },
		    {
      "op_name": "seg",
      "param_target": "outputs",
      "param_name": "seg",
      "post_process_transpose_perm": [0, 3, 2, 1]
    }
  ]
}

Can you help me confirm what adjustments are needed? Thank you.

I attempted to add a transpose layer at the end of an ONNX model, but after the conversion, that layer was directly removed.

image
image