Reputation: 71
I am trying to predict 3D medical brain images based on their assessment score using CNN, however the accuracy scores I have received were within a range of numbers (ex: there are 7 possible test scores: 1, 1.5, 2, 2.5, 3, 4, 5 and the output only gives predictions within 1-1.5 range)
I have resized, normalized, and separated the images into train (66 imgs), test (22 imgs), and validation (22 imgs) sets. Because there are so few images, I have added a custom 3D image augmentation (from github) so the total number of images increased to 10x what I originally had.
I have tried changing most, if not all, the parameters (batch size, optimizer, learning rate, simpler/complex nn's, activation, loss, etc) within my network to no avail. I have also looked online for similar problems in hope that someone has had the same issue and solved it.
Here is an example image that I am using:
the size of this image is (96, 96, 96) and a strip of its array value is (after normalizing them):
[0.54124768 0.59549533 0.61464823 0.59833751 0.50441322 0.33578409
0.40528049 0.4359369 0.39544678 0.32074109 0.20008253 0.28538722
0.27870766 0.37098099 0.13504691 0.2372147 0.4171059 0.56398624
0.38187722 0.71896363 0.44387385 0.41523819 0.31195372 0.10586056
0.12634818 0.13454185 0.57811427 0.6465261 0.61814963 0.61493715]
After preprocessing steps, I fed this into my CNN model:
batch_size = 3
model = Sequential()
model.add(Conv3D(32, [3, 3, 3], padding='same', activation='relu',
input_shape=input_size))
model.add(Conv3D(32, [3, 3, 3], padding='same', activation='relu'))
model.add(MaxPooling3D(pool_size=(2, 2, 2), padding='same'))
model.add(Conv3D(64, [3, 3, 3], padding='same', activation='relu'))
model.add(Conv3D(64, [3, 3, 3], padding='same', activation='relu'))
model.add(MaxPooling3D(pool_size=(2, 2, 2), padding='same'))
model.add(Dropout(0.5))
model.add(Conv3D(128, [3, 3, 3], padding='same', activation='relu'))
model.add(Conv3D(128, [3, 3, 3], padding='same', activation='relu'))
model.add(Conv3D(128, [3, 3, 3], padding='same', activation='relu'))
model.add(MaxPooling3D(pool_size=(2, 2, 2), padding='same'))
model.add(Conv3D(256, [3, 3, 3], padding='same', activation='relu'))
model.add(Conv3D(256, [3, 3, 3], padding='same', activation='relu'))
model.add(Conv3D(256, [3, 3, 3], padding='same', activation='relu'))
model.add(MaxPooling3D(pool_size=(2, 2, 2), padding='same'))
model.add(Dropout(0.5))
model.add(Flatten())
model.add(Dense(1024, activation='relu'))
model.add(Dense(1024, activation='relu'))
model.add(Dropout(0.5))
model.add(Dense(1, activation='linear'))
opt = optimizers.Adam(lr=1e-6)
model.compile(loss='mean_squared_logarithmic_error', optimizer=opt, metrics=['accuracy'])
train_datagen = customImageDataGenerator(shear_range=0.2,
zoom_range=0.2,
horizontal_flip=True)
val_datagen = customImageDataGenerator()
test_datagen = customImageDataGenerator()
training_set = train_datagen.flow(x_train, y_train, batch_size=batch_size, shuffle=True)
validation_set = val_datagen.flow(x_val, y_val, batch_size=batch_size, shuffle=False)
testing_set = test_datagen.flow(x_test, y_test, batch_size=batch_size, shuffle=False)
earlystop = EarlyStopping(monitor='val_loss', patience=30)
history = model.fit(
training_set,
steps_per_epoch = len(x_train)//batch_size,
epochs = 50,
#callbacks = [earlystop],
validation_data = validation_set,
validation_steps = len(x_val)//batch_size
)
I created a custom accuracy check to visualize the outputs which are:
Predicted score: [1.8405123] True score: 3.0
Predicted score: [1.4033222] True score: 3.0
Predicted score: [1.4690828] True score: 1.0
Predicted score: [1.5127727] True score: 3.0
Predicted score: [1.6159409] True score: 1.0
Predicted score: [1.4333361] True score: 1.5
Predicted score: [1.7470968] True score: 3.0
Predicted score: [1.2196972] True score: 1.5
Predicted score: [1.5940914] True score: 4.0
Predicted score: [1.4052064] True score: 1.0
Predicted score: [1.5127727] True score: 1.0
Predicted score: [1.4584785] True score: 1.0
Predicted score: [1.7860543] True score: 3.0
Predicted score: [1.4752649] True score: 2.5
Predicted score: [1.8568267] True score: 1.0
Predicted score: [1.4793051] True score: 3.0
Predicted score: [1.395096] True score: 2.5
Predicted score: [1.6011616] True score: 4.0
Predicted score: [1.9094267] True score: 1.0
Predicted score: [1.6322718] True score: 1.0
Predicted score: [1.7284409] True score: 4.0
Predicted score: [1.5262214] True score: 1.5
Out: 0.09090909090909091
As you can see, the predicted values fall within the 1-2 range even though there are test scores at the 2.5, 3, 4, and 5 range.
print(y_pred.min(), y_pred.max())
1.2196972 1.9094267
Finally, here are my graphs:
As you can see, the loss decreases beautifully, but the accuracy freezes midway and I am not sure what the cause may be.
Sorry for the long post, but I would appreciate any answers, thank you!
Upvotes: 2
Views: 1320
Reputation: 1920
There are several things that may help with the accuracy of your model.
softmax
activation in your last layer.import tensorflow as tf
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Layer, Conv3D, BatchNormalization, Dropout, InputLayer
class ConvBlock(Layer):
def __init__(self, filters=32, kernel_size = [3, 3, 3],
padding='same', activation='relu', dropout=0.1):
super(ConvBlock, self).__init__()
self.conv = Conv3D(filters=filters,
kernel_size=kernel_size,
activation=activation,
padding=padding)
self.norm = BatchNormalization()
self.dropout = Dropout(dropout)
def call(self, input, training=False):
x = self.conv(input)
x = self.norm(x)
x = self.dropout(x, training=training)
return x
model = Sequential()
model.add(InputLayer((96, 96, 96, 1)))
model.add(ConvBlock())
model.summary()
Hope this helps to improve it at least a little bit.
Upvotes: 1