昇腾故障案例详情页

算子dtype类型不一致报错

更新时间: 2023/05/24

暂无评分

问题信息

问题来源产品大类关键字
官方算子开发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算子无法排查。初步分析分析如下:

  1. 设置“export DUMP_GE_GRAPH=2”打开GE图,根据报错找到xxx-xxx-after_infershape.pbtxt图。
  2. 在图中找到报错算子,结构一般为:[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')
  3. 如还有下层算子的dtype类型不一致报错,可继续重复上述操作, 一般即可完成模型修改,不再影响om转换和离线推理。
  4. 如影响层数较多,且远大于onnx整网一半以上的 graph.initializer,可先对整网initializer全部修改,然后恢复成不影响部分。

以某项目中PyTorch onnx2om为例进行具体说明。

  1. 根据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.

  2. 由于内部动态shape的问题,om转换后生成的build图全是PartitionedCall节点,无法确定具体问题。

    如果模型不走动态shape或者内部不存在动态shape,便可在om图中直接观察到算子的dtype类型不一致。

  3. 使用 “export DUMP_GE_GRAPH=2 ”生成Dump图,在Dump图目录下找到ge_onnx_***_graph_0_after_infershape.pbtxt,可在GE图中确定在inftershape之后sub算子确实存在两个input,算子的dtype类型分别为int32和int64。

  4. 返回到原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')

  5. 修改完成后重新进行模型转换,依旧报错,利用onnxsim工具继续排查。

    onnxsim smoke.onnx models.onnx

  6. TopK算子输出不再插值cast,可以在模型转换的过程中看出有明显报错的div算子,继续进行问题分析。

    问题出现在div算子中Initializer的初始值为int64,使得div算子输出(即sub算子的上一层的输入)为int64, 而TopK算子为int32。

  7. 修改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')

  8. 重新进行模型转换后,推理成功。

本页内容

该页面对您有帮助吗?
我要评分