airockchip / rknn-toolkit2

Other
991 stars 104 forks source link

使用onnx_edit插入新维度后得到的模型无法转换 #170

Open happyme531 opened 1 month ago

happyme531 commented 1 month ago

原模型输出结构: 图片

onnx_edit后结构: 图片

转换代码:

#!/usr/bin/env python
# coding: utf-8

import os
from rknn.api import RKNN
from math import exp
from sys import exit
import argparse
import onnxscript
from onnxscript.rewriter import pattern
import onnx.numpy_helper as onh
import numpy as np
import onnx
import onnxruntime as ort
from rknn.utils import onnx_edit

os.chdir(os.path.dirname(os.path.abspath(__file__)))

speech_length = 171

def convert_encoder():
    rknn = RKNN(verbose=True)

    ONNX_MODEL=f"sense-voice-encoder.onnx"
    RKNN_MODEL=ONNX_MODEL.replace(".onnx",".rknn")
    DATASET="dataset.txt"
    QUANTIZE=False

    #开局先给我来个大惊喜,rknn做第一步常量折叠的时候就会在这个子图里报错,所以要单独拿出来先跑一遍
    #然后把这个子图的输出结果保存下来喂给rknn
    onnx.utils.extract_model(ONNX_MODEL, "extract_model.onnx", ['speech_lengths'], ['/make_pad_mask/Cast_2_output_0'])
    sess = ort.InferenceSession("extract_model.onnx", providers=['CPUExecutionProvider'])
    extract_result = sess.run(None, {"speech_lengths": np.array([speech_length], dtype=np.int64)})[0]

    # 删掉模型最后的多余transpose
    ret = onnx_edit(model = ONNX_MODEL,
        export_path = ONNX_MODEL.replace(".onnx", "_edited.onnx"),
        # 1, len, 25055 -> 1, 25055, 1, len
        outputs_transform = {'encoder_out': 'a,b,c->a,c,1,b'},
    )
    ONNX_MODEL = ONNX_MODEL.replace(".onnx", "_edited.onnx")

    # pre-process config
    print('--> Config model')
    rknn.config(quantized_algorithm='normal', quantized_method='channel', target_platform='rk3588', optimization_level=3)
    print('done')

    # Load ONNX model
    print("--> Loading model")
    ret = rknn.load_onnx(
        model=ONNX_MODEL,
        inputs=["speech", "/make_pad_mask/Cast_2_output_0"],
        input_size_list=[[1, speech_length, 560], [extract_result.shape[0], extract_result.shape[1]]],
        input_initial_val=[None, extract_result],
        # outputs=["output"]
    )

    if ret != 0:
        print('Load model failed!')
        exit(ret)
    print('done')

    # Build model
    print('--> Building model')
    ret = rknn.build(do_quantization=QUANTIZE, dataset=DATASET, rknn_batch_size=None)
    if ret != 0:
        print('Build model failed!')
        exit(ret)
    print('done')

    # export
    print('--> Export RKNN model')
    ret = rknn.export_rknn(RKNN_MODEL)
    if ret != 0:
        print('Export RKNN model failed!')
        exit(ret)
    print('done')

# usage: python convert_rknn.py encoder|all
if __name__ == "__main__":
    parser = argparse.ArgumentParser()
    parser.add_argument("model", type=str, help="model to convert", choices=["encoder", "all"], nargs='?')
    args = parser.parse_args()
    if args.model is None:
        args.model = "all"

    if args.model == "encoder":
        convert_encoder()
    elif args.model == "all":
        convert_encoder()
    else:
        print(f"Unknown model: {args.model}")
        exit(1)

输出:

> python ./convert_rknn.py                                                                                           
I rknn-toolkit2 version: 2.2.0
I For 'encoder_out':'a,b,c->a,c,1,b'
  Output:'encoder_out' was reset as shape-['a', 25055, 1, 'b'].(Origin shape is ['Addencoder_out_dim_0', 'encoder_out_length', 25055]) 
  Insert ops to transform ['Addencoder_out_dim_0', 'encoder_out_length', 25055] to ['a', 25055, 1, 'b']:
  - Insert transpose op. ['Addencoder_out_dim_0', 'encoder_out_length', 25055] transpose(0, 2, 1) to ['Addencoder_out_dim_0', 25055, 'encoder_out_length'].
  - Insert reshape op. ['Addencoder_out_dim_0', 25055, 'encoder_out_length'] reshape to ['a', 25055, 1, 'b'].
I Edited model has been saved to 'sense-voice-encoder_edited.onnx'.
--> Config model
done
--> Loading model
W load_onnx: If you don't need to crop the model, don't set 'inputs'/'input_size_list'/'outputs'!
W load_onnx: The input '/make_pad_mask/Cast_2_output_0' will be removed from the model,
             Please don't forget to remove the corresponding 'mean'/'std' of '/make_pad_mask/Cast_2_output_0' in rknn.config!
