resnet/dssm/roformer修改onnx节点

文章介绍了针对resnet101和dssm_part模型的内部节点修改方法,包括解决因动态shape导致的Segmentationfault错误,通过合并pad和max_pool2d节点,以及将Initializer类型的常量转换为Constant节点来消除精度问题。此外,还提到了模型切图用于定位精度问题和修改Roformer模型输入类型以适应不同数据类型的方法。
摘要由CSDN通过智能技术生成

目录

resnet101 修改内部节点

dssm_part 修改内部节点

修改前:

修改后:

其他解决方案:

resnet101 切图

roformer 输入修改

切图


resnet101 修改内部节点

文件链接:https://1drv.ms/u/s!ArOkNLeDa1G_iivsT-9z0uHyzVtH?e=bbb4gD

运行测试文件出现 Segmentation fault (core dumped) 错误,查看 relay 发现是 dyn.nn.pad 导致动态 shape 所致

手动修改 onnx 模型,将 pad 和 下面的 max_pool2d 合并,问题解决

model = onnx.load("resnet101_keras.onnx")

graph = model.graph

node = graph.node

"""

op_type (string): The name of the operator to construct

inputs (list of string): list of input names

outputs (list of string): list of output names

name (string, default None): optional unique identifier for NodeProto

doc_string (string, default None): optional documentation string for NodeProto

domain (string, default None): optional domain for NodeProto.

                If it's None, we will just use default domain (which is empty)

**kwargs (dict): the attributes of the node.  The acceptable values

                are documented in :func:`make_attribute`.

"""

new_maxPool_node = onnx.helper.make_node(

    op_type="MaxPool",

    inputs=["relu0/Relu:0"],

    outputs=["zero_padding2d_2/Pad:0_pooling0"],

    strides=[2,2],

    kernel_shape=[3,3],

    pads=[1,1,1,1],

    )

graph.node.remove(old_pad_node)

graph.node.remove(old_maxPool_node)

graph.node.insert(4, new_maxPool_node)

onnx.checker.check_model(model)

onnx.save(model, "resnet101_keras_modified.onnx")

dssm_part 修改内部节点

文件链接:https://1drv.ms/u/s!ArOkNLeDa1G_iixncRNKGJJuMc67?e=W05D6D

报错 Check failed: (false) is false: relay.concatenate requires all tensors have the same dtype,查看 relay 发现 dyn.tile 产生了动态 shape

修改 onnx 模型,将 Initializer 类型常量改为 Constant 类型图节点,问题解决

修改前:

修改后:

import onnx

model = onnx.load("./test_dssm_part.onnx")

graph = model.graph

node = graph.node

# initializer = graph.initializer

# print("============ initializer[1] ============")

# print(initializer[1])

# print("============ initializer[2]============")

# print(initializer[2])

  

# old_const_fold_opt__23 = initializer[1]

# old_const_fold_opt__22 = initializer[2]

# """

# make_tensor(name, data_type, dims, vals, raw=False)

#     Make a TensorProto with specified arguments.  If raw is False, this

#     function will choose the corresponding proto field to store the

#     values based on data_type. If raw is True, use "raw_data" proto

#     field to store the values, and values should be of type bytes in

#     this case.

# """

# new_const_fold_opt__23 = onnx.helper.make_tensor(

#     name="const_fold_opt__23",

#     data_type=onnx.TensorProto.INT64,

#     dims=[4],

#     vals=b"\001\000\000\000\000\000\000\000\001\000\000\000\000\000\000\000\031\000\000\000\000\000\000\000\001\000\000\000\000\000\000\000"

#     raw=True,

#     )

  

# graph.node.remove(old_const_fold_opt__23)

# graph.node.insert(1, new_const_fold_opt__23)

print("============ node[12] ============")

print(node[12])

print("============ node[34] ============")

print(node[34])

old_tile_1 = node[12]

old_tile = node[34]

"""

op_type (string): The name of the operator to construct

inputs (list of string): list of input names

outputs (list of string): list of output names

name (string, default None): optional unique identifier for NodeProto

doc_string (string, default None): optional documentation string for NodeProto

domain (string, default None): optional domain for NodeProto.

        If it's None, we will just use default domain (which is empty)

**kwargs (dict): the attributes of the node.  The acceptable values

        are documented in :func:`make_attribute`.

"""

new_tile_const = onnx.helper.make_node(

    name = "tile_const",

    op_type="Constant",

    inputs=[],

    outputs=["tile_const:0"],

    value=onnx.helper.make_tensor(

        'value',

        onnx.TensorProto.INT64,

        [4],

        b"\001\000\000\000\000\000\000\000\001\000\000\000\000\000\000\000\031\000\000\000\000\000\000\000\001\000\000\000\000\000\000\000",

        raw=True)

    )

new_tile = onnx.helper.make_node(

    name="Tile",

    op_type="Tile",

    inputs=["Reshape_1:0""tile_const:0"],

    outputs=["Tile:0"],

)

