YAML Metadata Warning: empty or missing yaml metadata in repo card (https://huggingface.co/docs/hub/model-cards#model-card-metadata)

CardioSyntax v2: SYNTAX Score Prediction from Coronary Angiography

This repository contains code and pre-trained models for automated SYNTAX score prediction from coronary angiography videos. The SYNTAX score is a validated metric for quantifying the anatomical complexity of coronary artery disease.

Overview

CardioSyntax v2 is a large-scale dataset of 11,410 angiography studies with SYNTAX scores, designed for developing machine learning models for automated coronary lesion complexity assessment. This repository provides:

  • Dataset: 11,209 training studies (Philips Allura Clarity + Azurion 7) + 120 test studies (100 Philips + 20 Siemens) annotated by 6 independent interventional cardiologists
  • Baseline Models:
    • Backbone network (R3D-18): single projection β†’ SYNTAX contribution
    • RNN head (LSTM/GRU/Transformer): multi-view aggregation β†’ final SYNTAX score
  • Pre-trained Weights: 5-fold ensemble with post-calibration
  • Evaluation: Pearson correlation r β‰ˆ 0.81, balanced accuracy β‰ˆ 82% for SYNTAX > 22 classification

The dataset addresses inter-observer variability through multi-expert annotation and enables systematic investigation of domain shift effects across imaging systems.

Repository Structure

coronary-syntax-prediction/
β”œβ”€β”€ backbone/                          # Single-frame backbone (3D ResNet)
β”‚   β”œβ”€β”€ dataset.py                    # SyntaxDataset for single-view training
β”‚   β”œβ”€β”€ pl_model.py                   # SyntaxLightningModule (Lightning wrapper)
β”‚   β”œβ”€β”€ pl_train.py                   # Training script for backbone
β”‚   └── __init__.py
β”œβ”€β”€ full_model/                        # Multi-view RNN head + backbone
β”‚   β”œβ”€β”€ rnn_dataset.py                # SyntaxDataset for multi-view (RNN) training
β”‚   β”œβ”€β”€ rnn_model.py                  # SyntaxLightningModule with RNN variants
β”‚   β”œβ”€β”€ rnn_train.py                  # Training script for full model
β”‚   └── __init__.py
β”œβ”€β”€ inference/                         # Inference & evaluation
β”‚   β”œβ”€β”€ rnn_apply.py                  # Ensemble inference script
β”‚   β”œβ”€β”€ metrics_visualization.py       # Plotly-based metrics & visualization
β”‚   └── __init__.py
β”œβ”€β”€ backbone_weights/                 # Backbone .pt checkpoints (5 folds Γ— 2 arteries)
β”œβ”€β”€ full_model_weights/               # Full model .pt checkpoints (5 folds Γ— 2 arteries Γ— variants)
β”œβ”€β”€ scaling_coeffs/                   # Calibration coefficients (a, b) per fold
β”œβ”€β”€ requirements.txt
└── README.md

Installation

# Clone the repository
git clone https://huggingface.co/MesserMMP/coronary-syntax-prediction
cd coronary-syntax-prediction

# Install dependencies
pip install -r requirements.txt

Requirements

Key packages:

  • PyTorch 2.0+ with CUDA support
  • Lightning 2.x
  • torchvision, pytorchvideo
  • numpy, scikit-learn, pandas
  • plotly for visualization
  • click for CLI

See requirements.txt for full list.

Training

Stage 1: Backbone Training (Single-View)

Train 3D ResNet-18 on single angiographic projections (left/right coronary artery separately):

python backbone/pl_train.py \
  -r /path/to/dataset_root \
  --fold 0 \
  -a right \
  --num-classes 2 \
  -b 50 \
  -f 32 \
  -v 256 256 \
  --max-epochs 10 \
  --num-workers 8 \
  --devices 0 \
  --precision bf16-mixed \
  --logdir ./logs/backbone \
  --use-weighted-sampler

Parameters:

  • -r, --dataset-root: Path to dataset root (default: .)
  • --fold: Fold number (0-4, default: 4)
  • -a, --artery: left or right (default: right)
  • -nc, --num-classes: Output units: 2 for (classification, regression) (default: 2)
  • -b, --batch-size: Batch size (default: 50)
  • -f, --frames-per-clip: Frames per clip (default: 32)
  • -v, --video-size: Frame resolution H W (default: 256 256)
  • --max-epochs: Epochs for full training (default: 10)
  • --num-workers: DataLoader workers (default: 8)
  • --devices: GPU device IDs (default: )
  • --precision: Training precision mode (default: bf16-mixed)
  • --logdir: Log directory (default: ./logs/backbone)
  • --use-weighted-sampler: Balance classes by score intervals (flag)
  • --seed: Random seed (default: 42)

Output: TensorBoard logs + .ckpt checkpoints in --logdir

Stage 2: RNN Head Training (Multi-View)

Train LSTM/GRU/Transformer aggregation head on multi-view studies:

python full_model/rnn_train.py \
  -r /path/to/dataset_root \
  --fold 0 \
  -a right \
  --variant lstm_mean \
  --num-classes 2 \
  -b 8 \
  -f 32 \
  -v 256 256 \
  --max-epochs 15 \
  --num-workers 16 \
  --devices 0 \
  --precision bf16-mixed \
  --logdir ./logs/rnn \
  --backbone-pt-dir backbone_weights \
  --backbone-from-pt \
  --rnn-folds-dir rnn_folds

Key Parameters:

  • --variant: Head architecture:
    • mean_out: Mean of projection scores (no RNN)
    • mean: MLP on mean pooled backbone features
    • lstm_mean: LSTM with mean pooling of hidden states
    • lstm_last: LSTM, use last hidden state
    • gru_mean, gru_last: GRU variants
    • bert_mean, bert_cls, bert_cls2: Transformer encoder variants
    • (default: lstm_mean)
  • --backbone-pt-dir: Path to .pt backbone weights (default: backbone_weights)
  • --backbone-from-pt: Load backbone from .pt files (flag, default: True)
  • --backbone-logdir: Alternative: load backbone from Lightning logs
  • --rnn-folds-dir: Directory with rnn_fold{fold}_train.json, rnn_fold{fold}_eval.json (default: rnn_folds)
  • --use-weighted-sampler: Balance by score (flag)
  • --pt-weights-format: If loading pre-trained head, expect .pt instead of .ckpt (flag)

Output: Full model checkpoints in --logdir/{artery}BinSyntax_R3D_fold{fold:02d}_{variant}_post/...

Inference

Run ensemble inference on test datasets:

python inference/rnn_apply.py \
  -d "test_philips_100.json" "test_siemens_20.json" \
  -n "Philips Test" "Siemens Test" \
  -p "philips_100" "siemens_20" \
  -r /path/to/dataset_root \
  --model-dir full_model_weights \
  -v 256 256 \
  --frames-per-clip 32 \
  --num-workers 8 \
  --variant lstm_mean \
  --pt-weights-format \
  --use-scaling \
  --scaling-file scaling_coeffs.json \
  -e "Ensemble_lstm_mean" \
  -m metrics.json

Parameters:

  • -d, --dataset-paths: Multiple JSON test dataset paths (relative to --dataset-root)
  • -n, --dataset-names: Display names for each dataset (must match -d count)
  • -p, --postfixes: Suffixes for result files (must match -d count)
  • -r, --dataset-root: Dataset root (default: .)
  • --model-dir: Directory with full model .pt weights (default: full_model_weights)
  • -v, --video-size: Frame resolution H W (default: 256 256)
  • --frames-per-clip: Frames per clip (default: 32)
  • --num-workers: DataLoader workers (default: 8)
  • --variant: Head model variant (default: lstm_mean)
  • --pt-weights-format: Model weights are .pt raw state_dict (flag, default: True)
  • --use-scaling: Apply post-calibration scaling a*x+b from JSON (flag)
  • --scaling-file: Calibration coefficients file relative to --dataset-root
  • -e, --ensemble-name: Experiment name for metrics (e.g., "Ensemble_lstm_mean")
  • -m, --metrics-file: JSON output file path for all metrics
  • --seed: Random seed (default: 42)

Output:

  • Per-dataset predictions: results/{postfix}.json
  • Ensemble metrics: {metrics_file} with Pearson correlation, balanced accuracy, per-fold statistics
  • Plotly HTML plots: visualizations/{postfix}.html

Dataset

Link: https://huggingface.co/datasets/MesserMMP/coronary-angiography-syntax

Data Format

The dataset provides two different JSON annotation formats depending on the training stage:

Format 1: Backbone Training (Single-View/Per-Video)

Used for training the backbone model (backbone/ scripts). Each record represents one angiographic video projection.

File structure: folds/fold{fold_id}_{split}.json

[
  {
    "study_uid": "1.3.46.670589.28.26690171363123020190823114413193175",
    "series_uid": "1.3.46.670589.28.26690171363123020190823115102913895.2.2",
    "sop_uid": "1.3.46.670589.28.266901713631230201908231158145991852211512",
    "path": "../anon_data/chunk1/.../IM-2254-0039.dcm",
    "shape": [38, 512, 512],
    "artery": 0,
    "artery_prob": 1.9078343029832467e-05,
    "syntax": 0.0,
    "syntax_left": 0.0,
    "syntax_right": 0.0,
    "bin_syntax": 0,
    "manufacturer": "Philips",
    "device_model": "Allura Clarity"
  },
  {
    "study_uid": "1.3.46.670589.28.26690171363123020190823114413193175",
    "series_uid": "1.3.46.670589.28.26690171363123020190823115648342907.2.2",
    "sop_uid": "1.3.46.670589.28.266901713631230201908231158148282212211512",
    "path": "../anon_data/chunk1/.../IM-2260-0022.dcm",
    "shape": [15, 512, 512],
    "artery": 1,
    "artery_prob": 0.9559882879257202,
    "syntax": 0.0,
    "syntax_left": 0.0,
    "syntax_right": 0.0,
    "bin_syntax": 0,
    "manufacturer": "Philips",
    "device_model": "Allura Clarity"
  }
]

Field descriptions:

Field Type Description
study_uid str Unique study identifier (DICOM)
series_uid str Unique series identifier (DICOM)
sop_uid str Unique SOP instance UID (DICOM)
path str Relative path to DICOM video file
shape list[int] Video dimensions: [T, H, W] (frames, height, width)
artery int Coronary artery: 0 = left (LCA), 1 = right (RCA)
artery_prob float Model confidence for artery classification (0–1)
syntax float Total SYNTAX score (LCA + RCA)
syntax_left float SYNTAX score for left coronary artery
syntax_right float SYNTAX score for right coronary artery
bin_syntax int Binary classification: 0 = SYNTAX < threshold, 1 = SYNTAX β‰₯ threshold
manufacturer str Imaging equipment manufacturer (e.g., "Philips", "Siemens")
device_model str Equipment model (e.g., "Allura Clarity", "AXIOM-Artis")

Format 2: RNN Head Training (Multi-View/Per-Patient)

Used for training the full RNN model (full_model/ scripts). Each record represents one patient study with all angiographic projections grouped by artery.

File structure: rnn_folds/rnn_fold{fold_id}_{split}.json

[
  {
    "study_uid": "1.3.46.670589.28.26690171363123020190823114413193175",
    "manufacturer": "Philips",
    "device_model": "Allura Clarity",
    "syntax": 0.0,
    "syntax_left": 0.0,
    "syntax_right": 0.0,
    "bin_syntax": 0,
    "videos": [
      {
        "series_uid": "1.3.46.670589.28.26690171363123020190823115102913895.2.2",
        "sop_uid": "1.3.46.670589.28.266901713631230201908231158145991852211512",
        "path": "../anon_data/chunk1/.../IM-2254-0039.dcm",
        "shape": [38, 512, 512],
        "artery": 0,
        "artery_prob": 1.9078343029832467e-05
      },
      {
        "series_uid": "1.3.46.670589.28.26690171363123020190823115648342907.2.2",
        "sop_uid": "1.3.46.670589.28.266901713631230201908231158148282212211512",
        "path": "../anon_data/chunk1/.../IM-2260-0022.dcm",
        "shape": [15, 512, 512],
        "artery": 1,
        "artery_prob": 0.9559882879257202
      }
    ],
    "videos_left": [
      {
        "series_uid": "1.3.46.670589.28.26690171363123020190823115102913895.2.2",
        "sop_uid": "1.3.46.670589.28.266901713631230201908231158145991852211512",
        "path": "../anon_data/chunk1/.../IM-2254-0039.dcm",
        "shape": [38, 512, 512],
        "artery": 0,
        "artery_prob": 1.9078343029832467e-05
      },
      {
        "series_uid": "1.3.46.670589.28.26690171363123020190823115533239902.2.2",
        "sop_uid": "1.3.46.670589.28.266901713631230201908231158147562092211512",
        "path": "../anon_data/chunk1/.../IM-2258-0055.dcm",
        "shape": [50, 512, 512],
        "artery": 0,
        "artery_prob": 0.0003698925720527768
      },
      {
        "series_uid": "1.3.46.670589.28.26690171363123020190823115052517893.2.2",
        "sop_uid": "1.3.46.670589.28.266901713631230201908231158145581792211512",
        "path": "../anon_data/chunk1/.../IM-2253-0047.dcm",
        "shape": [47, 512, 512],
        "artery": 0,
        "artery_prob": 0.00018035581160802394
      },
      {
        "series_uid": "1.3.46.670589.28.26690171363123020190823115550658904.2.2",
        "sop_uid": "1.3.46.670589.28.266901713631230201908231158147942152211512",
        "path": "../anon_data/chunk1/.../IM-2259-0047.dcm",
        "shape": [41, 512, 512],
        "artery": 0,
        "artery_prob": 0.00022948876721784472
      },
      {
        "series_uid": "1.3.46.670589.28.26690171363123020190823115523054900.2.2",
        "sop_uid": "1.3.46.670589.28.266901713631230201908231158147162032211512",
        "path": "../anon_data/chunk1/.../IM-2257-0047.dcm",
        "shape": [43, 512, 512],
        "artery": 0,
        "artery_prob": 0.00034276593942195177
      }
    ],
    "videos_right": [
      {
        "series_uid": "1.3.46.670589.28.26690171363123020190823115648342907.2.2",
        "sop_uid": "1.3.46.670589.28.266901713631230201908231158148282212211512",
        "path": "../anon_data/chunk1/.../IM-2260-0022.dcm",
        "shape": [15, 512, 512],
        "artery": 1,
        "artery_prob": 0.9559882879257202
      },
      {
        "series_uid": "1.3.46.670589.28.26690171363123020190823115657547909.2.2",
        "sop_uid": "1.3.46.670589.28.266901713631230201908231158149262272211512",
        "path": "../anon_data/chunk1/.../IM-2261-0070.dcm",
        "shape": [62, 512, 512],
        "artery": 1,
        "artery_prob": 0.9999938011169434
      },
      {
        "series_uid": "1.3.46.670589.28.26690171363123020190823115712699912.2.2",
        "sop_uid": "1.3.46.670589.28.266901713631230201908231158149652332211512",
        "path": "../anon_data/chunk1/.../IM-2262-0063.dcm",
        "shape": [54, 512, 512],
        "artery": 1,
        "artery_prob": 0.999855637550354
      }
    ],
    "videos_other": [
      {
        "series_uid": "1.3.46.670589.28.26690171363123020190823115128658897.2.2",
        "sop_uid": "1.3.46.670589.28.266901713631230201908231158146391912211512",
        "path": "../anon_data/chunk1/.../IM-2255-0035.dcm",
        "shape": [33, 512, 512],
        "artery": 0,
        "artery_prob": 0.2866898477077484
      },
      {
        "series_uid": "1.3.46.670589.28.26690171363123020190823115132067898.2.2",
        "sop_uid": "1.3.46.670589.28.266901713631230201908231158146771972211512",
        "path": "../anon_data/chunk1/.../IM-2256-0035.dcm",
        "shape": [32, 512, 512],
        "artery": 0,
        "artery_prob": 0.3251875042915344
      }
    ]
  }
]

Field descriptions:

Field Type Description
study_uid str Unique study identifier (same across all videos for this patient)
manufacturer str Imaging equipment manufacturer
device_model str Equipment model
syntax float Total SYNTAX score (LCA + RCA)
syntax_left float SYNTAX score for left coronary artery
syntax_right float SYNTAX score for right coronary artery
bin_syntax int Binary classification label
videos list[object] All video projections (unfiltered)
videos_left list[object] Projections classified as left coronary (artery=0, high confidence)
videos_right list[object] Projections classified as right coronary (artery=1, high confidence)
videos_other list[object] Low-confidence projections (excluded from training); typically ~5–7% of total

Video object fields:

Field Type Description
series_uid str Unique series identifier (DICOM)
sop_uid str Unique SOP instance UID (DICOM)
path str Relative path to DICOM video file
shape list[int] Video dimensions: [T, H, W]
artery int Artery classification: 0 = left, 1 = right
artery_prob float Model confidence (0–1); threshold typically 0.5 for videos_left/videos_right inclusion

Test Set Format (Multi-Expert Annotations)

Test data (test_philips_100.json, test_siemens_20.json) follows Format 2 with additional expert annotations:

[
  {
    "study_uid": "...",
    "manufacturer": "Philips",
    "device_model": "Allura Clarity",
    "syntax": 18.5,
    "syntax_left": 10.0,
    "syntax_right": 8.5,
    "mean_syntax": 18.5,
    "expert0": 18,
    "expert1": 19,
    "expert2": 17,
    "expert3": 19,
    "expert4": 20,
    "expert5": 18,
    "videos_left": [...],
    "videos_right": [...],
    "videos_other": [...]
  }
]

Additional fields for test data:

Field Type Description
mean_syntax float Consensus SYNTAX score (mean of 6 experts)
expert0–expert5 float Individual expert SYNTAX score (6 independent cardiologists)

Note: expert0 typically represents aggregated/consensus annotations, while expert1–expert5 are individual readers.


DICOM Video Format

Each DICOM file contains:

  • Dimensions: [T, H, W] = [frames, 512, 512] at 15 fps
  • Data type: uint8 (8-bit grayscale)
  • Frame count: Typically 15–60 frames per projection
  • Resolution: 512Γ—512 pixels (standard for X-ray angiography)

Data Splits

Set Files Size Equipment Artery Classification
Backbone training folds/fold{0-4}_train.json ~8,000 videos Philips Single video
Backbone validation folds/fold{0-4}_eval.json ~1,000 videos Philips Single video
RNN training rnn_folds/rnn_fold{0-4}_train.json ~2,200 studies Philips Multi-view (patient)
RNN validation rnn_folds/rnn_fold{0-4}_eval.json ~290 studies Philips Multi-view (patient)
Test 1 (Philips) test_philips_100.json 100 studies Philips Allura Clarity 6 experts
Test 2 (Siemens) test_siemens_20.json 20 studies Siemens AXIOM-Artis 6 experts

SYNTAX > 0 prevalence: 39.26% in training data

Results

Baseline Model Performance (5-Fold Ensemble)

Metric Test Set (Philips) Test Set (Siemens) Description
Pearson r 0.814 0.482 Raw predictions
Balanced Accuracy 0.687 0.566 Pre-calibration, SYNTAX > 22
Post-Calibration
Pearson r 0.816 0.482 After scaling
Balanced Accuracy 0.825 0.643 After scaling, SYNTAX > 22

Key findings:

  • Strong performance on in-distribution (Philips) test data
  • Domain shift effect on out-of-distribution (Siemens) data
  • Calibration effective for Philips, limited benefit for Siemens
  • Inter-observer variability constrains upper bound on accuracy

Model Architecture

  • Backbone: R3D-18 (video ResNet) pre-trained on Kinetics-400
  • Head (default): LSTM with mean-pooling aggregation + linear regressor
  • Output: 2 channels (classification logit + log-transformed regression)
  • Loss: Weighted BCE (classification) + scaled MSE (regression)

Weights & Checkpoints

Pre-trained weights available in repository:

  • backbone_weights/: .pt files for 5 folds Γ— 2 arteries
    • Example: RightBinSyntax_R3D_full_fold00.pt
  • full_model_weights/: .pt files for ensemble variants
    • Example: RightBinSyntax_R3D_fold00_lstm_mean_post_best.pt
  • scaling_coeffs/: Calibration parameters (a, b) per fold

Citation

If you use this dataset or code, please cite:

@dataset{cardiosyntax_v2_2025,
  title={CardioSyntax v2: Angiographic dataset for SYNTAX score estimation},
  author={MesserMMP and collaborators},
  year={2025},
  url={https://huggingface.co/datasets/MesserMMP/coronary-angiography-syntax}
}

Related Work

  • SYNTAX Score Definition: Sianos et al., EuroIntervention (2005)
  • Original CardioSyntax: Ponomarchuk et al., arXiv:2407.19894 (2024)
  • Video Understanding: Hara et al., CVPR (2018) β€” R3D architecture

License

CC0 1.0 (Public Domain)

Contact & Support

For issues, questions, or contributions, please refer to the HuggingFace repository discussions.


Last updated: January 2026

Downloads last month

-

Downloads are not tracked for this model. How to track
Inference Providers NEW
This model isn't deployed by any Inference Provider. πŸ™‹ Ask for provider support

Paper for MesserMMP/coronary-syntax-prediction