unable to initialize Keras model through subclassing - python

im trying to create a keras model through subclassing using:
class MyModel(Model):
def __init__(self):
super(MyModel, self).__init__()
self.dense1 = Dense(64, activation='relu')
self.dense2 = Dense(10)
def call(self, inputs):
x = self.dense1(inputs)
return self.dense2(x)
model = MyModel(tf.random.uniform([1, 10]))
model.summary()
I want it to be equal to this squential api:
inputs = tf.keras.Input(shape=(3,))
x = tf.keras.layers.Dense(64, activation=tf.nn.relu)(inputs)
outputs = tf.keras.layers.Dense(10, activation=tf.nn.softmax)(x)
model = tf.keras.Model(inputs=inputs, outputs=outputs)
but after running those lines i get:
TypeError: __init__() takes 1 positional argument but 2 were given
can u assist?

You passed the input data as arguments to the model constructor. You need to instantiate it
model = MyModel()
Then you can pass input tensors
model(tf.random.uniform([1, 10]))
And this will work
<tf.Tensor: shape=(1, 10), dtype=float32, numpy=
array([[-0.10745259, -0.21291552, -0.04618738, -0.0118152 , -0.1662825 ,
0.8145975 , 0.44216082, -0.07359659, 0.68233466, -0.15205911]],
dtype=float32)>

Related

Tensorflow: cannot create a custom LSTMCell model using keras

This model doesn't work.
import tensorflow as tf
class LNSimpleRNNCell(tf.keras.layers.Layer):
def __init__(self, units, activation="tanh", **kwargs):
super().__init__(**kwargs)
self.state_size = units
self.output_size = units
self.simple_rnn_cell = tf.keras.layers.LSTMCell(units, activation=None)
self.layer_norm = tf.keras.layers.LayerNormalization()
self.activation = tf.keras.activations.get(activation)
def get_initial_state(self, inputs=None, batch_size=None, dtype=None):
if inputs is not None:
batch_size = tf.shape(inputs)[0]
dtype = inputs.dtype
else:
return [tf.zeros([batch_size, self.state_size], dtype=dtype)]
#tf.function
def call(self, inputs, states):
outputs, new_states = self.simple_rnn_cell(inputs, states)
norm_outputs = self.activation(self.layer_norm(outputs))
return norm_outputs, [norm_outputs]
model = tf.keras.models.Sequential([
tf.keras.layers.RNN(LNSimpleRNNCell(units=73), return_sequences=True, input_shape=[73, 17]),
tf.keras.layers.RNN(LNSimpleRNNCell(units=73), return_sequences=True),
tf.keras.layers.TimeDistributed(tf.keras.layers.Dense(units=1, activation=None))
])
model.summary()
I get the following error:
IndexError: Exception encountered when calling layer "lstm_cell" " f"(type LSTMCell).
tuple index out of range
Call arguments received by layer "lstm_cell" "f"(type LSTMCell):
• inputs=tf.Tensor(shape=(None, 17), dtype=float32)
• states=('tf.Tensor(shape=(None, 73), dtype=float32)',)
• training=None
Call arguments received by layer "ln_simple_rnn_cell" "f"(type LNSimpleRNNCell):
• inputs=tf.Tensor(shape=(None, 17), dtype=float32)
• states=('tf.Tensor(shape=(None, 73), dtype=float32)',)
In class LNSimpleRNNCell, it operates when LSTMCell is changed to SimpleRNNCell. It seems that something more is needed in the process of change.

Keras plot_model: How do I write a new block and give it a name

Is there a possibility to create my own block using keras
Maybe something like this:
import tensorflow as tf
class NewLayer(tf.keras.layers.Layer):
def __init__(self):
super(NewLayer, self).__init__()
self.dense1 = tf.keras.layers.Dense(64, activation='relu')
self.dense2 = tf.keras.layers.Dense(16, activation='relu')
self.dense3 = tf.keras.layers.Dense(3)
self._name = 'My_model'
def call(self, inputs):
x = tf.keras.layers.Flatten()(inputs)
x = self.dense1(x)
x = self.dense2(x)
output = self.dense3(x)
return output
inputs = tf.keras.layers.Input((128, 128, 3))
x = tf.keras.layers.Conv2D(256, 67)(inputs)
new_layer = NewLayer()
outputs = new_layer(x)
model = tf.keras.Model(inputs, outputs)
dot_img_file = 'model.png'
tf.keras.utils.plot_model(model, to_file=dot_img_file, show_shapes=True)

