Different accuracy on same CNN - python

I have this CNN:
def cnn(trainImages, trainLabels, testImages, testLabels):
trainImages = np.array(trainImages)
trainLabels = np.array(trainLabels)
testImages = np.array(testImages)
testLabels = np.array(testLabels)
trainImages = trainImages / 255
testImages = testImages / 255
model = Sequential()
model.add(Conv2D(filters = 32, kernel_size = (3, 3), padding = 'same', activation = 'relu', input_shape = (224, 224, 3)))
model.add(MaxPool2D(pool_size = (2, 2), strides = (2, 2)))
model.add(Conv2D(filters = 64, kernel_size = (3, 3), padding = 'same', activation = 'relu'))
model.add(MaxPool2D(pool_size = (2, 2), strides = (2, 2)))
model.add(Conv2D(filters = 128, kernel_size = (3, 3), padding = 'same', activation = 'relu'))
model.add(MaxPool2D(pool_size = (2, 2), strides = (2, 2)))
model.add(Flatten())
model.add(Dense(256, activation = 'relu'))
model.add(Dense(9))
model.compile(optimizer = 'adam', loss = tensorflow.keras.losses.SparseCategoricalCrossentropy(from_logits = True), metrics = ['accuracy'])
model.fit(trainImages, trainLabels, epochs = 10)
predictionResult = model.predict(testImages)
pred = []
for i in range(len(predictionResult)):
pred.append(np.argmax(predictionResult[i], axis = -1))
print('Accuracy: ', metrics.accuracy_score(testLabels, pred))
print(metrics.classification_report(testLabels, pred))
print(metrics.confusion_matrix(testLabels, pred))
1). I got different accuracy everytime when I run the CNN, between 87% and 93%. How can I get permanently when I run the same accuracy? I tried tensorflow.set_random_seed(), but without effect.
2). What should I improve at my network to get over 95%? Input has shape (224, 224, 3). 2831 training images and 665 testing. 9 output classes. A problem of color recognition.

As I posted in a comment, one possibility for such a behavior is the use of GPUs: cuda introduces some little variability and therefore you could experience some fluctuations in the accuracy of two models trained it the same way. You could try to disable the GPU:
os.environ["CUDA_VISIBLE_DEVICES"] = "-1"
And setting the seed as before. However, this would limit your performance and you will need more time to complete the same training, since you would use only CPUs and not your GPU

Related

Keras denoising autoencoder - logits and labels must have the same first dimension, got logits shape [986624,38] and labels shape [32]

