convert Lasagne to Keras code (CNN -> LSTM) - python

I would like to convert this Lasagne code:
et = {}
net['input'] = lasagne.layers.InputLayer((100, 1, 24, 113))
net['conv1/5x1'] = lasagne.layers.Conv2DLayer(net['input'], 64, (5, 1))
net['shuff'] = lasagne.layers.DimshuffleLayer(net['conv1/5x1'], (0, 2, 1, 3))
net['lstm1'] = lasagne.layers.LSTMLayer(net['shuff'], 128)
in Keras code. Currently I came up with this:
multi_input = Input(shape=(1, 24, 113), name='multi_input')
y = Conv2D(64, (5, 1), activation='relu', data_format='channels_first')(multi_input)
y = LSTM(128)(y)
But I get the error: Input 0 is incompatible with layer lstm_1: expected ndim=3, found ndim=4

Solution
from keras.layers import Input, Conv2D, LSTM, Permute, Reshape
multi_input = Input(shape=(1, 24, 113), name='multi_input')
print(multi_input.shape) # (?, 1, 24, 113)
y = Conv2D(64, (5, 1), activation='relu', data_format='channels_first')(multi_input)
print(y.shape) # (?, 64, 20, 113)
y = Permute((2, 1, 3))(y)
print(y.shape) # (?, 20, 64, 113)
# This line is what you missed
# ==================================================================
y = Reshape((int(y.shape[1]), int(y.shape[2]) * int(y.shape[3])))(y)
# ==================================================================
print(y.shape) # (?, 20, 7232)
y = LSTM(128)(y)
print(y.shape) # (?, 128)
Explanations
I put the documents of Lasagne and Keras here so you can do cross-referencing:
Lasagne
Recurrent layers can be used similarly to feed-forward layers except
that the input shape is expected to be (batch_size, sequence_length, num_inputs)
Keras
Input shape
3D tensor with shape (batch_size, timesteps, input_dim).
Basically the API is the same, but Lasagne probably does reshape for you (I need to check the source code later). That's why you got this error:
Input 0 is incompatible with layer lstm_1: expected ndim=3, found ndim=4
, since the tensor shape after Conv2D is (?, 64, 20, 113) of ndim=4
Therefore, the solution is to reshape it to (?, 20, 7232).
Edit
Confirmed with the Lasagne source code, it does the trick for you:
num_inputs = np.prod(input_shape[2:])
So the correct tensor shape as input for LSTM is (?, 20, 64 * 113) = (?, 20, 7232)
Note
Permute is redundant here in Keras since you have to reshape anyway. The reason why I put it here is to have a "full translation" from Lasagne to Keras, and it does what DimshuffleLaye does in Lasagne.
DimshuffleLaye is however needed in Lasagne because of the reason I mentioned in Edit, the new dimension created by Lasagne LSTM is from the multiplication of "the last two" dimensions.

Related

How to Feed Tensor Dataset to Model

I am new to Tensorflow and trying to figure out how to build a simple text classification model. Taking a basic model from this tutorial, I am trying to adapt it to my own custom dataset.
I have tensors with shape=(32, 2, 500) grouped into training and validation datasets with shape=(None, 2, 500).
def get_model(max_features=20000, embedding_dim=128):
# A integer input for vocab indices.
inputs = tf.keras.Input(shape=(None,), dtype="int64")
# Next, we add a layer to map those vocab indices into a space of dimensionality
#'embedding_dim'.
x = layers.Embedding(max_features, embedding_dim)(inputs)
x = layers.Dropout(0.5)(x)
# Conv1D + global max pooling
x = layers.Conv1D(128, 7, padding="valid", activation="relu", strides=3)(x)
x = layers.Conv1D(128, 7, padding="valid", activation="relu", strides=3)(x)
x = layers.GlobalMaxPooling1D()(x)
# We add a vanilla hidden layer:
x = layers.Dense(128, activation="relu")(x)
x = layers.Dropout(0.5)(x)
# We project onto a single unit output layer, and squash it with a sigmoid:
predictions = layers.Dense(1, activation="sigmoid", name="predictions")(x)
model = tf.keras.Model(inputs, predictions)
# Compile the model with binary crossentropy loss and an adam optimizer.
model.compile(loss="binary_crossentropy", optimizer="adam", metrics=["accuracy"])
return model
I get the following warning:
WARNING:tensorflow:Model was constructed with shape (None, None) for input KerasTensor(type_spec=TensorSpec(shape=(None, None), dtype=tf.int64, name='input_16'), name='input_16', description="created by layer 'input_16'"), but it was called on an input with incompatible shape (None, 2, 500).
And the following error message:
Input 0 of layer "global_max_pooling1d_6" is incompatible with the layer: expected ndim=3, found ndim=4. Full shape received: (None, 2, 53, 128)
Call arguments received by layer "model_7" " f"(type Functional):
• inputs=tf.Tensor(shape=(None, 2, 500), dtype=int64)
• training=True
• mask=None
What do I need to change to get rid of this error and get the model working?

