Keras fit_generator incorrect input shapes - machine-learning

I'm using an ImageDataGenerator to input batches of images to a neural network, but can't work out the correct way to feed it. Running the following:
train_datagen = ImageDataGenerator(rescale=1./255, shear_range=0.2, zoom_range=0.2, horizontal_flip=True)
test_datagen = ImageDataGenerator(rescale=1./255)
training_set = train_datagen.flow_from_directory('/home/Training', target_size=(256,256), batch_size=32, class_mode='binary', color_mode = 'grayscale')
test_set = test_datagen.flow_from_directory('/home/Test', target_size=(256,256), batch_size=32, class_mode='binary',color_mode = 'grayscale' )
input_size = (256, 256, 1)
inputs = Input(input_size)
conv1 = Conv2D(64, 3, activation = 'relu', padding = 'same', kernel_initializer = 'he_normal')(inputs)
conv2 = Conv2D(2, 3, activation = 'relu', padding = 'same', kernel_initializer = 'he_normal')(conv1)
conv3 = Conv2D(1, 1, activation = 'sigmoid')(conv2)
model1 = Model(inputs = inputs, outputs = conv3)
model1.compile(optimizer = Adam(lr = 1e-4), loss = 'binary_crossentropy', metrics = ['accuracy'])
model1.fit_generator(training_set, steps_per_epoch=160, epochs=10, validation_data=test_set, validation_steps=800)   
Results in:
Error when checking target: expected conv2d_198 to have 4 dimensions,
but got array with shape (14, 1)
It seems to use the batches as the input tensor, since removing all layers but the input layer results in a similar error. How can I correctly input them into the network?

Basically Keras is expecting your to pass your input dimensions and rows. Looks like you are passing an array with two dimensions. Can you make sure you are passing something like (-1, dimension 1, dimension 2, channels) ? you may need to use reshape. The -1 should tell Keras to infer the rows/observations. Im pretty new to Keras so I am sure someone else will have a better answer but you might be able to just do.. myinputarray.reshape()

Related

Errors with LSTM input shapes with time series data

I'm trying to predict torque from 8 features with an LSTM layer in my neural network. I'm having trouble with the input shape and have looked around on many sites for a solution. I'm quite new to machine learning and am having trouble understanding the problem and how I can fix this. Here is my code, dataset, and error message.
file = r'/content/drive/MyDrive/only_force_pt1.csv'
df = pd.read_csv(file)
X = df.iloc[:, 1:9]
y = df.iloc[:,9]
print(X)
print(y)
df.head()
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size = 0.1, shuffle = True)
X_train, X_val, y_train, y_val = train_test_split(X, y, test_size = 0.1, shuffle = True)
[verbose, epochs, batch_size] = [1, 200, 32]
input_shape = (X_train.shape[0],X_train.shape[1])
model = Sequential()
# LSTM
model.add(LSTM(64, input_shape=input_shape, return_sequences = True))
model.add(Dense(32, activation='relu', kernel_regularizer=keras.regularizers.l2(0.001)))
#model.add(Dropout(0.2))
#model.add(Dense(32, activation='relu', kernel_regularizer=keras.regularizers.l2(0.001)))
model.add(Dense(1,activation='relu'))
earlystopper = EarlyStopping(monitor='val_loss', min_delta=0, patience = 20, verbose =1, mode = 'auto')
model.summary()
model.compile(loss = 'mse', optimizer = Adam(learning_rate = 0.001), metrics=[tf.keras.metrics.RootMeanSquaredError()])
history = model.fit(X_train, y_train, batch_size = batch_size, epochs = epochs, verbose = verbose, validation_data=(X_val,y_val), callbacks = [earlystopper])
ValueError: Input 0 of layer "sequential_17" is incompatible with the layer: expected shape=(None, 3634, 8), found shape=(None, 8)
dataset: https://drive.google.com/drive/folders/1BQOXffFYioCiPug2VcBZEZVD-u3y9bcl?usp=sharing][1]
As I understand your problem, I think that you are passing the number of data points as an additional dimension on the input shape of the LSTM layer. Your data dimensionality is 8 and 3634(=X_train.shape[0]) is the number of data points, which should match the first dimension (with None) of the input tensors, and should not be passed as a dimension to the LSTM because it is determined by the batch size.
If that's the case, change the input_shape definition to:
input_shape = (X_train.shape[1],)
and it should work.

Mel Spectrogram feature extraction to CNN

