MPolaris / onnx2tflite

Tool for onnx->keras or onnx->tflite. If tool is useful for you, please star it.

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

模型转换缺少conv3d算子

yuqilol opened this issue · comments

我的模型中含有3d卷积算子,转换模型无法解析这个算子,请问我要如何解决这个问题,是您这边更新3d卷积算子还是我在本地重构算子代码,如果我要在本地重构应该从哪着手,如果想要您这边更新3d算子我是否能提交算子函数。
Traceback (most recent call last):
File "/data1/home/pengyuling/onnx2tflite-main/easy_transfor.py", line 2, in
onnx_converter(
File "/data1/home/pengyuling/onnx2tflite-main/converter.py", line 21, in onnx_converter
keras_model = keras_builder(model_proto, native_groupconv)
File "/data1/home/pengyuling/onnx2tflite-main/utils/builder.py", line 82, in keras_builder
tf_tensor[node_outputs[index]] = tf_operator(tf_tensor, onnx_weights, node_inputs, op_attr, index=index)(_inputs)
File "/data1/home/pengyuling/onnx2tflite-main/layers/conv_layers.py", line 75, in init
self.conv = TFConv(in_channel, out_channel, kernel_shape, strides, dilations, pads, weights, bias)
File "/data1/home/pengyuling/onnx2tflite-main/layers/conv_layers.py", line 100, in init
self.conv3d_init(in_channel_num, out_channel_num, kernel_size, strides, dilations, pads, weights, bias, group)
File "/data1/home/pengyuling/onnx2tflite-main/layers/conv_layers.py", line 150, in conv3d_init
raise NotImplementedError("Conv3d is not implemented")
NotImplementedError: Conv3d is not implemented

你只需要新加入算子映射就好,你可以参照readme里面的添加HardSigmoid算子流程,在layers/conv_layers.py文件中加入相关实现即可。
另外在ONNX中,所有类型的卷积均被称为Conv,是通过weight.shape来区分Conv1d、Conv2d,通过group来区分是否是分组卷积(或者深度可分离卷积)。具体实现请查看这里的代码
最后,非常欢迎提交PR。

好的conv3d算子我已经添加成功,但是又出现了不可转换的算子depthwiseconv3d
conv3d具体的代码实现如下

class TFConv():
def init(self, in_channel_num, out_channel_num, kernel_size=1,
strides=1, dilations=1, pads=None, weights=None, bias=None, group=1):
super().init()
if len(weights.shape) == 3:
self.conv1d_init(in_channel_num, out_channel_num, kernel_size, strides, dilations, pads, weights, bias, group)
elif len(weights.shape) == 4:
self.conv2d_init(in_channel_num, out_channel_num, kernel_size, strides, dilations, pads, weights, bias, group)
elif len(weights.shape) == 5:
self.conv3d_init(in_channel_num, out_channel_num, kernel_size, strides, dilations, pads, weights, bias, group)
else:
raise NotImplementedError(f"Conv{len(weights.shape)-2}d is not implemented")

def conv1d_init(self, in_channel_num, out_channel_num, kernel_size=1, 
                strides=1, dilations=1, pads=None, weights=None, bias=None, group=1):
    self.pad =None
    if pads is not None and max(pads) == 1 and max(strides) == 1:
        self.conv = keras.layers.Conv1D(
            out_channel_num, kernel_size, strides, "SAME", use_bias=False if bias is None else True,
            weights=[weights] if bias is None else [weights, bias],
            dilation_rate=dilations, groups=group)
    else:
        self.conv = keras.layers.Conv1D(
            out_channel_num, kernel_size, strides, "VALID", use_bias=False if bias is None else True,
            weights=[weights] if bias is None else [weights, bias],
            dilation_rate=dilations, groups=group)
        if pads is not None and max(pads) != 0:
            self.pad = keras.layers.ZeroPadding1D(padding=pads)

def conv2d_init(self, in_channel_num, out_channel_num, kernel_size=1, 
                    strides=1, dilations=1, pads=None, weights=None, bias=None, group=1):
    if isinstance(dilations, int):
        dilations = (dilations, dilations)
    if isinstance(strides, int):
        strides = (strides, strides)
    if dilations[0] != 1 and strides[0] != 1:
        raise Exception("Currently, specifying any dilation_rate value != 1 is incompatible with specifying any stride value != 1.")

    self.pad =None
    if pads is not None and max(pads) == 1 and max(strides) == 1:
        self.conv = keras.layers.Conv2D(
            out_channel_num, kernel_size, strides, "SAME", use_bias=False if bias is None else True,
            weights=[weights] if bias is None else [weights, bias],
            dilation_rate=dilations, groups=group)
    else:
        self.conv = keras.layers.Conv2D(
            out_channel_num, kernel_size, strides, "VALID", use_bias=False if bias is None else True,
            weights=[weights] if bias is None else [weights, bias],
            dilation_rate=dilations, groups=group)
        if pads is not None and max(pads) != 0:
            padding = None
            if len(pads) == 2 and (pads[0] > 0 or pads[1] > 0):
                padding = (pads[0], pads[1])
            elif len(pads) == 4 and (pads[0] > 0 or pads[1] > 0 or pads[2] > 0 or pads[3] > 0):
                padding = ((pads[0], pads[2]), (pads[1], pads[3]))
            self.pad = keras.layers.ZeroPadding2D(padding=padding)

def conv3d_init(self, in_channel_num, out_channel_num, kernel_size=1,
                    strides=1, dilations=1, pads=None, weights=None, bias=None, group=1):
    if isinstance(dilations, int):
        dilations = (dilations, dilations, dilations)
    if isinstance(strides, int):
        strides = (strides, strides, strides)
    if dilations[0] != 1 and strides[0] != 1:
        raise Exception("Currently, specifying any dilation_rate value != 1 is incompatible with specifying any stride value != 1.")

    self.pad =None
    if pads is not None and max(pads) == 1 and max(strides) == 1:
        self.conv = keras.layers.Conv3D(
            out_channel_num, kernel_size, strides, "SAME", use_bias=False if bias is None else True,
            weights=[weights] if bias is None else [weights, bias],
            dilation_rate=dilations, groups=group)
    else:
        self.conv = keras.layers.Conv3D(
            out_channel_num, kernel_size, strides, "VALID", use_bias=False if bias is None else True,
            weights=[weights] if bias is None else [weights, bias],
            dilation_rate=dilations, groups=group)
        if pads is not None and max(pads) != 0:
            padding = None
            if len(pads) == 2 and (pads[0] > 0 or pads[1] > 0):
                padding = (pads[0], pads[1], 0)
            elif len(pads) == 6 and (pads[0] > 0 or pads[1] > 0 or pads[2] > 0 or pads[3] > 0 or pads[4] > 0 or pads[5] > 0):
                padding = ((pads[0], pads[3]), (pads[1], pads[4]), (pads[2], pads[5]))
            self.pad = keras.layers.ZeroPadding3D(padding=padding)

def __call__(self, inputs):
    if self.pad:
        inputs = self.pad(inputs)
    return self.conv(inputs)

depthwiseconv3d就是3d可分离卷积,目前tensorflow似乎没有支持3d可分离卷积,你可以使用group卷积来代替,请参考TFGroupConvTFDepthwiseConv类。
你开发测试完成欢迎提交一个PR。