I Loading : 100%|███████████████████████████████████████████████| 923/923 [00:00<00:00, 5360.80it/s]
W load_onnx: The config.mean_values is None, zeros will be set for input 0!
W load_onnx: The config.std_values is None, ones will be set for input 0!
done
--> Building model
W build: The dataset='dataset.txt' is ignored because do_quantization = False!
D base_optimize ...
D base_optimize done.
D 
D fold_constant ...
I    FoldConstant : 100%|█████████████████████████████████████▉| 5078/5094 [00:13<00:00, 228.03it/s]2024-10-10 00:05:22.204331654 [E:onnxruntime:, sequential_executor.cc:514 ExecuteKernel] Non-zero status code returned while running Gather node. Name:'encoder_out_oxedit_ins_tp_1_shape_dim_3' Status Message: indices element out of data bounds, idx=3 must be within the inclusive range [-3,2]
I    FoldConstant : 100%|█████████████████████████████████████▉| 5089/5094 [00:13<00:00, 371.95it/s]
E build: Traceback (most recent call last):
  File "rknn/api/rknn_log.py", line 309, in rknn.api.rknn_log.error_catch_decorator.error_catch_wrapper
  File "rknn/api/rknn_base.py", line 1920, in rknn.api.rknn_base.RKNNBase.build
  File "rknn/api/graph_optimizer.py", line 976, in rknn.api.graph_optimizer.GraphOptimizer.fold_constant
  File "rknn/api/session.py", line 150, in rknn.api.session.Session.run
  File "/home/zt/.conda/envs/rknn/lib/python3.8/site-packages/onnxruntime/capi/onnxruntime_inference_collection.py", line 220, in run
    return self._sess.run(output_names, input_feed, run_options)
onnxruntime.capi.onnxruntime_pybind11_state.InvalidArgument: [ONNXRuntimeError] : 2 : INVALID_ARGUMENT : Non-zero status code returned while running Gather node. Name:'encoder_out_oxedit_ins_tp_1_shape_dim_3' Status Message: indices element out of data bounds, idx=3 must be within the inclusive range [-3,2]

W build: ===================== WARN(5) =====================
E rknn-toolkit2 version: 2.2.0
Traceback (most recent call last):
  File "rknn/api/rknn_log.py", line 309, in rknn.api.rknn_log.error_catch_decorator.error_catch_wrapper
  File "rknn/api/rknn_base.py", line 1920, in rknn.api.rknn_base.RKNNBase.build
  File "rknn/api/graph_optimizer.py", line 976, in rknn.api.graph_optimizer.GraphOptimizer.fold_constant
  File "rknn/api/session.py", line 150, in rknn.api.session.Session.run
  File "/home/zt/.conda/envs/rknn/lib/python3.8/site-packages/onnxruntime/capi/onnxruntime_inference_collection.py", line 220, in run
    return self._sess.run(output_names, input_feed, run_options)
onnxruntime.capi.onnxruntime_pybind11_state.InvalidArgument: [ONNXRuntimeError] : 2 : INVALID_ARGUMENT : Non-zero status code returned while running Gather node. Name:'encoder_out_oxedit_ins_tp_1_shape_dim_3' Status Message: indices element out of data bounds, idx=3 must be within the inclusive range [-3,2]

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "./convert_rknn.py", line 91, in <module>
    convert_encoder()
  File "./convert_rknn.py", line 65, in convert_encoder
    ret = rknn.build(do_quantization=QUANTIZE, dataset=DATASET, rknn_batch_size=None)
  File "/home/zt/.conda/envs/rknn/lib/python3.8/site-packages/rknn/api/rknn.py", line 192, in build
    return self.rknn_base.build(do_quantization=do_quantization, dataset=dataset, expand_batch_size=rknn_batch_size)
  File "rknn/api/rknn_log.py", line 314, in rknn.api.rknn_log.error_catch_decorator.error_catch_wrapper
  File "rknn/api/rknn_log.py", line 95, in rknn.api.rknn_log.RKNNLog.e
ValueError: Traceback (most recent call last):
  File "rknn/api/rknn_log.py", line 309, in rknn.api.rknn_log.error_catch_decorator.error_catch_wrapper
  File "rknn/api/rknn_base.py", line 1920, in rknn.api.rknn_base.RKNNBase.build
  File "rknn/api/graph_optimizer.py", line 976, in rknn.api.graph_optimizer.GraphOptimizer.fold_constant
  File "rknn/api/session.py", line 150, in rknn.api.session.Session.run
  File "/home/zt/.conda/envs/rknn/lib/python3.8/site-packages/onnxruntime/capi/onnxruntime_inference_collection.py", line 220, in run
    return self._sess.run(output_names, input_feed, run_options)
onnxruntime.capi.onnxruntime_pybind11_state.InvalidArgument: [ONNXRuntimeError] : 2 : INVALID_ARGUMENT : Non-zero status code returned while running Gather node. Name:'encoder_out_oxedit_ins_tp_1_shape_dim_3' Status Message: indices element out of data bounds, idx=3 must be within the inclusive range [-3,2]
zen-xingle commented 1 month ago

麻烦截图看一下生成的两个gather op,他们的第二个输入,里面存储的常量值是什么。

happyme531 commented 1 month ago

麻烦截图看一下生成的两个gather op,他们的第二个输入,里面存储的常量值是什么。

左侧为int64 [3], 右侧为int64 [0]