flexray / README.md
VictorButoi's picture
align evaluation summary with eight held-out datasets
6b63ddf verified
|
Raw
History Blame Contribute Delete
11.1 kB
---
license: cc-by-nc-4.0
library_name: flexray
pipeline_tag: image-segmentation
datasets:
- VictorButoi/flexray-data
tags:
- pytorch
- medical-image-segmentation
- x-ray
- radiograph
- anatomy
- flexray
---
# FleXray: `VictorButoi/flexray`
- Website and in-browser demo: [flexray.csail.mit.edu](https://flexray.csail.mit.edu/)
- Code: [github.com/VictorButoi/FleXray](https://github.com/VictorButoi/FleXray)
- Data: [`VictorButoi/flexray-data`](https://huggingface.co/datasets/VictorButoi/flexray-data)
- Tutorial: [Colab notebook](https://colab.research.google.com/drive/1jMBoOyV8PkRThHi3i6QIMjolmNoRE0cD)
- Paper: [FleXray: Universal Clinical X-ray Segmentation](https://arxiv.org/abs/2609.26756)
FleXray is a single 2D UNet that segments anatomy from standard radiographs
across body regions, projections, and acquisition settings. It predicts 60
anatomical structures (plus background) as independent sigmoid channels at
256 x 256 resolution.
This repository holds the **flagship model** and the four sibling models of
the FleXray ensemble, one bundle per `members/` subfolder (see
[Repository layout](#repository-layout)). `flexify` and
`FleXraySegmenter.from_pretrained` load the flagship by default.
## Quick start
```bash
python -m pip install flexray
flexify --input ./image.png --output-dir ./predictions
```
```python
from fxr.inference import FleXraySegmenter
segmenter = FleXraySegmenter.from_pretrained("VictorButoi/flexray")
prediction = segmenter.predict("./image.png", threshold=0.5)
prediction.masks # uint8, BxCxHxW thresholded masks
prediction.probabilities # float32, BxCxHxW sigmoid probabilities
prediction.logits # float32, BxCxHxW raw scores
```
`flexify` writes `<name>_masks.npy`, `<name>_probabilities.npy`, and
`<name>_logits.npy` per image, each shaped `CxHxW`. The Python API keeps
the batch dimension (`B=1` for a single image). Channel order follows
`label_schema.json`.
Pass `--binary LABEL` (for example `--binary femurs`) to write one label. See
[docs/inference.md](https://github.com/VictorButoi/FleXray/blob/main/docs/inference.md)
for the full CLI and Python API.
## The FleXray ensemble
The flagship was trained with a 0.375 FluXray proportion in the training mix.
Four sibling models share its architecture, label schema, preprocessing, and
training recipe and differ only in that proportion:
| Subfolder | FluXray proportion | Role |
| --- | --- | --- |
| `members/flux000` | 0.0 | ensemble member |
| `members/flux025` | 0.25 | ensemble member |
| **`members/flux0375`** | **0.375** | **flagship (loaded by default)** |
| `members/flux050` | 0.5 | ensemble member |
| `members/flux075` | 0.75 | ensemble member |
`ensemble.json` at the repository root lists the flagship and the members.
Because the members share one output space, they are averaged in probability
space:
```bash
flexify --ensemble --tta-samples 16 --input ./image.png --output-dir ./predictions
flexify --subfolder members/flux000 --input ./image.png --output-dir ./predictions
```
```python
segmenter = FleXraySegmenter.from_pretrained("VictorButoi/flexray", ensemble=True)
prediction = segmenter.predict("./image.png", tta_samples=16)
member = FleXraySegmenter.from_pretrained(
"VictorButoi/flexray", subfolder="members/flux000"
)
```
The website demo exposes the same choices as quality modes: **Low** runs the
flagship once, **Normal** runs the flagship with 8-pass TTA, **High** runs the
five-model ensemble once, and **X-High** runs the ensemble with 8-pass TTA.
The members are also listed in
[MODEL_ZOO.md](https://github.com/VictorButoi/FleXray/blob/main/MODEL_ZOO.md).
## Test-time augmentation
The reported results use 16 passes per model (`--tta-samples 16` or
`predict(..., tta_samples=16)`). The browser demo uses 8 passes per model in
Normal and X-High modes; its current settings are published in the
[demo manifest](https://flexray.csail.mit.edu/demo/demo_manifest.json).
`tta_samples=N` runs one un-augmented pass plus `N - 1` randomly augmented
passes and averages their sigmoid probabilities, then converts that mean
back to logits. The package and browser implement the released `tta_v3`
chain in this order:
| Transform | Probability | Parameters |
| --- | --- | --- |
| Horizontal flip | 0.5 | Exactly inverted on the prediction before averaging |
| Invert intensities | 0.5 | `1 - image` |
| CLAHE | 0.1 | Clip limit 1.0-2.0; 8 x 8 grid |
| Gamma | 0.25 | Gamma 0.9-1.1; gain 0.9-1.1; mutually exclusive with CLAHE |
| Contrast | 0.25 | Multiply intensities by 0.7-1.3 and clamp to [0, 1] |
| Sharpness | 0.5 | Factor 0.7-1.3 |
| Gaussian noise | 0.25 | Standard deviation 0.01 |
The flip is the only geometric transform; intensity transforms are not
inverted. The CLAHE/gamma branch leaves the image unchanged with probability
0.65. See the
[Python implementation](https://github.com/VictorButoi/FleXray/blob/main/src/fxr/inference/tta.py)
and [browser implementation](https://flexray.csail.mit.edu/demo/tta.js).
Use `predict(..., tta_samples=16, seed=42)` to reproduce the Python
augmentation draws without changing the global torch RNG. With no seed,
draws use the global torch RNG. The browser uses its own random-number
source, so matching augmentation settings do not imply identical random views.
With an ensemble, each view is drawn once and run through every member.
`M` models and `N` passes therefore require `M x N` forward passes: 80 for
the five-model ensemble at N=16, or 40 for the browser's X-High mode at N=8.
`tta_samples<=1` disables augmentation.
## Input contract
`preprocessing.json` is applied automatically by the public loaders:
- grayscale input (RGB is converted), any 8-bit or 16-bit PNG / JPEG / TIFF / BMP
- per-image percentile min-max normalization to `[0, 1]` (0.5th / 99.5th
percentiles, `eps = 1e-8`)
- zero-pad to a square, then resize to 256 x 256
- outputs are `multilabel` sigmoid probabilities; masks use threshold 0.5
Outputs are at the 256 x 256 model resolution; the CLI and Python API do not
resample back to the original image size.
## Output labels
FleXray outputs 60 foreground masks (61 channels including `background`). The
broader dataset/evaluation protocol also recognizes aggregate `lumbar_spine` and
`thoracolumbar_spine` annotations; these are evaluated by combining the relevant
per-vertebra outputs and are not checkpoint channels. Channel order is stored in
each bundle's `label_schema.json`.
- **Skull / shoulder girdle:** skull, scapulae, clavicles
- **Upper limb:** humeri, radii, ulnae, carpals, metacarpals, phalanges
- **Lower limb:** femurs, patellae, tibiae, fibulae, tarsals, metatarsals, toes
- **Thorax:** rib_1 - rib_12, sternum
- **Spine:** vertebra_c1 - c7, t1 - t12, l1 - l5, sacrum
- **Pelvis:** hips
- **Soft tissue:** lungs, heart, liver, spleen, kidneys
Paired structures are merged (for example `femurs` covers both sides);
laterality is not predicted.
## Architecture
`fxr.models.UNet`, 2D, 1 input channel, 61 output channels; filters
`[64, 128, 256, 512, 512, 720, 1024]`, 3 convolutions per block, residual
blocks with instance norm, `align_corners=True` upsampling. The full
architecture is in each bundle's `config.yml`.
## Training data
The models were trained on three source types unified under the FleXray label
protocol. For training mixture proportions, please refer to the paper:
- **Real X-ray masks:** HandBones, FootBones, MURA forearm, and MURA humerus,
with our own annotations.
- **Generated FluXray images:** digitally reconstructed radiographs from the
MOOSE CTs, generatively edited toward real X-ray appearance, with exact
overlapping masks for every protocol structure.
- **Online CT->DRR rendering:** MOOSE / ENHANCE-PET 1.6k, Shoulder-CT, HaN-Seg,
PedsCT, RSNA cervical-spine fracture CTs, and ElbowCT, rendered to DRRs at
random poses during training with per-label attenuation jitter.
Training used AdamW (lr 3e-4, cosine schedule), a Dice + binary cross-entropy
loss routed per dataset (partially labeled sources ignore unlabeled channels),
and separate augmentation presets for CT-derived and X-ray inputs. The exact
recipe is `fxr/configs/training/base.yml` in the code release.
Every dataset's license, redistribution status, and download pointer is
documented in the
[`VictorButoi/flexray-data`](https://huggingface.co/datasets/VictorButoi/flexray-data)
card. That repository ships the real X-ray sources whose licenses permit
redistribution as image/mask pairs with packaging manifests, the MURA masks,
and the FluXray database.
## Evaluation
FleXray was evaluated on eight real-radiograph datasets held out from training
(DarwinCVD19, DeepFluoro, ElbowLat, HipRay, LowerLimbs, RAM-W600, PedsTorso,
and VinDr-Rib), spanning lungs, ribs, peripheral bones, spine, and pelvis.
Against supported generalist baselines (FluoroSAM, TotalSegmentator2D, PAXray),
FleXray performs best or ties on all eight datasets, with significant
improvements on seven and no statistically detectable difference from PAXray
on VinDr-Rib. Per-dataset numbers and confidence intervals are in the paper;
the benchmark figure is on
the [project website](https://flexray.csail.mit.edu/#results).
Evaluation ignores ground-truth labels covering less than 0.1% of the image.
## Intended use and limitations
Research use only. FleXray is **not a medical device** and is not cleared for
clinical diagnosis, treatment planning, or patient-care decisions.
- Targets conventional radiographs; dental and mammographic images are out of
scope.
- Predicts anatomy, not pathology.
- No laterality (left/right) and no uncertainty estimates.
- Performance on acquisition settings, views, or populations far from the
training sources has not been validated.
## Repository layout
- `README.md`: this card.
- `ensemble.json`: the `flagship` subfolder and the `members` list with their
FluXray proportions.
- `members/<name>/model.safetensors`: exported model weights.
- `members/<name>/config.yml`: architecture and protocol config consumed by
`from_pretrained`.
- `members/<name>/label_schema.json`: ordered output labels.
- `members/<name>/preprocessing.json`: public preprocessing contract.
- `members/<name>/checksums.json`: SHA256 checksums of the bundle files.
- `members/<name>/onnx/flexray-<name>-256-fp16.onnx`: fp16 ONNX export
(opset 18, sigmoid baked in) used by the in-browser demo; parity-checked
against the PyTorch weights by `scripts.release.export_web_demo` in the
release tooling.
## Licenses
- Code: MIT
- Weights: CC-BY-NC-4.0
## Citation
```bibtex
@misc{butoi2026flexray,
title={FleXray: Universal Clinical X-ray Segmentation},
author={Victor Ion Butoi and Vivek Gopalakrishnan and John V. Guttag and Adrian V. Dalca and Neel Dey},
year={2026},
eprint={2609.26756},
archivePrefix={arXiv},
primaryClass={cs.CV},
url={https://arxiv.org/abs/2609.26756},
}
```
Please also cite the source datasets listed in the
[`flexray-data`](https://huggingface.co/datasets/VictorButoi/flexray-data) card
for any dataset you use.