[confusion matrix (https://i.sstatic.net/WiTyUOew.png)]
model performance (validation and training testing acc) (https://i.sstatic.net/r8AK1wkZ.png)
here are all the dataset distributions (https://i.sstatic.net/LhBXJeTd.png)](https://i.sstatic.net/mLpB7vDs.png)(https://i.sstatic.net/IYvPpRzW.png)
Sorry I am relatively new to coding in general so I apologize if I misspeak.
So I attached the performance metrics of the model including validation and testing accuracy. It seemed to do pretty well. It reads Brain MRI scans and predicts among 3 different types of tumors or no tumor (healthy brain) — so 4 categories in total.
I got 24 new images (6 per category) and used the predict function…the model guessed them all to be the same label (pituatary tumor) leading to an accuracy of 25%.
My datasets are relatively balanced Ill post them as images.
What might be happening here and is there anything I can do to fix it?
I’ll paste the code below.
from google.colab import drive
import numpy as np
from PIL import Image
import os
import random
import tensorflow as tf
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Conv2D, MaxPooling2D, Flatten, Dense
from tensorflow.keras.utils import to_categorical
from tensorflow.keras.regularizers import l2
from tensorflow.keras.layers import Dropout
import matplotlib.pyplot as plt
#from tensorflow.keras.preprocessing.image import ImageDataGenerator
from tensorflow.keras.callbacks import EarlyStopping, ReduceLROnPlateau
# Mount Google Drive
drive.mount('/content/drive')
# Define the data folder path
data_folder = '/content/drive/My Drive/mldata/data'
from skimage.transform import resize
# Function to load images and labels with dynamic resizing and width filtering
def load_images_and_labels(data_folder, target_size, width_range):
images = []
labels = []
class_names = os.listdir(data_folder) # Get class names from folder names
for label, class_name in enumerate(class_names):
class_folder = os.path.join(data_folder, class_name)
for filename in os.listdir(class_folder):
img_path = os.path.join(class_folder, filename)
img = Image.open(img_path)
img = img.convert('L') # Convert to grayscale if needed
img_width, img_height = img.size
if img_width >= width_range[0] and img_width <= width_range[1]: # Filter by width range
img_array = np.array(img) # Convert PIL Image to NumPy array
img_resized = resize(img_array, target_size, anti_aliasing=True) # Dynamic resizing while preserving aspect ratio
images.append(img_resized)
labels.append(label)
return np.array(images), np.array(labels), class_names
# Define the target size for resizing
target_size = (512, 512) # or (480, 480)
# Define the width range for filtering
width_range = (420, 540)
# Load images and labels with dynamic resizing and width filtering
images, labels, class_names = load_images_and_labels(data_folder, target_size, width_range)
# Normalize pixel values to [0, 1]
images = images / 255.0
# Add a channel dimension to the image arrays
images = np.expand_dims(images, axis=-1)
# Shuffle the dataset
indices = np.arange(images.shape[0])
np.random.shuffle(indices)
images = images[indices]
labels = labels[indices]
# Define the split sizes
train_size = int(len(images) * 0.7)
val_size = int(len(images) * 0.2)
test_size = len(images) - train_size - val_size
# Split the dataset
train_images = images[:train_size]
train_labels = labels[:train_size]
val_images = images[train_size:train_size+val_size]
val_labels = labels[train_size:train_size+val_size]
test_images = images[train_size+val_size:]
test_labels = labels[train_size+val_size:]
# Convert labels to one-hot encoding
train_labels = to_categorical(train_labels, num_classes=len(class_names))
val_labels = to_categorical(val_labels, num_classes=len(class_names))
test_labels = to_categorical(test_labels, num_classes=len(class_names))
from tensorflow.keras.layers import BatchNormalization
model = Sequential([
Conv2D(32, (3, 3), activation='relu', input_shape=(512, 512, 1), kernel_regularizer=l2(0.001)),
BatchNormalization(),
MaxPooling2D((2, 2)),
Conv2D(64, (3, 3), activation='relu', kernel_regularizer=l2(0.001)),
BatchNormalization(),
MaxPooling2D((2, 2)),
Conv2D(128, (3, 3), activation='relu', kernel_regularizer=l2(0.001)),
BatchNormalization(),
MaxPooling2D((2, 2)),
Flatten(),
Dense(128, activation='relu', kernel_regularizer=l2(0.001)),
BatchNormalization(),
Dropout(0.5),
Dense(len(class_names), activation='softmax')
])
# Compile the model
model.compile(optimizer='adam',
loss='categorical_crossentropy',
metrics=['accuracy'])
from tensorflow.keras.callbacks import ReduceLROnPlateau
lr_reduction = ReduceLROnPlateau(monitor='val_loss',
patience=3,
verbose=1,
factor=0.5,
min_lr=0.00001)
from tensorflow.keras.callbacks import EarlyStopping
# Early stopping callback
early_stopping = EarlyStopping(
monitor='val_accuracy', # Monitor validation accuracy
patience=10, # Number of epochs with no improvement after which training will be stopped
verbose=1, # Verbosity mode
restore_best_weights=True # Restore model weights from the epoch with the best value of the monitored quantity
)
from tensorflow.keras.callbacks import ModelCheckpoint
checkpoint = ModelCheckpoint('/content/drive/My Drive/RadiologyTumorModelUSF2_checkpoint.h5', save_best_only=True, monitor='val_loss', mode='min')
# Update the model.fit() call to include the early stopping callback
history = model.fit(
train_images, train_labels, # Pass training images and labels separately
batch_size=16, # Specify batch_size separately
epochs=100, # Start with a high number and let early stopping decide
validation_data=(val_images, val_labels),
callbacks=[lr_reduction, early_stopping, checkpoint] # Add callbacks
)
model_path = '/content/drive/My Drive/RadiologyTumorModelUSF2.h5'
# Save the model
model.save(model_path)
print("Model saved successfully at:", model_path)
# Evaluate the model on the validation set
val_loss, val_accuracy = model.evaluate(val_images, val_labels, verbose=2)
print(f"Validation Accuracy: {val_accuracy}")
# Evaluate the model on the test set
test_loss, test_accuracy = model.evaluate(test_images, test_labels, verbose=2)
print(f"Test Accuracy: {test_accuracy}")
I thought it was due to the discrepency between quality of pictures at first due to variations in pixel width and resizing so I tried revising and retraining my model using img_resized = resize(img_array, target_size, anti_aliasing=True) # Dynamic resizing while preserving aspect ratio
since most of my training data was between 420-540 px width and my new testing images were originally 512×512 or 630×630
Alex Huang is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.