密集层 Keras 中的输出维度

Dimension of output in Dense layer Keras

我有以下型号的样品

from tensorflow.keras import models
from tensorflow.keras import layers

sample_model = models.Sequential()
sample_model.add(layers.Dense(32, input_shape=(4,)))
sample_model.add(layers.Dense(16, input_shape = (44,)))

sample_model.compile(loss="binary_crossentropy",
                     optimizer="adam", metrics = ["accuracy"])

模型的IP:

sam_x = np.random.rand(10,4)
sam_y = np.array([0,1,1,0,1,0,0,1,0,1,])
sample_model.fit(sam_x,sam_y)

令人困惑的是 fit 应该抛出 shape mismatch 错误,因为 2nd Dense Layerexpected_input_shape 给出为 (None,44) 但是 output 对于 1st Dense Layer(这是 2nd Dense Layer 的输入)将具有 (None,32) 的形状。但是它 运行 成功了。

我不明白为什么没有错误。任何澄清都会有所帮助

我认为 Keras 将创建(或保留创建)一个额外的输入层 - 但是当使用 model.add() 添加第二个密集层时,它将自动连接到之前的层,因此额外的输入层保持未连接并且 不是模型的一部分 。 (我同意 Keras 暗示未连接的层会很好,我有时会在使用功能 API 并更改输入时创建未连接的层。Keras 不会提醒我我已经跳了几层,我只是想知道为什么 summary() 这么短...)

input_shape 关键字参数仅对 Sequential 的第一层有效。其他层的输入形状将从它们的前一层导出。

tf.keras.layers.InputShape 的文档中暗示了该行为:

When using InputLayer with Keras Sequential model, it can be skipped by moving the input_shape parameter to the first layer after the InputLayer.

并在 the Sequential Model guide.

可以通过查看 Sequential.add method 的来源来确认行为:

if not self._layers:
  if isinstance(layer, input_layer.InputLayer):
    # Case where the user passes an Input or InputLayer layer via `add`.
    set_inputs = True
  else:
    batch_shape, dtype = training_utils.get_input_shape_and_dtype(layer)
    if batch_shape:
      # Instantiate an input layer.
      x = input_layer.Input(
          batch_shape=batch_shape, dtype=dtype, name=layer.name + '_input')
      # This will build the current layer
      # and create the node connecting the current layer
      # to the input layer we just created.
      layer(x)
      set_inputs = True 

如果模型中还没有层,则会将 Input 添加到模型中,其形状来自模型的第一层。 只有如果模型中还没有层,才会这样做。

该形状要么完全已知(如果 input_shape 已传递到模型的第一层),要么在模型构建后完全已知(例如,调用 model.build(input_shape)).

问题是检查第一层模型的input shape后,不会检查或处理里面声明的其他input shape那个相同的模型。例如,如果您按以下方式编写模型

sample_model.add(layers.Dense(32, input_shape=(4,)))
sample_model.add(layers.Dense(16, input_shape = (44,)))
sample_model.add(layers.Dense(8, input_shape = (32,)))

程序将始终检查第一个声明的 input shape 层并丢弃其余层。所以,如果你用 input_shape = (44,) 开始你的第一层,你需要将准确的特征数字作为输入传递给你的模型,例如:

sam_x = np.random.rand(10,44)
sam_y = np.array([0,1,1,0,1,0,0,1,0,1,])
sample_model.fit(sam_x,sam_y)

此外,如果您查看 Functional API,与 Sequential 模型不同,您必须创建并定义一个指定输入数据形状的独立 Input 层。它不可学习,而只是一个规范层。它是模型输入数据的一种网关。这意味着即使我们在其他层中定义 input_shape ,它们也会被丢弃。例如:

nputs = keras.Input(shape=(4,))

dense = layers.Dense(64, input_shape=(8,)) # dicard input_shape 
x = dense(inputs)

x = layers.Dense(64, input_shape=(16,))(x) # dicard input_shape 
outputs = layers.Dense(10)(x)

model = keras.Model(inputs=inputs, outputs=outputs, name="mnist_model")

这是一个使用 Conv2D 和 MNIST 的更复杂的示例。

encoder_input = keras.Input(shape=(28, 28, 1),)
x = layers.Conv2D(16, 3, activation="relu",  input_shape=[32,32,3])(encoder_input)
x = layers.Conv2D(32, 3, activation="relu",  input_shape=[64,64,3])(x) 
x = layers.MaxPooling2D(3)(x)
x = layers.Conv2D(32, 3, activation="relu",  input_shape=[224,321,3])(x)
x = layers.Conv2D(16, 3, activation="relu",  input_shape=[420,32,3])(x)
x = layers.GlobalMaxPooling2D()(x)
out = layers.Dense(10, activation='softmax')(x)

encoder = keras.Model(encoder_input, out, name="encoder")
encoder.summary()
Model: "encoder"
_________________________________________________________________
Layer (type)                 Output Shape              Param #   
=================================================================
input_15 (InputLayer)        [(None, 28, 28, 1)]       0         
_________________________________________________________________
conv2d_8 (Conv2D)            (None, 26, 26, 16)        160       
_________________________________________________________________
conv2d_9 (Conv2D)            (None, 24, 24, 32)        4640      
_________________________________________________________________
max_pooling2d_2 (MaxPooling2 (None, 8, 8, 32)          0         
_________________________________________________________________
conv2d_10 (Conv2D)           (None, 6, 6, 32)          9248      
_________________________________________________________________
conv2d_11 (Conv2D)           (None, 4, 4, 16)          4624      
_________________________________________________________________
global_max_pooling2d_2 (Glob (None, 16)                0         
_________________________________________________________________
dense_56 (Dense)             (None, 10)                170       
=================================================================
Total params: 18,842
Trainable params: 18,842
Non-trainable params: 0
def pre_process(image, label):
    return (image / 256)[...,None].astype('float32'), 
            tf.keras.utils.to_categorical(label, num_classes=10)

(x, y), (_, _) = tf.keras.datasets.mnist.load_data('mnist')
encoder.compile(
          loss      = tf.keras.losses.CategoricalCrossentropy(),
          metrics   = tf.keras.metrics.CategoricalAccuracy(),
          optimizer = tf.keras.optimizers.Adam())

encoder.fit(x, y, batch_size=256)
4s 14ms/step - loss: 1.4303 - categorical_accuracy: 0.5279