This question is in line with the question posted here but with a slight nuance of the CNN. Using the feature extraction definition:
max_pad_len = 174
n_mels = 128
def extract_features(file_name):
try:
audio, sample_rate = librosa.core.load(file_name, res_type='kaiser_fast')
mely = librosa.feature.melspectrogram(y=audio, sr=sample_rate, n_mels=n_mels)
#pad_width = max_pad_len - mely.shape[1]
#mely = np.pad(mely, pad_width=((0, 0), (0, pad_width)), mode='constant')
except Exception as e:
print("Error encountered while parsing file: ", file_name)
return None
return mely
How do you go about getting the correct dimension of the num_rows, num_columns and num_channels to be input to the train and test data?
In constructing the CNN Model, how to determine the correct shape to input?
model = Sequential()
model.add(Conv2D(filters=16, kernel_size=2, input_shape=(num_rows, num_columns, num_channels), activation='relu'))
model.add(MaxPooling2D(pool_size=2))
model.add(Dropout(0.2))
I dont know if it is exactly your problem but I also have to use a MEL as an input to a CNN.
Short answer:
input_shape = (x_train.shape[1], x_train.shape[2], 1)
x_train = x_train.reshape(x_train.shape[0], x_train.shape[1], x_train.shape[2], 1)
or
x_train = x_train.reshape(x_train.shape[0], x_train.shape[1], x_train.shape[2], 1)
input_shape = x_train.shape[1:]
Long answer
In my case I have a DataFrame with speakers_id and mel spectrograms (previously calculated with librosa).
The Keras CNN models are prepared for images with width, height and channels of colors (grayscale - RGB)
The Mel Spectrograms given by librosa are image-like arrays with width and height, so you need to do a reshape to add the channel dimension.
Define the input and expected output
# It looks stupid but that way i could convert the panda.Series to a np.array
x = np.array(list(df.mel))
y = df.speaker_id
print('X shape:', x.shape)
X shape: (2204, 128, 24)
2204 Mels, 128x24
Split in train-test
x_train, x_test, y_train, y_test = train_test_split(x, y)
print(f'Train: {len(x_train)}', f'Test: {len(x_test)}')
Train: 1653 Test: 551
Reshape to add the extra dimension
x_train = x_train.reshape(x_train.shape[0], x_train.shape[1], x_train.shape[2], 1)
x_test = x_test.reshape(x_test.shape[0], x_test.shape[1], x_test.shape[2], 1)
print('Shapes:', x_train.shape, x_test.shape)
Shapes: (1653, 128, 24, 1) (551, 128, 24, 1)
Set input_shape
# The input shape is independent of the amount of inputs
input_shape = x_train.shape[1:]
print('Input shape:', input_shape)
Input shape: (128, 24, 1)
Put it into the model
model = Sequential()
model.add(Conv2D(32, (3, 3), activation='relu', input_shape=input_shape))
model.add(MaxPooling2D())
# More layers...
model.compile(optimizer='adam',loss=tf.keras.losses.SparseCategoricalCrossentropy(from_logits=False),metrics=['accuracy'])
Run model
model.fit(x_train, y_train, epochs=20, validation_data=(x_test, y_test))
Hope this is helpfull

xception model incorrect classification over training dataset [duplicate]

I want to predict the kind of 2 diseases but I get results as binary (like 1.0 and 0.0). How can I get accuracy of these (like 0.7213)?
Training code:
from keras.models import Sequential
from keras.layers import Conv2D
from keras.layers import MaxPooling2D
from keras.layers import Flatten
from keras.layers import Dense
# Intialising the CNN
classifier = Sequential()
# Step 1 - Convolution
classifier.add(Conv2D(32, (3, 3), input_shape = (64, 64, 3), activation = 'relu'))
# Step 2 - Pooling
classifier.add(MaxPooling2D(pool_size = (2, 2)))
# Adding a second convolutional layer
classifier.add(Conv2D(32, (3, 3), activation = 'relu'))
classifier.add(MaxPooling2D(pool_size = (2, 2)))
# Step 3 - Flattening
classifier.add(Flatten())
# Step 4 - Full connection
classifier.add(Dense(units = 128, activation = 'relu'))
classifier.add(Dense(units = 1, activation = 'sigmoid'))
# Compiling the CNN
classifier.compile(optimizer = 'adam', loss = 'binary_crossentropy', metrics = ['accuracy'])
# Part 2 - Fitting the CNN to the images
import h5py
from keras.preprocessing.image import ImageDataGenerator
train_datagen = ImageDataGenerator(rescale = 1./255,
shear_range = 0.2,
zoom_range = 0.2,
horizontal_flip = True)
test_datagen = ImageDataGenerator(rescale = 1./255)
training_set = train_datagen.flow_from_directory('training_set',
target_size = (64, 64),
batch_size = 32,
class_mode = 'binary')
test_set = test_datagen.flow_from_directory('test_set',
target_size = (64, 64),
batch_size = 32,
class_mode = 'binary')
classifier.fit_generator(training_set,
steps_per_epoch = 100,
epochs = 1,
validation_data = test_set,
validation_steps = 100)
Single prediction code:
import numpy as np
from keras.preprocessing.image import ImageDataGenerator, array_to_img, img_to_array, load_img,image
test_image = image.load_img('path_to_image', target_size = (64, 64))
test_image = image.img_to_array(test_image)
test_image = np.expand_dims(test_image, axis = 0)
result = classifier.predict(test_image)
print(result[0][0]) # Prints 1.0 or 0.0
# I want accuracy rate for this prediction like 0.7213
The file structures is like:
test_set
benigne
benigne_images
melignant
melignant_images
training set
Training set structure is also the same as test set.
Update: As you clarified in the comments, you are looking for the probabilities of each class given one single test sample. Therefore you can use predict method. However, note that you must first preprocess the image the same way you have done in the training phase:
test_image /= 255.0
result = classifier.predict(test_image)
The result would be the probability of the given image belonging to class one (i.e. positive class).
If you have a generator for test data, then you can use evaluate_generator() to get the loss as well as the accuracy (or any other metric you have set) of the model on the test data.
For example, right after fitting the model, i.e. using fit_generator, you can use evaluate_generator on your test data generator, i.e. test_set:
loss, acc = evaluate_generator(test_set)

