模型总结(model.summary())中出现“该模型尚未构建”的错误。

60

我有一个 keras 模型,定义如下

class ConvLayer(Layer) :
    def __init__(self, nf, ks=3, s=2, **kwargs):
        self.nf = nf
        self.grelu = GeneralReLU(leak=0.01)
        self.conv = (Conv2D(filters     = nf,
                            kernel_size = ks,
                            strides     = s,
                            padding     = "same",
                            use_bias    = False,
                            activation  = "linear"))
        super(ConvLayer, self).__init__(**kwargs)

    def rsub(self): return -self.grelu.sub
    def set_sub(self, v): self.grelu.sub = -v
    def conv_weights(self): return self.conv.weight[0]

    def build(self, input_shape):
        # No weight to train.
        super(ConvLayer, self).build(input_shape)  # Be sure to call this at the end

    def compute_output_shape(self, input_shape):
        output_shape = (input_shape[0],
                        input_shape[1]/2,
                        input_shape[2]/2,
                        self.nf)
        return output_shape

    def call(self, x):
        return self.grelu(self.conv(x))

    def __repr__(self):
        return f'ConvLayer(nf={self.nf}, activation={self.grelu})'
class ConvModel(tf.keras.Model):
    def __init__(self, nfs, input_shape, output_shape, use_bn=False, use_dp=False):
        super(ConvModel, self).__init__(name='mlp')
        self.use_bn = use_bn
        self.use_dp = use_dp
        self.num_classes = num_classes

        # backbone layers
        self.convs = [ConvLayer(nfs[0], s=1, input_shape=input_shape)]
        self.convs += [ConvLayer(nf) for nf in nfs[1:]]
        # classification layers
        self.convs.append(AveragePooling2D())
        self.convs.append(Dense(output_shape, activation='softmax'))

    def call(self, inputs):
        for layer in self.convs: inputs = layer(inputs)
        return inputs

我能够编译这个模型而没有任何问题。

>>> model.compile(optimizer=tf.keras.optimizers.Adam(lr=lr), 
              loss='categorical_crossentropy',
              metrics=['accuracy'])

但是,当我查询该模型的概要时,发现出现了错误

>>> model = ConvModel(nfs, input_shape=(32, 32, 3), output_shape=num_classes)
>>> model.summary()
---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
<ipython-input-220-5f15418b3570> in <module>()
----> 1 model.summary()

