--- license: cc-by-nc-4.0 tags: [electrocardiogram, ecg, cardiovascular-risk, foundation-model, self-supervised, deepecg-ssl] library_name: pytorch pipeline_tag: tabular-classification --- # 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 needs `fairseq-signals` and 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. ```python 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: ```bash 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.