ValueError: Input 0 is incompatible with layer lstm_1: expected ndim=3, found ndim=2 [keras]

I got the error: ValueError: Input 0 is incompatible with layer lstm_1: expected ndim=3, found ndim=2 with the following code:
def make_model():
model = Sequential()
model.add(Conv2D(20,(5,5), input_shape = (24,48,30), activation = "relu", strides = 1, padding = "valid"))
model.add(MaxPooling2D(pool_size=(2,2)))
model.add(Conv2D(50, (5,5), use_bias = 50))
model.add(MaxPooling2D(pool_size=(2,2)))
model.add(Flatten())
model.add(Dense(20, activation = "relu"))
model.add(LSTM(50, activation="relu", return_sequences=True))
return model
My input is 30 matrices of size 24*48 each.
The problem lies in the fact that after the last Dense layer (before the lstm layer), the output shape is (?, 20) and the lstm layer expects 3D tensor, not 2D.So, you can expand the dimensions in order to add one more before feeding to lstm layer.
You can expand dimensions using tf.expand_dims (assuming you use tensorflow as backend) tf expand
input_layer = Input((30,24,48))
model = Conv2D(20,(5,5), input_shape = (30,24,48), activation = "relu", strides = 1, padding = "valid")(input_layer)
model = MaxPooling2D(pool_size=(2,2))(model)
model = Conv2D(50, (5,5), use_bias = 50)(model)
model = MaxPooling2D(pool_size=(2,2))(model)
model = Flatten()(model)
model = Dense(20, activation = "relu")(model)
model = tf.expand_dims(model, axis=-1)
model = LSTM(50, activation="relu", return_sequences=True)(model)
(I didn't use Sequential mode, I am using functional api since it is more flexible)
If you want to use sequential model:
model = Sequential()
model.add(Conv2D(20,(5,5), input_shape = (30, 24, 48), activation = "relu", strides = 1, padding = "valid"))
model.add(MaxPooling2D(pool_size=(2,2)))
model.add(Conv2D(50, (5,5), use_bias = 50))
model.add(MaxPooling2D(pool_size=(2,2)))
model.add(Flatten())
model.add(Dense(20, activation = "relu"))
model.add(Lambda(lambda x: tf.expand_dims(model.output, axis=-1)))
model.add(LSTM(50, activation="relu", return_sequences=True))
you must use expand dims inside Lambda

Error in Input Dimensions - Keras

I'm training a neural net with keras with input data that has a shape of (116, 2, 3, 58) and output data that has a shape of (116, 2). I'm getting this error:
ValueError: Error when checking target: expected dense_3 to have 4 dimensions, but got array with shape (116, 2)
What could I be doing wrong? Here is my code:
trainingInput = np.load("trainingInput.npy")
trainingOutput = np.load("trainingOutput.npy")
inp = Input(batch_shape=(116, 2, 3, 58))
d1 = Dense(16, activation='relu')(inp)
d2 = Dense(32, activation='relu')(d1)
out = Dense(2, activation='softmax')(d2)
model = Model(inputs=inp, outputs=out)
lrSet = SGD(lr=0.01)
model.compile(loss='categorical_crossentropy', optimizer=lrSet, metrics=['accuracy'])
model.fit(trainingInput, trainingOutput, batch_size=16, epochs=50, verbose=1, validation_split=0.1)
Dense is a full-connected layer. It will not change the shape of Input. If you want use Dense, you should resize (116,2,3,68) -> (116,2*3*68)

Resources