How add tf.keras.Input in a custom keras model?

I'm writting a custom keras model here is my code:
class Model(tf.keras.Model):
def __init__(self, first_layer, num_classes):
super(Model, self).__init__()
self.layer_1 = tf.keras.layers.Dense(first_layer, activation='relu')
self.layer_2 = tf.keras.layers.Dense(num_classes, activation='softmax')
def call(self,inp):
output = self.layer_1(inp)
output = self.layer_2(output)
return output
but I get this error:
ValueError: The last dimension of the inputs to `Dense` should be defined. Found `None`.
I found the tf.keras.input, but all the examples with that are with sequential models for example with a sequential model this is the solution with keras.input:
encoder_input = keras.Input(shape=(28, 28, 1), name="img")
x = layers.Conv2D(16, 3, activation="relu")(encoder_input)
x = layers.Conv2D(32, 3, activation="relu")(x)
but how I introduce this in a custom keras model?
please
version: TF 2.6
Edited code:
import tensorflow as tf
class Model(tf.keras.Model):
def __init__(self, first_layer, num_classes):
super(Model, self).__init__()
self.layer_1 = tf.keras.layers.Dense(first_layer, activation='relu')
self.layer_2 = tf.keras.layers.Dense(num_classes, activation='softmax')
def call(self,inp):
output = self.layer_1(inp)
output = self.layer_2(output)
return output
encoder_input = tf.keras.Input(shape=(28, 28, 1))
x = tf.keras.layers.Conv2D(16, 3, activation="relu")
#x = layers.Conv2D(32, 3, activation="relu")(x)
model = Model(5,3) #instantiated the model
y=model(encoder_input)#took input
print(y)
Output:
KerasTensor(type_spec=TensorSpec(shape=(None, 28, 28, 3),
dtype=tf.float32, name=None), name='model_4/dense_6/Softmax:0',
description="created by layer 'model_4'")
Reference:
https://www.tensorflow.org/guide/keras/custom_layers_and_models

How to visualize nested `tf.keras.Model (SubClassed API)` GAN model with plot_model?

