系统信息
- 是否编写了自定义代码(与使用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,而不是如果是元组的话。
我将提交一个补丁来修复这个问题
4条答案
按热度按时间kadbb4591#
我已经在Colab中尝试过TensorFlow版本2.3 gist,以及夜间版本gist,并能够重现这个问题。谢谢!
vmjh9lq92#
我能够在tf 2.5上复现这个问题,请找到gist here。
omtl5h9j3#
在Tf Nightly 2.6.0-dev20210528中,我成功复现了你的问题,请查看gist here。谢谢!
wwwo4jvm4#
我能够在2.10v和tf-nightly版本中重现这个问题。
谢谢!