leimao / Frozen-Graph-TensorFlow

Save, Load Frozen Graph and Run Inference From Frozen Graph in TensorFlow 1.x and 2.x
MIT License
300 stars 92 forks source link

如果是两个输入,请问full_model.get_concrete_function下的如何设置? #5

Closed jerry1993-tech closed 3 years ago

jerry1993-tech commented 4 years ago

这是我的模型:

class xbert_gru(tf.keras.models.Model):
    def __init__(self):
        super(gru, self).__init__()
        self.xbert_model = build_transformer_model(config_path,
                                                   checkpoint_path,
                                                   model='bert',
                                                   with_pool=False,          # 不提取CLS向量
                                                   return_keras_model=False  # 不返回keras的model结构
                                                   )
        self.gru_dense = GRU(units=384,
                    dropout=0.2,
                    recurrent_dropout=0.15,
                    return_sequences=True,
                    name='GRU-Dense'
                    )
        self.ave_pooing = GlobalAveragePooling1D(name='GlobalAveragePooling1D')

        self.x_out = Dense(168,
                      activation='softmax',
                      name='Out-Dense'
                      )
#     @tf.function(input_signature=(
#         [tf.TensorSpec(shape=(None,None), dtype=tf.float32), tf.TensorSpec(shape=(None,None), dtype=tf.float32)])
#                 )
    @tf.function
    def call(self, inputs):
        x = self.xbert_model.model([inputs[0], inputs[1]])
        x = self.gru_dense(x)
        x = self.ave_pooing(x)
        x = self.x_out(x)
        return x

我有两个点比较有疑问就是:

第一:tf.function()里面我改如何设置?这是我目前的设置:
full_model = tf.function(model)
第二: full_model.get_concrete_function( )里面我该如何设置输入层的两个输入的Tensor ? 这是我目前的设置:
full_model = full_model.get_concrete_function(
         tf.TensorSpec(model.inputs[0].shape, model.inputs[0].dtype),
         tf.TensorSpec(model.inputs[1].shape, model.inputs[0].dtype))

按照我目前的设置的报错:

TypeError: in converted code:

    /home/xuyingjie/.virtualenvs/py3venv/lib/python3.6/site-packages/tensorflow_core/python/keras/engine/base_layer.py:778 __call__  *
        outputs = call_fn(cast_inputs, *args, **kwargs)
    /home/xuyingjie/.virtualenvs/py3venv/lib/python3.6/site-packages/tensorflow_core/python/eager/def_function.py:568 __call__
        result = self._call(*args, **kwds)

    TypeError: tf__call() takes 2 positional arguments but 3 were given\

请大佬指点,谢谢啦!

leimao commented 4 years ago

https://github.com/leimao/Frozen_Graph_TensorFlow/blob/master/TensorFlow_v2/train.py#L55

Try something like:

    full_model = tf.function(lambda x1, x2: model(x1, x2))
    full_model = full_model.get_concrete_function(
        tf.TensorSpec(model.inputs[0].shape, model.inputs[0].dtype),
        tf.TensorSpec(model.inputs[1].shape, model.inputs[1].dtype))
jerry1993-tech commented 4 years ago

https://github.com/leimao/Frozen_Graph_TensorFlow/blob/master/TensorFlow_v2/train.py#L55

Try something like:

    full_model = tf.function(lambda x1, x2: model(x1, x2))
    full_model = full_model.get_concrete_function(
        tf.TensorSpec(model.inputs[0].shape, model.inputs[0].dtype),
        tf.TensorSpec(model.inputs[1].shape, model.inputs[1].dtype))

大神 ,谢谢你的指点,我试过了你给的方案,未成功。 报错:

ValueError: in converted code:

    <ipython-input-4-3b89b31dc50d>:71 None  *
        full_model = tf.function(lambda x1, x2: model(x1, x2))
    /home/xuyingjie/.virtualenvs/py3venv/lib/python3.6/site-packages/tensorflow_core/python/keras/engine/base_layer.py:737 __call__
        self.name)
    /home/xuyingjie/.virtualenvs/py3venv/lib/python3.6/site-packages/tensorflow_core/python/keras/engine/input_spec.py:155 assert_input_compatibility
        ' input tensors. Inputs received: ' + str(inputs))

    ValueError: Layer model_1 expects 2 inputs, but it received 1 input tensors. Inputs received: [<tf.Tensor 'x1:0' shape=(None, None) dtype=float32>]

是因为我的输入是一个list结构: x = self.xbert_model.model([inputs[0], inputs[1]]) ==> [inputs[0], inputs[1]]。 还请大神指点一下针对上述的情况这个如何写:

第一:tf.function()里面我改如何设置?
full_model = tf.function()
第二: full_model.get_concrete_function( )里面我该如何设置输入层的两个Tensor组成的list输入 ?
leimao commented 4 years ago

