keras-onnx icon indicating copy to clipboard operation
keras-onnx copied to clipboard

set_converter not working for tf2.X

Open liob opened this issue 5 years ago • 6 comments

Hello,

I think set_converter is not working properly in tf.keras 2.2. Here is a minimal example:

#!/usr/bin/env python
# -*- coding: utf-8 -*-

import tensorflow as tf
import tensorflow.keras as keras
from tensorflow.keras.models import Model
from tensorflow.keras.layers import Input, Conv3D, Layer
import keras2onnx
from keras2onnx import set_converter


class MyDenseLayer(Layer):
    ''' https://www.tensorflow.org/tutorials/customization/custom_layers '''
    def __init__(self, num_outputs):
        super(MyDenseLayer, self).__init__()
        self.num_outputs = num_outputs

    def build(self, input_shape):
        self.kernel = self.add_weight("kernel",
                                  shape=[int(input_shape[-1]),
                                  self.num_outputs])

    def call(self, input):
        return tf.matmul(input, self.kernel)
    
    def get_config(self):
        config = {'num_outputs':  self.num_outputs}
        base_config = super(MyDenseLayer, self).get_config()
        return dict(list(base_config.items()) + list(config.items()))


# create model
input_tensor = Input(shape=(64, 64, 64, 1))
net = Conv3D(12, 3, activation='relu')(input_tensor)
net = MyDenseLayer(10)(net)
model = Model(input_tensor, net)


def convert_my_dense_layer(scope, operator, container):
    raise Exception('conversion function reached!')

set_converter(MyDenseLayer, convert_my_dense_layer)
onnx_model = keras2onnx.convert_keras(model, debug_mode=True)

I would expect, that the convert_my_dense_layer function is being called when encountering the MyDenseLayer instance during conversion. This is not the case.

Furthermore, the debug output is somewhat strange: If MyDenseLayer is not present in the model topology, than Conv3D is recognized as one unit:

Converting the operator (Identity): Identity Converting the operator (Identity1): Identity Converting the operator (Identity2): Identity Converting the operator (conv3d): <class 'tensorflow.python.keras.layers.convolutional.Conv3D'> Converting the operator (Identity3): Identity

If MyDenseLayer is present, than the log looks something like this:

Converting the operator (Identity): Identity Converting the operator (Identity1): Identity Converting the operator (Identity2): Identity Converting the operator (Identity3): Identity Converting the operator (model/my_dense_layer/MatMul): BatchMatMulV2 Converting the operator (model/conv3d/Relu): Relu Converting the operator (model/my_dense_layer/MatMul/ReadVariableOp): Identity Converting the operator (model/conv3d/BiasAdd): BiasAdd Converting the operator (model/my_dense_layer/MatMul/ReadVariableOp/resource): Const Converting the operator (model/conv3d/Conv3D): Conv3D Converting the operator (model/conv3d/BiasAdd/ReadVariableOp): Identity Converting the operator (model/conv3d/Conv3D/ReadVariableOp): Identity Converting the operator (model/conv3d/BiasAdd/ReadVariableOp/resource): Const Converting the operator (model/conv3d/Conv3D/ReadVariableOp/resource): Const Converting the operator (Identity4): Identity

liob avatar Jun 26 '20 00:06 liob

Yes, it's a known issue that the tf 2.x subclassed layer doesn't support the custom conversion, only tensorflow op could be converted in the custom mode.

wenbingl avatar Jun 26 '20 01:06 wenbingl

@wenbingl I have backported the custom layer to tf 1.15. I see the same behavior as in tf 2.2 (the graph disintegrates into tensorflow ops). Does this mean, that set_converter is only working with keras.io?

If this is the case, is there any other way to implement custom layers?

liob avatar Jul 23 '20 20:07 liob

with tf2.x, set_converter only supports to customize tf.op, with tf1.x, set_converter works on both tf.op and keras.layer. Is the above model source the issue happen?

wenbingl avatar Jul 23 '20 23:07 wenbingl

@wenbingl i did try to convert another dummy model. In this other model, I did use a tensorflow.keras.backend.zeros node. This did derail the conversion. After substituting the zeros node, the conversion function is being called. Sorry for the confusion.

liob avatar Jul 25 '20 22:07 liob

Do you have an idea what's necessary to support this? Changing the parser? Or are the keras layer converters not used at all for converting tf 2.2 models?

thoomi avatar Sep 21 '20 12:09 thoomi

@thoomi in the end, I was unable to achieve good results for my specific network topology and ended up writing my own custom onnx converter which works directly with tf.keras (2.x) layers: https://github.com/liob/naive_k2onnx

However, this is certainly not sustainable and I will switch to keras-onnx when there is an easy way to support custom tf.keras layers in 2.x.

liob avatar Sep 21 '20 15:09 liob