是否可以在没有输入层的情况下在 Keras Functional API 中创建模型?

Is it possible to create a model in Keras Functional API without an input layer?

我想在 Keras 中创建一个包含 2 个卷积层、1 个展平层和 1 个密集层的模型。这将是一个具有共享权重的模型,因此没有任何预定义的输入层。

可以使用顺序方式:

model = tf.keras.models.Sequential()
model.add(tf.keras.layers.Conv2D(10,3,2,'valid',activation=tf.nn.relu))
model.add(tf.keras.layers.Conv2D(20,3,2,'valid',activation=tf.nn.relu))
model.add(tf.keras.layers.Flatten())
model.add(tf.keras.layers.Dense(200,activation=tf.nn.relu))

但是,使用函数 API,会产生类型错误:

model2 = tf.keras.layers.Conv2D(10,3,2,'valid',activation=tf.nn.relu)
model2 = tf.keras.layers.Conv2D(20,3,2,'valid',activation=tf.nn.relu)(model2)
model2 = tf.keras.layers.Flatten()(model2)
model2 = tf.keras.layers.Dense(200,activation=tf.nn.relu)(model2)

错误:

TypeError: Inputs to a layer should be tensors. Got: <tensorflow.python.keras.layers.convolutional.Conv2D object at 0x7fb060598100>

这是不可能的,还是我漏掉了什么?

keras 中的 linking 通过层传播 tensors 来工作。因此,在您的第二个示例中,开头 model2keras.layers.Layer 而不是 tf.Tensor 的实例,这就是您收到错误的原因。

Input 创建一个张量,然后可以将其用于 link 层。所以如果没有具体原因,你就加一个:

model2 = tf.keras.layers.Input((10,3,2))
model2 = tf.keras.layers.Conv2D(10,3,2,'valid',activation=tf.nn.relu)(model2)

keras sequential api 旨在更易于使用,因此不如函数 api 灵活。这样做的好处是输入的 'layer' 形状可以根据您传递给它的任何形状的数据自动推断出来。缺点是这个更容易使用的模型被简化了,所以你不能做像使用多个输入这样的事情。

来自 keras 文档:

A Sequential model is not appropriate when:

  • Your model has multiple inputs or multiple outputs
  • Any of your layers has multiple inputs or multiple outputs
  • You need to do layer sharing
  • You want non-linear topology (e.g. a residual connection, a multi-branch model)

函数式 api 设计得更灵活,即多个输入,因此它不会为您进行任何类型的自动推理,因此会出现错误。在这种情况下,您必须显式传递一个输入层。对于您的用例,它不会自动推断形状可能看起来很奇怪,但是当您考虑更广泛的用例场景时,它是有道理的。

所以第二种情况应该是:

model2 = tf.keras.layers.Input((10,3,2)) # specified input layer
model2 = tf.keras.layers.Conv2D(10,3,2,'valid',activation=tf.nn.relu)(model2)
model2 = tf.keras.layers.Conv2D(20,3,2,'valid',activation=tf.nn.relu)(model2)
model2 = tf.keras.layers.Flatten()(model2)
model2 = tf.keras.layers.Dense(200,activation=tf.nn.relu)(model2)

更新

如果您想创建两个单独的模型并将它们连接在一起,您应该使用函数 API,然后由于它的限制,您必须使用输入层。所以你可以这样做:

import tensorflow as tf
from tensorflow.keras.layers import Input, Flatten, Dense, concatenate, Conv2D
from tensorflow.keras.models import Model

input1 = Input((10,3,2))
model1 = Dense(200,activation=tf.nn.relu)(input1)

input2 = Input((10,3,2))
model2 = Dense(200,activation=tf.nn.relu)(input2)

merged = concatenate([model1, model2])

merged = Conv2D(10,3,2,'valid',activation=tf.nn.relu)(merged)
merged = Flatten()(merged)
merged = Dense(200,activation=tf.nn.relu)(merged)

model = Model(inputs=[input1, input2], outputs=merged)

上面我们有两个单独的输入,然后是两个密集层 - 您可以根据需要构建这些单独的线,然后将它们合并在一起以通过卷积层传递它们,您需要使用 tf.keras.layers.concatenate层,然后您可以从那里继续联合模型。将整个事物包装在模型对象中,然后允许您访问训练和推理方法,如 fit/predict 等