K230的AI推理部分,有关于模型输入归一化的API吗?

Viewed 24

问题描述


K230的AI推理部分,有关于模型输入归一化的API吗?
对,我设置了这两个值,但是GUI版本的nncase转换有问题,使用库API转换成功了,但模型的运行结果不对

import argparse
import numpy as np
from PIL import Image
import onnxsim
import onnx
import nncase

def parse_model_input_output(model_file):
    onnx_model = onnx.load(model_file)
    input_all = [node.name for node in onnx_model.graph.input]
    input_initializer = [node.name for node in onnx_model.graph.initializer]
    input_names = list(set(input_all) - set(input_initializer))
    input_tensors = [
        node for node in onnx_model.graph.input if node.name in input_names]

    # input
    inputs = []
    for _, e in enumerate(input_tensors):
        onnx_type = e.type.tensor_type
        input_dict = {}
        input_dict['name'] = e.name
        input_dict['dtype'] = onnx.helper.tensor_dtype_to_np_dtype(onnx_type.elem_type)
        
        input_dict['shape'] = [(i.dim_value if i.dim_value != 0 else d) for i, d in zip(
            onnx_type.shape.dim, [1, 3, 288, 384])]
        inputs.append(input_dict)

    return onnx_model, inputs


def onnx_simplify(model_file, dump_dir):
    onnx_model, inputs = parse_model_input_output(model_file)
    onnx_model = onnx.shape_inference.infer_shapes(onnx_model)
    input_shapes = {}
    for input in inputs:
        input_shapes[input['name']] = input['shape']

    onnx_model, check = onnxsim.simplify(onnx_model, input_shapes=input_shapes)
    assert check, "Simplified ONNX model could not be validated"

    model_file = os.path.join(dump_dir, 'simplified.onnx')
    onnx.save_model(onnx_model, model_file)
    return model_file


def read_model_file(model_file):
    with open(model_file, 'rb') as f:
        model_content = f.read()
    return model_content


def generate_data(shape, batch, calib_dir):
    img_paths = [os.path.join(calib_dir, p) for p in os.listdir(calib_dir) if p.lower().endswith(('png', 'jpg', 'jpeg'))]
    data = []
    for i in range(batch):
        assert i < len(img_paths), "calibration images not enough."
        img_data = Image.open(img_paths[i]).convert('RGB')
        img_data = img_data.resize((shape[3], shape[2]), Image.BILINEAR)
        img_data = np.asarray(img_data, dtype=np.uint8)
        img_data = np.transpose(img_data, (2, 0, 1))
        data.append([img_data[np.newaxis, ...]])
    return data

def main():
    parser = argparse.ArgumentParser(prog="nncase")
    parser.add_argument("--target", type=str, default="k230", help='target to run')
    parser.add_argument("--model", type=str, required=True, help='model file')
    parser.add_argument("--dataset", type=str, required=True, help='calibration_dataset')

    args = parser.parse_args()

    input_shape = [1, 3, 384, 288]

    dump_dir = 'tmp/rtmpose_onnx'
    if not os.path.exists(dump_dir):
        os.makedirs(dump_dir)

    # onnx simplify
    model_file = onnx_simplify(args.model, dump_dir)

    # compile_options
    compile_options = nncase.CompileOptions()
    compile_options.target = args.target
    compile_options.preprocess = True
    compile_options.swapRB = False 
    compile_options.input_shape = input_shape
    compile_options.input_type = 'uint8'
    compile_options.input_range = [0, 255]
    
    # RTMPose ImageNet 均值与标准差
    compile_options.mean = [123.675, 116.28, 103.53]
    compile_options.std = [58.395, 57.12, 57.375]
    
    compile_options.input_layout = 'NCHW'
    compile_options.output_layout = 'NCHW'
    compile_options.dump_ir = True
    compile_options.dump_asm = True
    compile_options.dump_dir = dump_dir

    # compiler
    compiler = nncase.Compiler(compile_options)

    # import
    model_content = read_model_file(model_file)
    import_options = nncase.ImportOptions()
    compiler.import_onnx(model_content, import_options)

    # ptq_options
    ptq_options = nncase.PTQTensorOptions()
    ptq_options.samples_count = 6
    ptq_options.quant_type = "uint8"
    ptq_options.w_quant_type = "uint8"
    ptq_options.export_weight_range_by_channel = True
    ptq_options.set_tensor_data(generate_data(input_shape, ptq_options.samples_count, args.dataset))
    compiler.use_ptq(ptq_options)

    # compile
    compiler.compile()

    # kmodel
    kmodel = compiler.gencode_tobytes()
    with open(os.path.join(dump_dir, 'rtmpose.kmodel'), 'wb') as f:
        f.write(kmodel)
    print(f"Successfully generated rtmpose.kmodel at {dump_dir}/rtmpose.kmodel")

if __name__ == '__main__':
    main()

硬件板卡


CanMV K230 V3.0(创乐博)

软件版本


CanMV-K230_V3P0_linux_v1.4_nncase_v2.11.0_fc6cc215_sdcard.img.gz

Nncase.Studio这个可视化版的转换工具在加入前处理归一化之后软件会崩溃

1 Answers

具体是什么归一化?是设置mean和std的部分吗?

对,GUI版本的那个转换软件在输入mean和std之后一直崩溃,使用nncase的API转换成功了(问题中已补充转换代码),但是模型的输出tensor是乱码

什么模型?

RTMPose-M-288x384,能确定后处理前处理没问题,前处理保存验证了输入模型的图片tensor尺寸那些都是正常的,目前能想到的唯一的变量就是mean、std部分放到了模型内部,怀疑有可能是这里出了问题,有没有将mean、std放到模型外部相关代码例子?