简体   繁体   English

TensorFlow2 / Keras:当子类化 keras.Model 时 input_shape 似乎没有效果

[英]TensorFlow2 / Keras: input_shape seems to not have an effect when subclassing keras.Model

When accessing the output of an intermediate layer I always received the error message: AttributeError: Layer l has no inbound nodes.访问中间层的输出时,我总是收到错误消息: AttributeError: Layer l has no inbound nodes. I read that one has to determine the input_shape in the entry layer to overcome this problem:我读到input_shape在入口层确定input_shape才能克服这个问题:

class MyModel(tf.keras.Model):
    def __init__(self):
        super(MyModel, self).__init__()
        self.flatten = tf.keras.layers.Flatten(input_shape=(28, 28))
        self.dense = tf.keras.layers.Dense(64, activation=tf.nn.relu)
        self.classifier = tf.keras.layers.Dense(10, name='classifier')

    def call(self, inputs):
        x = self.flatten(inputs)
        x = self.dense(x)
        return self.classifier(x)

Unfortunately, this didn't work for me.不幸的是,这对我不起作用。

After this failed attempt, I tried to reconstruct my model using tf.keras.Sequential and again specified the input_shape for the first layer:在这次失败的尝试之后,我尝试使用tf.keras.Sequential重建我的模型,并再次为第一层指定input_shape

tf.keras.Sequential([
    tf.keras.layers.Flatten(input_shape=(28, 28)),
    tf.keras.layers.Dense(64, activation=tf.nn.relu),
    tf.keras.layers.Dense(10, name='classifier')
])

This, on the other hand worked!另一方面,这有效!

So I asked myself why the first approach didn't work.所以我问自己为什么第一种方法不起作用。 To test this I specified arbitrary/wrong input_shapes for the subclassed model like this:为了测试这一点,我为子类模型指定了任意/错误的input_shapes ,如下所示:

class WrongInputShapeModel(tf.keras.Model):
    def __init__(self):
        super(WrongInputShapeModel, self).__init__()
        self.flatten = tf.keras.layers.Flatten(input_shape=(42, 42, 42))
        # ...

I noticed that this model still functioned with MNIST (which has 28x28 images).我注意到这个模型仍然可以与 MNIST(具有 28x28 图像)一起使用。 That let me to believe that the keyword input_shape has no effect when defining a model subclassing tf.keras.Model .这让我相信关键字input_shape在定义模型子类化tf.keras.Model

Is this a bug, or am I missing something?这是一个错误,还是我错过了什么?

From your model subclassing code, it looks like you are not returning the model's forward-pass output.从您的模型子类化代码来看,您似乎没有返回模型的前向传递输出。 Maybe that's the reason it didn't work.也许这就是它不起作用的原因。

This should work:这应该有效:

import tensorflow as tf

class MyModel(tf.keras.Model):
    def __init__(self):
        super().__init__()
        self.flatten = tf.keras.layers.Flatten()
        self.dense = tf.keras.layers.Dense(64, activation=tf.nn.relu)
        self.classifier = tf.keras.layers.Dense(10, name='classifier', activation='softmax')

    def call(self, inputs):
        x = self.flatten(inputs)
        x = self.dense(x)
        return self.classifier(x)

And then, just as an example:然后,举个例子:

(x_train, y_train), (x_test, y_test) = tf.keras.datasets.mnist.load_data()

model = MyModel()
model.compile(optimizer=tf.keras.optimizers.Adam(1e-3), loss=tf.keras.losses.SparseCategoricalCrossentropy(),
             metrics=[tf.keras.metrics.SparseCategoricalAccuracy()])
history = model.fit(x_train, y_train, epochs=5)

Now, Flatten input shape is actually defined by the shape of the layer's input tensor, so it does not require an input_shape argument.现在, Flatten输入形状实际上是由层的输入张量的形状定义的,因此它不需要input_shape参数。 input_shape is an attribute of Layer , so you can pass it, but the layer's forward-pass doesn't use it. input_shapeLayer一个属性,所以你可以传递它,但是 layer 的 forward-pass 不使用它。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM