venthanvi/fracture-api
Forearm Fracture Detection
AI-gestützte Frakturerkennung aus Unterarm-Röntgenbildern — konzipiert für den radiologischen Einsatz.
Modell: EfficientNetV2-M · Test-AUC: 0.884 · Sensitivität: 74.6% · Spezifität: 85.1%
Inhalt
Projektübersicht
Dieses Projekt implementiert einen binären Klassifikator (Fraktur / Normal) für Unterarm-Röntgenbilder. Die Pipeline umfasst:
- Zwei-Phasen-Training — Phase 1: Backbone eingefroren, nur Head trainieren · Phase 2: Letzte Backbone-Blöcke fine-tunen
- Grad-CAM++ Heatmaps — visuelle Erklärung der Modellentscheidung für Radiologen
- FastAPI Backend — REST-API mit Einzel- und Batch-Inferenz
- React Frontend — Side-by-side Bildvergleich mit Opacity-Slider und Konfidenz-Warnung
Ergebnisse
Evaluiert auf dem gehaltenen Test-Set (495 Bilder, nie während des Trainings gesehen):
Datensplit: 3 831 Train · 480 Val · 495 Test (80/10/10, patienten-stratifiziert)
Modell-Vergleich (Val-AUC)
Projektstruktur
FractureDataset/
├── ml/ # Python-Package: alle ML-Komponenten
│ ├── config.py # Hyperparameter & Pfade (env-var-overridable)
│ ├── model.py # EfficientNet-Wrapper (timm) + Freeze-Utilities
│ ├── dataloader.py # Dataset + Augmentation-Pipelines
│ ├── dataset.py # splits.csv generieren (einmalig ausführen)
│ ├── train.py # Zwei-Phasen-Training-Loop
│ ├── evaluate.py # Test-Set-Evaluation + Plots
│ ├── tune.py # Optuna Hyperparameter-Suche
│ └── compare_models.py # Architektur-Vergleich
│
├── api/ # FastAPI Backend
│ ├── main.py # Endpoints: /health /predict /predict/batch /model/stats
│ ├── predictor.py # Modell-Singleton + Grad-CAM++ (COLORMAP_INFERNO)
│ ├── schemas.py # Pydantic Response-Modelle
│ └── requirements.txt # API-spezifische Dependencies
│
├── frontend/ # React + Vite Frontend
│ └── src/
│ ├── pages/ # SingleUpload, BatchUpload, ModelStats
│ ├── components/ # HeatmapViewer, PredictionCard, ThresholdStatusBar, ...
│ ├── hooks/ # useOptimalThreshold
│ └── utils/ # isUncertain(), getErrorMessage(), DEFAULT_THRESHOLD
│
├── notebooks/ # Jupyter Notebooks
│ ├── kaggle_train.ipynb # Kompletter Kaggle-Trainings-Workflow
│ ├── thesis_analysis.ipynb
│ └── eda.ipynb
│
├── checkpoints/ # Modell-Gewichte (nicht in git)
│ ├── best_model.pth
│ └── best_model_config.json # Architektur-Metadaten zum Checkpoint
│
├── data/
│ └── splits.csv # Train/Val/Test-Splits (in git)
│
├── logs/ # Evaluations-Ergebnisse
│ ├── eval_results.json # Test-Metriken (in git, Frontend liest sie)
│ ├── model_comparison.csv
│ └── *.png # ROC-Kurve, Konfusionsmatrix (nicht in git)
│
├── Dockerfile
├── render.yaml
└── requirements.txtSchnellstart
Voraussetzungen
- Python 3.11+
- Node.js 18+
- Checkpoint-Datei:
checkpoints/best_model.pth(von Kaggle oder Hugging Face laden)
Backend starten
cd api
uvicorn main:app --reload --port 8000→ API erreichbar unter http://localhost:8000 → Swagger-Doku unter http://localhost:8000/docs
Frontend starten
cd frontend
npm install
npm run dev→ App erreichbar unter http://localhost:5173
Checkpoint laden (falls nicht vorhanden)
# Von Hugging Face (automatisch beim ersten API-Start falls HF_REPO_ID gesetzt):
export HF_REPO_ID=VenthanVi/fracture-detection
cd api && uvicorn main:app --port 8000Training
Lokal (MacBook M4, Debug)
python -m ml.trainVerwendet efficientnet_b0 mit IMG_SIZE=224, ~50–80s pro Epoch.
Kaggle (GPU T4 x2, Produktionstraining)
- Notebook öffnen:
notebooks/kaggle_train.ipynb - Accelerator: GPU T4 x2 · Internet: On
HF_TOKENundIMAGE_DATASET_SLUGin Cell 2 eintragen- Alle Cells ausführen (~2–5h)
best_model.pthaus dem Output-Tab herunterladen →checkpoints/
Umgebungsvariablen für Cloud-Training
Evaluation
python -m ml.evaluate --save-json
# → schreibt logs/eval_results.json (wird vom Frontend angezeigt)Hyperparameter-Suche
python -m ml.tune --trials 20
# → Ergebnisse in logs/best_params.jsonAPI-Referenz
GET /health
{ "status": "ok", "model": "tf_efficientnetv2_m" }POST /predict
Einzelbild-Inferenz mit Grad-CAM.
curl -X POST http://localhost:8000/predict \
-F "file=@bild.png" \
-F "threshold=0.613"{
"filename": "bild.png",
"label": "fracture",
"probability": 0.8734,
"threshold_used": 0.613,
"gradcam_image": "data:image/png;base64,..."
}POST /predict/batch
Mehrere Bilder in einem Request. Führt einen einzigen Batch-Forward-Pass durch.
curl -X POST http://localhost:8000/predict/batch \
-F "files=@bild1.png" \
-F "files=@bild2.png" \
-F "threshold=0.613"GET /model/stats
Gibt den Inhalt von logs/eval_results.json zurück (gecacht in-memory).
Konfiguration
Alle Hyperparameter sind in ml/config.py definiert und per Umgebungsvariable überschreibbar:
Checkpoint-Format
Ab dieser Version speichert train.py Checkpoints mit Architektur-Metadaten:
{
"state_dict": { ... },
"model_name": "tf_efficientnetv2_m",
"img_size": 480
}Ältere plain-state-dict Checkpoints werden weiterhin geladen (Sidecar best_model_config.json).
