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

- Pneumonia recall
- 98.2%
- Accuracy
- 90.5%
- F1
- 92.8%
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

Results
Results on the held-out test set
- Accuracy
- 90.5%
- Pneumonia recall
- 98.2%
- F1 score
- 92.8%
- Test images
- 624

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
Normal images correctly cleared
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.

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.

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