dipnas/chest-xray-multilabel-diagnosis2
<div align="center">
Multi-label Chest X-ray Disease Classifier
Deep learning for pathology detection across 5 disease classes from a single chest X-ray
Live demo: dipnas-chest-xray-multilabel-diagnosis2.hf.space
</div>
What It Does
How It Works
X-ray image
|
v
[ Grayscale check ] rejects non-X-ray uploads with strong color content
|
v
[ Preprocessing ] 224x224 resize, ImageNet normalization
|
v
[ ResNet50 backbone ] pretrained on ImageNet, fine-tuned on ChestX-ray14
|
v
[ BCEWithLogitsLoss ] with pos_weight to handle 49x class imbalance
|
v
[ Per-class thresholds ] tuned on validation set to maximize macro F1
|
v
[ Grad-CAM ] gradients from layer4 -> spatial heatmap per predicted class
|
v
Predicted labels + probability scores + heatmap overlay- Uploaded images are checked for grayscale content; images with strong color (i.e. not X-rays) are rejected with a 400 error.
- Images are resized to 224x224 and normalized with ImageNet mean/std.
- ResNet50 replaces its final FC layer with a 5-output head (one logit per class).
BCEWithLogitsLosswithpos_weightpenalizes false negatives on rare classes more heavily.- After training, per-class thresholds are tuned on the validation set to push macro F1 above the default 0.5 cutoff.
- Grad-CAM backpropagates through
layer4to produce a spatial activation map, resized and alpha-blended over the original image.
Model Results
Full per-class breakdown: results/metrics/model_comparison.md
Grad-CAM Visualizations
Grad-CAM on ResNet50's last conv block (layer4), showing what the model attends to for each predicted class:
The Cardiomegaly heatmap lands on the heart silhouette; Effusion lights up the lower lung and costophrenic region. Both match where a radiologist would look, which suggests the model learned real anatomical features rather than dataset artifacts.
Full write-up: results/RESULTS.md
Tech Stack
Setup
Prerequisites:
- Python 3.10+
- Node.js 18+ (for the frontend)
- A Kaggle account with
~/.kaggle/kaggle.jsonconfigured - GPU with 4GB+ VRAM recommended (tested on RTX 3050 4GB)
Steps:
- Install Python dependencies:
pip install -r requirements.txt- Download the dataset and run EDA:
jupyter notebook notebooks/01_eda.ipynb This downloads the NIH ChestX-ray14 sample via the Kaggle API and writes data/metadata/dataset_splits.csv.
- Train models (each script saves its best checkpoint to
results/models/):
python scripts/train_baseline.py
python scripts/train_resnet.py
python scripts/train_efficientnet.py- Tune per-class thresholds:
python scripts/tune_thresholds.py- Build the frontend (one-time, or after changing
web/):
cd web
npm install
npm run build
cd ..- Run the web demo:
uvicorn app.main:app --reloadOpen http://127.0.0.1:8000, upload a chest X-ray, and get per-class probabilities plus a Grad-CAM heatmap for the top predicted class.
For frontend development with hot reload, run npm run dev inside web/ (proxies /predict and /health to port 8000) and open http://localhost:5173.
Project Structure
.
├── data/
│ ├── raw/ # Raw images from Kaggle (gitignored)
│ └── metadata/ # dataset_splits.csv, EDA plots
├── src/
│ ├── data/ # Dataset class and DataLoader utilities
│ ├── models/ # Baseline CNN, ResNet50, EfficientNet-B0
│ ├── training/ # Train/eval engine, early stopping, pos_weight
│ ├── evaluation/ # Per-class AUC-ROC/F1, threshold tuning
│ ├── visualization/ # Grad-CAM implementation
│ └── utils/ # Config and shared helpers
├── scripts/
│ ├── train_baseline.py # Train CNN from scratch
│ ├── train_resnet.py # Fine-tune ResNet50
│ ├── train_efficientnet.py # Fine-tune EfficientNet-B0
│ ├── tune_thresholds.py # Per-class threshold search
│ └── run_gradcam.py # Generate Grad-CAM overlays
├── app/
│ └── main.py # FastAPI server (predict + gradcam, serves web/dist)
├── web/ # React + Vite + Tailwind + shadcn/ui frontend
├── notebooks/
│ └── 01_eda.ipynb # Dataset download, EDA, split creation
└── results/
├── metrics/ # Training history, test metrics, model_comparison.md
├── visualizations/ # Grad-CAM example overlays
└── RESULTS.md # Final write-up with analysisDataset
NIH ChestX-ray14 sample set via Kaggle (nih-chest-xrays/sample): 5,606 images across 5 classes.
The 5,606-image sample rather than the full 112k dataset (45 GB) was used to fit within a 4 GB VRAM budget while preserving the same ~49x class imbalance ratio that the project is built to handle.
Design Decisions
Progress
License
MIT
Author: Dippy2003