Keras input_shape for conv2d for 2d tabular data of regression problem?

I am trying to implement the CNN on a regression problem using Keras
> x_train2 = x_train.values.reshape(list(x_train.shape) + [1])
> input_shape = x_train2.shape model = Sequential()
> model.add(Conv2D(filters = 32, kernel_size = (5,5),padding = 'Same', activation ='relu', input_shape = input_shape))
output of x_train2.shape is (8000, 28, 1) and output of x_train.shape is (8000, 28)
The problem is that Input_shape should be a 4dim vectors but since the date is tabular so we have 2d data
I have tried this transformation to convert my 2d data but still have some issues
x_train2 = x_train.values.reshape(list(x_train.shape) + [1])
Any idea what am I missing or is it not possible to user the Keras Conv2D function for 2d data
This is the error i am getting
ValueError: Input 0 of layer sequential_15 is incompatible with the
layer: : expected min_ndim=4, found ndim=3. Full shape received: [32,
28, 1]
Thanks in Advance

ValueError: Input 0 of layer sequential is incompatible with the layer: : expected min_ndim=4, found ndim=3. Full shape received: [8, 28, 28]

I keep on getting this error related to input shape. Any help would be highly appreciated. Thanks!
import tensorflow as tf
(xtrain, ytrain), (xtest, ytest) = tf.keras.datasets.mnist.load_data()
model = tf.keras.Sequential([
tf.keras.layers.Conv2D(16, kernel_size=3, activation='relu'),
tf.keras.layers.MaxPooling2D(pool_size=2),
tf.keras.layers.Conv2D(32, kernel_size=3, activation='relu'),
tf.keras.layers.MaxPooling2D(pool_size=2),
tf.keras.layers.Flatten(),
tf.keras.layers.Dense(64, activation='relu'),
tf.keras.layers.Dense(10, activation='softmax')
])
model.compile(loss='categorical_crossentropy',
optimizer='adam',
metrics='accuracy')
history = model.fit(xtrain, ytrain,
validation_data=(xtest, ytest),
epochs=10, batch_size=8)
ValueError: Input 0 of layer sequential is incompatible with the layer: : expected min_ndim=4, found ndim=3. Full shape received: [8, 28, 28]
The input layers of the model you created needs a 4 dimension tensor to work with but the x_train tensor you are passing to it has only 3 dimensions
This means that you have to reshape your training set with .reshape(n_images, 286, 384, 1). Now you have added an extra dimension without changing the data and your model is ready to run.
you need to reshape your x_train tensor to a 4 dimension before training your model.
for example:
x_train = x_train.reshape(-1, 28, 28, 1)
for more info on keras inputs Check this answer
You need to add a channel dimension. Keras expects this data format:
(n_samples, height, width, channels)
For instance this, if your images are greyscale, they have 1 channel, and so they need to be given to Keras in this format:
(60000, 28, 28, 1)
Unfortunately, grayscale pictures will often be given/downloaded without a channel dimension, for instance in tf.keras.datasets.mnist.load_data, which will be (60000, 28, 28), which is problematic.
Solution:
You can use tf.expand_dims to add a dimension
xtrain = tf.expand_dims(xtrain, axis=-1)
Now your input shape will be:
(60000, 28, 28, 1)
There are other alternatives that do the same:
xtrain = xtrain[..., np.newaxis]
xtrain = xtrain[..., None]
xtrain = xtrain.reshape(-1, 28, 28, 1)
xtrain = tf.reshape(xtrain, (-1, 28, 28, 1))
xtrain = np.expand_dims(xtrain, axis=-1)
You can also use tf.newaxis to add a new axis:
arr = tf.random.uniform(shape=(8,8,28))
print(arr.shape)
arr = arr[:,:,:,tf.newaxis]
print(arr.shape)
# (8, 8, 28)
# (8, 8, 28, 1)

