DeepECG-SSL-CLSA-CVD
Fine-tuned DeepECG-SSL (self-supervised 12-lead ECG transformer; Nolin-Lapalme et al., Eur Heart J 2026, doi:10.1093/eurheartj/ehaf1119) to predict incident cardiovascular disease over a median 5.8 years in the Canadian Longitudinal Study on Aging (CLSA). The model accompanies the manuscript "A Lab-Free ECG Foundation Model Versus Guideline Risk Scores for Incident Cardiovascular Disease: Development in CLSA and External Validation at the Montreal Heart Institute".
What is in this repository
weights/deepecg_ssl_clsa_cvd_fold{0-4}.safetensors: the five cross-validation fold models (full fine-tuning; ECG only).model_params.json:- per-fold Platt calibration parameters;
- the Model A+ logistic equation (DeepECG-SSL score + age + sex + hypertension; no blood test).
inference.py: a loader and prediction functions. It needsfairseq-signalsand the matching DeepECG-SSL v2 (amplitude-preserved) encoder checkpoint for the architecture.
Input
- 12-lead resting ECG, 10 s, resampled to 250 Hz: an array of shape (12, 2500).
- Units are millivolts, with no per-lead normalisation.
- Standard lead order: I, II, III, aVR, aVL, aVF, V1โV6.
Performance (from the manuscript)
CLSA held-out test set (n = 3,906; 394 events). The guideline scores need a blood test; Model A+ does not.
| Model | AUROC |
|---|---|
| Model A+ | 0.733 (95% CI 0.707โ0.759) |
| PREVENT | 0.715 |
| PCE | 0.709 |
| SCORE2/OP | 0.708 |
| FRS | 0.689 |
- Where the gain comes from: it is driven by the non-specific self-reported "heart disease" outcome item.
- Endpoints the gain does not cover: for hard atherosclerotic endpoints, PREVENT and SCORE2 are as good or better.
External validation at the Montreal Heart Institute (n = 21,647; 6-year hard MACE; DeepECG-SSL + age + sex with CLSA coefficients):
| Model | AUROC |
|---|---|
| DeepECG-SSL + age + sex | 0.761 |
| Age + sex | 0.728 |
- By component: the gain is in heart failure and stroke, not in myocardial infarction.
- Calibration: absolute risks need local recalibration before use.
Intended use and limitations
- Research use only. This is not a medical device and has not been prospectively validated.
- Training data: CLSA, a mostly White community cohort aged 45โ85, with GE CardioSoft ECGs.
- Other populations and devices: performance may differ.
- No CLSA participant data are included in this repository.
Citation
Please cite the manuscript (citation to be added on publication) and DeepECG-SSL (Nolin-Lapalme A, et al. Eur Heart J 2026;47:2174โ2186).
Strict inference package
The clsa_cvd package adds strict five-fold checkpoint loading, explicit raw-source
mV conversion, full-precision logistic coefficients and the external age/sex variant.
It uses the same five fold weights already staged in this repository. The existing
root inference.py API remains present for compatibility; use this package for the
external variant and strict input/checkpoint validation.
from clsa_cvd.model import CLSACVDModel
model = CLSACVDModel(
weights_dir="weights",
base_checkpoint="/approved/models/deepecg-ssl-v2-wcr-amp-preserved-encoder.pt",
params_path="clsa_cvd/model_params.json",
device="cuda:0",
precision="float32",
)
# ecg_mv: finite float32 (N, 12, 2500), 10 seconds at 250 Hz in mV.
# age/female/hypertension: one numeric value per ECG; female/HTN are binary.
pred = model.predict(ecg_mv, age, female, hypertension, batch_size=32)
# p_ecg, risk_Aplus, ecg_logit_uncal, risk_ecg_age_sex
Lead order: I, II, III, aVR, aVL, aVF, V1โV6. For raw NPY inputs use
clsa_cvd.preprocessing.prepare_waveform or load_waveform with an explicit
format: clsa = 500-Hz CardioSoft ADC ร0.005 then polyphase resampling;
muse = 250-Hz MUSE ADC ร0.00488; mv250 = already in mV at 250 Hz.
No spectral-power normalization or per-lead z-scoring is applied.
risk_ecg_age_sex uses the logit of the mean uncalibrated fold probabilities.
It is the transported MHI variant, not A+ with hypertension set to zero, and its
absolute risks require local recalibration. A+ uses the mean of Platt-calibrated
fold probabilities with age, female and physician-diagnosed hypertension.
The new package defaults to IEEE float32 with TF32 disabled. Historical test
predictions used CUDA bfloat16, batch 128. Select precision="bfloat16" and
batch size 128 to reproduce that arithmetic. On all 3,906 CLSA test participants,
historical-mode predictions matched the archive within 9e-8. Float32 is stable
under the tested single/batch ordering but differs from the historical ECG
probabilities by up to 0.001780 and A+ by 0.000998. Full-precision equation
coefficients reproduce archived A+ outputs within 2.3e-16 when supplied stored
ECG probabilities. Do not assume bit-identical results across precision modes.
Validated Python environment: PyTorch NVIDIA 26.08, CUDA 13.4, Python 3.12;
fairseq-signals Jwoo5/fairseq-signals commit
f8f0ff1c788a82c2059cb452cd5462898867489e. requirements-clsa.txt records
the observed direct dependency versions. The matching encoder checkpoint is still
required to define the architecture; its SHA-256 and fold artifact hashes are in
clsa_cvd/artifacts.json. Container build/run has not yet been verified.
synthetic_validation.json describes non-participant sinusoidal fixtures and
expected outputs. No participant-level data are included in this update.
Pretraining overlap and subgroup reporting
No patient crosswalk between the encoder pretraining sources and the MHI validation cohort is available. Patient-level pretraining/validation overlap has therefore not been independently verified. This repository does not claim a reproduced zero-overlap audit.
Exploratory racial/cultural subgroup reporting is limited by small event counts and disclosure restrictions; suppressed results do not establish fairness in those groups. Disclosure and fairness review were confirmed complete by the project owner on 23 October 2026.
Environment setup
The reference environment uses the NVIDIA PyTorch 26.08 container. In that environment, install the direct dependencies and use the pinned fairseq source:
python -m pip install -r requirements-clsa.txt
git clone https://github.com/Jwoo5/fairseq-signals.git
git -C fairseq-signals checkout f8f0ff1c788a82c2059cb452cd5462898867489e
export PYTHONPATH="$PWD/fairseq-signals${PYTHONPATH:+:$PYTHONPATH}"
Download this repository (including weights/) using the Hugging Face client.
Supply the matching encoder checkpoint separately; its public download location
has not been verified. Verify its SHA-256 against clsa_cvd/artifacts.json.
The fine-tuned fold weights are included here; the separate base encoder is not.