Brain Tumor Classification using Convolutional Neural Networks¶
Project Overview¶
This notebook demonstrates the implementation of a CNN-based deep learning model for brain tumor classification using MRI images. The model achieves 94.8% accuracy in classifying four different types of brain conditions.
Important Notes:¶
- Dataset: Available on Kaggle
- Training Time: ~30 minutes
- Requirements: See
requirements.txt
Medical Context¶
Brain tumors represent a major challenge in neurology, with over 250,000 new cases diagnosed worldwide each year. Early and accurate diagnosis is crucial for optimizing treatment and improving patient prognosis.
Types of Analyzed Tumors¶
Glioma
Tumor developed from glial cells
Meningioma
Tumor of the meninges
Pituitary Tumor
Tumor of the pituitary gland
Project Objectives¶
- Develop an automatic classification model achieving ~95% accuracy
- Create a robust MRI image processing pipeline
- Provide a diagnostic support tool for healthcare professionals
Technologies and Tools¶
- Deep Learning: TensorFlow 2.x, Keras
- Image Processing: OpenCV, PIL
- Data Analysis: NumPy, Pandas
- Visualization: Matplotlib, Seaborn
Project Structure¶
brain_tumor_model_CNN/
├── brain_tumor_model_CNN.py # Main script
├── data/ # Dataset directory
│ ├── Training/ # Training images
│ └── Testing/ # Test images
├── model_performance.csv # Performance metrics
└── visualizations/ # Generated visualizations
import os
import sys
import tensorflow as tf
from keras import models, layers
import matplotlib.pyplot as plt
import numpy as np
from sklearn.metrics import confusion_matrix
import seaborn as sns
import pandas as pd
import csv
from keras.models import model_from_json
# Environment setup
os.environ['PYTHONIOENCODING'] = 'utf-8'
sys.stdout.reconfigure(encoding='utf-8')
# Version information
print(f"TensorFlow version: {tf.__version__}")
print(f"Keras version: {tf.keras.__version__}")
Configuration Parameters¶
These parameters have been optimized through experimentation limited by my harware:
Parameter | Value | Description |
---|---|---|
BATCH_SIZE | 32 | Optimal for memory usage and training speed |
IMAGE_SIZE | 256 | Preserves important medical details |
CHANNELS | 3 | RGB image processing |
EPOCHS | 20 | Prevents overfitting while ensuring convergence |
# Configuration
BATCH_SIZE = 32
IMAGE_SIZE = 256
CHANNELS = 3
EPOCHS = 20
# Directory paths
current_dir = os.path.dirname(os.path.abspath(__file__))
parent_dir = os.path.dirname(os.path.dirname(current_dir))
data_dir = os.path.join(parent_dir, "data", "Training")
test_data_dir = os.path.join(parent_dir, "data", "Testing")
2. Data Pipeline¶
2.1 Data Loading Function¶
The load_data
function implements a robust data loading pipeline with the following features:
- Automatic directory structure parsing
- Image resizing and normalization
- Batch processing
- Shuffling for better training
Note: Before running this code, ensure you have downloaded and extracted the dataset from Kaggle to the appropriate directory structure.
def load_data(data_dir, batch_size, image_size):
"""Load and preprocess the image dataset.
Args:
data_dir (str): Path to the data directory
batch_size (int): Number of images per batch
image_size (int): Target size for image resizing
Returns:
tf.data.Dataset: Preprocessed dataset ready for training
"""
return tf.keras.utils.image_dataset_from_directory(
data_dir,
seed=123,
shuffle=True,
image_size=(image_size, image_size),
batch_size=batch_size
)
# Load datasets
# Note: This assumes you have already downloaded and structured the dataset
dataset = load_data(data_dir, BATCH_SIZE, IMAGE_SIZE)
test_dataset = load_data(test_data_dir, BATCH_SIZE, IMAGE_SIZE)
2.2 Dataset Splitting¶
The dataset is split into training and validation sets using the following ratios:
- Training: 90%
- Validation: 10%
This split ensures enough data for training while maintaining a representative validation set.
def split_dataset(ds, train_split=0.9, val_split=0.1, shuffle=True, shuffle_size=10000):
"""Split the dataset into training and validation sets.
Args:
ds (tf.data.Dataset): Input dataset
train_split (float): Proportion for training (default: 0.9)
val_split (float): Proportion for validation (default: 0.1)
shuffle (bool): Whether to shuffle the dataset
shuffle_size (int): Buffer size for shuffling
Returns:
tuple: (train_dataset, val_dataset)
"""
ds_size = len(ds)
if shuffle:
ds = ds.shuffle(shuffle_size, seed=12)
train_size = int(train_split * ds_size)
val_size = int(val_split * ds_size)
train_ds = ds.take(train_size)
val_ds = ds.skip(train_size).take(val_size)
return train_ds, val_ds
# Split dataset
train_ds, val_ds = split_dataset(dataset)
2.3 Performance Optimization¶
The following optimizations are implemented to improve training performance:
- Data caching to prevent I/O bottlenecks
- Prefetching to optimize CPU-GPU pipeline
- Memory-efficient shuffling
Note: These optimizations are crucial for handling the large medical imaging dataset efficiently.
# Performance optimization settings
AUTOTUNE = tf.data.AUTOTUNE
SHUFFLE_BUFFER_SIZE = 1000
# Class names definition
class_names = ['glioma', 'meningioma', 'notumor', 'pituitary']
n_classes = len(class_names)
# Apply optimizations to datasets
train_ds = train_ds.cache().shuffle(SHUFFLE_BUFFER_SIZE).prefetch(buffer_size=AUTOTUNE)
val_ds = val_ds.cache().prefetch(buffer_size=AUTOTUNE)
test_dataset = test_dataset.cache().prefetch(buffer_size=AUTOTUNE)
3. Model Architecture¶
3.1 CNN Architecture Overview¶
Input Layer (256x256x3)
↓
Rescaling (1/255)
↓
Conv2D (16 filters) + ReLU
↓
MaxPooling2D
↓
Conv2D (32 filters) + ReLU
↓
MaxPooling2D
↓
Conv2D (64 filters) + ReLU
↓
MaxPooling2D
↓
Flatten
↓
Dense (128) + ReLU
↓
Dense (4) + Softmax
Key Features:
- Progressive filter increase (16→32→64)
- Multiple convolution layers for feature extraction
- MaxPooling for dimensionality reduction
- Dense layers for classification
Note: This architecture was chosen after extensive experimentation with different configurations.
def create_model():
"""Create and compile the CNN model.
The model architecture is optimized for brain tumor classification,
with multiple convolution layers for feature extraction and
dense layers for classification.
Returns:
tf.keras.Model: Compiled model ready for training
"""
model = models.Sequential([
# Input normalization
layers.Rescaling(1./255, input_shape=(IMAGE_SIZE, IMAGE_SIZE, CHANNELS)),
# First convolution block
layers.Conv2D(16, 3, padding='same', activation='relu'),
layers.MaxPooling2D(),
# Second convolution block
layers.Conv2D(32, 3, padding='same', activation='relu'),
layers.MaxPooling2D(),
# Third convolution block
layers.Conv2D(64, 3, padding='same', activation='relu'),
layers.MaxPooling2D(),
# Classification layers
layers.Flatten(),
layers.Dense(128, activation='relu'),
layers.Dense(n_classes, activation='softmax')
])
# Model compilation
model.compile(
optimizer='adam',
loss=tf.keras.losses.SparseCategoricalCrossentropy(from_logits=False),
metrics=['accuracy']
)
return model
# Create model
# Note: This cell will only create the model structure, not train it
model = create_model()
model.summary()
4. Model Training¶
4.1 Training Process¶
Important Note: The training process takes approximately 30 minutes. This notebook shows the code and expected results, but actual training should be done separately.
Training Configuration:
- Epochs: 20
- Batch Size: 32
- Optimizer: Adam
- Loss Function: Sparse Categorical Crossentropy
# Model training
# Note: This cell requires significant computational resources
# and will take ~30 minutes to complete
history = model.fit(
train_ds,
validation_data=val_ds,
epochs=EPOCHS,
verbose=1
)
4.2 Training Visualization¶
The following functions visualize the training progress and results:
def plot_training_history(history):
"""Visualize training metrics over time.
Args:
history: Training history from model.fit()
"""
plt.figure(figsize=(12, 4))
# Accuracy plot
plt.subplot(1, 2, 1)
plt.plot(history.history['accuracy'], label='Training Accuracy')
plt.plot(history.history['val_accuracy'], label='Validation Accuracy')
plt.title('Model Accuracy')
plt.xlabel('Epoch')
plt.ylabel('Accuracy')
plt.legend()
# Loss plot
plt.subplot(1, 2, 2)
plt.plot(history.history['loss'], label='Training Loss')
plt.plot(history.history['val_loss'], label='Validation Loss')
plt.title('Model Loss')
plt.xlabel('Epoch')
plt.ylabel('Loss')
plt.legend()
plt.tight_layout()
plt.show()
# Plot training history
# Note: This requires a trained model's history
plot_training_history(history)
Result for a generated model :
def create_confusion_matrix(model, test_dataset):
"""Generate and visualize confusion matrix.
Args:
model: Trained model
test_dataset: Test dataset
"""
y_pred = []
y_true = []
for images, labels in test_dataset:
predictions = model.predict(images)
y_pred.extend(np.argmax(predictions, axis=1))
y_true.extend(labels.numpy())
cm = confusion_matrix(y_true, y_pred)
plt.figure(figsize=(10, 8))
sns.heatmap(cm, annot=True, fmt='d', cmap='Blues',
xticklabels=class_names,
yticklabels=class_names)
plt.title('Confusion Matrix')
plt.xlabel('Predicted')
plt.ylabel('True')
plt.show()
# Generate confusion matrix
# Note: Requires a trained model
create_confusion_matrix(model, test_dataset)
Result for a generated model :
5.2 Prediction Analysis¶
Let's analyze the model's predictions in detail, including:
- Correct predictions with confidence levels
- Misclassified cases analysis
- Confidence distribution
Note: These visualizations help understand the model's strengths and limitations.
def create_prediction_diagrams(model, test_dataset):
"""Create comprehensive prediction analysis diagrams.
Args:
model: Trained CNN model
test_dataset: Dataset for testing
Generates:
- Incorrect predictions scatter plot
- Confidence distribution for correct predictions
"""
all_predictions = []
all_true_labels = []
all_confidences = []
for images, labels in test_dataset:
predictions = model.predict(images)
predicted_classes = np.argmax(predictions, axis=1)
confidences = np.max(predictions, axis=1)
all_predictions.extend(predicted_classes)
all_true_labels.extend(labels.numpy())
all_confidences.extend(confidences)
df = pd.DataFrame({
'True Label': [class_names[i] for i in all_true_labels],
'Predicted Label': [class_names[i] for i in all_predictions],
'Confidence': all_confidences
})
df['Correct'] = df['True Label'] == df['Predicted Label']
# Visualization of incorrect predictions
plt.figure(figsize=(12, 8))
sns.scatterplot(data=df[~df['Correct']],
x='True Label',
y='Predicted Label',
hue='Confidence',
size='Confidence',
sizes=(20, 200),
palette='viridis')
plt.title('Incorrect Predictions with Confidence Levels')
plt.xticks(rotation=45)
plt.tight_layout()
plt.show()
# Confidence distribution for correct predictions
plt.figure(figsize=(10, 6))
sns.boxplot(data=df[df['Correct']],
x='True Label',
y='Confidence')
plt.title('Confidence Distribution for Correct Predictions')
plt.xticks(rotation=45)
plt.tight_layout()
plt.show()
# Generate prediction analysis
# Note: Requires a trained model
create_prediction_diagrams(model, test_dataset)
Result for a generated model :
# Save model weights
model.save_weights(os.path.join(current_dir, "brain_tumor_model_weights.weights.h5"))
# Save model architecture
model_json = model.to_json()
with open(os.path.join(current_dir, "brain_tumor_model.json"), "w") as json_file:
json_file.write(model_json)
print("Model saved successfully")
6.2 Model Loading and Prediction¶
Example of how to load and use the saved model for predictions:
def load_and_predict(image_path):
"""Load saved model and make predictions.
Args:
image_path (str): Path to the image file
Returns:
tuple: (predicted_class, confidence)
"""
# Load model architecture
json_file = open(os.path.join(current_dir, "brain_tumor_model.json"), 'r')
loaded_model_json = json_file.read()
json_file.close()
loaded_model = model_from_json(loaded_model_json)
# Load weights
loaded_model.load_weights(os.path.join(current_dir, "brain_tumor_model_weights.weights.h5"))
# Prepare image
img = tf.keras.preprocessing.image.load_img(
image_path,
target_size=(IMAGE_SIZE, IMAGE_SIZE)
)
img_array = tf.keras.preprocessing.image.img_to_array(img)
img_array = tf.expand_dims(img_array, 0)
# Make prediction
predictions = loaded_model.predict(img_array)
predicted_class = class_names[np.argmax(predictions[0])]
confidence = float(np.max(predictions[0]))
return predicted_class, confidence
# Example usage:
# predicted_class, confidence = load_and_predict('path/to/your/image.jpg')
7. Results and Conclusions¶
7.1 Performance Summary¶
The model achieved:
- Overall Accuracy: 94.8%
- Average Prediction Time: < 2 seconds
- Consistent performance across all tumor types
7.2 Key Findings¶
Model Strengths:
- High accuracy across all classes
- Robust to image variations
- Fast inference time
Limitations:
- Requires high-quality MRI images
- Limited to four specific categories
- No tumor localization
7.3 Future Improvements¶
Technical Enhancements:
- Implementation of tumor segmentation
- Support for additional tumor types
- Model optimization for mobile devices
Practical Applications:
- Web interface development
- Integration with medical imaging systems
- Clinical validation studies
7.4 Usage Instructions¶
To use this model:
- Download the dataset from Kaggle
- Install required dependencies
- Run training script (approximately 30 minutes)
- Use the prediction interface for new images
For detailed implementation, refer to the main script: brain_tumor_model_CNN.py