I know that it is possible to create customize layer in tensorflow 2 like this:
class CustomDense(tf.keras.layers.Layer):
def __init__(self,unit,activation):
super(CustomDense, self).__init__(name='my_layer')
self.unit=unit
self.activation=activation
def build(self, input_shape):
self.kernel = self.add_weight(shape=(input_shape[1],self.unit),trainable=Truename='kernel')
self.bias = self.add_weight(shape=(self.unit,),name='bias')
def call(self,inputs):
x=tf.matmul(inputs,self.kernel) + self.bias
output=self.activation(x)
return output
But is it possible to create a custom layer which its parent's class is an existing layer like Dense or Conv2D?
class CustomDense(tf.keras.layers.Dense):
Related
Here is a demo code (not work). I want the filters (output_channels) equal to the input_channels, where I do not know the input_channels before hand. (i.e., it is dynamic).
import tensorflow.keras as keras
class CustomLayer(keras.layers.Layer):
def __init__(self, strides):
super().__init()
self.conv = keras.layers.Conv2D(
filters=input_channels,
strides=strides
)
def call(self, inputs):
return self.conv(inputs)
I have defined a custom LSTM Layer as follows:
class LSTMModel(tf.keras.Model):
def __init__(self, CNN_model, num_classes):
super().__init__()
self.cnn_model = CNN_model
self.lstm = tf.keras.layers.LSTM(units=64, return_state=True, dropout=0.3)
self.dense = tf.keras.layers.Dense(num_classes, activation="softmax")
def call(self, input):
pass
However, I am unclear what needs too occur in the call function here. I also wrote a generic CNN class like below:
class generic_vns_function(tf.keras.Model):
# Where would we use layer_units here?
def __init__(self, input_shape, layers, layer_units):
super().__init__()
self.convolutions = []
# Dynamically create Convolutional layers and MaxPools
for layer in range(len(layers)):
self.convolutions.append(tf.keras.layers.Conv2D(layer, 3, padding="same",
input_shape=input_shape, activation="relu"))
# Add MaxPooling layer
self.convolutions.append(tf.keras.layers.MaxPooling2D((2,2)))
# Flatten
self.flatten = tf.keras.layers.Flatten()
# Dense layer
self.dense1 = tf.keras.layers.Dense(1024, activation="relu")
def call(self, input):
x = input
for layer in self.convolutions:
x = layer(x)
x = self.flatten(x)
x = self.dense1(x)
return x
but here the required structure makes a lot more sense to me. I am just initializing all of the layers. What do I need to do to initialize my LSTM layers?
You could write it like this:
import tensorflow as tf
from tensorflow.keras.layers import Dense
from tensorflow.keras.layers import LSTM
from tensorflow.keras import Model
class LSTMModel(Model):
def __init__(self, num_classes, num_units=64, drop_prob=0.3):
super().__init__()
self.num_classes = num_classes
self.num_units = num_units
self.drop_prob = drop_prob
self.lstm = LSTM(
units=self.num_units,
return_state=True,
dropout=self.drop_prob)
self.dense = Dense(
num_classes,
activation="softmax")
def call(self, x, training=True):
x, *state = self.lstm(x, training=training)
x = self.dense(x)
return x
And then you would use it like:
model = LSTMModel(num_classes=2)
time_series = tf.random.normal((32, 64, 128))
x_pred = model(time_series)
# loss and gradients calculations ...
It is a common tensorflow idom to instantiate layers when initializing a custom layer/model, and then execute their call() methods by passing data through them in your custom call implementation.
I am new to Tensorflow. I want to connect a layer with another layer in which only the corresponding neurons are connected with weights to each other as shown below. This means all the neurons in the previous layer are not connected to a neuron in the next layer.
Now I get 4 neurons with wixi. Further, I need to add all these outputs to get a single value. Now I want to pass this single value to a dense layer of size 4 for the autoencoder operation to complete.
I have created my custom layer for the wixi operation and I am correctly getting it but when I apply normal dense layer after addition I get the following error:
'''
ValueError: Input 0 of layer dense_15 is incompatible with the layer: : expected min_ndim=2, found ndim=1. Full shape received: [100]
'''
Following is my code for custom layer and model-
class Layer_w_x(tf.keras.layers.Layer):
def __init__(self):
super(Layer_w_x, self).__init__()
def build(self, input_shape):
self.w = self.add_weight(shape=(input_shape[-1],),
initializer="random_normal", trainable=True)
def call(self, inputs):
return tf.multiply(inputs, self.w)
class MyModel(Model):
def __init__(self, **kwargs):
super(MyModel, self).__init__(**kwargs)
self.layer_1 = Layer_w_x()
self.dense = Dense(4,activation = 'sigmoid')
def call(self, inputs):
# CALCULATION FOR FIRST NEURON
h1 = self.layer_1(inputs)
h4 = tf.reduce_sum(h1,1)
encoded = self.dense(h4)
return encoded
model = MyModel()
output =model(my_train_data1)
my_train_data1 has size (100,4)
You can make your own layer by subclassing from tf.keras.layers.Layer.
Creating custom layers is described in https://www.tensorflow.org/guide/keras/custom_layers_and_models
and https://www.tensorflow.org/tutorials/customization/custom_layers.
I created the layer for you.
import tensorflow as tf
class DirectLayer(tf.keras.layers.Layer):
def __init__(self):
super(DirectLayer, self).__init__()
def build(self, input_shape):
self.w = self.add_weight(
shape=input_shape,
initializer="random_normal",
trainable=True,
)
self.b = self.add_weight(
shape=(input_shape[-1],), initializer="random_normal", trainable=True
)
def call(self, inputs):
# outputs shape
return tf.multiply(inputs, self.w) + self.b
layer1 = DirectLayer()
layer2 = DirectLayer()
x = tf.ones([16,2])
y = layer1(x)
y = layer2(y)
tf.print(y.shape)
It outputs TensorShape([16, 2]), which means that it maintains the input's dimensions, which, I believe, is what you want. Notice I used tf.multiply (multiply elementwise) as opposed to what the Dense layer does—tf.matmul (matrix multiplication).
From tensorflow keras example. I can create a custom layer which contains Linear layer recursively
class MLPBlock(layers.Layer):
def __init__(self):
super(MLPBlock, self).__init__()
self.linear_1 = Linear(32)
self.linear_2 = Linear(32)
self.linear_3 = Linear(1)
def call(self, inputs):
x = self.linear_1(inputs)
x = tf.nn.relu(x)
x = self.linear_2(x)
x = tf.nn.relu(x)
return self.linear_3(x)
how do i access all the component layers of a custom layer, I want to access weight and biases of all the component layers.
ex:
MLPBlock(Parent Layer):
linear_1
linear_2
linear_3
I have looked into tensorflow keras api version r 1.14 https://www.tensorflow.org/guide/keras
but could not find any way to do this.
I assume that you are following this tutorial. Based on that, here is how you can access the weights:
class MLPBlock(tf.keras.Model):
def __init__(self):
super(MLPBlock, self).__init__()
self.linear_1 = tf.keras.layers.Dense(32)
self.linear_2 = tf.keras.layers.Dense(32)
self.linear_3 = tf.keras.layers.Dense(1)
def call(self, inputs):
x = self.linear_1(inputs)
x = tf.nn.relu(x)
x = self.linear_2(x)
x = tf.nn.relu(x)
return self.linear_3(x)
mlp_block = MLPBlock()
y = mlp_block(tf.ones(shape=(3, 64)))
for layer in mlp_block.layers:
weights, biases = layer.get_weights()
Please note that I slightly modified the example so that you can access the layer's weights and biases. Namely, what I did is instead of subclassing the class with tf.keras.layers.Layer, I subclassed with tf.keras.Model so that the stack of layers can be treated as a model, and then you can access the layers of that model. Then, instead of using the custom Linear layer, I used the tf.keras.layers.Dense for simplicity, however, using the custom layer should not make a difference.
I was trying to implement the Google Bert model in tensorflow-keras using tensorflow hub. For this I designed a custom keras layer "Bertlayer" . Now the problem is when I am compiling the keras model it keeps showing that
AttributeError: 'Bertlayer' object has no attribute '_keras_style'
I don't know where I am wrong and what _keras_style attribute is.Please help to find the error in the code.
This is the github link to the full code: https://github.com/PradyumnaGupta/BERT/blob/master/Untitled21.ipynb
class BertLayer(tf.layers.Layer):
def __init__(self, n_fine_tune_layers=10, **kwargs):
self.n_fine_tune_layers = n_fine_tune_layers
self.trainable = True
self.output_size = 768
super(BertLayer, self).__init__(**kwargs)
def build(self, input_shape):
self.bert = hub.Module(
bert_path,
trainable=self.trainable,
name="{}_module".format(self.name)
)
trainable_vars = self.bert.variables
# Remove unused layers
trainable_vars = [var for var in trainable_vars if not "/cls/" in var.name]
# Select how many layers to fine tune
trainable_vars = trainable_vars[-self.n_fine_tune_layers :]
# Add to trainable weights
for var in trainable_vars:
self._trainable_weights.append(var)
for var in self.bert.variables:
if var not in self._trainable_weights:
self._non_trainable_weights.append(var)
super(BertLayer, self).build(input_shape)
def call(self, inputs):
inputs = [K.cast(x, dtype="int32") for x in inputs]
input_ids, input_mask, segment_ids = inputs
bert_inputs = dict(
input_ids=input_ids, input_mask=input_mask, segment_ids=segment_ids
)
result = self.bert(inputs=bert_inputs, signature="tokens", as_dict=True)[
"pooled_output"
]
return result
def compute_output_shape(self, input_shape):
return (input_shape[0], self.output_size)
So, tensorflow version 1.* is a bit misleading. It actually has 2 bases classes called Layer. One - the one that you are using. It is intended to implement shortcut wrappers over regular TF operations. The other from tensorflow.keras.layers import Layer is for Keras-like models and sequencies.
Judging by your error, you are using keras/models to train further.
You probably should start form derivering your layer from keras.layers.Layer instead of tf.layers.Layer.