I am trying to construct a denoising autoencoder for a facial recognition project, and with the initial tests i am using the cropped yalefaces dataset, with the training (noisy) images in a folder (with separate folders for each class/person inside) and the testing (regular) images in another one with the same structure. But with every test i have the following error:
InvalidArgumentError: logits and labels must have the same first
dimension, got logits shape [986624,38] and labels shape [32] [[node
sparse_categorical_crossentropy/SparseSoftmaxCrossEntropyWithLogits/SparseSoftmaxCrossEntropyWithLogits
(defined at \Desktop\projetos\conv autoencoder teste.py:75) ]]
[Op:__inference_train_function_8691]
Function call stack: train_function
I am using Keras 2.6.0.
batch_size = 32
height = 168
width = 192
depth = 1
chanDim = -1
inputShape = (height, width, depth)
data_dir='C:\\Users\\User\\Desktop\\projetos\\Test1\\Data'
train_data_dir='C:\\Users\\User\\Desktop\\projetos\\Test1\\Test_Images\\sp_noise'
images_noisy = tf.keras.preprocessing.image_dataset_from_directory(directory=train_data_dir, labels='inferred', label_mode='int',class_names=None, color_mode='grayscale', batch_size=batch_size, image_size=(height,width),shuffle=True,seed=2457,interpolation='bilinear')
images_regular = tf.keras.preprocessing.image_dataset_from_directory(directory=data_dir, labels='inferred', label_mode='int',class_names=None, color_mode='grayscale', batch_size=batch_size, image_size=(height,width),shuffle=True,seed=2457,interpolation='bilinear')
datagen = tf.keras.preprocessing.image.ImageDataGenerator()
train_it = datagen.flow_from_directory(train_data_dir, class_mode='sparse', batch_size=32,target_size=(height, width),color_mode='grayscale')
val_it = datagen.flow_from_directory(data_dir, class_mode='sparse', batch_size=32,target_size=(height, width),color_mode='grayscale')
#input = tf.keras.layers.Input(shape=(inputShape))
Input_img = Input(shape=(168,192,1))
#Input_img = Input(shape=(None))
#encoding architecture
#x1 = tf.keras.layers.Reshape((168, 192, 1), input_shape=(None, 168, 192, 1))(Input_img)
x1 = tf.keras.layers.Conv2D(64, (3, 3), activation='relu', padding='same')(Input_img)
x1 = tf.keras.layers.MaxPooling2D( (2, 2), padding='same')(x1)
x2 = tf.keras.layers.Conv2D(32, (3, 3), activation='relu', padding='same')(x1)
x2 = tf.keras.layers.MaxPooling2D( (2, 2), padding='same')(x2)
x3 = tf.keras.layers.Conv2D(16, (3, 3), activation='relu', padding='same')(x2)
encoded = tf.keras.layers.MaxPooling2D( (2, 2), padding='same')(x3)
# decoding architecture
x3 = tf.keras.layers.Conv2D(16, (3, 3), activation='relu', padding='same')(encoded)
x3 = tf.keras.layers.UpSampling2D((2, 2))(x3)
x2 = tf.keras.layers.Conv2D(32, (3, 3), activation='relu', padding='same')(x3)
x2 = tf.keras.layers.UpSampling2D((2, 2))(x2)
x1 = tf.keras.layers.Conv2D(64, (3, 3), activation='relu')(x2)
x1 = tf.keras.layers.UpSampling2D((2, 2))(x1)
decoded = tf.keras.layers.Conv2D(38, (3, 3), activation='sigmoid', padding='same')(x1)
autoencoder = Model(Input_img, decoded)
autoencoder.compile(optimizer='adam', loss=tf.keras.losses.SparseCategoricalCrossentropy(from_logits=False))
history = autoencoder.fit(
images_noisy,
epochs=20,
batch_size=32,
shuffle=True,
validation_data=(images_regular))
autoencoder.summary()
At this point i frankly have no idea what is causing the issue. I used the dataset with the image_dataset_from_directory function in a facial recognition/classification cnn with no issues but here nothing seems to work.
I was able to reproduce the error, the input dimension and the output dimension needs to be the same in an autoencoder. Changing the architecture of the decoder as follows will help.
#decoding architecture
x3 = tf.keras.layers.Conv2D(16, (3, 3), activation='relu', padding='same')(encoded)
x3 = tf.keras.layers.UpSampling2D((2, 2))(x3)
x2 = tf.keras.layers.Conv2D(1, (3, 3), activation='relu', padding='same')(x3)
x1 = tf.keras.layers.UpSampling2D((2, 2))(x2)
decoded = tf.keras.layers.UpSampling2D((2, 2))(x1)

Saving Layer Values of CNN- Keras

I have created the following simple CNN in Keras (borrowed from a DeepLizard tutorial).
model = Sequential([
Conv2D(filters = 10, kernel_size = (3, 3), activation = 'relu', padding = 'same', input_shape = (320, 320, 3)),
MaxPool2D(pool_size = (2, 2), strides = 2),
Conv2D(filters = 10, kernel_size = (3, 3), activation = 'relu', padding = 'same'),
MaxPool2D(pool_size = (2, 2), strides = 2),
Flatten(),
Dense(20, activation = 'softmax'),
])
model.summary()
model.compile(optimizer = Adam(lr = 0.0001), loss = 'categorical_crossentropy', metrics =['accuracy'])
model.fit(x = train_batches, validation_data = valid_batches, epochs = 10, verbose = 2)
predictions = model.predict(x = test_batches, verbose = 0)
As you can see, I am saving the predictions generated by the model to a dataframe named "predictions". But I am also interested in saving the outputs for each of the MaxPool2D layers, the Conv2D layer, and the flatten layer as well. Is there a way that I can save the outputs of those layers to dataframes/lists as well? Is there a functionality for this in Keras?
Thank you!
You can use model.get_layer() function to extract any layer of your model. Visit the documentation here: https://keras.io/api/models/model/#getlayer-method
Thank you for your responses. They led me in the right direction. Here is the solution I ended up utilizing. I recreated the model, but configured the predictions to output the desired layer (in this case, "conv2d", the first convolutional layer). This produces a 4-D array as an output, where the 1st dimension corresponds to the input, the 2nd and 3rd dimensions are the two dimensions of a filter's outputted feature map, and the 4th dimension corresponds to the n-filters being used in that layer (in this case, the 4th dimension would be '10'). My next quest is to find a way to split that 4 dimensional array into separate 3-dimensional arrays, where each new array corresponds to a distinct filter. In this case, I would be looking for 10 3-dimensional arrays, one for each of the filters used in the first convolutional layer.
from keras.models import Model
model = Sequential([
Conv2D(filters = 10, kernel_size = (3, 3), activation = 'relu', padding = 'same', input_shape = (320, 320, 3)),
MaxPool2D(pool_size = (2, 2), strides = 2),
Conv2D(filters = 10, kernel_size = (3, 3), activation = 'relu', padding = 'same'),
MaxPool2D(pool_size = (2, 2), strides = 2),
Flatten(),
Dense(20, activation = 'softmax'),
])
layer_name = 'conv2d'
intermediate_layer_model = Model(inputs=model.input, outputs=model.get_layer(layer_name).output)
intermediate_output = intermediate_layer_model.predict(valid_batches)

