Detecting Brain Tumors with Deep Learning: A Step-by-Step Guide
Brain tumors are a serious medical condition that can have devastating effects if not caught and treated early. According to the American Brain Tumor Association, an estimated 88,970 people will receive a primary brain tumor diagnosis in 2022, and brain tumors are the leading cause of cancer-related deaths in children under age 15.
Fortunately, advances in medical imaging and artificial intelligence are providing new tools to help detect brain tumors earlier and more accurately. In particular, deep learning—a subfield of machine learning that uses neural networks with many layers—has shown great promise for analyzing complex medical images like MRI scans.
In this article, we‘ll walk through how to build a deep learning model for detecting brain tumors in MRI images. We‘ll be using a publicly available dataset of brain MRIs, along with the popular deep learning library TensorFlow. Whether you‘re a medical researcher, data scientist, or AI enthusiast, this guide will give you a practical introduction to applying deep learning to a real-world medical use case.
A Brief Primer on Deep Learning for Medical Imaging
Before we dive into the implementation details, let‘s set the stage with some background on deep learning for medical image analysis. Broadly speaking, there are two main types of tasks:
-
Classification: Determining whether an image contains a specific condition or feature, such as a tumor. The output is a binary label (e.g. tumor present vs. absent) or a probability score.
-
Segmentation: Identifying the precise pixels in an image that represent an object of interest, such as the region containing a tumor. The output is a pixel-wise mask.
Some key advantages of deep learning over traditional machine learning approaches for these tasks include:
- Ability to automatically learn hierarchical features from raw image data, without the need for manual feature engineering
- Flexibility to handle complex, high-dimensional data like medical images
- Improved accuracy, especially with large datasets
- Transfer learning: Leveraging features learned from other imaging datasets to boost performance
However, there are also challenges in applying deep learning to medical imaging, such as:
- Scarcity of large, high-quality labeled datasets, since annotations often require domain expertise
- Algorithmic bias and generalization to new populations and image acquisition protocols
- Interpretability and trustworthiness of deep learning systems for clinical decision support
With these opportunities and challenges in mind, let‘s see how to implement a deep learning approach for brain tumor classification.
Loading and Preprocessing the Data
We‘ll be using the Brain Tumor Classification dataset from Kaggle, which contains 3264 brain MRI images across 4 classes: glioma tumor, meningioma tumor, pituitary tumor, and no tumor. The images are provided in JPEG format and have been resized to 224×224 pixels.
First, let‘s download the dataset from Kaggle and unzip it locally. Then, we can load the image and label data into memory:
import os
import numpy as np
from PIL import Image
# Set path to image files
data_dir = ‘brain_tumor_dataset/‘
# Get list of image filenames
img_files = os.listdir(data_dir)
# Load images and labels
images = []
labels = []
for img_file in img_files:
img_path = os.path.join(data_dir, img_file)
img = Image.open(img_path).resize((224, 224))
img = np.array(img) / 255.0 # Scale pixel values to [0, 1]
images.append(img)
label = img_file.split(‘.‘)[0] # Extract label from filename
labels.append(label)
images = np.array(images)
labels = np.array(labels)
This code reads in each image file, resizes it to 224×224 pixels, converts the pixel values to floats between 0 and 1, and stores the image array and corresponding label. We extract the label from the filename, assuming a format like "label.tumortype.jpg".
Next, we‘ll convert the string labels to integer encodings and split the data into training and test sets:
from sklearn.preprocessing import LabelEncoder
from sklearn.model_selection import train_test_split
# Encode string labels as integers
le = LabelEncoder()
labels = le.fit_transform(labels)
# Split into train and test sets
X_train, X_test, y_train, y_test = train_test_split(images, labels, test_size=0.2, random_state=42)
We use scikit-learn‘s LabelEncoder to map the string labels (e.g. "glioma", "no_tumor") to integers, and we do a 80%/20% train/test split.
Augmenting the Training Data
A common challenge with medical imaging datasets is that they tend to be fairly small, which can lead to overfitting. One way to mitigate this is to artificially enlarge the training set using data augmentation.
The idea is to apply random transformations to the images, such as flips, rotations, and zooms, to create new "fake" training examples. This helps the model learn features that are invariant to these transformations and improves generalization.
We can easily do data augmentation using the ImageDataGenerator class in Keras:
from tensorflow.keras.preprocessing.image import ImageDataGenerator
# Create data generator with augmentation
datagen = ImageDataGenerator(
rotation_range=20,
width_shift_range=0.2,
height_shift_range=0.2,
shear_range=0.2,
zoom_range=0.2,
horizontal_flip=True,
vertical_flip=True,
fill_mode=‘nearest‘)
datagen.fit(X_train)
Here we‘re applying random rotations up to 20 degrees, horizontal and vertical shifts up to 20% of the image size, shears, zooms, and flips. The fill_mode parameter tells it how to fill in any empty pixels created by the transformations.
Building the Model
Now comes the fun part—constructing the actual neural network! There are two main approaches we could take:
- Build and train a model from scratch
- Fine-tune a pretrained model
Option 1 gives us complete flexibility in the model architecture but requires a lot of labeled data and compute time. Option 2 leverages transfer learning by starting with a model pretrained on a large dataset, usually ImageNet, and fine-tuning it on our specific dataset. This is much faster and works well even with small datasets.
We‘ll go with option 2 and use a pretrained ResNet50 model as our starting point. We can load this easily using Keras:
from tensorflow.keras.applications import ResNet50
from tensorflow.keras.models import Model
from tensorflow.keras.layers import Dense, GlobalAveragePooling2D
# Load pretrained ResNet model
base_model = ResNet50(weights=‘imagenet‘, include_top=False, input_shape=(224, 224, 3))
# Freeze base model layers
for layer in base_model.layers:
layer.trainable = False
# Add custom classifier on top
x = base_model.output
x = GlobalAveragePooling2D()(x)
x = Dense(128, activation=‘relu‘)(x)
output = Dense(4, activation=‘softmax‘)(x)
model = Model(inputs=base_model.input, outputs=output)
We load the ResNet model without the final fully connected layer (include_top=False), so we can add our own classifier on top for our specific task. We freeze the weights of the pretrained layers since we don‘t want to modify them during training.
Then, we take the output of the base model, add a global average pooling layer to flatten it, and add two dense layers—one as a hidden layer with 128 units and ReLU activation, and a final output layer with 4 units (one per class) and softmax activation to get a probability distribution.
Finally, let‘s compile the model and train it:
# Compile model
model.compile(optimizer=‘adam‘,
loss=‘sparse_categorical_crossentropy‘,
metrics=[‘accuracy‘])
# Train model
batch_size = 32
epochs = 10
model.fit(datagen.flow(X_train, y_train, batch_size=batch_size),
validation_data=(X_test, y_test),
epochs=epochs)
We‘re using the Adam optimizer with a learning rate of 0.001, sparse categorical cross-entropy loss since our labels are integers, and accuracy as an evaluation metric. We train for 10 epochs with a batch size of 32, using the augmented data generator for the training data.
Evaluating Performance
After training, we can evaluate our model‘s performance on the test set:
test_loss, test_acc = model.evaluate(X_test, y_test)
print(‘Test accuracy:‘, test_acc)
In my experiment, this model achieved about 92% accuracy on the test set after 10 epochs, which is quite good! However, accuracy alone doesn‘t tell the whole story. It‘s also important to look at the confusion matrix to see which classes the model tends to mix up:
from sklearn.metrics import confusion_matrix
# Get predicted labels for test set
y_pred = model.predict(X_test)
y_pred = np.argmax(y_pred, axis=1)
# Plot confusion matrix
cm = confusion_matrix(y_test, y_pred)
sns.heatmap(cm, annot=True, fmt=‘d‘, cmap=‘Blues‘)

