subclassing API: expected 'trainable' argument to be a boolean TF2

Question:

I am following a tutorial for TensorFlow subclassing API: https://www.youtube.com/watch?v=WcZ_1IAH_nM&ab_channel=AladdinPersson

When executing the code, I receive the following error:

TypeError: Expected `trainable` argument to be a boolean, but got: [32, 32, 64]

Which from what I gather comes from the ResBlock (as if trying to use it in a tf.keras.Sequential([ResBlock([32, 32, 64]), ...]) ) generates the same error.

I have tried introducing **kwargs but it did not solve the problem.

This is the code:

import tensorflow as tf
from tensorflow.keras.datasets import mnist

(x_train, y_train), (x_test, y_test) = mnist.load_data()
x_train = x_train.reshape(-1, 28, 28, 1).astype("float32")/255.0  # divided by 255 to normalize the data
x_test = x_test.reshape(-1, 28, 28, 1).astype("float32")/255.0

# %%
# CNN -> BatchNorm -> ReLU (Common structure)
# same but 10 times

class CNNBlock(tf.keras.layers.Layer):
    """We input layers.Layer for backpropagation and everything """
    def __init__(self, out_channels, kernel_size=3):
        super(CNNBlock, self).__init__()
        print("INIT OF CNNBlock")
        self.conv = tf.keras.layers.Conv2D(out_channels, kernel_size, padding="same")
        self.bn = tf.keras.layers.BatchNormalization()  # works differently for training or evaluation

    def call(self, input_tensor, training=False):
        x = self.conv(input_tensor)
        # print(x.shape)
        x = self.bn(x, training=training)
        x = tf.nn.relu(x)
        return x

class ResBlock(tf.keras.layers.Layer):
    def __init___(self, channels):
        print('start resnet block inside init')
        print(f'channels of resnet block, {channels}')
        super(ResBlock, self).__init__()
        print("INIT OF ResBlock")
        # Each CNN Block is a convolution a batch norm and a relu
        self.cnn1 = CNNBlock(channels[0])
        self.cnn2 = CNNBlock(channels[1])
        self.cnn3 = CNNBlock(channels[2])
        self.pooling = tf.keras.layers.MaxPooling2D()  # to have input size, height and width
        # Identity mapping: same number of channels
        # same convolution = height and width do not change but channels might
        self.identity_mapping = tf.keras.layers.Conv2D(channels[1], kernel_size=1, padding="same")

    def call(self, input_tensor, training=False):
        x = self.cnn1(input_tensor, training=training)
        x = self.cnn2(x, training=training)
        x = self.cnn3(
            x+self.identity_mapping(input_tensor), training=training
        )
        x = self.pooling(x)
        return x

class ResNet_Like(tf.keras.Model):
    def __init__(self, num_classes=10):
        super(ResNet_Like, self).__init__()
        print("INIT OF ResNet_Like")
        self.block1 = ResBlock([32, 32, 64])
        print('passed block1')
        self.block2 = ResBlock([128, 128, 256])
        self.block3 = ResBlock([128, 256, 512])
        self.pool = tf.keras.layers.GlobalAveragePooling2D()
        self.classifier = tf.keras.layers.Dense(num_classes)

    def call(self, input_tensor, training=False):
        x = self.block1(input_tensor, training=training)
        x = self.block2(x, training=training)
        x = self.block3(x, training=training)
        x = self.pool(x)
        return self.classifier(x)

    def model(self):
        """Overwrite the function call in tf.Model"""
        x = tf.keras.Input(shape=(28, 28, 1))  # input_tensor shape
        return tf.keras.Model(inputs=[x], outputs=self.call(x))


# %%
#
# model0 = tf.keras.Sequential(
#     [
#         CNNBlock(32),
#         CNNBlock(64),
#         CNNBlock(128),
#         tf.keras.layers.Flatten(),
#         tf.keras.layers.Dense(10)
#     ]
# )
#
# model0.compile(
#     optimizer=tf.keras.optimizers.Adam(),
#     loss=tf.keras.losses.SparseCategoricalCrossentropy(from_logits=True),
#     metrics=["accuracy"],
# )
#
# model0.fit(x_train, y_train, batch_size=64, epochs=1, verbose=2)
#
# print(model0.summary())  # multiple --> due to subclassing
# print('finished')

# %%
channels_test = [100, 32, 64]
model = tf.keras.Sequential(
    [
        ResBlock(channels_test),
        ResBlock([32, 32, 64]),
        ResBlock([32, 32, 64]),
        ResBlock([32, 32, 64]),
        tf.keras.layers.Flatten(),
        tf.keras.layers.Dense(10)
    ]
)

model.compile(
    optimizer=tf.keras.optimizers.Adam(),
    loss=tf.keras.losses.SparseCategoricalCrossentropy(from_logits=True),
    metrics=["accuracy"],
)

model.fit(x_train, y_train, batch_size=64, epochs=1, verbose=2)

print(model.summary())  # multiple --> due to subclassing
print('finished')
Asked By: Nankin

||

Answers:

You have a typo in class ResBlock, you don’t have an init function.
Change

def __init___(self, channels):

to

def __init__(self, channels):

Just 2 underscores not 3

Answered By: AndrzejO