jesliu
jesliu

Reputation: 71

Keras CNN predicts same class even after augmentation

I am trying to create a CNN that classifies 3D brain images. However, the CNN program always predict the same class when I run it and am not sure what other methods I can do to prevent this. I have searched up this problem with many plausible solutions, but they did not work

So far, I have tried:

Please note that the amount of images I am using is a total of 20 3D brain images (5 per category) and that I cannot increase the sample size since there are simply not enough images. I have recently tried data augmentation, however that does not seem to help.

Any help would be appreciated!

import os
import csv
import tensorflow as tf  # 2.0
import nibabel as nib
import numpy as np
import pandas as pd
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import OneHotEncoder, LabelEncoder
from keras.models import Model
from keras.layers import Conv3D, MaxPooling3D, Dense, Dropout, Activation, Flatten 
from keras.layers import Input, concatenate
from keras import optimizers
from keras.utils import to_categorical
from sklearn.metrics import accuracy_score
from sklearn.metrics import confusion_matrix
import seaborn as sns
import matplotlib.pyplot as plt
from augmentedvolumetricimagegenerator.generator import customImageDataGenerator
from keras.callbacks import EarlyStopping


# Administrative items
os.environ['TF_CPP_MIN_LOG_LEVEL'] = '2'

# Where the file is located
path = r'C:\Users\jesse\OneDrive\Desktop\Research\PD\decline2'
folder = os.listdir(path)

target_size = (96, 96, 96)


# creating x - converting images to array
def read_image(path, folder):
    mri = []
    for i in range(len(folder)):
        files = os.listdir(path + '\\' + folder[i])
        for j in range(len(files)):
            image = np.array(nib.load(path + '\\' + folder[i] + '\\' + files[j]).get_fdata())
            image = np.resize(image, target_size)
            image = np.expand_dims(image, axis=3)
            mri.append(image)
    return mri

# creating y - one hot encoder
def create_y():
    excel_file = r'C:\Users\jesse\OneDrive\Desktop\Research\PD\decline_label.xlsx'
    excel_read = pd.read_excel(excel_file)
    excel_array = np.array(excel_read['Label'])
    label = LabelEncoder().fit_transform(excel_array)
    label = label.reshape(len(label), 1)
    onehot = OneHotEncoder(sparse=False).fit_transform(label)
    return onehot

# Splitting image train/test
x = np.asarray(read_image(path, folder))
y = np.asarray(create_y())
test_size = .2
x_train, x_test, y_train, y_test = train_test_split(x, y, test_size=test_size)
print(x_train.shape, x_test.shape, y_train.shape, y_test.shape)


batch_size = 4
num_classes = 4

inputs = Input((96, 96, 96, 1))
conv1 = Conv3D(32, [3, 3, 3], padding='same', activation='relu')(inputs)
conv1 = Conv3D(32, [3, 3, 3], padding='same', activation='relu')(conv1)
pool1 = MaxPooling3D(pool_size=(2, 2, 2), padding='same')(conv1)
drop1 = Dropout(0.5)(pool1)

conv2 = Conv3D(64, [3, 3, 3], padding='same', activation='relu')(drop1)
conv2 = Conv3D(64, [3, 3, 3], padding='same', activation='relu')(conv2)
pool2 = MaxPooling3D(pool_size=(2, 2, 2), padding='same')(conv2)
drop2 = Dropout(0.5)(pool2)

conv3 = Conv3D(128, [3, 3, 3], padding='same', activation='relu')(drop2)
conv3 = Conv3D(128, [3, 3, 3], padding='same', activation='relu')(conv3)
pool3 = MaxPooling3D(pool_size=(2, 2, 2), padding='same')(conv3)
drop3 = Dropout(0.5)(pool3)

conv4 = Conv3D(256, [3, 3, 3], padding='same', activation='relu')(drop3)
conv4 = Conv3D(256, [3, 3, 3], padding='same', activation='relu')(conv4)
pool4 = MaxPooling3D(pool_size=(2, 2, 2), padding='same')(conv4)
drop4 = Dropout(0.5)(pool4)

conv5 = Conv3D(256, [3, 3, 3], padding='same', activation='relu')(drop4)
conv5 = Conv3D(256, [3, 3, 3], padding='same', activation='relu')(conv5)
pool5 = MaxPooling3D(pool_size=(2, 2, 2), padding='same')(conv5)
drop5 = Dropout(0.5)(pool5)

flat1 = Flatten()(drop5)
dense1 = Dense(128, activation='relu')(flat1)
dense2 = Dense(64, activation='relu')(dense1)
dense3 = Dense(32, activation='relu')(dense2)
drop6 = Dropout(0.5)(dense3)
dense4 = Dense(num_classes, activation='softmax')(drop6)

model = Model(inputs=[inputs], outputs=[dense4])

opt = optimizers.Adam(lr=1e-8, beta_1=1e-3, beta_2=1e-4, decay=2e-5)
model.compile(loss='categorical_crossentropy', optimizer=opt, metrics=['accuracy'])


train_datagen = customImageDataGenerator(rescale=1./255,
                                         #width_shift_range=0.2,
                                         #height_shift_range=0.2,
                                         #rotation_range=15,
                                         #shear_range=0.2,
                                         #zoom_range=0.2,
                                         #brightness_range=[0.2, 1.0],
                                         data_format='channels_last',
                                         horizontal_flip=True)

test_datagen = customImageDataGenerator(rescale=1./255)


training_set = train_datagen.flow(x_train, y_train, batch_size=batch_size)

testing_set = test_datagen.flow(x_test, y_test, batch_size=batch_size)


callbacks = EarlyStopping(monitor='val_loss')

model.fit_generator(training_set,
                    steps_per_epoch = 20,
                    epochs = 30,
                    validation_steps = 5,
                    callbacks = [callbacks],
                    validation_data = testing_set)

#score = model.evaluate(x_test, y_test, batch_size=batch_size)
#print(score)


y_pred = model.predict(x_test, batch_size=batch_size)
y_test = np.argmax(y_test, axis=1)
y_pred = np.argmax(y_pred, axis=1)
confusion = confusion_matrix(y_test, y_pred)
map = sns.heatmap(confusion, annot=True)
print(map)

Upvotes: 0

Views: 149

Answers (1)

Alexis
Alexis

Reputation: 57

Not sure about exactly what's happening. But I have a few remarks suggestions.

First look at the learning curve to see if it does actually fit something.

Secondly, you use 0.2 of the dataset for a dataset of 20 images of 5 classes. If all of your last images are of the same label. You will only test on that label. So that might be one issue here unless the images aren't sorted.

Thirdly, for the few data it looks like you might have a lot of dense parameters. Usually start small and increase the number of parameters. You can see some hint about that by watching the learning curve.

Lastly, sadly machine learning is not magical and you can't expect good results with that few data.

Alexis

Upvotes: 1

Related Questions