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/<checkpoint_id>/, byte-identical to the directory the
PointWise runtime serves from (data/lateral-runtime/bundles/<checkpoint_id>/):
| 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/.
# 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.