tensorflow 保存和加载使用多个输入和常数的RNN层Keras模型时,当使用model.predict()时会出现ValueError,

jhkqcmku  于 3个月前  发布在  其他
关注(0)|答案(4)|浏览(37)

系统信息

  • 是否编写了自定义代码(与使用TensorFlow提供的库存示例脚本相反):是
  • OS平台和发行版(例如,Linux Ubuntu 16.04):Windows 10
  • 如果问题发生在移动设备上:
  • 从哪里安装的TensorFlow(源代码或二进制文件):二进制
  • TensorFlow版本(请使用以下命令):2.3.0
  • Python版本:3.8.5
  • Bazel版本(如果从源代码编译):
  • GCC/编译器版本(如果从源代码编译):
  • CUDA/cuDNN版本:
  • GPU型号和内存:
    描述当前行为

当使用具有多个输入的RNN层以及常量输入时,使用H5文件格式将模型保存到磁盘并使用model.predict进行加载时,会出现以下情况:
`tensorflowpython\keras\engine\input_spec.py:155 assert_input_compatibility
raise ValueError('Layer ' + layer_name + ' expects ' +

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

描述预期行为

我希望在调用model.predict()时,对于某一组输入,结果相等(因此没有ValueError),然后再次保存和加载模型。

独立代码以重现问题

import numpy as np
import tensorflow as tf
from tensorflow import keras
from tensorflow.keras import layers

class RNNCellWithConstants(keras.layers.Layer):

  def __init__(self, units, constant_size, **kwargs):
    self.units = units
    self.state_size = units
    self.constant_size = constant_size
    super(RNNCellWithConstants, self).__init__(**kwargs)

  def build(self, input_shape):
    self.input_kernel = self.add_weight(
        shape=(input_shape[0][1], self.units),
        initializer='uniform',
        name='kernel')
    self.recurrent_kernel = self.add_weight(
        shape=(self.units, self.units),
        initializer='uniform',
        name='recurrent_kernel')
    self.constant_kernel = self.add_weight(
        shape=(self.constant_size, self.units),
        initializer='uniform',
        name='constant_kernel')
    self.built = True

  def call(self, inputs, states, constants):
    [x1, _] = inputs
    [prev_output] = states
    [constant] = constants
    h_input = keras.backend.dot(x1, self.input_kernel)
    h_state = keras.backend.dot(prev_output, self.recurrent_kernel)
    h_const = keras.backend.dot(constant, self.constant_kernel)
    output = h_input + h_state + h_const
    return output, [output]

  def get_config(self):
    config = {'units': self.units, 'constant_size': self.constant_size}
    base_config = super(RNNCellWithConstants, self).get_config()
    return dict(list(base_config.items()) + list(config.items()))

x1 = keras.Input((None, 5))
x2 = keras.Input((None, 5))
c = keras.Input((3,))
cell = RNNCellWithConstants(32, constant_size=3)
layer = keras.layers.RNN(cell)
y = layer((x1,x2), constants=c)

model = keras.models.Model([x1, x2, c], y)
model.compile(
    optimizer='rmsprop',
    loss='mse')
model.train_on_batch(
    [np.zeros((6, 5, 5)), np.zeros((6, 5, 5)), np.zeros((6, 3))],
    np.zeros((6, 32))
)

# Test basic case 
x1_np = np.random.random((6, 5, 5))
x2_np = np.random.random((6, 5, 5))
c_np = np.random.random((6, 3))
y_np = model.predict([x1_np, x2_np, c_np]) 

model.save("test.h5")
loaded_model = keras.models.load_model("test.h5", custom_objects={"RNNCellWithConstants":RNNCellWithConstants})
loaded_y_np = loaded_model.predict([x1_np, x2_np, c_np]) 
assert np.array_equal(y_np, loaded_y_np)

其他信息/日志

我也弄清楚了为什么会发生这种情况:Python的标准json编码器将列表和元组转换为数组,而解码器总是将数组转换为列表。当RNN 调用 函数接收到列表而不是元组时,以下行

full_input_spec = generic_utils.to_list(
            nest.map_structure(lambda _: None, inputs)) + additional_specs

将对此输入进行不同的Map,而不是如果是元组的话。
我将提交一个补丁来修复这个问题

kadbb459

kadbb4591#

我已经在Colab中尝试过TensorFlow版本2.3 gist,以及夜间版本gist,并能够重现这个问题。谢谢!

vmjh9lq9

vmjh9lq92#

我能够在tf 2.5上复现这个问题,请找到gist here

omtl5h9j

omtl5h9j3#

在Tf Nightly 2.6.0-dev20210528中,我成功复现了你的问题,请查看gist here。谢谢!

wwwo4jvm

wwwo4jvm4#

我能够在2.10v和tf-nightly版本中重现这个问题。
谢谢!

相关问题