graph.node.remove(old_tile)

graph.node.insert(34, new_tile)

graph.node.insert(34, new_tile_const)

new_tile_1_const = onnx.helper.make_node(

    name = "tile_1_const",

    op_type="Constant",

    inputs=[],

    outputs=["tile_1_const:0"],

    value=onnx.helper.make_tensor(

        'value',

        onnx.TensorProto.INT64,

        [3],

        b"\001\000\000\000\000\000\000\000\001\000\000\000\000\000\000\000\001\000\000\000\000\000\000\000",

        raw=True)

    )

new_tile_1 = onnx.helper.make_node(

    name="Tile_1",

    op_type="Tile",

    inputs=["ExpandDims:0""tile_1_const:0"],

    outputs=["Tile_1:0"],

)

graph.node.remove(old_tile_1)

graph.node.insert(12, new_tile_1)

graph.node.insert(12, new_tile_1_const)

onnx.checker.check_model(model)

onnx.save(model, "./test_dssm_part_modified.onnx")

其他解决方案:

from_onnx 中添加参数 freeze_params=True

mod, params = relay.frontend.from_onnx(graph_def, shape=input_shape, freeze_params=True)

resnet101 切图

文件链接:https://1drv.ms/u/s!ArOkNLeDa1G_ii310CmCT6y6rXW0?e=q9E7O6

resnet101 编译成 stcobj 后,给定同样的输入,输出的内容有差异。为定位该精度问题,对 onnx 模型进行切图操作,通过指定新的 output 节点,对比输出内容来判断出错节点。切图输出示例:

正在上传…重新上传取消

def cut_onnx_model():

    model = onnx.load(model_path_modified_onnx)

    new_output = onnx.helper.make_tensor_value_info("output"1, ['N'3224224])

    LAST_NODE_IDX = 1

    model.graph.output[0].CopyFrom(new_output)

    model.graph.node[LAST_NODE_IDX].CopyFrom(

        onnx.helper.make_node(

            name="xxx",

            op_type="BatchNormalization",

            inputs=["data:01_transposed","scale101","bias101","mean101","var101"],

            outputs=["output"],

            epsilon=1.999999987845058e-08,

            momentum=0.9900000095367432,

            domain=""

        )

    )

    for in range(len(model.graph.node)-1, LAST_NODE_IDX, -1):

        = model.graph.node[i]

        model.graph.node.remove(n)

     

    onnx.checker.check_model(model)

    onnx.save(model, model_path_cut_onnx)

roformer 输入修改

输入 input_token 为 float16,转 int 出现精度问题,手动修改模型输入接受 int32 类型的 input_token

def modify_onnx_model(model_path):

    print("====================== modify onnx model ======================")

    model_path_modified = "model_zoo/models/roformer/open_roformer-tf-fp32_modified.onnx"

    model = onnx.load(model_path)

    graph = model.graph

    node = graph.node

    model.graph.input[1].type.tensor_type.elem_type = onnx.TensorProto.INT32

    old_cast = node[9]

    old_gather = node[13]

    old_equal = node[0]

    new_gather = onnx.helper.make_node(

        op_type="Gather",

        inputs=["Func/StatefulPartitionedCall/input/_2:0""input_token:0"],

        outputs=["StatefulPartitionedCall/model_1/Embedding-Token/embedding_lookup:0"],

        name="StatefulPartitionedCall/model_1/Embedding-Token/embedding_lookup",

        axis=0,

    )

    old_gather.CopyFrom(new_gather)

    new_cast = onnx.helper.make_node(

        op_type="Cast",

        inputs=["input_token:0"],

        outputs=["StatefulPartitionedCall/model_1/Embedding-Token/Cast:0"],

        name="StatefulPartitionedCall/model_1/Embedding-Token/Cast",

        to=onnx.TensorProto.FLOAT,

    )

    old_cast.CopyFrom(new_cast)

    new_equal = onnx.helper.make_node(

        op_type="Equal",

        inputs=["StatefulPartitionedCall/model_1/Embedding-Token/Cast:0""zero_reduce__65"],

        outputs=["StatefulPartitionedCall/model_1/Embedding-Token/NotEqual:0"],

        name="StatefulPartitionedCall/model_1/Embedding-Token/NotEqual",

    )

    old_equal.CopyFrom(new_equal)

    new_cast = node[9]

    node.remove(new_cast)

    node.insert(0, new_cast)

    onnx.checker.check_model(model)

    onnx.save(model, model_path_modified)

    return model_path_modified

切图

onnx.utils.extract_model(

        model_path,

        model_path2,

        ["input_segment:0""input_token:0"],

        ["StatefulPartitionedCall/model_1/Embedding-Norm/sub:0"]

    )

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

想要好好撸AI

你的鼓励就是我最大的创作动力!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值