Transfer learning, wrong dense layer's shape - python

I am trying to apply transfer learning to my ANN for image classification.
I have found an example of it, and I would personalize the network.
Here there are the main blocks of code:
model = VGG19(weights='imagenet',
include_top=False,
input_shape=(224, 224, 3))
batch_size = 16
for layer in model.layers[:5]:
layer.trainable = False
x = model.output
x = Flatten()(x)
x = Dense(1024, activation="relu")(x)
x = Dense(1024, activation="relu")(x)
predictions = Dense(16, activation="sigmoid")(x)
model_final = Model(input = model.input, output = predictions)
model_final.fit_generator(
train_generator,
samples_per_epoch = nb_train_samples,
epochs = epochs,
validation_data = validation_generator,
validation_steps = nb_validation_samples,
callbacks = [checkpoint, early])
When I run the code above I get this error:
ValueError: Error when checking target: expected dense_3 to have shape (16,) but got array with shape (1,).
I suppose that the problem is about the dimensions' order in the dense layer, I have tried to transpose it, but I get the same error.

Maybe this simple example can help:
import numpy as np
test = np.array([1,2,3])
print(test.shape) # (3,)
test = test[np.newaxis]
print(test.shape) # (1, 3)
Try apply [np.newaxis] in your train_generator output.

Related

Shape error of Tensorflow GRU while doing slot filling

I'm trying to train slot filling by LSTM in tensorflow, but received a shape error after first epoch.
Error mes: "Input to reshape is a tensor with 5632 values, but the requested shape has 12800"
I used sequences model and defined timestep = 128, which is the length of the input data sequence(after padding).
input data in model.fit : x_train.shape = (7244, 128) , y_train.shape = (7244, 128)
I have no idea why the model work on in the first epoch but fail in the latter , appreciate to any suggestion!
batch_size = 100
sequence_input = Input(shape=(128,), dtype='int32',batch_size=batch_size)
embedding_layer = Embedding(embeddings.shape[0],
embedding_dim,
weights = [embeddings],
input_length = 128,
name = 'embeddings',mask_zero=True)
# embedding layer use a dict according to glove 300d,
# and I set input_length =128 because I gauss this parameter also mentioned time step? not pretty sure.
embedded_sequences = embedding_layer(sequence_input)
x = Bidirectional(GRU(90,
stateful=True,
return_sequences=True,
name='lstm_layer',
go_backwards=True))(embedded_sequences)
x = Dense(50, activation="sigmoid")(x)
pred = Dense(9, activation="sigmoid")(x)
_model = Model(sequence_input, pred)
_model.compile(loss = 'SparseCategoricalCrossentropy',
optimizer='adam',
metrics = ['accuracy'])
_model.summary()
history = _model.fit(x_train, y_train,
epochs =10, batch_size =batch_size, shuffle = False,
validation_data=(sequences['train'], labels['train']))
model summary

Error when checking input: expected input_1 to have 5 dimensions, but got array with shape (740, 19, 163, 279)

