算子dtype类型不一致报错
2023/05/24
765
问题信息
问题来源 | 产品大类 | 关键字 |
---|---|---|
官方 | 算子开发 | TopK算子、dtype类型 |
问题现象描述
在执行onnx2om进行模型导出时报错“op[xxx], The xxx op dtype is not same, type1:xxx, type2:xxx”。
onnx模型转换成om模型后,执行模型推理失败,报错提示为“Aicpu kernel execute failed”。
原因分析
目前版本中TopK算子的数据类型仅支持int32,而TopK算子下层算子Initializer值一般为int64,这就导致下层算子在inftershape阶段后进行数据类型校验报错。
可以根据onnx图快速定位报错算子的上层输入为TopK算子,算子dtype类型不一致。
解决措施
涉及动态shape的模型,可先将shape固定后再进行问题排查,防止报错后GE图中原始框架中的算子映射成PartitionedCall算子无法排查。初步分析分析如下:
- 设置“export DUMP_GE_GRAPH=2”打开GE图,根据报错找到xxx-xxx-after_infershape.pbtxt图。
- 在图中找到报错算子,结构一般为:[xxx] --> [topK] --> [报错算子], 确定后对onnx进行修改。
import onnx onnx_model = onnx.load('model.onnx') graph = onnx_model.graph for initializer in graph.initializer: if initializer.name == 'xxx': #找到init所在的node节点名,在onnx图中可以确定 initializer.data_type = 6 #6是代表int32 onnx.save(onnx_model, 'model_fix.onnx')
- 如还有下层算子的dtype类型不一致报错,可继续重复上述操作, 一般即可完成模型修改,不再影响om转换和离线推理。
- 如影响层数较多,且远大于onnx整网一半以上的 graph.initializer,可先对整网initializer全部修改,然后恢复成不影响部分。
以某项目中PyTorch onnx2om为例进行具体说明。
- 根据Device侧debug日志可知报错sub算子的输入dtype一个是int32, 一个是int64,如下图所示。
[ERROR] AICPU(15590,aicpu_scheduler): [sub.cc:63][AICPU][DoCompute:63][tid:15601]:Input[x1] data type[DT_INT32] and input[x2] data type[DT_INT64] must be same.
- 由于内部动态shape的问题,om转换后生成的build图全是PartitionedCall节点,无法确定具体问题。
如果模型不走动态shape或者内部不存在动态shape,便可在om图中直接观察到算子的dtype类型不一致。
- 使用 “export DUMP_GE_GRAPH=2 ”生成Dump图,在Dump图目录下找到ge_onnx_***_graph_0_after_infershape.pbtxt,可在GE图中确定在inftershape之后sub算子确实存在两个input,算子的dtype类型分别为int32和int64。
- 返回到原ONNX图中查看,可以确定TopK算子的dtype类型为int32, 而向上排查需要将gather算子的init初始值修改为int32,与TopK算子保持一致。
import onnx onnx_model = onnx.load('smoke.onnx') graph = onnx_model.graph for initializer in graph.initializer: if initializer.name == '1113': #找到init所在的node节点名 initializer.data_type = 6 #6是代表int32 onnx.save(onnx_model, 'dynamic_model_fix.onnx')
- 修改完成后重新进行模型转换,依旧报错,利用onnxsim工具继续排查。
onnxsim smoke.onnx models.onnx
- TopK算子输出不再插值cast,可以在模型转换的过程中看出有明显报错的div算子,继续进行问题分析。
问题出现在div算子中Initializer的初始值为int64,使得div算子输出(即sub算子的上一层的输入)为int64, 而TopK算子为int32。
- 修改Div算子的Initializer初始值;使得Div算子的dtype类型为int32,TopK算子的dtype类型也为int32,在sub算子上的两个输入经过校验能确定为一致了。
import onnx onnx_model = onnx.load('dynamic_model_fix_1212.onnx') graph = onnx_model.graph onnx_model.graph.output[0].type.tensor_type.shape.dim[0].dim_param = '?' #修改输出dim0为动态 #参考issue[https://github.com/onnx/onnx/issues/654] for initializer in graph.initializer: if initializer.name == '1114': initializer.data_type = 6 onnx.save(onnx_model, 'models_1212_fixed_div.onnx')
- 重新进行模型转换后,推理成功。
本页内容