Knee implant detector
Binary classifier that flags total-knee-replacement hardware in pre-cropped knee radiograph regions. Used as a preprocessing gate for DeepKnee: knees with an implant are discarded instead of KL-graded.
- Architecture: torchvision
mobilenet_v3_small(2.5M params), single-logit head, 256x256 input, ImageNet normalization. - Checkpoint format: plain
state_dict+ metadata (arch, input size, normalization, two operating thresholds). No pickle of custom classes - loads with torch >= 1.6 and torchvision >= 0.9. - Training data: OAI post-replacement knees (254 positives) vs OAI implant-free knee crops (10,129 negatives), patient-grouped 5-fold split.
- Inference preprocessing: per-crop 5/99-percentile contrast
normalization (built into
infer_implant.py); robust to input brightness and 8/16-bit depth.
Results
Pooled 5-fold out-of-fold: PR-AUC 0.9886, ROC-AUC 0.9998. Hold-out fold 0 via the shipped inference code: PR-AUC 0.9988, sens 51/51, spec 0.9985.
Stored operating points:
| key | threshold | sens | spec |
|---|---|---|---|
threshold (max-F1) |
0.5485 | 98.4% | 99.92% |
threshold_sens99 (gate default) |
0.2992 | 99.2% | 99.85% |
Usage
from infer_implant import load_model, predict_image, has_implant
model, meta = load_model() # downloads this checkpoint (or pass a path)
prob = predict_image(model, meta, "knee_crop.png")
discard = has_implant(model, meta, "knee_crop.png") # sens99 threshold
infer_implant.py lives in the KneePilot repo
(experiements/implant_detector/); it depends only on torch,
torchvision, numpy and Pillow, and runs on CPU or GPU.