ADA
ADA

Reputation: 259

Why am i getting the following the following error when using keras subclassing?

I am using the subclassing API in keras and I am getting the following error when I try to build the model, and I cannot find anything about the issue on github. As a note I set training to false cause I plan to just upload weights I already have saved.

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

When I try to call model.summary() I get the following error:

RuntimeError: You tried to call count_params on conv2d_22, but the layer isn't built. You can build it manually via: conv2d_22.build(batch_input_shape).

Upvotes: 0

Views: 975

Answers (3)

Siddhant Tandon
Siddhant Tandon

Reputation: 701

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

Upvotes: 1

Siddhant Tandon
Siddhant Tandon

Reputation: 701

okay so I did some changes.

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

Check the model for other functions like train,save,compile etc. And that error you mentioned in the comment, is because you need to write your own function to compute_output_shape when subclassing models.

Upvotes: 1

Daniel Möller
Daniel Möller

Reputation: 86650

Warning: this model will not work because the input channels you are giving to the same convolution layer are different

It seems a bug in the framework. You build the model, all layers should be automatically built, but this is not happening.

So, I suggest you pass an input to the model (and then you will see the problem I mentioned before):

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

Upvotes: 1

Related Questions