Keras allows to create our own customized layer. Once a new layer is created, it can be used in any model without any restriction. Let us learn how to create new layer in this chapter.
Keras provides a base layer class, Layer which can sub-classed to create our own customized layer. Let us create a simple layer which will find weight based on normal distribution and then do the basic computation of finding the summation of the product of input and its weight during training.
First, let us import the necessary modules −
from keras import backend as K from keras.layers import Layer
Here,
backend is used to access the dot function.
Layer is the base class and we will be sub-classing it to create our layer
Let us create a new class, MyCustomLayer by sub-classing Layer class −
class MyCustomLayer(Layer): ...
Let us initialize our new class as specified below −
def __init__(self, output_dim, **kwargs): self.output_dim = output_dim super(MyCustomLayer, self).__init__(**kwargs)
Here,
Line 2 sets the output dimension.
Line 3 calls the base or super layer’s init function.
build is the main method and its only purpose is to build the layer properly. It can do anything related to the inner working of the layer. Once the custom functionality is done, we can call the base class build function. Our custom build function is as follows −
def build(self, input_shape): self.kernel = self.add_weight(name = 'kernel', shape = (input_shape[1], self.output_dim), initializer = 'normal', trainable = True) super(MyCustomLayer, self).build(input_shape)
Here,
Line 1 defines the build method with one argument, input_shape. Shape of the input data is referred by input_shape.
Line 2 creates the weight corresponding to input shape and set it in the kernel. It is our custom functionality of the layer. It creates the weight using ‘normal’ initializer.
Line 6 calls the base class, build method.
call method does the exact working of the layer during training process.
Our custom call method is as follows
def call(self, input_data): return K.dot(input_data, self.kernel)
Here,
Line 1 defines the call method with one argument, input_data. input_data is the input data for our layer.
Line 2 return the dot product of the input data, input_data and our layer’s kernel, self.kernel
def compute_output_shape(self, input_shape): return (input_shape[0], self.output_dim)
Here,
Line 1 defines compute_output_shape method with one argument input_shape
Line 2 computes the output shape using shape of input data and output dimension set while initializing the layer.
Implementing the build, call and compute_output_shape completes the creating a customized layer. The final and complete code is as follows
from keras import backend as K from keras.layers import Layer class MyCustomLayer(Layer): def __init__(self, output_dim, **kwargs): self.output_dim = output_dim super(MyCustomLayer, self).__init__(**kwargs) def build(self, input_shape): self.kernel = self.add_weight(name = 'kernel', shape = (input_shape[1], self.output_dim), initializer = 'normal', trainable = True) super(MyCustomLayer, self).build(input_shape) # Be sure to call this at the end def call(self, input_data): return K.dot(input_data, self.kernel) def compute_output_shape(self, input_shape): return (input_shape[0], self.output_dim)
Let us create a simple model using our customized layer as specified below −
from keras.models import Sequential from keras.layers import Dense model = Sequential() model.add(MyCustomLayer(32, input_shape = (16,))) model.add(Dense(8, activation = 'softmax')) model.summary()
Here,
Our MyCustomLayer is added to the model using 32 units and (16,) as input shape
Running the application will print the model summary as below −
Model: "sequential_1" _________________________________________________________________ Layer (type) Output Shape Param #================================================================ my_custom_layer_1 (MyCustomL (None, 32) 512 _________________________________________________________________ dense_1 (Dense) (None, 8) 264 ================================================================= Total params: 776 Trainable params: 776 Non-trainable params: 0 _________________________________________________________________