I am trying to train a 3D CNN on images ( in the form of NumPy arrays ) of dimension (19,163,279). My X_train has a shape of (740,19,163,279) and y_train has a shape of (185,19,163,279).
if K.image_data_format() == 'channels_first':
INPUT_SHAPE = (1, 19, 163, 279)
else:
INPUT_SHAPE = (19, 163, 279, 1)
And this is my model
def get_model(width=163, height=279, depth=19):
"""Build a 3D convolutional neural network model."""
inputs = keras.Input(INPUT_SHAPE)
x = layers.Conv3D(filters=64, kernel_size=3, activation="relu",padding='same')(inputs)
x = layers.MaxPool3D(pool_size=2,padding='same')(x)
x = layers.BatchNormalization()(x)
x = layers.Conv3D(filters=64, kernel_size=3, activation="relu",padding='same')(x)
x = layers.MaxPool3D(pool_size=2,padding='same')(x)
x = layers.BatchNormalization()(x)
x = layers.Conv3D(filters=128, kernel_size=3, activation="relu", padding='same')(x)
x = layers.MaxPool3D(pool_size=2,padding='same')(x)
x = layers.BatchNormalization()(x)
x = layers.Conv3D(filters=64, kernel_size=3, activation="relu", padding='same')(x)
x = layers.MaxPool3D(pool_size=2,padding='same')(x)
x = layers.BatchNormalization()(x)
x = layers.GlobalAveragePooling3D()(x)
x = layers.Dense(units=16, activation="relu")(x)
x = layers.Dropout(0.3)(x)
outputs = layers.Dense(units=1, activation="sigmoid")(x)
# Define the model.
model = keras.Model(inputs, outputs, name="3dcnn")
return model
# Build model.
model = get_model(width=163, height=279, depth=19)
model.summary()
However, while training using the following code,
# Train the model, doing validation at the end of each epoch
epochs = 100
model.fit(
X_train,
validation_data=y_test,
epochs=epochs,
shuffle=True,
verbose=2,
callbacks=[checkpoint_cb, early_stopping_cb],
)
I am getting the following error
Error when checking input: expected input_1 to have 5 dimensions, but got array with shape (740, 19, 163, 279)
How do I solve this?
I don't think you're clear with what the code's doing.
For plain images you should use a 2D CNN. 3D CNN's are used for CT scans and MRI images.
Your input shape has to be the shape of the image, which does not include the number of examples. Your INPUT_SHAPE should be (19, 263, 179)
Your kernel size should have a number of filters = dimension of the conv layer. For a Conv2D layer your kernel_size would be for example equal to (3, 3)
In model.fit() you have to pass X_train, then y_train, then the rest of the parameters. How else will the model which labels to learn from?
In model.fit() the validation_data argument is a list of (X_test, y_test)
Hope this clarifies everything

Keras multi-output model wrongly calculate target dimensions: ValueError: Error when checking target

I'm trying to build a multi-output keras model starting from a working single output model. Keras however, is complaining about tensors dimensions.
The single output Model:
This GRU model is training and predicting fine:
timesteps = 250
features = 2
input_tensor = Input(shape=(timesteps, features), name="input")
conv = Conv1D(filters=128, kernel_size=6,use_bias=True)(input_tensor)
b = BatchNormalization()(conv)
s_gru, states = GRU(256, return_sequences=True, return_state=True, name="gru_1")(b)
biases = keras.initializers.Constant(value=88.15)
out = Dense(1, activation='linear', name="output")(s_gru)
model = Model(inputs=input_tensor, outputs=out)
My numpy arrays are:
train_x # shape:(7110, 250, 2)
train_y # shape: (7110, 250, 1)
If fit the model with the following code and everything is fine:
model.fit(train_x, train_y,batch_size=128, epochs=10, verbose=1)
The Problem:
I want to use a slightly modified version of the network that outputs also the GRU states:
input_tensor = Input(shape=(timesteps, features), name="input")
conv = Conv1D(filters=128, kernel_size=6,use_bias=True)(input_tensor)
b = BatchNormalization()(conv)
s_gru, states = GRU(256, return_sequences=True, return_state=True, name="gru_1")(b)
biases = keras.initializers.Constant(value=88.15)
out = Dense(1, activation='linear', name="output")(s_gru)
model = Model(inputs=input_tensor, outputs=[out, states]) # multi output
#fit the model but with a list of numpy array as y
model.compile(optimizer=optimizer, loss='mae', loss_weights=[0.5, 0.5])
history = model.fit(train_x, [train_y,train_y], batch_size=128, epochs=10, callbacks=[])
This training fails and keras is complaining about the target dimensions:
ValueError: Error when checking target: expected gru_1 to have 2 dimensions, but got array with shape (7110, 250, 1)
I'm using Keras 2.3.0 and Tensorflow 2.0.
What am I missing here?
The dimensions of the second output and the second element in the outputs list should be of similar shape. In this case, states would be of shape (7110, 256), which can't really be compared to the train_y shape (which will be of shape (7110, 250, 1) as noted in the first code block. Make sure the outputs can be compared with a similar shape.

