fnokke
fnokke

Reputation: 1161

Subclassing Sequential() keras-model

I wanted to subclass a sequential model in order to be able to write a custom call() and handle named inputs. However, I got, for me, some unexpected behavior already for very minor changes to the __init__ function. If I try to add a new member to my subclass and initialize it after calling super().__init__() the model fails to build automatically.

from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Conv2D, Activation, MaxPooling2D, Dense, Flatten
import tensorflow as tf
class Sequential2(Sequential):

    def __init__(self):
        super(Sequential2, self).__init__()
        self.custom_member = []

    def get_my_custom_member(self):
        return self.custom_member

model = Sequential2()

if tf.keras.backend.image_data_format() == 'channels_first':
    input_shape = (1, 28, 28)
else:
    assert tf.keras.backend.image_data_format() == 'channels_last'
    input_shape = (28, 28, 1)

layers = [Conv2D(32, (3, 3), input_shape=input_shape)]

for layer in layers:
    model.add(layer)

model.add(Dense(10))
model.add(Activation('relu'))

model.summary()

fails with output: 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.

However if self.custom_member = [] is left out it works as expected.

What am I missing here? (tested with Tensorflow 1.14)

Upvotes: 1

Views: 1248

Answers (1)

user11530462
user11530462

Reputation:

This issue was fixed in TF 2.2. You can refer working code as shown below

from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Conv2D, Activation, MaxPooling2D, Dense, Flatten

import tensorflow as tf
print(tf.__version__)

class Sequential2(Sequential):

    def __init__(self):
        super(Sequential2, self).__init__()
        self.custom_member = []

    def get_my_custom_member(self):
        return self.custom_member

model = Sequential2()

if tf.keras.backend.image_data_format() == 'channels_first':
    input_shape = (1, 28, 28)
else:
    assert tf.keras.backend.image_data_format() == 'channels_last'
    input_shape = (28, 28, 1)

layers = [Conv2D(32, (3, 3), input_shape=input_shape)]

for layer in layers:
    model.add(layer)

model.add(Dense(10))
model.add(Activation('relu'))

model.summary()

Output:

2.2.0
Model: "sequential"
_________________________________________________________________
Layer (type)                 Output Shape              Param #   
=================================================================
conv2d (Conv2D)              (None, 26, 26, 32)        320       
_________________________________________________________________
dense (Dense)                (None, 26, 26, 10)        330       
_________________________________________________________________
activation (Activation)      (None, 26, 26, 10)        0         
=================================================================
Total params: 650
Trainable params: 650
Non-trainable params: 0
_________________________________________________________________

Upvotes: 1

Related Questions