前端转换
本章以 onnx 模型为例介绍模型/算子在本工程中的前端转换流程。
主要工作
前端主要负责将原始模型转换为 Top 层(芯片无关层)mlir 模型的工作(不包含 Canonicalize 部分, 因
此生成的文件名为“*_origin.mlir”), 这个过程会根据原始模型与运行 model_transform.py 时输入的参数逐
一创建并添加对应的算子(Op), 最终生成 mlir 文件与保存权重的 npz 文件。
工作流程
前提(Prereq): Top 层算子定义, 该部分内容保存在 TopOps.td 文件
输入(Input): 输入原始 onnx 模型与参数(主要是预处理参数)
初始化 OnnxConverter(load_onnx_model + initMLIRImporter)
load_onnx_model 部分主要是对模型进行精简化, 根据 arguments 中的 output_names 截取模型, 并提取精简后模型的相关信息
init_MLIRImporter 部分主要是生成初始的 mlir 文本
generate_mlir
输出(Output)
将精简后的模型保存为“*_opt.onnx”文件
生成”.prototxt”文件保存除权重外的模型信息
将生成的文本转为 str 并保存为“.mlir”文件
将模型权重(tensors)保存为“.npz”文件
前端转换的工作流程如图所示(前端转换流程)。
- 补充说明:
-
Build input op 需要:
input_names
每个 input 对应的 index
预处理参数(若输入为图像)
Convert nodes op 需要:
从 operands 获取该 node 的输入 op(即前一个已经 build 或 convert 好的算子)
从 shapes 中获取 output_shape
从 onnx node 中提取的 attrs。Attrs 会通过 MLIRImporter 设定为与 TopOps.td 定义一一对应的属性
Build return op 需要:
依照 output_names 从 operands 获取相应的 op
每创建或者转换一个算子都会执行一次插入操作, 将算子插入到 mlir 文本中, 使最终生成的文本能从头到尾与原 onnx 模型一一对应
算子转换样例
本节以 Conv 算子为例, 将单 Conv 算子的 onnx 模型转换为 Top mlir, 原模型如图所示(单 Conv 模型)
转换流程为:
算子定义
在 TopOps.td 中定义 Top.Conv 算子, 算子定义如图所示(Conv 算子定义)
初始化 OnnxConverter
load_onnx_model:
由于本例使用的是最简模型, 所以生成的 Conv_opt.onnx 模型与原模型相同。
input_names 保存了 Conv 算子的输入名“input”
tensors 中保存了 Conv 算子的权重 weight 与 bias
shapes 中保存了Conv算子的输入和输出shape。
output_names 中保存了 Conv 算子的输出名“output”
init_MLIRImporter:
根据 input_names 与 output_names 从 shapes 中获取了对应的 input_shape 与 output_shape, 加上model_name, 生成了初始的 mlir 文本 MLIRImporter.mlir_module, 如图所示(初始 mlir 文本)。
generate_mlir
build input op, 生成的 Top.inputOp 会被插入到 MLIRImporter.mlir_module 中。
根据 node.op_type (即“ Conv ”) 调用 convert_conv_op() , 该函数中会调用MLIRImporter.create_conv_op 来创建 ConvOp, 而 create 函数需要的参数有:
输入 op: 从(单 Conv 模型)可知, Conv 算子的 inputs 一共包含了 input, weight 与 bias, inputOp 已被创建好, weight 与 bias 的 op 则通过 getWeightOp()创建。
output_shape: 利用 onnx_node.name 从 shapes 中获取 Conv 算子的输出shape。
Attributes: 从 onnx Conv 算子中获取如(单 Conv 模型)中的 attributes。
在 create 函数里 Top.Conv 算子的 attributes 会根据(Conv 算子定义)中的定义来设定。Top.ConvOp 创建后会被插入到 mlir 文本中
根据 output_names 从 operands 中获取相应的 op, 创建 return_op 并插入到 mlir 文本中。到此为止, 生成的 mlir 文本如图所示(完整的 mlir 文本)。
输出
将 mlir 文本保存为 Conv_origin.mlir, tensors 中的权重保存为 Conv_TOP_F32_all_weight.npz。