Models implemented as subclasses of keras. Model can generally not be visualized with plot_model. There is a workaround as described here. However, it only applies to simple models. As soon as a model is enclosed by another model, the nestings will not be resolved.
I am looking for a way to resolve nested models implemented as subclasses of the keras. Model. As an example, I have created a minimal GAN model:
import keras
from keras import layers
from tensorflow.python.keras.utils.vis_utils import plot_model
class BaseModel(keras.Model):
def __init__(self, *args, **kwargs):
super(BaseModel, self).__init__(*args, **kwargs)
def call(self, inputs, training=None, mask=None):
super(BaseModel, self).call(inputs=inputs, training=training, mask=mask)
def get_config(self):
super(BaseModel, self).get_config()
def build_graph(self, raw_shape):
""" Plot models that subclass `keras.Model`
Adapted from https://stackoverflow.com/questions/61427583/how-do-i-plot-a-keras-tensorflow-subclassing-api-model
:param raw_shape: Shape tuple not containing the batch_size
:return:
"""
x = keras.Input(shape=raw_shape)
return keras.Model(inputs=[x], outputs=self.call(x))
class GANModel(BaseModel):
def __init__(self, generator, discriminator):
super(GANModel, self).__init__()
self.generator = generator
self.discriminator = discriminator
def call(self, input_tensor, training=False, mask=None):
x = self.generator(input_tensor)
x = self.discriminator(x)
return x
class DiscriminatorModel(BaseModel):
def __init__(self, name="Critic"):
super(DiscriminatorModel, self).__init__(name=name)
self.l1 = layers.Conv2D(64, 2, activation=layers.ReLU())
self.flat = layers.Flatten()
self.dense = layers.Dense(1)
def call(self, inputs, training=False, mask=None):
x = self.l1(inputs, training=training)
x = self.flat(x)
x = self.dense(x, training=training)
return x
class GeneratorModel(BaseModel):
def __init__(self, name="Generator"):
super(GeneratorModel, self).__init__(name=name)
self.dense = layers.Dense(128, activation=layers.ReLU())
self.reshape = layers.Reshape((7, 7, 128))
self.out = layers.Conv2D(1, (7, 7), activation='tanh', padding="same")
def call(self, inputs, training=False, mask=None):
x = self.dense(inputs, training=training)
x = self.reshape(x)
x = self.out(x, training=training)
return x
g = GeneratorModel()
d = DiscriminatorModel()
plot_model(g.build_graph((7, 7, 1)), to_file="generator_model.png",
expand_nested=True, show_shapes=True)
gan = GANModel(generator=g, discriminator=d)
plot_model(gan.build_graph((7, 7, 1)), to_file="gan_model.png",
expand_nested=True, show_shapes=True)
Edit
Using the functional keras API I get the desired result (see here). The nested models are correctly resolved within the GAN model.
from keras import Model, layers, optimizers
from tensorflow.python.keras.utils.vis_utils import plot_model
def get_generator(input_dim):
initial = layers.Input(shape=input_dim)
x = layers.Dense(128, activation=layers.ReLU())(initial)
x = layers.Reshape((7, 7, 128))(x)
x = layers.Conv2D(1, (7, 7), activation='tanh', padding="same")(x)
return Model(inputs=initial, outputs=x, name="Generator")
def get_discriminator(input_dim):
initial = layers.Input(shape=input_dim)
x = layers.Conv2D(64, 2, activation=layers.ReLU())(initial)
x = layers.Flatten()(x)
x = layers.Dense(1)(x)
return Model(inputs=initial, outputs=x, name="Discriminator")
def get_gan(input_dim, latent_dim):
initial = layers.Input(shape=input_dim)
x = get_generator(input_dim)(initial)
x = get_discriminator(latent_dim)(x)
return Model(inputs=initial, outputs=x, name="GAN")
m = get_generator((7, 7, 1))
m.compile(optimizer=optimizers.Adam())
plot_model(m, expand_nested=True, show_shapes=True, to_file="generator_model_functional.png")
gan = get_gan((7, 7, 1), (7, 7, 1))
plot_model(gan, expand_nested=True, show_shapes=True, to_file="gan_model_functional.png")
Whenever you pass each generator and discriminator to GANModel, they act like an encompassed child layer consisting of n times layers. So, if you plot only the generator model by the GANModel instances, it will show as follows (same goes to discriminator) unlike plots while using them separately.
The fact is while we pass data at this point using the call() method of GANModel, the input passes implicitly all internal layers (generator, discriminator) according to its design. Here I will show you two workaround for this to get your desired plot.
Option 1
I believe you probably guess the method. In the GANModel model, we will pass the input very explicitly to each internal layer of those child layers (generator, discriminator).
class GANModel(BaseModel):
def __init__(self, generator, discriminator):
super(GANModel, self).__init__()
self.generator = generator
self.discriminator = discriminator
def call(self, input_tensor, training=False, mask=None):
x = input_tensor
for gen_lyr in self.generator.layers:
print(gen_lyr) # checking
x = gen_lyr(x)
for disc_lyr in self.discriminator.layers:
print(disc_lyr) # checking
x = disc_lyr(x)
return x
If you plot now, you will get
# All Internal Layers of self.generator, self.discriminator
<tensorflow.python.keras.layers.core.Dense object at 0x7f2a472a3710>
<tensorflow.python.keras.layers.core.Reshape object at 0x7f2a461e8f50>
<tensorflow.python.keras.layers.convolutional.Conv2D object at 0x7f2a44591f90>
<tensorflow.python.keras.layers.convolutional.Conv2D object at 0x7f2a47317290>
<tensorflow.python.keras.layers.core.Flatten object at 0x7f2a47317ed0>
<tensorflow.python.keras.layers.core.Dense object at 0x7f2a57f42910>
Option 2
I think it's a bit ugly approach. First, we take each internal layer and build a Sequential model with them. Then use .build to create its input layer. BOOM.
gan = GANModel(generator=g, discriminator=d)
all_layer = []
for layer in gan.layers:
all_layer.extend(layer.layers)
gan_plot = tf.keras.models.Sequential(all_layer)
gan_plot.build((None,7,7,1))
list(all_layer)
[<tensorflow.python.keras.layers.core.Dense at 0x7f2a461ab390>,
<tensorflow.python.keras.layers.core.Reshape at 0x7f2a46156110>,
<tensorflow.python.keras.layers.convolutional.Conv2D at 0x7f2a461fedd0>,
<tensorflow.python.keras.layers.convolutional.Conv2D at 0x7f2a461500d0>,
<tensorflow.python.keras.layers.core.Flatten at 0x7f2a4613ea10>,
<tensorflow.python.keras.layers.core.Dense at 0x7f2a462cae10>]
tf.keras.utils.plot_model(gan_plot, expand_nested=True, show_shapes=True)

