I am trying to make a model in tensorflow using the keras subclasses method.
Q1) I am correctly calling layers as
layers =  and then using
Q2) calling GTLayer in init of GTN will run class GTLayer and will it call self.conv1 (which will return a tensor A from GTNconv) and self.conv2 (which will again return a tensor A from GTNconv)and then start the
call mrthod of GTLayer to
H,W , Am I right?
Q3) What happens to the returned
H and W from ‘Q2’ will it store in
layers list ? and then when we further call the GTNs
call method it will bring up those layer? Am I correct?
Q4)Later in the
call method I had to implement linear layers and thus I defined
model = tf.keras.models.Sequential() and after theat initialised
self.linear2, this way I have implemented subclassing and sequential both! Is that correct?
Q5) I will finally get
loss, y, Ws from calling GTN , now if I assign my
model = GTN(arguments..) how will I do the training and back-propagation steps? using an optimiser and loss function? will it follow
model.fit ? Or can we make it any different in the sub-classing method of keras?
import tensorflow as tf from tensorflow import keras from tensorflow.keras import layers class GTN(layers.Layer): def __init__(self, num_edge, num_channels,num_layers,norm): super(GTN, self).__init__() self.num_edge = num_edge self.num_channels = num_channels self.num_layers = num_layers self.is_norm = norm layers =  for i in tf.range(num_layers): if i == 0: layers.append(GTLayer(num_edge, num_channels, first=True)) else: layers.append(GTLayer(num_edge, num_channels, first=False)) model = tf.keras.models.Sequential() self.loss = tf.keras.losses.BinaryCrossentropy(from_logits=True) self.linear1 = model.add(tf.keras.layers.Dense(self.w_out, input_shape=(self.w_out*self.num_channels,), activation=None)) self.linear2 = model.add(tf.keras.layers.Dense(self.num_class, input_shape=(self.w_out,), activation=None)) def gcn_conv(self,X,H): X = tf.matmul(X, self.weight) H = self.norm(H, add=True) return tf.matmul(tf.transpose(H),X) def call(self, A, X, target_x, target): A = tf.expand_dims(A, 0) Ws =  for i in range(self.num_layers): H = self.normalization(H) H, W = self.layers[i](A, H) Ws.append(W) for i in range(self.num_channels): X_tmp = tf.nn.relu(self.gcn_conv(X,H[i])).numpy() X_ = tf.concat((X_,X_tmp), dim=1) X_ = self.linear1(X_) X_ = tf.nn.relu(X_).numpy() y = self.linear2(X_[target_x]) loss = self.loss(y, target) return loss, y, Ws class GTLayer(keras.layers.Layer): def __init__(self, in_channels, out_channels, first=True): super(GTLayer, self).__init__() self.in_channels = in_channels self.out_channels = out_channels self.conv1 = GTConv(in_channels, out_channels) self.conv2 = GTConv(in_channels, out_channels) def call(self, A, H_=None): a = self.conv1(A) b = self.conv2(A) H = tf.matmul( a, b) W = [tf.stop_gradient(tf.nn.softmax(self.conv1.weight, axis=1).numpy()), tf.stop_gradient(tf.nn.softmax(self.conv2.weight, axis=1).numpy()) ] return H,W class GTConv(keras.layers.Layer): def __init__(self, in_channels, out_channels): super(GTConv, self).__init__() def call(self, A): A = tf.add_n(tf.nn.softmax(self.weight)) return A
No. There are two possibilities here
1 – If you want to access a standard
layers property of Keras models:
keras.layers.Layerdoesn’t have this property
- You are not supposed to mess with the
layersproperty of a
Model, you should just read it
- The variable you are creating named
layersis not a property of your class because you did not use
2 – If you just want a list named
layers for personal use in your class:
- I recommend you don’t use a standard name like this and change it to
myLayersor something like that to avoid confusion.
- The variable
layersyou created is not being used anywhere else in your code, you just created it and never used.
- Remember that
layers = just creates a local variable, while
self.layers = creates a property in your class that can be used in other methods inside your class
You are not "calling"
GTLayer, you are "creating"
GTLayer. This means that you are running
This distinction is important in Keras:
- This is "creating" a layer:
layer_instance = GTLayer(...), which runs
- This is "calling" a layer:
layer_instance(input_tensors), which runs
__call__(which will eventually run
callas defined by you)
You can do both in the same line as
output_tensors = GTLayer(...)(input_tensors)
So, this is happening in
- You are "creating" two instances of the
- This runs
GTLayer.__init__()for each instance
- This hits the lines
self.conv1 = GTConv(in_channels, out_channels)and
self.conv2 = GTConv(in_channels, out_channels)
- This is also "creating" (not "calling")
self.conv2are "Layer" instances, not tensors.
No tensor is produced here because you never "called" any layer in
(And this is ok. Usually, you "create" layers inside
__init__() and "call" layers inside
layers local variable will have "instances of
You mixed two approaches in a strange way.
You can, of course, use a
Sequential model if you want, but it’s not necessary, and you’re not using it correcly.
call you are calling each layer (that is
X_ = self.linear1(X_) and
y = self.linear2(X_[target_x])), you don’t need a
Sequential model at all, and you can just have the following in
GTN.__init__() (this is the best approach for subclassing):
self.linear1 = tf.keras.layers.Dense(self.w_out, input_shape=(self.w_out*self.num_channels,), activation=None) self.linear2 = tf.keras.layers.Dense(self.num_class, input_shape=(self.w_out,), activation=None)
But you could have
self.submodel = Sequential(...) and then use
GTN.call(). But having a
Model inside a layer sounds weird and might cause some strange behavior in specific cases. And, of course, the ReLUs should be a part of this submodel.
I will finally get
loss, y, Ws from calling GTN
That loss and weights coming from
call is a "very very" strange thing. I never saw this and I don’t understand why you’re doing it this way. This is not standard use of Keras and only in very specific and otherwise unsolvable cases you’d try something like this. I cannot say it will work.
How will I do the training and back-propagation steps?
You should have implemented a
keras.models.Model, not a
keras.layers.Layer. Only models have the ability to compile and train.
Usually, you’d not create a loss in call, you’d create a loss in
model.compile, unless you’re dealing with unconventional losses, like weight or activity regularization, things that really depend on the layer and not on the model’s inputs/outputs.
There is no need to create custom layers if you’re not going to create custom trainable weights. It’s not wrong, of course, but also not necessary. It can help organize your code, or just add extra complication.
You are trying to use
weight from your layers, but you never defined any weight anywhere.
I’m pretty sure there is a better way to achieve what you want, but I don’t know what you want (and that would be something for another question, I think…)
This might be a good reading for subclassing: https://www.tensorflow.org/guide/keras/custom_layers_and_models?hl=en
Answered By – Daniel Möller