--- library_name: pytorch pipeline_tag: keypoint-detection tags: - medical-imaging - radiography - knee - landmark-detection - heatmap-regression - posterior-tibial-slope --- # PointWise lateral PTS landmark model (LatPTS v1) Suggests the four points that define the **posterior tibial slope (PTS)** on a lateral knee radiograph: | Output | Meaning | |---|---| | `plateau_anterior` | anterior edge of the tibial plateau (sagittal plateau line) | | `plateau_posterior` | posterior edge of the tibial plateau (sagittal plateau line) | | `shaft_center_proximal` | tibial shaft centre, 60 mm below the plateau midpoint along the shaft line | | `shaft_center_distal` | tibial shaft centre, 120 mm below the plateau midpoint along the shaft line | PTS is the acute angle between the plateau line (anterior → posterior) and the shaft line (proximal → distal), reported folded below 90°. This is a private research artifact of the PointWise annotation app. It is a suggestion tool: every point is meant to be reviewed and corrected by the researcher before it is confirmed. It is not a medical device and makes no claim beyond the evaluation below. ## What is in this repository Each promoted model is an immutable **bundle** under `bundles//`, byte-identical to the directory the PointWise runtime serves from (`data/lateral-runtime/bundles//`): | File | Content | |---|---| | `chosen.pt` | PyTorch checkpoint: weights (14.3 M parameters), the embedded inference specification, training config, epoch | | `inference.json` | the inference specification (preprocessing, decoding, gates, τ); its SHA-256 is recorded in the checkpoint | | `evaluation.json` | validation and locked-test metrics, and the per-film validation outcomes used by the runtime's `parity` check | | `source/` | the exact executable files the model was trained, evaluated and served with, plus `source.json` with their digests | | `provenance.json` | checkpoint and manifest checksums, training run, environment lock, promotion time | | `bundle.json` | model version, checkpoint id, inference / source / bundle digests | `bundle_sha256` covers every file of the bundle except `bundle.json`. The runtime refuses to load a bundle whose digest, code version or executable files differ from what it recorded. The training data (lateral knee films and their confirmed annotations) is private and is **not** in this repository. The bundle contains no patient identifiers: the validation outcomes are keyed by random dataset sample ids. ## Current model: `pointwise-lateral-pts@f3ecbde9edc54ed2+a3a61b0bf1b4` - **Architecture.** torchvision ResNet-18 encoder (ImageNet initialisation, BatchNorm statistics frozen) with a U-Net decoder (GroupNorm, widths 256/128/64/32) and four heatmaps at full canvas resolution (stride 1). - **Input.** The whole film resampled to 0.5 mm/px on a 704 × 896 px canvas (352 × 448 mm), windowed at the film's 1st/99th percentiles, MONOCHROME1 inverted, replicated to three channels with ImageNet normalisation. Pixel spacing is required; uncalibrated films are refused. - **Loss and decoding.** A spatial cross-entropy per channel against a σ = 2 mm Gaussian; the logits become a softmax map scaled by 2πσ², decoded with DARK sub-pixel refinement and support masking. A point is refused rather than guessed when its map is flat, ambiguous (two peaks), peaks at the canvas border, scores below τ = 0.2, or when the plateau (25–65 mm) or shaft (45–75 mm) segment length is implausible. - **Training data.** 453 confirmed lateral knee films of 135 patients from the PointWise study, split by patient with seed 0 into 321 train / 49 validation / 83 test films (94 / 17 / 24 patients in the partition). Flagged knees and films without calibration or patient identity were excluded. - **Selection.** Three configurations were trained. The one with the lowest validation PTS error (90° per refused film) was chosen, with PCK@1.5 mm as the tie-break, before the test set was touched. | Configuration (CPU validation, 49 films / 12 patients) | PTS mean absolute error (95 % CI) | |---|---| | stride 2 with cutout | 2.03° (1.67–2.35) | | stride 2 without cutout | 2.04° (1.71–2.37) | | **stride 1 with cutout (this model)** | **1.94° (1.50–2.37)**, bias +0.39° | ### Locked test evaluation (evaluated once, CPU, batch size 1) 83 test films of 24 patients; 81 films of 19 patients accepted, 2 refused. | Metric | Value | |---|---| | PTS mean absolute error, film-weighted | **2.07°** (95 % CI 1.80–2.35, patient-cluster bootstrap) | | PTS mean absolute error, patient-weighted | 2.14° (1.90–2.36) | | SD of absolute error | 1.65° | | Films off by ≥ 2° / ≥ 5° | 40 % / 9 % | | Bland–Altman bias (model − researcher) | −0.35° (−1.05 to +0.37) | | Limits of agreement | −5.5° to +4.8° | | Point error, median / mean | 2.30 mm / 2.77 mm | | PCK @ 1 / 1.5 / 2 / 2.5 mm | 15 % / 28 % / 41 % / 55 % | | Plateau anterior / posterior, mean error | 1.99 mm / 2.37 mm | | Shaft samples proximal / distal, mean error | 2.64 mm / 4.10 mm | | Shaft-line perpendicular offset, proximal / distal | 1.08 mm / 1.07 mm | | Plateau inclination direction agreement | 80 / 81 films | | Coverage | 97.6 % (both refusals on the distal shaft sample) | These numbers describe this checkpoint on these 83 films of one study and nothing more. The validation intervals of the three configurations overlap. The shaft samples are compared along the researcher's line, so their error along the line does not change PTS. ## Reusing the model The bundle runs with the PointWise repository's `backend/app/lateral/local_runtime.py` in the lateral runtime environment (Python 3.12, torch 2.6.0, torchvision 0.21.0, NumPy 2.2.4, Pillow 12.3.0; `make lateral-setup`). The installed executable files must hash to the bundle's `source_sha256`: use the repository commit that contains this model (`28aa9a1`) or copy the files from `source/` into `backend/`. ```sh # restore the bundle into the runtime's directory (lands in data/lateral-runtime/bundles/f3ecbde9edc54ed2/) hf download dongj21/pointwise-lateral-pts --revision lateral-pts-f3ecbde9edc54ed2 \ --include "bundles/f3ecbde9edc54ed2/*" --local-dir data/lateral-runtime make lateral-use VERSION=pointwise-lateral-pts@f3ecbde9edc54ed2+a3a61b0bf1b4 # activate it make lateral-selftest # checksum, digest and a synthetic film make lateral # serve on 127.0.0.1:5004 ``` `make lateral-parity` additionally reproduces the 49 validation outcomes bit for bit, which needs the local frozen dataset (`5931e030831143e2`) that is not published here. Outside the app, `app.lateral.model.Predictor("chosen.pt")` loads the checkpoint on the CPU and `app.training.filmprep.preprocess_film` builds its input from a raw raster and its pixel spacing; the runtime's `/lateral/predict` endpoint returns original-pixel-centre coordinates, per-point scores and a receipt of the geometry it used.