We can see that the model does well on the "no tumor" and "meningioma" classes but sometimes confuses "glioma" and "pituitary" tumors. This suggests that we may need more training data for those classes or a more fine-grained label space.
Next Steps and Future Directions
There are many ways we could extend and improve this basic brain tumor classification model:
- Experiment with other model architectures, e.g. DenseNet, Inception, or custom CNNs
- Incorporate additional MRI modalities and sequences (e.g. T1, T2, FLAIR)
- Perform 3D modeling using volumetric scans rather than 2D slices
- Implement multi-task learning to jointly predict tumor presence, type, grade, and other attributes
- Use model explanations (e.g. Grad-CAM) to visualize what image features the model is attending to
- Deploy the trained model as a web app or integrate it into a clinical workflow
Ultimately, the goal is to develop AI systems that can assist radiologists and doctors in detecting and diagnosing brain tumors more rapidly and accurately. Of course, much more clinical testing and validation would be needed before deploying such a system. However, deep learning models like the one we built offer a promising step towards that vision.
I hope this step-by-step guide has given you a practical sense of how to apply deep learning to medical imaging tasks like brain tumor classification. The complete code for this example is available on GitHub.
Please feel free to leave a comment if you have any questions or feedback! I‘d also encourage you to try applying these techniques to other datasets and share what you learn.