Tensorflow 2.0 Model subclassing

I made this function that incorporates a resnet into a model. It works well, and I can save it.
My problem is that I can't load it because it needs a call function. I am not exactly sure of how to turn this into a class. The attempt is at the bottom. some pointers would be helpful.
def build_network():
inp = Input(shape=(256,256,3))
resnet = tf.keras.applications.ResNet152V2(
include_top=False, weights='imagenet', input_tensor=None,
input_shape=(256,256,3), pooling=None, classes=1000
)
# classifier_activation='softmax'
x = resnet(inp)
x = GlobalAveragePooling2D()(x)
x = Dropout(0.3)(x)
x = Dense(9, activation='softmax')(x)
model = tf.keras.Model(inputs=inp,outputs = x)
opt = tf.keras.optimizers.SGD(momentum=0.9)
# optimizer = 'adam',
model.compile(loss='categorical_crossentropy',
optimizer = opt,
metrics=['accuracy'])
model.summary()
return model
class Resnet(tf.keras.Model):
def __init__(self, num_classes=9):
super(Resnet, self).__init__()
self.block_1 = tf.keras.applications.ResNet152V2(
include_top=False, weights='imagenet', input_tensor=None,
input_shape=(256,256,3), pooling=None, classes=1000)
self.global_pool = layers.GlobalAveragePooling2D()
self.dropout = Dropout(0.3)
self.classifier = Dense(num_classes, activation = 'softmax')
def call(self, inputs):
x = self.block_1(inputs)
x = self.global_pool(x)
x = self.dropout(x)
x = self.classifier(x)
return tf.keras.Model(inputs = inputs, outputs = x)
Using the subclassing API will actually make your model unserializable (see the "Limitations section in the "What are Symbolic and Imperative APIs in TensorFlow 2.0? " blogpost):
Imperative models are also more difficult to inspect, copy, or clone.
For example, model.save(), model.get_config(), and clone_model do not work for subclassed models. Likewise, model.summary() only gives you a list of layers (and doesn’t provide information on how they’re connected, since that’s not accessible).
Edit: From Tensorflow 2.4, it is possible to pass a save_traces argument to model.save to serialize models built using the subclassing API. See https://www.tensorflow.org/guide/keras/save_and_serialize#how_savedmodel_handles_custom_objects.
Here's a simple example of how you can do this:
import tensorflow as tf
from tensorflow.keras.layers import (Dense, Dropout, GlobalAveragePooling2D,
Input)
def build_network():
inp = Input(shape=(256, 256, 3))
resnet = tf.keras.applications.ResNet152V2(include_top=False,
weights="imagenet",
input_tensor=None,
input_shape=(256, 256, 3),
pooling=None,
classes=1000)
# classifier_activation="softmax"
x = resnet(inp)
x = GlobalAveragePooling2D()(x)
x = Dropout(0.3)(x)
x = Dense(9, activation="softmax")(x)
model = tf.keras.Model(inputs=inp, outputs=x)
# optimizer = "adam",
opt = tf.keras.optimizers.SGD(momentum=0.9)
model.compile(loss="categorical_crossentropy",
optimizer=opt,
metrics=["accuracy"])
model.summary()
return model
if __name__ == "__main__":
model = build_network()
model.summary()
# Save
model.save("my_model.h5")
# Load
loaded_model = tf.keras.models.load_model("my_model.h5")
loaded_model.summary()
To load your saved model from your build_network function use tf.keras.models.load_model.

Categories

Resources