Incompatible Dims with GlobalAveragePooling2D()

I'm trying to run a few different models, which ran fine until I added a GlobalAveragePooling2D() which now throws the following error:
ValueError: Input 0 is incompatible with layer flatten_105: expected min_ndim=3, found ndim=2
I feel it has something to do with a GlobalAveragePooling2D() layer not being compatible with a flatten() layer and my understand is lacking, but I'm not sure.
My code is below. Could anyone enlighten me on what they think is going on? It ran fine without the GlobalAveragePooling2D layer. I was hoping to experiment with it though.
dense_layers = [1,2,3]
layer_sizes = [32, 64, 128]
con_layers = [1,2,3]
con_layer_sizes = [32, 64, 128, 512]
for dense_layer in dense_layers:
for layer_size in layer_sizes:
for conv_layer in con_layers:
for con_layer_size in con_layer_sizes:
img_size = 125
batch_size = 16
K.input_shape = (img_size, img_size)
NAME = "{}-conv-{}-con_layer_sizes-{}-nodes-{}-dense-{}".format(conv_layer, con_layer_size, layer_size, dense_layer, int(time.time()))
print(NAME)
tensorboard = TensorBoard(log_dir= 'logs/{}'.format(NAME))
mcp = ModelCheckpoint(filepath='C:\\Users\\jordan.howell\\models\\'+NAME+'_model.h5',monitor="val_loss"
, save_best_only=True, save_weights_only=False)
reduce_learning_rate = ReduceLROnPlateau(monitor='val_loss', factor=0.3,patience=2,cooldown=2
, min_lr=0.00001, verbose=1)
#start model build
model = Sequential()
model.add(Conv2D(con_layer_size, (3, 3), activation="relu", padding = 'same', input_shape=input_shape))
model.add(MaxPooling2D(pool_size = (2, 2)))
model.add(BatchNormalization())
model.add(Dropout(0.15))
for l in range(conv_layer-1):
#Convolution
model.add(Conv2D(con_layer_size, (3, 3), activation="relu", padding = 'same'))
model.add(MaxPooling2D(pool_size = (2, 2)))
model.add(BatchNormalization())
model.add(Dropout(0.15))
model.add(GlobalAveragePooling2D())
# Flatten the layer
model.add(Flatten())
for l in range(dense_layer):
model.add(Dense(layer_size, activation = 'relu'))
model.add(Dense(activation = 'sigmoid', units = 1))
model.compile(loss ='binary_crossentropy', optimizer = 'adam'
, metrics=[km.binary_precision(), km.binary_recall()])
#generators = Generators(TRAIN_DATA_DIR, VALIDATION_DATA_DIR, TEST_DATA_DIR)
#train_generator = generators.train_generator(150, batch_size=32)
#validation_generator = generators.validation_generator(150, batch_size=16)
model.fit_generator(train_generator, steps_per_epoch=5216 // batch_size
,validation_data=validation_generator, validation_steps=1
, epochs = 50, callbacks = [reduce_learning_rate, tensorboard, mcp])
From Keras docs, GlobalAveragePooling2D input shape is 4D tensor, output shape is 2D tensor. In this case, Flatten is redundant.

Keras - Prediction accuracy of training data is worse?