How to change input shape of the model with lambda layer

Lets suppose I have specified mobilenet from keras models this way:
base_model = MobileNetV2(weights='imagenet', include_top=False, input_shape=(224, 224, 3))
# add a global spatial average pooling layer
x = base_model.output
x = GlobalAveragePooling2D()(x)
x = Dense(1024, activation='relu')(x)
predictions = Dense(12, activation='softmax')(x)
# this is the model we will train
model = Model(inputs=base_model.input, outputs=predictions)
model.compile(loss='categorical_crossentropy', optimizer = Adam(),
metrics=['accuracy'])
But I would like to add custom layer to preporess input image this way:
def myFunc(x):
return K.reshape(x/255,(-1,224,224,3))
new_model = Sequential()
new_model.add(Lambda(myFunc,input_shape =( 224, 224, 3), output_shape=(224, 224, 3)))
new_model.add(model)
new_model.compile(loss='categorical_crossentropy', optimizer = Adam(),
metrics=['accuracy'])
new_model.summary()
It works pretty well but now I need to have it input shape 224 224 3 instead of (None, 224, 224, 3) - how to make it
In order to expand the dimension of your tensor, you can use
import tensorflow.keras.backend as K
# adds a new dimension to a tensor
K.expand_dims(tensor, 0)
However, I do not see why you would need it, just like #meonwongac mentioned.
If you still want to use a Lambda layer instead of resizing / applying other operations on images with skimage/OpenCV/ other library, one way of using the Lambda layer is the following:
import tensorflow as tf
input_ = Input(shape=(None, None, 3))
next_layer = Lambda(lambda image: tf.image.resize_images(image, (128, 128))(input_)

InvalidArgumentError: logits and labels must have the same first dimension

I am trying to classify images. Those images have different shapes, but this is not a problem.
However, I am trying to create a dataset using the tf.data.Dataset.from_generator function provided by Tensorflow and I have the feeling that something is not working as it should.
Here is the code:
filenames_ds = tf.data.Dataset.from_tensor_slices(categ_img[:1000]['image_name'])
labels_ds = tf.data.Dataset.from_tensor_slices(categ_img[:1000]['category_label'])
images_ds = filenames_ds.map(lambda x: tf.image.decode_jpeg(tf.read_file(x)))
labels_ds = labels_ds.map(lambda x: tf.one_hot(x, NUM_CATEGORIES))
ds = tf.data.Dataset.zip((images_ds, labels_ds)).batch(1)
I also tried to create the labels_ds like this:
labels_ds.map(lambda x: tf.expand_dims(tf.one_hot(x, NUM_CATEGORIES), axis=0))
categ_imgis a pandas.DataFrame containing image paths and labels under image_name and category_label columns respectively.
And I keep getting this error:
InvalidArgumentError: logits and labels must have the same first dimension, got logits shape [1,50] and labels shape [50]
My model is based on a pretrained ResNet model provided by Keras:
base_model = ResNet50(weights='imagenet', include_top=False, input_shape=(None, None, 3))
for layer in base_model.layers:
layer.trainable = False
x = base_model.output
x = GlobalAveragePooling2D()(x)
for fc in FC_LAYERS:
x = Dense(fc, activation='relu')(x)
x = Dropout(DROPOUT)(x)
output = Dense(NUM_CATEGORIES, activation='softmax', name='fully-connected')(x)
model = Model(inputs=base_model.input, outputs=output)
optimizer = tf.keras.optimizers.SGD(lr=LEARNING_RATE)
cce = tf.keras.losses.CategoricalCrossentropy()
model.compile(optimizer, loss=cce)
return model
It is trained like this:
model_classification.fit(
ds,
epochs=epochs,
steps_per_epoch=steps
)
Which seems pretty straight-forward to me.
Any help would be appreciated.
Thank you.
I finally tried something that worked.
Here is the line you need to change:
model.compile(loss='categorical_crossentropy', optimizer='adam', metrics=['accuracy'])
I don't know why, but this made things working.

Categories