Write the flagship model card: ensemble members, TTA recipe, data release link
Browse files- README.md +217 -18
- checksums.json +1 -1
README.md
CHANGED
|
@@ -1,47 +1,246 @@
|
|
| 1 |
---
|
| 2 |
license: cc-by-nc-4.0
|
| 3 |
library_name: pytorch
|
|
|
|
|
|
|
|
|
|
| 4 |
tags:
|
| 5 |
- medical-image-segmentation
|
| 6 |
- x-ray
|
|
|
|
|
|
|
| 7 |
- flexray
|
| 8 |
---
|
| 9 |
|
| 10 |
-
#
|
| 11 |
|
| 12 |
-
|
| 13 |
-
|
|
|
|
|
|
|
|
|
|
| 14 |
|
| 15 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 16 |
|
| 17 |
-
|
| 18 |
-
|
| 19 |
-
|
|
|
|
| 20 |
|
| 21 |
-
##
|
| 22 |
|
| 23 |
-
|
| 24 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 25 |
|
| 26 |
## Evaluation
|
| 27 |
|
| 28 |
-
|
| 29 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 30 |
|
| 31 |
## Files
|
| 32 |
|
| 33 |
- `model.safetensors`: exported model weights.
|
| 34 |
-
- `config.yml`:
|
| 35 |
- `label_schema.json`: ordered output labels.
|
| 36 |
- `preprocessing.json`: public preprocessing contract.
|
| 37 |
-
- `checksums.json`: SHA256 checksums.
|
|
|
|
|
|
|
|
|
|
| 38 |
|
| 39 |
## Licenses
|
| 40 |
|
| 41 |
-
|
| 42 |
-
|
| 43 |
-
Weights license: CC-BY-NC-4.0
|
| 44 |
|
| 45 |
## Citation
|
| 46 |
|
| 47 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
---
|
| 2 |
license: cc-by-nc-4.0
|
| 3 |
library_name: pytorch
|
| 4 |
+
pipeline_tag: image-segmentation
|
| 5 |
+
datasets:
|
| 6 |
+
- VictorButoi/flexray-data
|
| 7 |
tags:
|
| 8 |
- medical-image-segmentation
|
| 9 |
- x-ray
|
| 10 |
+
- radiograph
|
| 11 |
+
- anatomy
|
| 12 |
- flexray
|
| 13 |
---
|
| 14 |
|
| 15 |
+
# FleXray: `flexray-base`
|
| 16 |
|
| 17 |
+
- Website and in-browser demo: [victorbutoi.github.io/FleXray](https://victorbutoi.github.io/FleXray/)
|
| 18 |
+
- Code: [github.com/VictorButoi/FleXray](https://github.com/VictorButoi/FleXray)
|
| 19 |
+
- Data: [`VictorButoi/flexray-data`](https://huggingface.co/datasets/VictorButoi/flexray-data)
|
| 20 |
+
- Tutorial: [Colab notebook](https://colab.research.google.com/drive/1MNIeN9LN-tY8wAifWSolxmFZi3Q0BlVX)
|
| 21 |
+
- Paper: *FleXray: Flexible Full-Body X-ray Segmentation* (coming soon)
|
| 22 |
|
| 23 |
+
`flexray-base` is the **flagship FleXray model**: a single 2D UNet that segments
|
| 24 |
+
anatomy from standard radiographs across body regions, projections, and
|
| 25 |
+
acquisition settings. It predicts 60 anatomical structures (plus background) as
|
| 26 |
+
independent sigmoid channels at 256 x 256 resolution and is the default bundle
|
| 27 |
+
loaded by `flexify` and `FleXraySegmenter.from_pretrained`.
|
| 28 |
|
| 29 |
+
It is also one member of a five-model ensemble; see
|
| 30 |
+
[The FleXray ensemble](#the-flexray-ensemble) for the other four and
|
| 31 |
+
[Test-time augmentation](#test-time-augmentation) for the inference recipe we
|
| 32 |
+
use for reported results.
|
| 33 |
|
| 34 |
+
## Quick start
|
| 35 |
|
| 36 |
+
```bash
|
| 37 |
+
python -m pip install flexray
|
| 38 |
+
flexify --input ./image.png --output-dir ./predictions
|
| 39 |
+
```
|
| 40 |
+
|
| 41 |
+
```python
|
| 42 |
+
from fxr.inference import FleXraySegmenter
|
| 43 |
+
|
| 44 |
+
segmenter = FleXraySegmenter.from_pretrained("VictorButoi/flexray-base")
|
| 45 |
+
prediction = segmenter.predict("./image.png", threshold=0.5)
|
| 46 |
+
prediction.masks # uint8, CxHxW thresholded masks
|
| 47 |
+
prediction.probabilities # float32, CxHxW sigmoid probabilities
|
| 48 |
+
prediction.logits # float32, CxHxW raw scores
|
| 49 |
+
```
|
| 50 |
+
|
| 51 |
+
`flexify` writes `<name>_masks.npy`, `<name>_probabilities.npy`, and
|
| 52 |
+
`<name>_logits.npy` per image. Channel order follows `label_schema.json`.
|
| 53 |
+
Pass `--binary LABEL` (for example `--binary femurs`) to write one label. See
|
| 54 |
+
[docs/inference.md](https://github.com/VictorButoi/FleXray/blob/main/docs/inference.md)
|
| 55 |
+
for the full CLI and Python API.
|
| 56 |
+
|
| 57 |
+
## The FleXray ensemble
|
| 58 |
+
|
| 59 |
+
The flagship was trained with a 0.375 FluXray proportion in the training mix.
|
| 60 |
+
Four sibling models share its architecture, label schema, preprocessing, and
|
| 61 |
+
training recipe and differ only in that proportion:
|
| 62 |
+
|
| 63 |
+
| Model ID | FluXray proportion | Role |
|
| 64 |
+
| --- | --- | --- |
|
| 65 |
+
| `VictorButoi/flexray-base-flux000` | 0.0 | ensemble member |
|
| 66 |
+
| `VictorButoi/flexray-base-flux025` | 0.25 | ensemble member |
|
| 67 |
+
| **`VictorButoi/flexray-base`** | **0.375** | **flagship (this repository)** |
|
| 68 |
+
| `VictorButoi/flexray-base-flux050` | 0.5 | ensemble member |
|
| 69 |
+
| `VictorButoi/flexray-base-flux075` | 0.75 | ensemble member |
|
| 70 |
+
|
| 71 |
+
Because the members share one output space, any subset can be averaged in
|
| 72 |
+
probability space:
|
| 73 |
+
|
| 74 |
+
```bash
|
| 75 |
+
flexify --model-id VictorButoi/flexray-base \
|
| 76 |
+
--model-id VictorButoi/flexray-base-flux000 \
|
| 77 |
+
--model-id VictorButoi/flexray-base-flux025 \
|
| 78 |
+
--model-id VictorButoi/flexray-base-flux050 \
|
| 79 |
+
--model-id VictorButoi/flexray-base-flux075 \
|
| 80 |
+
--tta-samples 16 --input ./image.png --output-dir ./predictions
|
| 81 |
+
```
|
| 82 |
+
|
| 83 |
+
```python
|
| 84 |
+
segmenter = FleXraySegmenter.from_pretrained([
|
| 85 |
+
"VictorButoi/flexray-base",
|
| 86 |
+
"VictorButoi/flexray-base-flux000",
|
| 87 |
+
"VictorButoi/flexray-base-flux025",
|
| 88 |
+
"VictorButoi/flexray-base-flux050",
|
| 89 |
+
"VictorButoi/flexray-base-flux075",
|
| 90 |
+
])
|
| 91 |
+
prediction = segmenter.predict("./image.png", tta_samples=16)
|
| 92 |
+
```
|
| 93 |
+
|
| 94 |
+
The website demo exposes the same choices as quality modes: **Low** runs the
|
| 95 |
+
flagship once, **Normal** runs the flagship with 16-pass TTA, **High** runs the
|
| 96 |
+
five-model ensemble once, and **X-High** runs the ensemble with 16-pass TTA.
|
| 97 |
+
Release status of each member is tracked in
|
| 98 |
+
[MODEL_ZOO.md](https://github.com/VictorButoi/FleXray/blob/main/MODEL_ZOO.md).
|
| 99 |
+
|
| 100 |
+
## Test-time augmentation
|
| 101 |
+
|
| 102 |
+
We typically run FleXray with test-time augmentation (TTA) rather than a single
|
| 103 |
+
forward pass; `--tta-samples 16` (or `predict(..., tta_samples=16)`) is the
|
| 104 |
+
setting behind reported results and the demo's Normal / X-High modes.
|
| 105 |
+
|
| 106 |
+
`tta_samples=N` runs one un-augmented pass plus `N - 1` randomly augmented
|
| 107 |
+
passes and averages them in probability space (mean of sigmoid outputs, then
|
| 108 |
+
converted back to logits). The augmentation chain is fixed in
|
| 109 |
+
[`fxr.inference.tta`](https://github.com/VictorButoi/FleXray/blob/main/src/fxr/inference/tta.py)
|
| 110 |
+
and the browser demo mirrors it exactly:
|
| 111 |
+
|
| 112 |
+
| Transform | Probability | Range |
|
| 113 |
+
| --- | --- | --- |
|
| 114 |
+
| Horizontal flip (exactly inverted on the logits before merging) | 0.5 | - |
|
| 115 |
+
| Gamma | 0.5 | gamma 0.9-1.1, gain 0.9-1.1 |
|
| 116 |
+
| Intensity scale (additive) | 0.5 | -0.1 to 0.1 |
|
| 117 |
+
| Brightness | 0.5 | 0.8-1.2 |
|
| 118 |
+
| Sharpness | 0.5 | 0.6-1.4 |
|
| 119 |
+
| Invert | 0.5 | - |
|
| 120 |
+
| Contrast | 0.5 | 0.7-1.3 |
|
| 121 |
+
|
| 122 |
+
The flip is the only geometric transform; intensity transforms do not move
|
| 123 |
+
pixels and are not inverted. Augmented views are drawn from the global torch
|
| 124 |
+
RNG (`torch.manual_seed` for reproducibility). With an ensemble, every view is
|
| 125 |
+
drawn once and run through every member, so `M` members with `tta_samples=N`
|
| 126 |
+
cost `M x N` forward passes (80 for the full ensemble at N=16). `tta_samples<=1`
|
| 127 |
+
reproduces the plain single pass.
|
| 128 |
+
|
| 129 |
+
## Input contract
|
| 130 |
+
|
| 131 |
+
`preprocessing.json` is applied automatically by the public loaders:
|
| 132 |
+
|
| 133 |
+
- grayscale input (RGB is converted), any 8-bit or 16-bit PNG / JPEG / TIFF / BMP
|
| 134 |
+
- per-image percentile min-max normalization to `[0, 1]` (0.5th / 99.5th
|
| 135 |
+
percentiles, `eps = 1e-8`)
|
| 136 |
+
- zero-pad to a square, then resize to 256 x 256
|
| 137 |
+
- outputs are `multilabel` sigmoid probabilities; masks use threshold 0.5
|
| 138 |
+
|
| 139 |
+
Outputs are at the 256 x 256 model resolution; the CLI and Python API do not
|
| 140 |
+
resample back to the original image size.
|
| 141 |
+
|
| 142 |
+
## Output labels
|
| 143 |
+
|
| 144 |
+
61 channels: `background` at index 0, then 60 anatomical structures in the
|
| 145 |
+
order stored in `label_schema.json` (protocol `all_structures_flexray_v4`):
|
| 146 |
+
|
| 147 |
+
- **Skull / shoulder girdle:** skull, scapulae, clavicles
|
| 148 |
+
- **Upper limb:** humeri, radii, ulnae, carpals, metacarpals, phalanges
|
| 149 |
+
- **Lower limb:** femurs, patellae, tibiae, fibulae, tarsals, metatarsals, toes
|
| 150 |
+
- **Thorax:** rib_1 - rib_12, sternum
|
| 151 |
+
- **Spine:** vertebra_c1 - c7, t1 - t12, l1 - l5, sacrum
|
| 152 |
+
- **Pelvis:** hips
|
| 153 |
+
- **Soft tissue:** lungs, heart, liver, spleen, kidneys
|
| 154 |
+
|
| 155 |
+
Paired structures are merged (for example `femurs` covers both sides);
|
| 156 |
+
laterality is not predicted.
|
| 157 |
+
|
| 158 |
+
## Architecture
|
| 159 |
+
|
| 160 |
+
`fxr.models.UNet`, 2D, 1 input channel, 61 output channels; filters
|
| 161 |
+
`[64, 128, 256, 512, 512, 720, 1024]`, 3 convolutions per block, residual
|
| 162 |
+
blocks with instance norm, `align_corners=True` upsampling. The full
|
| 163 |
+
architecture is in `config.yml`.
|
| 164 |
+
|
| 165 |
+
## Training data
|
| 166 |
+
|
| 167 |
+
The model was trained on three source types unified under the FleXray label
|
| 168 |
+
protocol (mixing proportions in parentheses):
|
| 169 |
+
|
| 170 |
+
- **Real X-ray masks:** HandBones (0.01), FootBones (0.01), MURA forearm
|
| 171 |
+
(0.01) and MURA humerus (0.01) with our own annotations.
|
| 172 |
+
- **Generated FluXray images (0.375):** digitally reconstructed radiographs from
|
| 173 |
+
the MOOSE CTs, generatively edited toward real X-ray appearance, with exact
|
| 174 |
+
overlapping masks for every protocol structure.
|
| 175 |
+
- **Online CT->DRR rendering:** MOOSE / ENHANCE-PET 1.6k (0.375), Shoulder-CT
|
| 176 |
+
(0.05), HaN-Seg (0.05), PedsCT (0.04), RSNA cervical-spine fracture CTs
|
| 177 |
+
(0.04), and ElbowCT (0.03), rendered to DRRs at random poses during training
|
| 178 |
+
with per-label attenuation jitter.
|
| 179 |
+
|
| 180 |
+
Training used AdamW (lr 3e-4, cosine schedule), a Dice + binary cross-entropy
|
| 181 |
+
loss routed per dataset (partially labeled sources ignore unlabeled channels),
|
| 182 |
+
and separate augmentation presets for CT-derived and X-ray inputs. The exact
|
| 183 |
+
recipe is `fxr/configs/training/base.yml` in the code release.
|
| 184 |
+
|
| 185 |
+
Every dataset's license, redistribution status, and download pointer is
|
| 186 |
+
documented in the
|
| 187 |
+
[`VictorButoi/flexray-data`](https://huggingface.co/datasets/VictorButoi/flexray-data)
|
| 188 |
+
card. That repository ships the real X-ray sources whose licenses permit
|
| 189 |
+
redistribution, already packed in the FleXray protocol, plus the MURA masks;
|
| 190 |
+
the FluXray database is released alongside it.
|
| 191 |
|
| 192 |
## Evaluation
|
| 193 |
|
| 194 |
+
FleXray was evaluated on nine real-radiograph datasets held out from training
|
| 195 |
+
(ElbowLat, HipRay, LowerLimbs, MendeleyCXR, MTDDH, DarwinCVD19, DeepFluoro,
|
| 196 |
+
RAM-W600, VinDr-Rib), spanning lungs, ribs, peripheral bones, spine, and
|
| 197 |
+
pelvis. Against generalist baselines (FluoroSAM, TotalSegmentator2D, PAXray)
|
| 198 |
+
it achieves the highest macro Dice in every comparison (9 of 9). Per-dataset
|
| 199 |
+
numbers and confidence intervals are in the paper; the benchmark figure is on
|
| 200 |
+
the [project website](https://victorbutoi.github.io/FleXray/#results).
|
| 201 |
+
Evaluation ignores ground-truth labels covering less than 0.1% of the image.
|
| 202 |
+
|
| 203 |
+
## Intended use and limitations
|
| 204 |
+
|
| 205 |
+
Research use only. FleXray is **not a medical device** and is not cleared for
|
| 206 |
+
clinical diagnosis, treatment planning, or patient-care decisions.
|
| 207 |
+
|
| 208 |
+
- Targets conventional radiographs; dental and mammographic images are out of
|
| 209 |
+
scope.
|
| 210 |
+
- Predicts anatomy, not pathology.
|
| 211 |
+
- No laterality (left/right) and no uncertainty estimates.
|
| 212 |
+
- Performance on acquisition settings, views, or populations far from the
|
| 213 |
+
training sources has not been validated.
|
| 214 |
|
| 215 |
## Files
|
| 216 |
|
| 217 |
- `model.safetensors`: exported model weights.
|
| 218 |
+
- `config.yml`: architecture and protocol config consumed by `from_pretrained`.
|
| 219 |
- `label_schema.json`: ordered output labels.
|
| 220 |
- `preprocessing.json`: public preprocessing contract.
|
| 221 |
+
- `checksums.json`: SHA256 checksums of the bundle files.
|
| 222 |
+
- `onnx/flexray-base-256-fp16.onnx`: fp16 ONNX export (opset 18, sigmoid
|
| 223 |
+
baked in) used by the in-browser demo; parity-checked against the PyTorch
|
| 224 |
+
weights by `tools/export_web_demo.py`.
|
| 225 |
|
| 226 |
## Licenses
|
| 227 |
|
| 228 |
+
- Code: MIT
|
| 229 |
+
- Weights: CC-BY-NC-4.0
|
|
|
|
| 230 |
|
| 231 |
## Citation
|
| 232 |
|
| 233 |
+
```bibtex
|
| 234 |
+
@software{butoi2026flexray,
|
| 235 |
+
title = {FleXray: Flexible Full-Body X-ray Segmentation},
|
| 236 |
+
author = {Butoi, Victor Ion and Gopalakrishnan, Vivek and
|
| 237 |
+
Guttag, John V. and Dalca, Adrian V. and Dey, Neel},
|
| 238 |
+
year = {2026},
|
| 239 |
+
license = {MIT},
|
| 240 |
+
url = {https://github.com/VictorButoi/FleXray}
|
| 241 |
+
}
|
| 242 |
+
```
|
| 243 |
+
|
| 244 |
+
Please also cite the source datasets listed in the
|
| 245 |
+
[`flexray-data`](https://huggingface.co/datasets/VictorButoi/flexray-data) card
|
| 246 |
+
for any dataset you use.
|
checksums.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
| 1 |
{
|
| 2 |
"algorithm": "sha256",
|
| 3 |
"files": {
|
| 4 |
-
"README.md": "
|
| 5 |
"config.yml": "7c7d52b2404d5e3cb5347036feac994ab8b8a18dd6bef5cfa47b749077af727a",
|
| 6 |
"label_schema.json": "c8fa61b6585fc4043e2c51ba1f53271f9313cdae8d812479449b8a2a0ba12d7a",
|
| 7 |
"model.safetensors": "716ce3a8fb2a6abe22b2f2188fd596ddc4642b273fb0d336d629448154fc6d24",
|
|
|
|
| 1 |
{
|
| 2 |
"algorithm": "sha256",
|
| 3 |
"files": {
|
| 4 |
+
"README.md": "e6e5c17b8ece40c296e1fd40d92774a44d6bb6fb1e5452b94f00533ebddf694f",
|
| 5 |
"config.yml": "7c7d52b2404d5e3cb5347036feac994ab8b8a18dd6bef5cfa47b749077af727a",
|
| 6 |
"label_schema.json": "c8fa61b6585fc4043e2c51ba1f53271f9313cdae8d812479449b8a2a0ba12d7a",
|
| 7 |
"model.safetensors": "716ce3a8fb2a6abe22b2f2188fd596ddc4642b273fb0d336d629448154fc6d24",
|