您好,抱歉回复的迟了。我手上现在没有很好的多inputs的简单例子,所以无法快速的帮你trouble shoot。但是我刚更新了一下代码,希望对你有所帮助。 https://github.com/leimao/Frozen_Graph_TensorFlow/blob/master/TensorFlow_v2/example_2.py 对于多输入的模型,我自己写了一个简单模型做了一下实验(但是没有训练数据进行模型训练),你可以尝试一下下面的方法

    full_model = tf.function(lambda x: model(x))
    full_model = full_model.get_concrete_function(
        x=(tf.TensorSpec(model.inputs[0].shape, model.inputs[0].dtype),
        tf.TensorSpec(model.inputs[1].shape, model.inputs[1].dtype)))
leimao commented 4 years ago

也请你在你的模型里面尝试一下,如果成功的话也请回复告知一下。

haifengkao commented 4 years ago

應該是這樣

    full_model = tf.function(lambda *x1: model(x1))
    full_model = full_model.get_concrete_function(
        tf.TensorSpec(model.inputs[0].shape, model.inputs[0].dtype),
        tf.TensorSpec(model.inputs[1].shape, model.inputs[1].dtype))

get_concrete_function可以接受多個參數,model只接受一個

leimao commented 3 years ago

應該是這樣

    full_model = tf.function(lambda *x1: model(x1))
    full_model = full_model.get_concrete_function(
        tf.TensorSpec(model.inputs[0].shape, model.inputs[0].dtype),
        tf.TensorSpec(model.inputs[1].shape, model.inputs[1].dtype))

get_concrete_function可以接受多個參數,model只接受一個

你我的方法应该是等价的。

zhaorookie commented 3 years ago

應該是這樣

    full_model = tf.function(lambda *x1: model(x1))
    full_model = full_model.get_concrete_function(
        tf.TensorSpec(model.inputs[0].shape, model.inputs[0].dtype),
        tf.TensorSpec(model.inputs[1].shape, model.inputs[1].dtype))

get_concrete_function可以接受多個參數,model只接受一個

你我的方法应该是等价的。

老哥,找到解决方法了吗,上面的方法都没有成功... 报错如下:

ValueError: Cannot call custom layer ex_model of type <class 'tensorflow.python.keras.saving.saved_model.load.ExModel'>, because the call function was not serialized to the SavedModel.Please try one of the following methods to fix this issue:

(1) Implement `get_config` and `from_config` in the layer/model class, and pass the object to the `custom_objects` argument when loading the model. For more details, see: https://www.tensorflow.org/guide/keras/save_and_serialize

(2) Ensure that the subclassed model or layer overwrites `call` and not `__call__`. The input shape and dtype will be automatically recorded when the object is called, and used when saving. To manually specify the input shape/dtype, decorate the call function with `@tf.function(input_signature=...)`.
zhaorookie commented 3 years ago

應該是這樣

    full_model = tf.function(lambda *x1: model(x1))
    full_model = full_model.get_concrete_function(
        tf.TensorSpec(model.inputs[0].shape, model.inputs[0].dtype),
        tf.TensorSpec(model.inputs[1].shape, model.inputs[1].dtype))

get_concrete_function可以接受多個參數,model只接受一個

你我的方法应该是等价的。

老哥,找到解决方法了吗,上面的方法都没有成功... 报错如下:

ValueError: Cannot call custom layer ex_model of type <class 'tensorflow.python.keras.saving.saved_model.load.ExModel'>, because the call function was not serialized to the SavedModel.Please try one of the following methods to fix this issue:

(1) Implement `get_config` and `from_config` in the layer/model class, and pass the object to the `custom_objects` argument when loading the model. For more details, see: https://www.tensorflow.org/guide/keras/save_and_serialize

(2) Ensure that the subclassed model or layer overwrites `call` and not `__call__`. The input shape and dtype will be automatically recorded when the object is called, and used when saving. To manually specify the input shape/dtype, decorate the call function with `@tf.function(input_signature=...)`.

搞定了,我这样写然后成功了

new_model = tf.saved_model.load('')
infer = new_model.signatures["serving_default"]

x_tensor_spec = tf.TensorSpec(shape=[None, 32, None, 1], dtype=tf.float32)
y_tensor_spec = tf.TensorSpec(shape=[None, None], dtype=tf.int32)  

full_model = tf.function(infer).get_concrete_function(inputs=x_tensor_spec, mask=y_tensor_spec)

forzen_func = convert_variables_to_constants_v2(full_model)
forzen_func.graph.as_graph_def()

tf.io.write_graph(
    graph_or_graph_def=forzen_func.graph,
    logdir="./",
    name="name.pb",
    as_text=False
)

其中inputs和mask可以saved_model_cli查看