Error defining an input shape in keras for (60000, 28, 28) array

I am setting up my first neural network with keras and tensorflow. I got my input into an array of shape (60000, 28, 28), but when I try and feed it to the model I get an error that the input shape is wrong.
I have tried multiple different input shapes including (60000, 28, 28) (1, 28, 28) (28, 28) (28, 28, 1) but none of them seem to work.
model = kr.Sequential()
model.add(InputLayer(input_shape=(60000, 28, 28)))
model.add(Dense(units=784, activation='relu'))
model.add(Dense(units=392, activation='relu'))
model.add(Dense(units=196, activation='relu'))
model.add(Dense(units=10, activation='softmax'))
model.compile(loss='categorical_crossentropy', optimizer='Adam', metrics=['accuracy'])
training = model.fit(x=images_array, y=labels_array, epochs=10, batch_size=256)
I would expect it to work with input shape (60000, 28, 28) but I always get this error:
ValueError: Error when checking input: expected input_1 to have 4
dimensions, but got array with shape (60000, 28, 28)
Edit:
Thanks to everyone who answerd. cho_uc answer indeed worked, which is why I accepted it.
What I shold have mentioned in the post was, that I was trying to build a model consisting only of Dense layers, so I can use it as a benchmark for future models.
I solved the input layer problem with:
images_array = images_array.reshape(-1, 28 * 28)
model.add(InputLayer(input_shape=(784, )))
Keras Conv2D layer performs the convolution operation. It requires its input to be a 4-dimensional array.
We have to reshape the input to ( , 1, 28, 28) or possibly to ( , 28, 28, 1), depending on your setup and backend (theano or tensorlow image layout convention).
from keras import backend as K
if K.image_data_format() == 'channels_first' :
input_shape = (1, 28, 28)
X_train = X_train.reshape(X_train.shape[0], 1, 28, 28)
X_test = X_test.reshape(X_test.shape[0], 1, 28, 28)
else:
input_shape = (28, 28, 1)
X_train = X_train.reshape(X_train.shape[0], 28, 28, 1)
X_test = X_test.reshape(X_test.shape[0], 28, 28, 1)
So, you should reshape your data to (60000, 28, 28, 1) or (60000, 1, 28, 28)
Two corrections are required.
TF and Keras expects image dimension as (Width, Height, Channels), channels being 3 for RGB images and 1 for greyscale images.
model.add(InputLayer(input_shape=(28, 28, 1)))
The training input to fit() method must be of dimension (Number of samples, Width, Height, Channels).
assert images_array.shape == (60000, 28, 28, 1)

Proper use of tf.layers.MaxPooling

I'm building a model in Tensorflow using tf.layers objects. When I run the following code using tf.layers.MaxPooling2D my model does not reduce in size. I've only recently switched from using Keras to Tensorflow directly so I presume I'm misunderstanding the usage.
import tensorflow as tf
import numpy as np
features = tf.constant(np.random.random((20,128,128,3)), dtype=tf.float32)
y_true = tf.constant(np.random.random((20,1)), dtype=tf.float32)
print('features = %s' % features)
conv = tf.layers.Conv2D(32,(2,2),padding='same')(features)
print('conv = %s' % conv)
pool = tf.layers.MaxPooling2D((2,2),(1,1),padding='same')(conv)
print('pool = %s' % pool)
# and so on ...
I see this output:
features = Tensor("Const:0", shape=(20, 128, 128, 3), dtype=float32)
conv = Tensor("conv2d/BiasAdd:0", shape=(20, 128, 128, 32), dtype=float32)
pool = Tensor("max_pooling2d/MaxPool:0", shape=(20, 128, 128, 32), dtype=float32)
I was expecting to see the output from the MaxPool layer to have a shape of (20,64,64,32).
Am I using this this correctly?
If you want to downsample by a factor of 2 your feature map, you should use a stride 2.
In [1]: tf.layers.MaxPooling2D(2, 2, padding='same')(conv)
Out[1]: <tf.Tensor 'max_pooling2d/MaxPool:0' shape=(20, 64, 64, 32) dtype=float32>

Categories