DeepECG-Bench

The deep learning architectures in DeepECG-Kit, trained and tested on PhysioNet ECG tasks through one interface. Open any row for the model's design, parameter counts, per-run results and diagnostic plots.

Installation

Install DeepECG-Kit from PyPI, or from source to work on it. Requires Python 3.10 or newer.

Quick install

# Using pip
pip install deepecgkit

# Using uv (recommended)
uv pip install deepecgkit

From source (development)

git clone https://github.com/stevenah/deepecg-kit.git
cd deepecg-kit
uv sync --group dev
# or, without uv: pip install -e ".[dev]"

Quick Start

Train any architecture on any dataset, predict on a raw recording, and explain the predictions, in a few lines of Python. Datasets download from PhysioNet on first use into ~/.deepecgkit/datasets; the command line does the same with deepecg train, predict and explain.

Train and test a model

from deepecgkit import ECGDataModule, ECGTrainer, build_model

ECGTrainer.seed_everything(42)

# PhysioNet 2017 (about 100 MB) as 10 s single-lead segments, resampled from
# 300 Hz to the 500 Hz the benchmark uses. The 70/20/10 split is by recording
# and stratified by class, so no recording has segments in both train and test.
data = ECGDataModule("af-classification", sampling_rate=500, download=True)

# Any name from `deepecg list-models` can replace "kanres".
model = build_model("kanres", data.input_channels, data.num_classes)

# Training ends by restoring the epoch with the lowest validation loss.
trainer = ECGTrainer(model)
trainer.fit(data, epochs=50, checkpoint_dir="runs/kanres-af")
print(trainer.test(data))  # {"test_loss": 0.806, "test_acc": 0.655}

The figures in this Quick Start come from the benchmark's KanRes run with this setup (seed 42, best epoch 50 of 50), which also scores macro F1 0.453, MCC 0.317 and AUROC 0.795 on the same test split. A new run differs slightly with hardware and library version.

The trainer reads the task from the data: multi-label datasets such as PTB-XL train with a sigmoid per class, with no setting to change. For a training loop of your own, data.train_dataloader() yields batches of signals shaped (32, 1, 5000) with their labels.

Predict on a raw recording

from deepecgkit import predict

# The checkpoint records its architecture, class names and preprocessing, so a
# recording at another rate and length is resampled, cut and normalised to match.
result = predict("ecg.npy", checkpoint="runs/kanres-af", sampling_rate=250)
print(result.label, result.confidence)
print(result.probabilities)  # every class, averaged over the recording's segments

A run directory stands for its best checkpoint wherever a checkpoint is expected. To predict many recordings, load the model once with ECGPredictor.from_checkpoint("runs/kanres-af") and call its predict method for each.

Explain the predictions

from deepecgkit import explain

# Saliency for every test segment, averaged over R-peak-aligned beats. The
# checkpoint does not record the rate the beat windows assume, so state it.
result = explain(data, checkpoint="runs/kanres-af", sampling_rate=500)

# Share of the average beat's attribution in each region
result.pqrst_fractions   # P 0.315, QRS 0.082, T 0.343, baseline 0.260
# Each share over the region's share of the beat, so 1 is chance
result.pqrst_enrichment  # P 1.26, QRS 0.66, T 0.92, baseline 1.04

On multi-lead data such as PTB-XL, result.lead_importance also gives each lead's share of the attribution.


Benchmark Results

The table is drawn in the browser and needs JavaScript. The numbers behind it are in results.json, registry.json and catalogue.json.