Skip to content
Lu Phone Maw

Pneumonia Detection

An educational deep-learning project that classifies chest X-rays as normal or pneumonia with a fine-tuned EfficientNet-B0, evaluated on a held-out test set and explained with Grad-CAM.

Focus
Machine Learning, Computer Vision
Core stack
PyTorch, EfficientNet-B0, Grad-CAM
Grid of four chest X-rays beside their Grad-CAM overlays: two correctly classified NORMAL cases and two correctly classified PNEUMONIA cases with prediction confidences.
Held-out test set · n = 624
Pneumonia recall
98.2%
Accuracy
90.5%
F1
92.8%

Educational model. Not a diagnostic tool.

Framing

An exercise in evaluation, not a diagnostic tool

This project trains a convolutional network to label chest X-rays as normal or pneumonia, using a public dataset. Its value is in the process: a sound training setup, an untouched test set, an honest look at the errors, and an explainability layer that is presented with its limits.

It is an educational machine-learning demonstration. The results below are test-set results, not clinical validation, and nothing here should be used for medical decisions.

Training

Small model, staged fine-tuning

EfficientNet-B0 is compact enough to train and serve cheaply while still benefiting from ImageNet pre-training. Training happens in two stages: first only a new classification head is trained on a frozen backbone, then the whole network is fine-tuned at a lower learning rate, so the pre-trained features aren't wrecked by large early gradients.

Two-stage transfer learning

Diagram

ImageNet weightsEfficientNet-B0
Stage 1Train the headbackbone frozen · 5 epochs · lr 1e-4
Stage 2Fine-tune everythingunfrozen · 15 epochs · lr 1e-5
Held-out test624 images, used once

Class imbalance — weighted loss

Validation — stratified 85 / 15 split

Regularisation — dropout 0.3 on the head

Values from the project configuration.

Fig. 1Training procedure.

Three training plots over 20 epochs — loss, validation accuracy and validation F1 — with a vertical line marking the start of stage two.

Fig. 2Training curves; the vertical line marks the switch from frozen-backbone training to full fine-tuning. — Output from the project.

Results

Results on the held-out test set

Accuracy
90.5%
Pneumonia recall
98.2%
F1 score
92.8%
Test images
624
Recorded in the executed evaluation notebook. Test split: 234 normal, 390 pneumonia images.
Test-set confusion matrix: 182 true negatives, 52 false positives, 7 false negatives, 383 true positives.

Fig. 3Confusion matrix on the 624-image test set. — Output from the project.

The model misses very few pneumonia cases — 7 of 390 — but it pays for that with false alarms: 52 of the 234 normal images were labelled pneumonia. Accuracy alone hides that asymmetry, which is why the confusion matrix and threshold analysis are part of the evaluation.

Pneumonia images correctly flagged

383 / 390 · 98.2%

Normal images correctly cleared

182 / 234 · 77.8%

Derived from the recorded test-set confusion matrix.

Threshold analysis

Where to draw the line

A classifier's output is a probability; the decision threshold turns it into a label. The analysis plots precision against recall and F1 across thresholds. F1 peaks around 0.89, well above the 0.5 default — but a higher threshold can only lower recall, so choosing it is a judgement about which mistake is worse, not a free improvement.

Two plots: a precision–recall curve with a 95% recall target line and the maximum-F1 point, and F1 score against decision threshold comparing the 0.5 default with the F1-optimal threshold of 0.89.

Fig. 4Threshold analysis: precision–recall curve and F1 across decision thresholds. — Output from the project.

Explainability

Grad-CAM, read carefully

Grad-CAM highlights the regions of an image that most influenced the prediction, using gradients at the network's final convolutional block. It's a useful sanity check: in the pneumonia examples shown, the activation falls on the lung fields.

But it shows what the model used, not where disease is. In one correctly classified normal image the strongest activation sits near the image edges — exactly the kind of signal that would warrant investigation before trusting a model. Grad-CAM output here is not evidence of clinical localisation.

Grid of four chest X-rays beside their Grad-CAM overlays: two correctly classified NORMAL cases and two correctly classified PNEUMONIA cases with prediction confidences.

Fig. 5Grad-CAM overlays for correctly classified test images. In the first NORMAL case the activation sits near the image edges — a reminder that saliency is not localisation. — Output from the project.

Serving

Two interfaces to the same model

Streamlit

An interactive demo for uploading an X-ray and viewing the model's prediction, hosted on Hugging Face Spaces.

FastAPI

A programmatic API with /predict, /predict/gradcam and a health check, packaged with Docker.

Scope

Limitations

Technologies

Stack

Modelling
Python, PyTorch, torchvision, EfficientNet-B0
Evaluation
scikit-learn, Grad-CAM (pytorch-grad-cam)
Serving
Streamlit, FastAPI, ONNX export
Deployment
Docker, Hugging Face Spaces, GitHub Actions