I've trained my model and got the .hdf5 file. (training and validation accuracy are about 0.9)
Below is my accuracy curve.
trainnig curve
Because of the imbalance of my data, I used SMOTE to oversample my data and then split it into training and validation data.
sm = SMOTE(random_state=42)
X_resampled, y_resampled = sm.fit_resample(X, Y)
X_resampled = X_resampled.reshape(X_resampled.shape[0],128,128,3)
X_tr, X_tst, y_tr, y_tst = train_test_split(X_resampled, y_resampled, test_size=0.33,random_state=22)
And below is my model structure.
image_input = Input(shape=(img_size, img_size, 3))
conv_1 = Conv2D(64, (5, 5), padding='same',
input_shape=(img_size, img_size, 3), activation='relu')(image_input)
drop_2 = Dropout(0.4)(conv_1)
conv_3 = Conv2D(64, (3, 3), padding='same', activation='relu')(drop_2)
drop_4 = Dropout(0.4)(conv_3)
max_5 = MaxPooling2D(pool_size=(2, 2))(drop_4)
conv_6 = Conv2D(32, (5, 5), padding='same', activation='relu')(max_5)
drop_7 = Dropout(0.4)(conv_6)
conv_8 = Conv2D(32, (3, 3), padding='same', activation='relu')(drop_7)
drop_9 = Dropout(0.4)(conv_8)
max_10= MaxPooling2D(pool_size=(2, 2))(drop_9)
conv_11 = Conv2D(32, (5, 5), padding='same', activation='relu')(max_10)
drop_12 = Dropout(0.4)(conv_11)
conv_13 = Conv2D(32, (3, 3), padding='same', activation='relu')(drop_12)
drop_14 = Dropout(0.4)(conv_13)
max_15= MaxPooling2D(pool_size=(2, 2))(drop_14)
flat_16 = Flatten()(max_15)
den_17= Dense(8,activation='relu')(flat_16)
output = Dense(nb_classes, activation='softmax')(den_17)
img_size = 128
nb_classes = 6
batch_size = 256
nb_epoch=1000
savedModelName = 'M.hdf5'
lr = 0.00001
After I finished training my model, I saved it (by ModelCheckpoint save_best_only according to validation accuracy).
And then I used it to predict the "same" data (same random_state).
sm = SMOTE(random_state=42)
X_resampled, y_resampled = sm.fit_resample(X, Y)
X_resampled = X_resampled.reshape(X_resampled.shape[0], 128, 128, 3)
X_tr, X_tst, y_tr, y_tst = train_test_split(X_resampled, y_resampled, test_size=0.33,random_state=22)
But!! I get the prediction accuracy about 0.3.
Why?
Shouldn't it be 0.9?
could you maybe provide the code of you fitting the model.
Also what happens if you predict the first test set with your model? Could you provide maybe a confusion matrix or the Precision/Recall-Values?
My first guess would be, that your model is maybe overfitting or not really learning.

Implementing a generator for keras results in worse results

I am doing multi-label image classification on a dataset of around 3000 images. Because this is the limit of my working memory and the dataset will increase, I was trying to implement my own generator because I am also parsing the images from an online source. The network reached an accuracy of 25% where the three labels with the highest accuracy gave a pretty good representation of the images.
A normal batch would be of shape (32, 64, 64, 3) with labels of shape (32, 57).
My model looks like:
def createModel(shape, classes):
x = shape[0]
y = shape[1]
z = shape[2]
model = Sequential()
model.add(Conv2D(32, (2, 2), padding='same',input_shape=(x,y,z)))
model.add(BatchNormalization())
model.add(Activation('relu'))
model.add(Conv2D(32, (2, 1), padding='same'))
model.add(BatchNormalization())
model.add(Activation('relu'))
model.add(Conv2D(32, (1, 2), padding='same'))
model.add(BatchNormalization())
model.add(Activation('relu'))
model.add(MaxPooling2D(pool_size=(2, 2), strides = 2))
model.add(Conv2D(48, (2, 2), padding='same'))
model.add(BatchNormalization())
model.add(Activation('relu'))
model.add(MaxPooling2D(pool_size=(2, 2), strides = 2))
model.add(Conv2D(80, (2, 2), padding='same'))
model.add(BatchNormalization())
model.add(Activation('relu'))
model.add(MaxPooling2D(pool_size=(2, 2), strides = 2))
model.add(Flatten())
model.add(Dense(classes, activation = 'sigmoid'))
where classes would be 57 and the x,y,z would be 64,64,3.
My generator looks like:
def generator(data, urls, labels, batch_size):
counter = 0
X_train = []
Y_train = []
while 1:
for i in range(len(data)):
if counter == batch_size:
yield (np.array(X_train), np.array(Y_train))
X_train = []
Y_train = []
counter = 0
try:
ID = data[i][0]
if random.uniform(0,1) > 0.5:
X_train.append(getImage(64, urls[ID]))
else:
X_train.append(np.flip(getImage(64, urls[ID]),1))
Y_train.append(labels[i])
counter+=1
except:
continue
where data is an list with image ID and labels, urls is a list with image ID and the url to find the image, labels is the labels converted by MultiLabelBinarizer() (.fit_transform) and the batch_size. the getImage() function results in a np.array() where 64 gives the shape.
The main calls:
epochs = 60
lr = 1e-6
mlc = model.createModel((64,64,3), 57)
opt = Adam(lr=lr, decay=lr / epochs)
trainGenerator = data.generator(structuredData, urls, mlb_labels, 32)
validationGenerator = data.generator(structuredData, urls, mlb_labels, 32)
mlc.compile(loss="categorical_crossentropy", optimizer=opt, metrics=
["accuracy"])
mlc.fit_generator(trainGenerator, steps_per_epoch = 10, epochs=epochs,
validation_steps = 1, validation_data=validationGenerator)
mlc.save("datagenerator_test.h5")
Furthermore the network thus already works and trains if I do not use the generator, with the generator it seems to get a random accuracy between 1 and 3%. I hope this provides enough information.
EDIT: I takes about 90 seconds to prepare one batch of 32 images. Does the training wait for a batch to be ready?

Categories

Resources