如何使用可选输入创建 Keras 模型
Posted
技术标签:
【中文标题】如何使用可选输入创建 Keras 模型【英文标题】:How to create Keras model with optional inputs 【发布时间】:2019-03-04 01:21:27 【问题描述】:我正在寻找一种方法来创建带有可选输入的 Keras 模型。在原始 TensorFlow 中,您可以使用可选输入创建占位符,如下所示:
import numpy as np
import tensorflow as tf
def main():
required_input = tf.placeholder(
tf.float32,
shape=(None, 2),
name='required_input')
default_optional_input = tf.random_uniform(
shape=(tf.shape(required_input)[0], 3))
optional_input = tf.placeholder_with_default(
default_optional_input,
shape=(None, 3),
name='optional_input')
output = tf.concat((required_input, optional_input), axis=-1)
with tf.Session() as session:
with_optional_input_output_np = session.run(output, feed_dict=
required_input: np.random.uniform(size=(4, 2)),
optional_input: np.random.uniform(size=(4, 3)),
)
print(f"with optional input: with_optional_input_output_np")
without_optional_input_output_np = session.run(output, feed_dict=
required_input: np.random.uniform(size=(4, 2)),
)
print(f"without optional input: without_optional_input_output_np")
if __name__ == '__main__':
main()
以类似的方式,我希望能够为我的 Keras 模型提供可选输入。似乎keras.layers.Input.__init__ 中的tensor
参数可能是我正在寻找的,但至少它不像我预期的那样工作(即与上面显示的tf.placeholder_with_default
相同)。这是一个打破的例子:
import numpy as np
import tensorflow as tf
import tensorflow_probability as tfp
def create_model(output_size):
required_input = tf.keras.layers.Input(
shape=(13, ), dtype='float32', name='required_input')
batch_size = tf.shape(required_input)[0]
def sample_optional_input(inputs, batch_size=None):
base_distribution = tfp.distributions.MultivariateNormalDiag(
loc=tf.zeros(output_size),
scale_diag=tf.ones(output_size),
name='sample_optional_input')
return base_distribution.sample(batch_size)
default_optional_input = tf.keras.layers.Lambda(
sample_optional_input,
arguments='batch_size': batch_size
)(None)
optional_input = tf.keras.layers.Input(
shape=(output_size, ),
dtype='float32',
name='optional_input',
tensor=default_optional_input)
concat = tf.keras.layers.Concatenate(axis=-1)(
[required_input, optional_input])
dense = tf.keras.layers.Dense(
output_size, activation='relu')(concat)
model = tf.keras.Model(
inputs=[required_input, optional_input],
outputs=[dense])
return model
def main():
model = create_model(output_size=3)
required_input_np = np.random.normal(size=(4, 13))
outputs_np = model.predict('required_input': required_input_np)
print(f"outputs_np: outputs_np")
required_input = tf.random_normal(shape=(4, 13))
outputs = model('required_input': required_input)
print(f"outputs: outputs")
if __name__ == '__main__':
main()
第一次调用model.predict
似乎给出了正确的输出,但由于某种原因,直接调用模型失败并出现以下错误:
ValueError:层模型需要 2 个输入,但它接收到 1 个输入张量。收到的输入:[]
Input.__init__
中的 tensor
参数能否用于实现 Keras 模型的可选输入,如我上面的示例所示?如果是,我应该在我的示例中进行哪些更改以使其正确运行?如果不是,在 Keras 中创建可选输入的预期方式是什么?
【问题讨论】:
您找到解决方案了吗?我正在努力解决类似的问题***.com/q/57307107/9318372 出于好奇,如果您尝试传递包含[x_train, None]
的输入列表会发生什么?这会骗走 Keras 吗?
【参考方案1】:
我真的认为没有变通办法是不可能的。 Keras 不是为此而生的。
但是,注意到您在每种情况下都使用了两个不同的session.run
命令,看来使用两个模型应该很容易做到这一点。一种模型使用可选输入,另一种则不使用。您选择要使用的方法与选择要调用的 session.run()
相同。
也就是说,您可以使用Input(tensor=...)
或简单地在Lambda
层内创建可选输入。两件事都很好。但是不要使用Input(shape=..., tensor=...)
,这些是多余的参数,有时 Keras 不能很好地处理这样的冗余。
理想情况下,将所有操作保留在 Lambda
层内,即使是 tf.shape
操作。
也就是说:
required_input = tf.keras.layers.Input(
shape=(13, ), dtype='float32', name='required_input')
#needs the input for the case you want to pass it:
optional_input_when_used = tf.keras.layers.Input(shape=(output_size,))
#operations should be inside Lambda layers
batch_size = Lambda(lambda x: tf.shape(x)[0])(required_input)
#updated for using the batch size coming from lambda
#you didn't use "inputs" anywhere in this function
def sample_optional_input(batch_size):
base_distribution = tfp.distributions.MultivariateNormalDiag(
loc=tf.zeros(output_size),
scale_diag=tf.ones(output_size),
name='sample_optional_input')
return base_distribution.sample(batch_size)
#updated for using the batch size as input
default_optional_input = tf.keras.layers.Lambda(sample_optional_input)(batch_size)
#let's skip the concat for now - notice I'm not "using" this layer yet
dense_layer = tf.keras.layers.Dense(output_size, activation='relu')
#you could create the rest of the model here if it's big, so you don't create it twice
#(check the final section of this answer)
使用传递输入的模型:
concat_when_used = tf.keras.layers.Concatenate(axis=-1)(
[required_input, optional_input_when_used]
)
dense_when_used = dense_layer(concat_when_used)
#or final_part_of_the_model(concat_when_used)
model_when_used = Model([required_input, optional_input_when_used], dense_when_used)
模型不使用可选输入:
concat_not_used = tf.keras.layers.Concatenate(axis=-1)(
[required_input, default_optional_input]
)
dense_not_used = dense_layer(concat_not_used)
#or final_part_of_the_model(concat_not_used)
model_not_used = Model(required_input, dense_not_used)
这样创建两个模型并选择一个使用是可以的(两个模型共享最终层,因此它们将始终一起训练)
现在,在您选择哪个session.run
时,现在您将选择要使用的模型:
model_when_used.predict([x1, x2])
model_when_used.fit([x1,x2], y)
model_not_used.predict(x)
model_not_used.fit(x, y)
如何创建共享的最终部件?
如果您的最终部分很大,您将不希望调用所有内容两次来创建两个模型。在这种情况下,首先创建一个最终模型:
input_for_final = Input(shape_after_concat)
out = Dense(....)(input_for_final)
out = Dense(....)(out)
out = Dense(....)(out)
.......
final_part_of_the_model = Model(input_for_final, out)
然后在上一个答案中使用这最后一部分。
dense_when_used = final_part_of_the_model(concat_when_used)
dense_not_used = final_part_of_the_model(concat_not_used)
【讨论】:
以上是关于如何使用可选输入创建 Keras 模型的主要内容,如果未能解决你的问题,请参考以下文章