How to gather a tensor from Keras using its backend? - keras

I trying to compile a model in Keras with an input that is a 2D numpy array.
What I need is to take the vector at the nth place of this 2D array and use it as a tensor 1D tensor for one of the layers.
How do I do it?

Using a lambda layer should do it:
extracted_tensor = Lambda(lambda x: x[:,nth_index,:], output_shape=(1,dim_vector))(input)
extracted_tensor = Flatten()(extracted_tensor)
note that in the x tensor (lambda function), you take the batch dimension into account, but you don't in the output_shape parameter.
I hope this helps

Use tf.gather( input_tensor, indices, axis ) to collect indices along the specified axis.

Related

numpy array for sequential network: varying sequence length

I have a recurrent network (RNN) whose task is to learn to classify vectors (float32) in two classes. My model is really simple so far:
model = Sequential([
SimpleRNN(units=10, input_shape=(None, len_vector)),
Dense(1, activation="relu")
])
model.compile(loss='mse', optimizer='Adam', metrics=['accuracy'])
history = model.fit(X_train, y_train, epochs=30)
To train this network, I create a dataset with 1000 instances of sequences of vectors. When I create sequences with the same length each, the training works perfectly and the dataset has shape:
[<number of sequences>, <number of vectors in each sequence>, <number of floats in each vector>]
The problem is that my model must be able to work on sequence with various length. I don't know how (or even if it is possible) to create a numpy array where one dimension is not constant.
While searching a solution, I saw that setting the array dtype=object made it possible to assign list of different shapes to element of a numpy array, but the keras model will only accept dtype="float32".
Is there a way I can make this numpy array dataset? Or should I change the algorithm to train the model? Or is the only solution to pad sequences with nul vectors to unify their length?
(Thanks for the help. I'm fairly new to deep learning so I apologize if I'm asking for something obvious.)
Use Ragged Tensors, they provide you to make variable length inputs,
import numpy as np
_input = tf.keras.layers.Input(shape=(None, 100))
lstm = tf.keras.layers.LSTM(20,)(_input)
func = tf.keras.backend.function(inputs=_input, outputs=lstm)
rt = tf.ragged.constant([np.random.randn(1,34,100),
np.random.randn(1,55,100) ,
np.random.randn(1,60,100) ,
np.random.randn(1,70,100)])
func(rt[1])

class_weight in fit_generator as np.array or dictionary?

I am trying to recreate binary image using a UNet. But the classification labels are extremely skewed (~10% are 0s and rest are 1s in the image). So I got the weights for each class using skearn. This is what I do:
wts = np.array([5.76901408, 0.54744721])
class_wts = dict(enumerate(wts))
Now, when I put this in fit_generator:
history_sgd = model.fit_generator(training_generator, validation_data=valid_generator, steps_per_epoch=train_steps, validation_steps=valid_steps, epochs=epochs, verbose=1, class_weight = class_wts)
I get the following error:
ValueError: class_weight not supported for 3+ dimensional targets.
Could this be because of the generator shape? Because that would be of the shape (batch_size, <image_size>).
Moreover, when I use class_weight as numpy array instead of dictionary, the code works. Why does that happen? I checked a lot of resources online but I cannot figure the difference between the two and why the numpy array format works but not the dictionary.

Convert 3D Tensor to 4D Tensor in Pytorch

I had difficulty finding information on reshaping in PyTorch. Tensorflow is quite easy.
My tensor has shape torch.Size([3, 480, 480]).
I want to convert it to a 4D tensor with shape [1,3,480,480].
How do I do that?
You can use unsqueeze()
For example:
x = torch.zeros((4,4,4)) # Create 3D tensor
x = x.unsqueeze(0) # Add dimension as the first axis (1,4,4,4)
I've seen a few people use indexing with None to add a singular dimension as well. For example:
x = torch.zeros((4,4,4)) # Create 3D tensor
print(x[None].shape) # (1,4,4,4)
print(x[:,None,:,:].shape) # (4,1,4,4)
print(x[:,:,None,:].shape) # (4,4,1,4)
print(x[:,:,:,None].shape) # (4,4,4,1)
Personally, I prefer unsqueeze(), but it's good to be familiar with both.

