#!/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]
原模型输出结构:
onnx_edit后结构:
转换代码:
输出: