Keras игнорирует input_shape, предоставленный первому слою - PullRequest
1 голос
/ 02 апреля 2020

Я строю простую модель, подобную этой, указав форму ввода (32, 32, 1) для первого (и единственного) слоя:

import numpy as np
import tensorflow as tf

class Model(tf.keras.Model):
  def __init__(self):
    super().__init__()
    self.conv = tf.keras.layers.Conv2D(64, 3, input_shape=(32, 32, 1))
  def call(self, x):
    x = self.conv(x)
    return x

model = Model()

Теперь, когда я вызываю

print(model.summary())

Я получаю следующую ошибку

This model has not yet been built. Build the model first by calling `build()` or calling `fit()`
with some data, or specify an `input_shape` argument in the first layer(s) for automatic build.

, несмотря на то, что input_shape действительно указан.

Модель также с радостью принимает ввод с несоответствующими формами:

x = np.zeros((1, 24, 24, 1), dtype=np.float32)
model(x)  # OK!

Значит ли это, что, несмотря на то, что сказано в документации, спецификация input_shape для первого уровня просто игнорируется? Как применить это значение?

(Моя версия TF - 2.1.0).

Ответы [ 2 ]

2 голосов
/ 02 апреля 2020

Я думаю, вы путаете последовательный и функциональный API.

Здесь вы подклассифицируете свою модель, нет графа слоев, только Python код, выполняемый в методе call(); поэтому summary() не имеет ни малейшего представления о том, через какие слои он будет go проходить в будущем.

Если вы действительно хотите создать подкласс Model, вы можете сделать что-то вроде этого:

model_ = Model()
inputs = tf.keras.input(shape=(32,32,1))
outputs = model_(inputs)
model = tf.keras.Model(inputs=inputs, outputs=outputs)

И вы получите summary(), отображающий правильную форму ввода и вывода.

Вы можете проверить это сообщение в блоге , если вам нужна дополнительная информация по этому вопросу. Надеюсь, это поможет,

РЕДАКТИРОВАТЬ (для пояснения после комментария):

  • При использовании императивного API:

    Большинство отладки произойдет на этапе определения модели, а не во время выполнения. У вас есть гарантия, что любая модель, которая компилируется, будет работать. Это ускоряет итерацию и упрощает отладку.

  • Когда вы используете API-интерфейс symboli c (модель подкласса):

    Существует почти нет проверок входных данных или межуровневой совместимости, поэтому при использовании этого стиля большая часть отладочной нагрузки переносится с платформы на разработчика.

0 голосов
/ 04 апреля 2020

Существует очень большая разница между моделью подклассов керас и другими моделями керас (последовательная и функциональная).

Последовательные модели и функциональные модели представляют собой структуры данных, которые представляют DAG слоев. Проще говоря, функциональная или последовательная модель - это статические графики слоев, построенные путем наложения друг на друга, как LE GO. Поэтому, когда вы предоставляете input_shape первому слою, эти (функциональные и последовательные) модели могут вывести форму всех других слоев и построить модель. Затем вы можете распечатать формы ввода / вывода, используя model.summary().

С другой стороны, подклассовая модель определяется с помощью тела (метода вызова) кода Python. Для подклассовой модели здесь нет графика слоев. Мы не можем знать, как слои связаны друг с другом (потому что это определено в теле вызова, а не в виде явной структуры данных), поэтому мы не можем вывести формы ввода / вывода. Таким образом, для модели подкласса форма ввода / вывода нам неизвестна, пока она не будет сначала проверена с правильными данными. В методе compile () мы будем выполнять отложенную компиляцию и ждать правильных данных. Чтобы он мог определить форму промежуточных слоев, нам нужно запустить с правильными данными и затем использовать model.summary(). Без запуска модели с данными она выдаст ошибку, как вы заметили.

Ниже приведен пример с сайта Tensorflow.

class ThreeLayerMLP(keras.Model):

  def __init__(self, name=None):
    super(ThreeLayerMLP, self).__init__(name=name)
    self.dense_1 = layers.Dense(64, activation='relu', name='dense_1')
    self.dense_2 = layers.Dense(64, activation='relu', name='dense_2')
    self.pred_layer = layers.Dense(10, name='predictions')

  def call(self, inputs):
    x = self.dense_1(inputs)
    x = self.dense_2(x)
    return self.pred_layer(x)

def get_model():
  return ThreeLayerMLP(name='3_layer_mlp')

model = get_model()

(x_train, y_train), (x_test, y_test) = keras.datasets.mnist.load_data()
x_train = x_train.reshape(60000, 784).astype('float32') / 255
x_test = x_test.reshape(10000, 784).astype('float32') / 255

model.compile(loss=keras.losses.SparseCategoricalCrossentropy(from_logits=True),
              optimizer=keras.optimizers.RMSprop())
history = model.fit(x_train, y_train,
                    batch_size=64,
                    epochs=1)

model.summary()

Надеюсь, это поможет. Спасибо!

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...