Does 1D Convolutional layer support variable sequence lengths?

I have a series of processed audio files I am using as input into a CNN using Keras. Does the Keras 1D Convolutional layer support variable sequence lengths? The Keras documentation makes this unclear.
https://keras.io/layers/convolutional/
At the top of the documentation it mentions you can use (None, 128) for variable-length sequences of 128-dimensional vectors. Yet at the bottom it declares that the input shape must be a
3D tensor with shape: (batch_size, steps, input_dim)
Given the following example how should I input sequences of variable length into the network
Lets say I have two examples (a and b) containing X 1 dimensional vectors of length 100 that I want to feed into the 1DConv layer as input
a.shape = (100, 100)
b.shape = (200, 100)
Can I use an input shape of (2, None, 100)? Do I need to concatenate these tensors into c where
c.shape = (300, 100)
Then reshape it to be something
c_reshape.shape = (3, 100, 100)
Where 3 is the batch size, 100, is the number of steps, and the second 100 is the input size? The documentation on the input vector is not very clear.
Keras supports variable lengths by using None in the respective dimension when defining the model.
Notice that often input_shape refers to the shape without the batch size.
So, the 3D tensor with shape (batch_size, steps, input_dim) suits perfectly a model with input_shape=(steps, input_dim).
All you need to make this model accept variable lengths is use None in the steps dimension:
input_shape=(None, input_dim)
Numpy limitation
Now, there is a numpy limitation about variable lengths. You cannot create a numpy array with a shape that suits variable lengths.
A few solutions are available:
Pad your sequences with dummy values until they all reach the same size so you can put them into a numpy array of shape (batch_size, length, input_dim). Use Masking layers to disconsider the dummy values.
Train with separate numpy arrays of shape (1, length, input_dim), each array having its own length.
Group your images by sizes into smaller arrays.
Be careful with layers that don't support variable sizes
In convolutional models using variable sizes, you can't for instance, use Flatten, the result of the flatten would have a variable size if this were possible. And the following Dense layers would not be able to have a constant number of weights. This is impossible.
So, instead of Flatten, you should start using GlobalMaxPooling1D or GlobalAveragePooling1D layers.

Keras - Reuse weights from a previous layer - converting to keras tensor

I am trying to reuse the weight matrix from a previous layer. As a toy example I want to do something like this:
import numpy as np
from keras.layers import Dense, Input
from keras.layers import merge
from keras import backend as K
from keras.models import Model
inputs = Input(shape=(4,))
inputs2 = Input(shape=(4,))
dense_layer = Dense(10, input_shape=(4,))
dense1 = dense_layer(inputs)
def my_fun(my_inputs):
w = my_inputs[0]
x = my_inputs[1]
return K.dot(w, x)
merge1 = merge([dense_layer.W, inputs2], mode=my_fun)
The problem is that dense_layer.W is not a keras tensor. So I get the following error:
Exception: Output tensors to a Model must be Keras tensors. Found: dot.0
Any idea on how to convert dense_layer.W to a Keras tensor?
Thanks
It seems that you want to share weights between layers.
I think You can use denselayer as shared layer for inputs and inputs2.
merge1=dense_layer(inputs2)
Do check out shared layers # https://keras.io/getting-started/functional-api-guide/#shared-layers
I don't think that you can use the merge layer like this.
But to answer your question, you will probably have to create a custom layer which has tied weights. Look at this example.
Otherwise, the way to access the weights of a layer is to use get_weights() method on that layer, this will retrun a list of numpy arrays containing the weights. For the case of the Dense layer, it will contain weights and bias.
There are two cases for the solution, depending on what you are trying to do:
You would like to share the W matrix between your two operations, and the W matrix for these two operations are kept the same even if its value changed during training or for some other reason. Then you should use dense.weights[0] which is the W matrix as a tensor from your dense layer.
If you are only going to use the value of W matrix at the time of your code is written and this value is never going to change, then use K.constant(dense.get_weights[0]) which extracts the weights as numpy array and is converted into tensor.

Resources