5. MacaRT工具链
MacaRT提供以下工具:
模型转换工具MacaConverter。针对各种深度学习框架(如PyTorch,Caffe,Tensorflow)训练出来的模型,可以使用MacaConverter将训练的模型转换为ONNX模型。
精度分析工具MacaPrecision。通过比较CPU和曦云系列GPU在各个层的输出值,更好地调试模型。
模型量化工具MacaQuantizer。相对于MacaRT提供的模型量化功能,MacaQuantizer可以在模型量化后达到更高的精度和更快的速度。
MacaRT模型部署工具链如下图所示:
图 5.1 MacaRT模型部署工具链
5.1. MacaConverter
ONNX是一种便于在各个主流深度学习框架中迁移模型的中间表达格式,可用于存储训练好的模型。它使得不同的深度学习框架(如PyTorch,Caffe,TensorFlow)可以采⽤相同格式存储模型数据,从而进行推理任务的执行。
为了将不同深度学习框架的模型转换为ONNX格式的模型,MacaConverter的内部封装了常用的开源转换工具,对外提供统一的转换接口(命令行),同时提供了部分算子优化功能。
5.1.1. 安装
MacaConverter以wheel安装包的形式对外发布,建议在Conda环境中安装(建议Python版本3.10)。安装MacaRT后,可以在/opt/maca-ai/onnxruntime-maca/python/tools目录下找到MacaConverter对应的Python安装包。
操作步骤
执行以下命令,安装MacaConverter。
conda create -n maca_test python=3.10 source activate maca_test pip install onnxruntime_gpu-1.12.0+mc*.whl pip install maca_converter-*.whl
备注
若运行时报以下错误:
ImportError: libpython3.10.so.1.0: cannot open shared object file: No such file or directory
可执行以下命令:
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/home/xxx/anaconda3/envs/maca_test/lib/
wheel包安装过程中会自动下载相关依赖库,主要有:
numpy
onnx
onnxruntime-gpu
TensorFlow==2.4.0
torch
torchvision
onnxoptimizer==0.2.6
rich==12.0.0
packaging
pyyaml
paddlepaddle
paddle2onnx
5.1.2. 功能列表
MacaConverter支持将多种类型的模型转换为ONNX模型,参见表 5.1。
源模型框架 |
目标模型框架 |
说明 |
|---|---|---|
Caffe |
ONNX |
支持将Caffe模型转换为ONNX模型 |
TensorFlow |
ONNX |
支持将TensorFlow模型转换为ONNX模型(包括CheckPoint,SavedModel,pb和H5四种格式) |
PyTorch |
ONNX |
支持将PyTorch模型转换为ONNX模型 |
PaddlePaddle |
ONNX |
支持将PaddlePaddle模型转换为ONNX模型 |
Darknet |
ONNX |
支持将Darknet模型转换为ONNX模型(目前只支持yolov3和yolov4) |
MacaConverter还支持其他功能,参见表 5.2。
功能 |
说明 |
|---|---|
动态batch转换 |
支持将BatchSize非动态的模型修改为动态BatchSize |
ONNX优化 |
支持常规的优化操作(如常量折叠、Conv+BN融合) |
Float32转Float16 |
支持将模型中相关算子的输入类型由Float32改为Float16 |
子图提取 |
按照给定的输入/输出提取模型的子图 |
融合Pad+Pool |
将相邻的Pad算子融合进Pool算子中 |
op_set版本转换 |
支持将原ONNX模型的op_set版本转换为目标版本 |
Float32转Uint8 |
支持将模型的输入类型由Float32改为Uint8(仅针对模型的input数据,非所有算子) |
MatMul+Add融合为Gemm |
支持将模型中的Matmul+Add算子转换成Gemm算子 |
MHA融合 |
支持将模型中的KQV组合融合成MultiHeadAttentionV1算子 |
5.1.3. 使用说明
5.1.3.1. Caffe模型转ONNX模型
操作步骤
执行以下命令,将Caffe模型转为ONNX模型。
python -m maca_converter --model_path ./caffe_model --model_type caffe --output ./output.onnx
参数说明:
model_path:Caffe模型路径(文件夹,需包含.prototxt和.caffemodel)model_type:模型类型(此处固定为caffe)output:目标模型的路径
5.1.3.2. TensorFlow(H5)模型转ONNX模型
操作步骤
执行以下命令,将TensorFlow H5格式的模型转为ONNX模型。
python -m maca_converter --model_path ./test.h5 --model_type tf-h5 --output ./output.onnx
参数说明:
model_path:H5模型路径model_type:模型类型(此处固定为tf-h5)output:目标模型的路径
5.1.3.3. TensorFlow(SavedModel)模型转ONNX模型
操作步骤
执行以下命令,将TensorFlow SavedModel格式的模型转为ONNX模型。
python -m maca_converter --model_path ./tfsm --model_type tf-sm --output ./output.onnx
参数说明:
model_path:SavedModel模型路径(文件夹,需包含assets/saved_model.pb/variables)model_type:模型类型(此处固定为tf-sm)output:目标模型的路径
5.1.3.4. TensorFlow(CheckPoint)模型转ONNX模型
操作步骤
执行以下命令,将TensorFlow CheckPoint格式的模型转为ONNX模型。
python -m maca_converter --model_path ./ckpt/test.meta --model_type tf-ckpt --output ./output.onnx --inputs x:0,y:0 --outputs op_to_store:0 –-inputs_as_nchw x:0,y:0
参数说明:
model_path:CheckPoint模型路径(文件夹,需包含checkpoint、.meta、.index、.data文件,此参数需指向.meta文件的路径)model_type:模型类型(此处固定为tf-ckpt)output:目标模型的路径inputs:TensorFlow模型的输入(tensor变量的名称,一般后面需加:0)outputs:TensorFlow模型的输出(tensor变量的名称,一般后面需加:0)inputs_as_nchw:可选项,如果原始输入维度是nhwc,可使用此选项转变为nchw
5.1.3.5. TensorFlow(pb)模型转ONNX模型
操作步骤
执行以下命令,将TensorFlow pb格式的模型转为ONNX模型。
python -m maca_converter --model_path ./test.pb --model_type tf-graph --output ./output.onnx --inputs x:0,y:0 --outputs op_to_store:0 --inputs_as_nchw x:0,y:0
参数说明:
model_path:pb模型路径model_type:模型类型(此处固定为tf-graph)output:目标模型的路径inputs:TensorFlow模型的输入(tensor变量的名称,一般后面需加:0)outputs:TensorFlow模型的输出(tensor变量的名称,一般后面需加:0)inputs_as_nchw:可选项,如果原始输入维度是nhwc,可使用此选项转变为nchw
5.1.3.6. PyTorch模型转ONNX模型(输入包含模型定义和权重)
操作步骤
执行以下命令,将PyTorch模型转为ONNX模型(输入包含模型定义和权重)。
python -m maca_converter --model_path ./mnist_model.pkl --model_type pytorch --output ./torch.onnx --model_def_file ./CNN.py --model_class_name CNN --input_shape [1,1,28,28]
参数说明:
model_path:PyTorch模型路径(模型中包含了权重和定义)model_type:模型类型(此处固定为pytorch)output:目标模型的路径model_def_file:模型定义文件(必须和执行命令的路径在同一目录下)model_class_name:模型中定义的类名input_shape:模型的输入形状
5.1.3.7. PyTorch模型转ONNX模型(输入仅包含权重)
操作步骤
执行以下命令,将PyTorch模型转为ONNX模型(输入仅包含权重)。
python -m maca_converter --model_path ./xxx --model_type pytorch --output ./unet.onnx --model_def_file ./unet.py --model_class_name Net --model_weights_file ./9_epoch_0.56322173.pth --input_shape [64,3,32,32]
参数说明:
model_path:PyTorch模型路径(此处可任意指定,因为这种场景下只有权重文件,没有模型)model_type:模型类型(此处固定为pytorch)output:目标模型的路径model_def_file:模型定义文件(必须和执行命令的路径在同一目录下)model_class_name:模型中定义的类别名称model_weights_file:模型权重文件的路径input_shape:模型的输入形状
5.1.3.8. PyTorch模型转ONNX模型(输入仅包含权重,且模型定义在Torchvision中)
操作步骤
执行以下命令,将PyTorch模型转为ONNX模型(输入仅包含权重,且模型定义在Torchvision中)。
python -m maca_converter --model_path ./xxx --model_type pytorch --output ./output.onnx --model_class_name torchvision.models.resnet50 --model_weights_file ./0.9696.pth --input_shape [16,3,256,256]
参数说明:
model_path:PyTorch模型路径(此处可任意指定,因为这种场景下只有权重文件,没有模型)model_type:模型类型(此处固定为pytorch)output:目标模型的路径model_class_name:模型中定义的类别名称input_shape:模型的输入形状
5.1.3.9. Darknet模型转ONNX模型
操作步骤
执行以下命令,将Darket模型转为ONNX模型。
python -m maca_converter --model_path ./my_model --model_type darknet --output ./output.onnx
参数说明:
model_path:Darknet模型路径(文件夹,需包含.cfg和.weights文件)model_type:模型类型(此处固定为darknet)output:目标模型的路径
5.1.3.10. PaddlePaddle模型转ONNX模型(输入包含权重和定义)
操作步骤
执行以下命令,将PaddlePaddle模型转为ONNX模型(输入包含权重和定义)。
python -m maca_converter --model_path ./paddle_model --model_type paddle --output ./output.onnx
参数说明:
model_path:PaddlePaddle模型路径(文件夹,需包含.pdmodel,.pdiparams.info和.pdiparams文件)model_type:模型类型(此处固定为paddle)output:目标模型的路径
5.1.3.11. PaddlePaddle模型转ONNX模型(输入仅包含权重)
操作步骤
执行以下命令,将PaddlePaddle模型转为ONNX模型(输入仅包含权重)。
python -m maca_converter --model_path ./xxx --model_type paddle --output ./paddle.onnx --model_def_file ./mnist.py --model_class_name LeNet --model_weights_file ./paddle_checkpoint/final.pdparams --input_shape [1,1,28,28]
参数说明:
model_path:PaddlePaddle模型路径(可任意指定,因为此场景下只有权重文件,没有模型)model_type:模型类型(此处固定为paddle)output:目标模型的路径model_def_file:模型定义文件(必须和执行命令的路径在同一目录下)model_class_name:模型中定义的类别名称model_weights_file:模型权重文件的路径input_shape:模型的输入形状
5.1.3.12. PaddlePaddle模型转ONNX模型(输入仅包含权重,模型在paddle.vision中定义)
操作步骤
执行以下命令,将PaddlePaddle模型转为ONNX模型(输入仅包含权重,模型在paddle.vision中定义)。
python -m maca_converter --model_path ./xxx --model_type paddle --output ./paddle.onnx --model_class_name paddle.vision.models.LeNet --model_weights_file ./final.pdparams --input_shape [1,1,28,28]
参数说明:
model_path:PaddlePaddle模型路径(此处可任意指定,因为这种场景下只有权重文件,没有模型)model_type:模型类型(此处固定为paddle)output:目标模型的路径model_class_name:模型中定义的类别名称model_weights_file:模型权重文件的路径input_shape:模型的输入形状
5.1.3.13. 动态Batch转换
操作步骤
执行以下命令,将BatchSize非动态的模型转换为动态模型。
python -m maca_converter --model_path ./caffe_model --model_type caffe --output ./output.onnx --dynamic_batch 1
5.1.3.14. ONNX简化
操作步骤
执行以下命令,对输入的模型进行常规优化(如常量折叠,Conv+BN融合等)。
python -m maca_converter --model_path ./test.onnx --model_type onnx --output ./output.onnx
备注
该功能默认打开。如需关闭,可加参数
–simplify 0。
5.1.3.15. FP32转FP16
操作步骤
执行以下命令,将模型中相关算子的输入类型由Float32改为Float16。
python -m maca_converter --model_path ./test.onnx --model_type onnx --output ./output.onnx --fp32_to_fp16 1
5.1.3.16. 子图提取
操作步骤
执行以下命令,按照给定的input/output,提取子图,保存模型。
python -m maca_converter --model_path ./test.onnx --model_type onnx --output ./output.onnx --extract_sub 1 --inputs input_1 --outputs functional_1/concatenate/concat
5.1.3.17. op_set版本转换
操作步骤
执行以下命令,转换ONNX模型的op_set版本。
python -m maca_converter --model_path ./test.onnx --model_type onnx --output ./output.onnx --op_set 13
5.1.3.18. Pad融合
操作步骤
执行以下命令,将模型中相邻的Pad+Pool组合,融合进Pool算子里。
python -m maca_converter --model_path ./test.onnx --model_type onnx --output ./output.onnx --fuse_pad_pool 1
5.1.3.19. Float32转Uint8(仅针对模型的input数据,非所有算子)
操作步骤
执行以下命令,将模型的输入类型由Float32改为Uint8。
python -m maca_converter --model_path ./test.onnx --model_type onnx --output ./output.onnx --fp32_to_u8 1
5.1.3.20. MatMul+Add融合为Gemm
操作步骤
执行以下命令,支持将模型中的Matmul+Add算子转换成Gemm算子(需要满足一定条件,内部会自动判断)。
python -m maca_converter --model_path ./test.onnx --model_type onnx --output ./output.onnx --matmul_to_gemm 1
备注
该功能默认打开。如需关闭,可加参数
–-matmul_to_gemm 0。
5.1.3.21. MHA融合
操作步骤
执行以下命令,支持将KQV组合融合成MultiHeadAttentionV1算子。
python -m maca_converter --model_path ./test.onnx --model_type onnx --output ./output.onnx --fuse_mha 1
备注
该功能默认打开。如需关闭,可加参数
–-fuse_mha 0。
5.2. MacaPrecision
GPU开发过程中,针对ONNX模型中每一个算子,需要验证其在GPU硬件上的计算结果是否正确,以保证相关算子软硬件实现的可靠性。MacaPrecision是用于保证整个流程完备性的精度对比工具。
MacaPrecision主要实现以下三个方面的功能:
逐层比较AI模型在GPU与CPU上的运行输出结果。
支持全量比较与指定节点比较两种方式。
单层计算结果的精度对比,支持SNR/Cosine/MSE三种方式。
5.2.1. 安装
MacaPrecision以wheel安装包的形式对外发布,建议在Conda环境中安装(建议Python版本为3.10)。 安装MacaRT后,可以在/opt/maca-ai/onnxruntime-maca/python/tools目录下找到MacaPrecision对应的Python安装包。
操作步骤
执行以下命令,安装MacaPrecision。
conda create -n maca_test python=3.10 source activate maca_test pip install onnxruntime_gpu-1.12.0+mc*.whl pip install maca_precision-*.whl
wheel包安装过程中会自动下载相关依赖库,主要有:
onnx
onnxruntime-gpu
numpy
5.2.2. 使用说明
MacaPrecision以CPU计算结果为基准,对比每一层的输出结果,误差超过一定范围,认为计算精度有误。具体流程如下:
加载ONNX模型。
解析ONNX模型,分析input变量,生成随机输入数据。
在CPU上运行模型,保存输出结果(output_cpu)。
在GPU上运行模型,保存输出结果(output_gpu)。
逐层比较output_cpu与output_gpu,如某一层的差值超过预设的阈值,则认为GPU计算精度存在问题,需要排查。
由于常规模型与量化模型在内部处理方式上存在差异,所以执行操作时需要区分常规模型与量化模型。
5.2.2.1. 常规模型(FP32/FP16)
全量模式
执行以下命令,在全量模式下进行常规模型推理。
python -m maca_precision -i ./test.onnx -c snr -t common -b 6
参数
-i指定需要测试的模型路径;参数
-c指定用于逐层对比的计算方法,支持snr/mse/cosine三种方式(可不指定,默认snr);参数
-t指定模型类型,此处固定为common;参数
-b指定每次比较的中间节点的个数,可不指定,默认为5(此处需要分批比较的原因是中间结果的参数量可能会比较大,如果直接全部比较会占用大量显存,如指定-1,则一次进行全量比较)。
全量模式下,会首先进行最后一层的比较,如果结果一致,则认为模型推理无异常,不会进行中间节点的比较。
指定模式
执行以下命令,在指定模式下进行常规模型推理。
python -m maca_precision -i ./test.onnx -c snr -t common -m Conv_0,Relu_1
参数 -m 指定需要比较的中间节点的名称,多个名称以逗号分隔。
指定模式下,无论最终的结果是否一致,都会进行指定的中间节点的比较。
5.2.2.2. 量化模型(经过MacaQuantizer量化后的模型)
量化模型的操作与常规模型基本一致,也分为全量模式和指定模式。指定模式下的节点,只能为量化节点。
唯一不同的是, -t 参数需要指定为 quantize。
例如:
python -m maca_precision –i ./test.onnx –t quantize -b 3
或
python -m maca_precision –i ./test.onnx –t quantize –m PPQ_Operation_152,PPQ_Operation_160
5.3. MacaQuantizer
MacaQuantizer是一个高效的神经网络量化工具,通过自定义的量化算子库、网络执行器、神经网络调度器、量化计算图等设计,即便在网络极度复杂的情况下,依然能够得到正确的网络量化结果。 量化过程中会通过读取配置参数文件,自动搜索最优的量化方案,同时量化中严格控制硬件模拟误差,保证硬件推理时的精度。
目前MacaQuantizer使用ONNX(opset 11~13)模型文件作为输入,覆盖常用的80余种ONNX算子类型。如果是PyTorch,TensorFlow等其他模型,可使用MacaConverter将模型转换为ONNX模型。
5.3.1. 安装
操作步骤
安装Python(建议版本为3.10)。
安装MacaRT后,可以在/opt/maca-ai/onnxruntime-maca/python/tools目录下找到MacaQuantizer对应的Python安装包。
执行以下命令,安装MacaQuantizer。
pip install maca_quantizer-xxxx-py3-none-any.whl
5.3.2. 使用说明
为了提高量化速度,MacaQuantizer 量化工具可以使用曦云系列GPU进行量化加速。使用曦云系列GPU可以加速量化过程中的重训练过程,提高量化速度。
默认采用曦云系列GPU进行加速计算。如果没有曦云系列GPU环境,可以使用CPU版本进行量化工具,通过设置以下环境变量来进行GPU版和CPU版切换。 环境变量设置为 0 时表示使用CPU版本进行加速计算,为 1 时表示使用曦云系列GPU进行加速计算。
export MACA_QUANTIZER_USING_MXGPU=0
运行MacaQuantizer之前,需要配置一个yaml格式的参数文件。格式如下所示:
import_model: /path/to/mode.onnx
export_model: /path/to/export_model.onnx
export_type: onnx
export_batch: 1
quant_algorithm: percentile
output_threshold: 0.1
without_bs: False
force_advance_quant: False
collecting_device: gpu
dataset:
calib_dir: /path/to/dataset/calibrate/
calib_num: 200
batch_size: 8
preprocessing:
enable: True
attributes:
isreverse: False
mean: [123.76, 116,28, 103,53]
std: [58.4, 57.12, 57.37]
resize:
keep_ratio: False
to: [3, 256, 256]
centercrop: [224, 224]
其中每个参数的说明,参见表 5.3。
参数 |
值 |
默认值 |
说明 |
|---|---|---|---|
import_model |
输入模型路径,目前只支持ONNX模型 |
||
export_model |
输出模型路径,目前只支持ONNX模型 |
||
export_type |
[onnx, native] |
onnx |
导出模型的类型 onnx:导出onnx qdq格式 native:导出qdq格式外,额外导出二进制的模型 |
quant_algorithm |
[percentile, minmax,mse, kl] |
percentile |
量化算法选择 |
export_batch |
[True, False] |
1 |
导出模型的BatchSize,默认为1 |
output_threshold |
0-1 |
0.1 |
量化后SNR误差最大允许范围 |
without_bs |
[True, False] |
False |
模型输入是否带有BatchSize维度 |
force_advance_quant |
[True, False] |
False |
是否量化过程中开启强制优化 |
calib_dir |
校准数据集的目录或dataset.txt路径。如果模型为多输入,仅支持dataset.txt文本格式,且数据为npy或二进制数据 |
||
calib_num |
[50-500] |
校准数据集的数量 |
|
batch_size |
量化计算时的BatchSize |
||
enable |
[True, False] |
是否对数据做预处理 False:校准数据需要是npy或二进制数据 |
|
isreverse |
[True, False] |
是否将图像通道RGB转为BGR |
|
mean |
预处理均值 |
||
std |
预处理方差。 |
||
keep_ratio |
[True, False] |
Resize是否保持等比例。 |
|
to |
Resize大小[chw]。 |
||
pad_value |
0 |
Resize边缘填充的值。 |
|
centercrop |
[True, False] |
False |
centercrop大小[h, w]。 如不需要centercrop,可删除该参数。 |
操作步骤
执行以下命令,运行模型量化。
python -m maca_quantizer -c quantize.yaml
参数说明:
-c/--config:yaml参数文件
5.3.2.1. 预处理说明
预处理流程如图 5.2 所示。
图 5.2 预处理流程
如果提供的预处理方案与模型的预处理方式不一致或无法满足要求时,可将预处理后的数据离线保存为npy或二进制格式,关闭数据读取时的预处理,直接读取预处理后的数据。
yaml示例如下所示:
import_model: /path/to/mode.onnx
export_model: /path/to/export_model.onnx
export_type: onnx
quant_algorithm: percentile
export_batch: 1
without_bs: False
force_advance_quant: False
dataset:
calib_dir: /path/to/dataset/calibrate/
calib_num: 200
batch_size: 8
preprocessing:
enable: False
5.3.2.2. dataset.txt文本格式说明
若输入 calib_dir 为dataset.txt文本格式,请参考如下格式。
单输入模型:只读取每行第一列参数(空格分割);
val/ILSVRC2012_val_00000001.JPEG 66 val/ILSVRC2012_val_00000002.JPEG 971 val/ILSVRC2012_val_00000003.JPEG 231 val/ILSVRC2012_val_00000004.JPEG 810 val/ILSVRC2012_val_00000005.JPEG 517 val/ILSVRC2012_val_00000006.JPEG 58 val/ILSVRC2012_val_00000007.JPEG 335 val/ILSVRC2012_val_00000008.JPEG 416 val/ILSVRC2012_val_00000009.JPEG 675
多输入模型:每一行为一个数据样本,输入空格分割。
1000000000_input_ids.npy 1000000000_input_mask.npy 1000000000_segment_ids.npy 1000000001_input_ids.npy 1000000001_input_mask.npy 1000000001_segment_ids.npy 1000000002_input_ids.npy 1000000002_input_mask.npy 1000000002_segment_ids.npy 1000000003_input_ids.npy 1000000003_input_mask.npy 1000000003_segment_ids.npy 1000000004_input_ids.npy 1000000004_input_mask.npy 1000000004_segment_ids.npy 1000000005_input_ids.npy 1000000005_input_mask.npy 1000000005_segment_ids.npy
5.3.3. 注意事项
目前只支持ONNX模型的量化,如果不是,建议量化前使用MacaConverter对模型进行转换。
目前只支持ONNX(opset 11~13)模型文件作为输入,如果不是,建议量化前使用MacaConverter对模型转换。
目前MacaQuantizer支持的算子参见表 5.4:
Gemm |
ReduceMean |
Sqrt |
grid_sampler |
ReduceSum |
Log |
GlobalAveragePool |
Relu |
Floor |
GlobalMaxPool |
Reshape |
RoiAlign |
Greater |
Resize |
MMCVRoiAlign |
LeakyRelu |
ScatterElements |
SpaceToDepth |
Less |
ScatterND |
DepthToSpace |
MatMul |
Shape |
Tanh |
Max |
Sigmoid |
Pow |
MaxPool |
Slice |
InstanceNormalization |
Min |
Softmax |
HardSigmoid |
Mul |
Softplus |
HardSwish |
NonMaxSuppression |
Split |
Neg |
NonZero |
Squeeze |
GRU |
Not |
Sub |
Swish |
Pad |
Tile |
Identity |
PRelu |
TopK |
OneHot |
Range |
Transpose |
Reciprocal |
ReduceL2 |
Unsqueeze |
Mish |
ReduceMax |
Where |
Elu |
Sum |
Erf |