CoolFace
Apppublic

venthanvi/fracture-api

sourceHugging Faceupdated 6mo agoView on Hugging Face
1likes
App README

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):

MetrikWert
AUC-ROC0.884
Sensitivität (Fraktur-Recall)0.746
Spezifität0.851
Accuracy0.800
PPV (Precision)0.825
NPV0.781
Optimaler Threshold (Youden's J)0.613

Datensplit: 3 831 Train · 480 Val · 495 Test (80/10/10, patienten-stratifiziert)

Modell-Vergleich (Val-AUC)

ModellParamsVal AUCTrainingszeit
tfefficientnetv2m (gewählt)Kaggle GPU
convnext_tiny28M0.788799s
densenet1217.2M0.775869s
efficientnet_b28.1M0.762754s
efficientnet_b04.3M0.740690s

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.txt

Schnellstart

Voraussetzungen

  • Python 3.11+
  • Node.js 18+
  • Checkpoint-Datei: checkpoints/best_model.pth (von Kaggle oder Hugging Face laden)

Backend starten

bash
cd api
uvicorn main:app --reload --port 8000

→ API erreichbar unter http://localhost:8000 → Swagger-Doku unter http://localhost:8000/docs

Frontend starten

bash
cd frontend
npm install
npm run dev

→ App erreichbar unter http://localhost:5173

Checkpoint laden (falls nicht vorhanden)

bash
# 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 8000

Training

Lokal (MacBook M4, Debug)

bash
python -m ml.train

Verwendet efficientnet_b0 mit IMG_SIZE=224, ~50–80s pro Epoch.

Kaggle (GPU T4 x2, Produktionstraining)

  1. 1.Notebook öffnen: notebooks/kaggle_train.ipynb
  2. 2.Accelerator: GPU T4 x2 · Internet: On
  3. 3.HF_TOKEN und IMAGE_DATASET_SLUG in Cell 2 eintragen
  4. 4.Alle Cells ausführen (~2–5h)
  5. 5.best_model.pth aus dem Output-Tab herunterladen → checkpoints/
Umgebungsvariablen für Cloud-Training
VariableLokalKaggle
MODEL_NAMEefficientnet_b0tf_efficientnetv2_m
IMG_SIZE224480
BATCH_SIZE3216
NUM_WORKERS48
DATA_ROOTlokaler Pfad/kaggle/input/.../alle Bilder

Evaluation

bash
python -m ml.evaluate --save-json
# → schreibt logs/eval_results.json (wird vom Frontend angezeigt)

Hyperparameter-Suche

bash
python -m ml.tune --trials 20
# → Ergebnisse in logs/best_params.json

API-Referenz

GET /health

json
{ "status": "ok", "model": "tf_efficientnetv2_m" }

POST /predict

Einzelbild-Inferenz mit Grad-CAM.

bash
curl -X POST http://localhost:8000/predict \
  -F "file=@bild.png" \
  -F "threshold=0.613"
json
{
  "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.

bash
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:

KonstanteStandardEnv-Var
MODEL_NAMEefficientnet_b0MODEL_NAME
IMG_SIZE224IMG_SIZE
BATCH_SIZE32BATCH_SIZE
HEAD_DROPOUT0.4HEAD_DROPOUT
DEFAULT_THRESHOLD0.5
UNCERTAINTY_MARGIN0.05
GRADCAM_IMAGE_WEIGHT0.4
PHASE1_LR1e-3
PHASE2_LR1e-5

Checkpoint-Format

Ab dieser Version speichert train.py Checkpoints mit Architektur-Metadaten:

python
{
  "state_dict": { ... },
  "model_name": "tf_efficientnetv2_m",
  "img_size": 480
}

Ältere plain-state-dict Checkpoints werden weiterhin geladen (Sidecar best_model_config.json).