为什么在使用keras子类化时出现以下错误?

时间:2019-12-20 12:09:32

标签: python tensorflow keras

我在keras中使用子类化API,并且在尝试构建模型时遇到以下错误,并且在github上找不到任何有关该问题的信息。请注意,我将训练设置为假,因为我打算仅上传已经保存的重量。

class VggBlock(Model):

    def __init__(self):
        super(VggBlock,self).__init__()

        self.conv1=Conv2D(filters=64,kernel_size=(3,3),padding='same')
        self.conv2=Conv2D(filters=128,kernel_size=(3,3),padding='same')
        self.conv3=Conv2D(filters=256,kernel_size=(3,3),padding='same')
        self.conv4=Conv2D(filters=512,kernel_size=(3,3),padding='same')

        self.relu=Activation('relu')
        self.pool=MaxPooling2D((2,2),strides=(2,2))

    def call(self,inputs,training=False):

        x=self.conv1(inputs)
        x=self.relu(x)
        x=self.conv1(x)
        x=self.relu(x)
        x=self.pool(x)

        x=self.conv2(x)
        x=self.relu(x)
        x=self.conv2(x)
        x=self.relu(x)
        x=self.pool(x)

        x=self.conv3(x)
        x=self.relu(x)
        x=self.conv3(x)
        x=self.relu(x)
        x=self.conv3(x)
        x=self.relu(x)
        x=self.conv3(x)
        x=self.relu(x)
        x=self.pool(x)

        x=self.conv4(x)
        x=self.relu(x)
        x=self.conv4(x)
        x=self.relu(x)

        x=self.conv3(x)
        x=self.relu(x)
        x=self.conv2(x)
        x=self.relu(x)

        return x
model = VggBlock()
model.build((1,224,224,3))
model.summary()

当我尝试调用model.summary()时,出现以下错误:

  

RuntimeError:您尝试在conv2d_22上调用count_params,但未构建该层。您可以通过conv2d_22.build(batch_input_shape)手动构建它。

3 个答案:

答案 0 :(得分:1)

  

警告:此模型无法正常工作,因为您提供给同一卷积层的输入通道不同

似乎是框架中的错误。您构建模型时,应该自动构建所有层,但这没有发生。

因此,我建议您将输入传递给模型(然后您将看到我之前提到的问题):

inputs = Input((224,224,3))
outputs = model(inputs)
model.summary()

#but it's better to do this with actual tensors, not with this dummy input

答案 1 :(得分:1)

好的,所以我做了一些更改。

import keras 
from keras import Model 
from keras.layers import Conv2D,Activation,MaxPooling2D

class VggBlock(Model):

    def __init__(self,inp_shape=(224,224,3)):
        super(VggBlock,self).__init__()

        self.conv1=Conv2D(filters=64,kernel_size=(3,3),padding='same',input_shape=inp_shape)
        self.conv2=Conv2D(filters=128,kernel_size=(3,3),padding='same')
        self.conv3=Conv2D(filters=256,kernel_size=(3,3),padding='same')
        self.conv4=Conv2D(filters=512,kernel_size=(3,3),padding='same')

        self.relu=Activation('relu')
        self.pool=MaxPooling2D((2,2),strides=(2,2))

    def get_new_layer(self,layer):
        return Conv2D(filters=layer.filters,kernel_size=layer.kernel_size,padding=layer.padding)


    def call(self,inputs,training=False):

        x=self.conv1(inputs)
        x=self.relu(x)
        x=self.get_new_layer(self.conv1)(x) #self.conv1(x)
        x=self.relu(x)
        x=self.pool(x)

        x=self.conv2(x)
        x=self.relu(x)
        x=self.get_new_layer(self.conv2)(x) #self.conv2(x)
        x=self.relu(x)
        x=self.pool(x)

        x=self.conv3(x)
        x=self.relu(x)
        x=self.get_new_layer(self.conv3)(x) #self.conv3(x)
        x=self.relu(x)
        x=self.get_new_layer(self.conv3)(x)#self.conv3(x)
        x=self.relu(x)
        x=self.get_new_layer(self.conv3)(x)#self.conv3(x)
        x=self.relu(x)
        x=self.pool(x)

        x=self.conv4(x)
        x=self.relu(x)
        x=self.get_new_layer(self.conv4)(x)#self.conv4(x)
        x=self.relu(x)

        x=self.get_new_layer(self.conv3)(x)#self.conv3(x)
        x=self.relu(x)
        x=self.get_new_layer(self.conv2)(x)#self.conv2(x)
        x=self.relu(x)
        print(x.shape)
        return x


    def compute_output_shape(self, input_shape):
        return (None,None,128)


model = VggBlock(inp_shape=(224,224,32))
inp = keras.Input(shape=(224,224,32))
out = model(inp)
model.summary() #works

检查模型中的其他函数,例如训练,保存,编译等。您在注释中提到的错误是因为在对模型进行子类化时需要将自己的函数写入compute_output_shape

答案 2 :(得分:1)

import keras 
from keras import Model 
from keras.layers import Conv2D,Activation,MaxPooling2D

class VggBlock:

    def __init__(self,inp_shape=(224,224,3),trainable=False):
        #super(VggBlock,self).__init__()
        # write whatever you want here... 
        # also no need to write these layers too, just use the functions get_CONV...
        # you can just store parameters here you would want for each layer...according to you

        self.conv1=Conv2D(filters=64,kernel_size=(3,3),padding='same',input_shape=inp_shape,trainable=trainable)
        self.conv1_dup = Conv2D(filters=64,kernel_size=(3,3),padding='same',trainable=trainable)
        self.conv2=Conv2D(filters=128,kernel_size=(3,3),padding='same',trainable=trainable)
        self.conv3=Conv2D(filters=256,kernel_size=(3,3),padding='same',trainable=trainable)
        self.conv4=Conv2D(filters=512,kernel_size=(3,3),padding='same',trainable=trainable)

        self.relu=Activation('relu')
        self.pool=MaxPooling2D((2,2),strides=(2,2))


    def get_CONV(self,layer,name):
        return Conv2D(filters=layer.filters,kernel_size=layer.kernel_size,padding=layer.padding,trainable=False,
                     name=name)

    def get_model(self,inputs,training=False):

        x=self.conv1(inputs)
        x=self.relu(x)
        x=self.get_CONV(self.conv1,name='conv1_duplicate')(x) #self.conv1(x)
        x=self.relu(x)
        x=self.pool(x)
        .
        .
        .
        #same as before 
        return keras.Model(inputs,x) #this is a keras Model object and it has all the functions you need.

vggClass = VggBlock(inp_shape=(224,224,32))
inp = keras.Input(shape=(224,224,32))

m = vggClass.get_model(inp) 
m.summary() #works