本文以 arcface 为例, 介绍如何编译迁移一个onnx模型至TPU平台运行。
有疑问具体可参考 TPU-MLIR
ONNX转MLIR
如果模型是图片输入, 在转模型之前我们需要了解模型的预处理。如果模型用预处理后的npz文件做输入, 则不需要考虑预处理。 预处理过程用公式表达如下:
官网yolov5的图片是rgb, 每个值会乘以 1/255 , 转换成mean和scale对应为 0.0,0.0,0.0 和 0.0039216,0.0039216,0.0039216 。
基本操作过程是用 model_transform.py 将模型转成mlir文件, 然后用 model_deploy.py 将mlir转成对应的model。
模型转换示例命令如下:
#!/bin/bash
source /workspace/tpu-mlir_v1.2.8-g32d7b3ec-20230802/envsetup.sh
/workspace/tpu-mlir_v1.2.8-g32d7b3ec-20230802/python/tools/model_transform.py \
--model_name arcface1 \
--model_def /workspace/sdk/myarcface/model/arcface1.onnx \
--input_shapes [[1,3,112,112]] \
--mean 125.0,125.0,125.0 \
--scale 0.008,0.008,0.008 \
--keep_aspect_ratio \
--pixel_format rgb \
--output_names prob \
--pad_type center \
--pad_value 114 \
--mlir arcface1.mlir
参数表:
注意,所有上述参数,不会附加在模型上直接生效,是提供给算能的程序在int8量化时用的,转换后的模型,还是裸模型。在量化过程中使用平均值(mean)和标准差(std)是为了将浮点数转换为整数表示时,确保量化后的数据可以在整个数据集上保持足够的动态范围和信息表达能力。标准化是通过减去均值并除以标准差的方式,将数据映射到以0为中心的分布,进而将数据转换为一个新的分布,使得量化后的数据在整个范围内都可以保留较高的精度。
这部分参数是量化参数,应该与后续stream中的预处理参数保持一致,并与训练时的参数保持一致。
指定模型的预处理过程
imagenet_mean = [0.5, 0.5, 0.5]
imagenet_std = [0.5, 0.5, 0.5]
image = cv2.imread(image, cv2.IMREAD_COLOR)
image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
image = image / 255.0
image = (image - imagenet_mean) / imagenet_std
模型的输入是:1, 3, 112, 112
由上可知,模型接收的是rgb图片
image = (image / 255.0 - imagenet_mean) / imagenet_std
=(image - imagenet_mean*255.0) / (imagenet_std*255.0)
=(image - imagenet_mean*255.0) *(1/(imagenet_std*255.0))
对应有:
#!/bin/bash
#!/bin/bash
source /workspace/tpu-mlir_v1.2.8-g32d7b3ec-20230802/envsetup.sh
/workspace/tpu-mlir_v1.2.8-g32d7b3ec-20230802/python/tools/model_transform.py \
--model_name arcface1 \
--model_def /workspace/sdk/myarcface/model/arcface1.onnx \
--input_shapes [[1,3,112,112]] \
--mean 125.0,125.0,125.0 \
--scale 0.008,0.008,0.008 \
--keep_aspect_ratio \
--pixel_format rgb \
--output_names prob \
--pad_type center \
--pad_value 114 \
--mlir arcface1.mlir
注:算能不推荐使用动态batch,会损失性能
–keep_aspect_ratio出现即生效
注:opencv的内存排布
实际上,在OpenCV中,图像的维度顺序是(height, width, channels),其中height表示图像的高度,width表示图像的宽度,channels表示图像的通道数。这个顺序是按照常见的习惯和约定来定义的,使得在处理图像时能更加直观和方便地使用。所以,正确的顺序是先高度再宽度,
转换结果
2023/10/27 17:50:57 - INFO :
_____________________________________________________
| preprocess: |
| (x - mean) * scale |
'-------------------------------------------------------'
config Preprocess args :
resize_dims : same to net input dims
keep_aspect_ratio : True
keep_ratio_mode : letterbox
pad_value : 114
pad_type : center
--------------------------
mean : [125.0, 125.0, 125.0]
scale : [0.008, 0.008, 0.008]
--------------------------
pixel_format : rgb
channel_format : nchw
--------------------------------
Before assigning input_shape:
True
True
Run onnxsim 1 times, model simplified: True
--------------------------------
After assigning input_shape:
True
True
Run onnxsim 1 times, model simplified: True
--------------------------------
Save mlir file: arcface512_origin.mlir
[Running]: tpuc-opt arcface512_origin.mlir --shape-infer --canonicalize --extra-optimize -o arcface512.mlir
[Success]: tpuc-opt arcface512_origin.mlir --shape-infer --canonicalize --extra-optimize -o arcface512.mlir
Mlir file generated:arcface512.mlir
接着将mlir文件转为16fp的半精度文件
同目录下新建文件,写入:
#!/bin/bash
source /workspace/tpu-mlir_v1.2.8-g32d7b3ec-20230802/envsetup.sh
/workspace/tpu-mlir_v1.2.8-g32d7b3ec-20230802/python/tools/model_deploy.py \
--mlir /workspace/sdk/myarcface/model/arcface1.mlir \
--chip bm1684x \
--quantize F16 \
--model arcface1.model
运行即得到最终的fp16模型。