/usr/local/lib/python3.6/dist-packages/tensorflow/python/keras/engine/network.py in summary(self, line_length, positions, print_fn)
   1575     """
   1576     if not self.built:
-> 1577       raise ValueError('This model has not yet been built. '
   1578                        'Build the model first by calling `build()` or calling '
   1579                        '`fit()` with some data, or specify '

ValueError: 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,为什么会抛出这个错误?


我知道这可能有点傻,但你能发一下完整的代码吗?我没有看到模型定义在哪里。另外,如果你这样做会发生什么呢?model.compile(optimizer=tf.train.Adam(lr=lr), loss='categorical_crossentropy', metrics=['accuracy']) - flyingmeatball
请发布ConvLayer函数的定义。 - nessuno
@nessuno 我已经添加了 ConvLayer 的定义。@flyingmeatball 你是什么意思?我没有看到你建议的 model.compile 有任何区别!! - bachr
9个回答

80

错误告诉我们该怎么做:

此模型尚未构建。首先调用build()构建模型。

model.build(input_shape) # `input_shape` is the shape of the input data
                         # e.g. input_shape = (None, 32, 32, 3)
model.summary()

谢谢,问题解决了。但是当我测试 Sequential 模型(而不是子类化)时,我不需要构建模型,只需设置第一层的输入形状即可! - bachr
18
如果你在模型开头添加 InputLayer 或者使用输入数据 model(input_data),就不需要显式地构建 Sequential() 模型。在这两种情况下,model.build() 会被隐式调用。很高兴能帮到你。 - Vlad
我的代码没有起作用。在我对输入形状运行.build之后,model.summary()调用返回“您尝试在IL上调用count_params,但该层尚未构建。”这很奇怪,因为我确实构建了模型。 - Geoffrey Anderson
1
@GeoffreyAnderson,你创建模型或自定义层的方式存在问题,而不是我的答案有问题。 - Vlad
1
最简单、最好的答案。对我有用。谢谢! - Rafael Monteiro
@RafaelMonteiro 谢谢您的反馈! - Vlad

33

使用Keras子类化模型和其他Keras模型(如Sequential和Functional)之间存在非常大的差异。

Sequential模型和Functional模型是表示层的DAG的数据结构。简单地说,Functional或Sequential模型是像乐高积木一样堆叠在一起的静态图层。因此,当您为第一层提供input_shape时,这些(Functional和Sequential)模型可以推断出所有其他层的形状并构建一个模型。然后,您可以使用model.summary()打印输入/输出形状。

另一方面,子类化模型是通过Python代码的body(一个call方法)定义的。对于子类化模型,这里没有层的图形。我们无法知道如何将层连接在一起(因为它是在调用的body中定义的,而不是作为显式数据结构),因此我们无法推断出输入/输出形状。因此,对于子类模型,我们在合适的数据首次测试之前不知道其输入/输出形状。在compile()方法中,我们将进行延迟编译并等待适当的数据。为了推断中间层的形状,我们需要使用适当的数据运行,然后使用model.summary()。如果不使用数据运行模型,则会像您注意到的那样抛出错误。请参见GitHub代码

下面是来自Tensorflow网站的示例。

import tensorflow as tf
from tensorflow import keras
from tensorflow.keras import layers

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())

model.summary() # This will throw an error as follows
# ValueError: 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.

# Need to run with real data to infer shape of different layers
history = model.fit(x_train, y_train,
                    batch_size=64,
                    epochs=1)

model.summary()

谢谢!


我找到了一个答案,当你不需要先训练就能看到摘要。这是链接:https://stackoverflow.com/a/63898244/16330649 - undefined

12

另一种方法是像这样添加属性input_shape():

model = Sequential()
model.add(Bidirectional(LSTM(n_hidden,return_sequences=False, dropout=0.25, 
recurrent_dropout=0.1),input_shape=(n_steps,dim_input)))

1
我在我的Seq模型中有输入形状。然而,它给了我错误。 - chikitin
5
请确保将 input_shape 添加到 Bidirectional 的括号中,而不是 LSTM 的括号中。在格式中看起来可能有点难以发现。 - Markus

3
# X is a train dataset with features excluding a target variable

input_shape = X.shape  
model.build(input_shape) 
model.summary()

2

确保您正确创建模型。像以下代码这样的小错别字也可能会导致问题:

model = Model(some-input, some-output, "model-name")

正确的代码应该为:

model = Model(some-input, some-output, name="model-name")

1
如果您的Tensorflow、Keras版本是2.5.0,那么导入Keras包时只需添加Tensorflow即可。
不要这样做:
from tensorflow import keras
from keras.models import Sequential
import tensorflow as tf

Like this:

from tensorflow import keras
from tensorflow.keras.models import Sequential
import tensorflow as tf

实际上,当我从第二个改变时,第一个代码对我起作用了。 - mitra mirshafiee

0

你的Tensorflow和Keras版本问题可能是导致这个问题的原因。

我在训练回归LSTM模型时遇到了同样的问题。

错误信息:

ValueError: This model has not yet been built. Build the model first by calling build() or by calling the model on a batch of data.

之前:

from tensorflow.keras.models import Sequential

from tensorflow.python.keras.models import Sequential

修正:

from keras.models import Sequential

0
# Creating a sample model
pattern = Sequential()
model.add( Dense(64, activation='relu', input_shape=(784,))))
model.add( Dense(32, activation='relu'))
model.add( Dense(10, activation='softmax'))

你必须输入激活参数。

-3
我之前也遇到同样的错误,所以我删除了model.summary()。然后问题就解决了。因为如果在构建模型之前定义了摘要模型,这个问题就会出现。
这里是链接,其中有描述。
Raises:
    ValueError: if `summary()` is called before the model is built.**

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接