fela-ecg / README.md
itstheraj's picture
initial commit
3e56604
|
Raw
History Blame Contribute Delete
12.7 kB
---
license: other
license_name: lowdown-labs-lovely-license-1.0
license_link: LICENSE
tags:
- fela
- fourier-neural-operator
- fno
- cpu
- on-device
- ecg
- biosignal
- healthcare
- time-series
library_name: transformers
model-index:
- name: fela-ecg
results:
- task:
type: time-series-classification
name: ECG diagnostic classification
dataset:
type: ptb-xl
name: PTB-XL superdiagnostic
metrics:
- type: auroc
value: 0.9248
name: macro AUROC
---
# DISCLAIMER
This model is a research preview. The license for the dataset may prohibit commercial use. Please
respect this. Lowdown Labs has put together this model in the interest of advancing public science.
# FELA-ECG: On device 12 lead ECG classifier
FELA-ECG reads a 10 second 12 lead electrocardiogram and returns the probability of five
diagnostic groups: normal, myocardial infarction (which could be a heart attack, past or acute), ST/T wave
change, conduction disturbance, and hypertrophy (which is a thickened heart muscle). It is a small
model that runs on a plain CPU with no GPU, so it can sit inside a wearable patch, a Holter
recorder, a bedside monitor, or in an on premises hospital tool and score ECGs without sending
the recording to the cloud with respect for low computing power. Ideally, this model could be used
to help improve consumer electronics to monitor user health and safety. This does not provide medical
diagnoses.
# What goes in, what comes out
- Input: one 10 second 12 lead ECG sampled at 100 Hz, shape `(1, 1000, 12)` (1000 time
samples, 12 leads), in the standard lead order I, II, III, aVR, aVL, aVF, V1 - V6, in
millivolts. Each lead is z scored (centered and scaled) with the training set statistics
that ship in `config.json`. The `preprocess` helper in `modeling.py` can help do this for you.
- Output: five independent probabilities, one per diagnostic superclass (NORM, MI, STTC, CD,
HYP). The head uses a sigmoid, so this is multi label: one ECG can carry more than one
finding, and the five numbers do not sum to one. A clinician sets the alert threshold per
class to trade sensitivity against specificity for the use.
- In plain terms: "this 10 second strip looks like an inferior myocardial infarction with
a conduction problem" comes out as high MI and CD probabilities.
# Why we built it this way
The main sequence mixer is a Fourier Neural Operator, a filter the model learns and applies in
the frequency domain. An ECG is a periodic signal, which is exactly what a Fourier operator is
good at reading, so the architecture fits the data.
There is a second branch that reads the
short time Fourier transform (the spectrogram) directly, and learned attention pooling
summarizes both branches into the five class decision. The model has no long range all pair
attention, so its working memory is small and fixed no matter how long the monitor has been
running.
That is what lets it run continuously on a low power CPU next to the patient, with no
cloud connection and the recording never leaving the device.
The shipped model is a single ~15.2M parameter student, distilled from a three member ensemble
(different seeds, mixer patterns, and patch sizes), then quantized to int8 for deployment.
# Performance
Speed and footprint, measured on CPU (AMD EPYC 9555, batch size 1, median of 20 runs).
| Format | Size on disk | Peak working RAM |
|---|---|---|
| fp32 | 60.64 MB | 0.03 MB |
| bf16 | 30.32 MB | 0.03 MB |
| int8 | 16.47 MB | 0.03 MB |
The model classifies a full 10 second 12 lead ECG in 17.0 ms on one CPU core and 10.3 ms on
four cores (fp32 profile), and its working RAM is 0.03 MB, which is why the whole thing could fit in a
small single board computer. Throughput on one core is 58.71 windows per second. int8 dynamic
quantization brings the model to 16.47 MB on disk (the shipped size is 16.5 MB) and holds
accuracy (see below).
Latency and size were measured on an x86 server CPU (AMD EPYC 9555).
Continuous stream numbers (real time factor and RAM drift over a multi hour stream) are not in
the standardized profile yet and are marked pending final evaluation. A separate stream
benchmark (8 threads, int8) reported flat RAM (drift about +0.0 MB over two hours of streamed
ECG) and a high real time factor; those are from the stream test, not the standardized
single window profile, so they are not quoted as a headline figure here.
What the standardized
profile does show is a 0.03 MB working set and a 17.0 ms single window latency, and the
architecture carries no KV cache and keeps O(1) state per window.
# Accuracy
Protocol: PTB-XL v1.0.3, 100 Hz, the official recommended split (folds 1 - 8 train, fold 9
validation, fold 10 test, n=2158), diagnostic superclass setting (5 classes), metric is
macro AUROC (the unweighted mean of the per class area under the ROC curve). The checkpoint is
selected on the validation fold only; the test fold is scored once. This is the same protocol
as the PTB-XL benchmark paper, so the numbers are directly comparable.
| Benchmark | Metric | This model (fp32) | This model (int8) | Baseline (named) | Source |
|---|---|---|---|---|---|
| PTB-XL superdiagnostic (5-class) | macro AUROC | 0.9248 | 0.9243 | xresnet1d101 (published) 0.925 | AUDIT_ecg.json |
The shipped int8 student reaches 0.9243 macro AUROC, within 0.001 of the xresnet1d101 CNN
specialist at 0.925 on the same protocol, and the fp32 student is 0.9248. In other words, the
v3 model essentially matches the strong published CNN baseline, at 15.2M parameters and CPU
real time speed. int8 dynamic quantization on the linear layers is close to lossless: 0.9243
versus 0.9248 fp32, a change of -0.0005.
## Per Class test AUROC
| Format | NORM | MI | STTC | CD | HYP |
|---|---|---|---|---|---|
| fp32 | 0.946 | 0.928 | 0.936 | 0.926 | 0.888 |
| int8 (shipped) | 0.946 | 0.927 | 0.936 | 0.925 | 0.887 |
NORM (normal) is the easiest class and HYP (hypertrophy) is the hardest, which matches the
pattern in the published PTB-XL benchmarks. The distilled student slightly exceeds the source
ensemble, because during distillation it also sees the hard labels and fresh augmentation.
# How to run it
See `quickstart/` for a runnable example. The short version:
```python
import torch
from modeling import load_model, preprocess
m = load_model("model.safetensors")
# raw: a (1000, 12) or (12, 1000) array, 10 s of 12 lead ECG at 100 Hz, in millivolts
x = preprocess(raw, m.cfg)
probs = m.predict(x)
```
The loader detects the int8 checkpoint and applies dynamic quantization before loading. For an
interactive playground, see the Hugging Face Space in `space/`.
## Loading with standard tooling
The repo ships `config.json` (the architecture hyperparameters and the per lead normalization
statistics) and a self-contained `modeling.py` with a `load_model` / `from_pretrained` entry
point. A few lines load the model from a Hugging Face repo, a local directory, or a checkpoint:
```python
from huggingface_hub import hf_hub_download
from modeling import load_model
m = load_model("/path/to/weights_dir") # OR
m = load_model("lowdown-labs/fela-ecg")
```
The fp32 weights are shipped as `model.safetensors`.
## Serving artifacts
- `model.safetensors` plus `config.json` for the safetensors load path (fp32, wired at push).
- `verify.py` runs a fixed sample input and checks the output shape and a verification value.
For serving at scale, use the separate CPU native FELA server (`https://github.com/Lowdown-Labs/fela_server`). It
runs this model on CPU with no GPU required. The quickstart here is the minimal single process
path; on a Raspberry Pi the deploy path would be the ONNX or TFLite export above.
# Training data
- PTB-XL v1.0.3 (Wagner et al. 2020, Scientific Data; PhysioNet), the 100 Hz 12 lead records,
superdiagnostic 5 class multi label setting (NORM, MI, STTC, CD, HYP). Official stratified
folds: train 1 - 8 = 17,084 records, validation fold 9 = 2,146, test fold 10 = 2,158.
Per lead z normalization uses training fold statistics only.
- License: Creative Commons Attribution 4.0 International (CC-BY-4.0). Open access, no
credentialed access, no data use agreement. Commercial use is permitted with attribution to
the PTB-XL authors and PhysioNet. Full split, size assertions, and license details are
reproduced in `train.py` (`--smoke` rebuilds the split and asserts the test count of 2158).
No teacher model outside the FELA family was distilled from; the student was distilled from a
three member FELA-ECG ensemble trained on the same PTB-XL folds.
# Intended use, limitations, and safety
What it is for: the inference core inside a clinical or consumer ECG product, running
on device or on premises. Fit includes 24/7 wearable and patch monitoring (continuous
abnormality flagging on a smartwatch or chest patch, no cloud round trip), Holter and
ambulatory review (scan a long recording and surface superclass findings for a technician),
ICU and bedside early warning (raise an alert when a class probability crosses a clinician set
threshold), and integration with WFDB / PhysioNet tooling (it reads standard WFDB records).
What it is not for: FELA-ECG is not a medical device and is not a diagnosis. The outputs are
probabilities for triage and decision support. Do not use it as the sole basis for a care
decision, and do not deploy it in patient care without independent clinical validation and the
regulatory clearance required in your jurisdiction. This is a medical adjacent model; treat its
output as a flag for a clinician to review, not an answer. This is a research preview, that
we are releasing as part of our mission to supercharge public science with responsible computing.
Privacy: the model runs on the device or on premises. The ECG does not have to leave the
machine, which is the point for settings that cannot or will not send patient data off site.
Evaluated conditions and known failure modes:
- Accuracy is at parity with, not ahead of, the strongest published CNN specialist (0.9243
int8 versus xresnet1d101 0.925 on the same protocol). We do not claim to beat it.
- Single dataset: trained and evaluated only on PTB-XL. Generalization to other acquisition
hardware, lead placements, populations, and noise profiles is not established and must be
validated before any clinical use.
- Five superclasses only. The finer subclass and full statement PTB-XL settings are not trained
here.
# How to cite
```bibtex
@misc{lowdownlabs_felaecg,
title = {FELA-ECG: On device Fourier Neural Operator classifier for 12 lead ECG},
author = {Lowdown Labs},
year = {2026},
note = {Model card}
}
```
You **must** also cite the dataset used:
- Wagner, P., Strodthoff, N., Bousseljot, R.-D., Kreiseler, D., Lunze, F. I., Samek, W., &
Schaeffter, T. (2020). PTB-XL, a large publicly available electrocardiography dataset.
Scientific Data, 7, 154. https://doi.org/10.1038/s41597-020-0495-6
# Acknowledgements and references
## Dataset
- PTB-XL: Wagner et al. (2020), Scientific Data 7, 154.
https://doi.org/10.1038/s41597-020-0495-6 . PhysioNet project (v1.0.3):
https://physionet.org/content/ptb-xl/1.0.3/ (project DOI https://doi.org/10.13026/kfzx-aw45 ).
Also cite PhysioNet: Goldberger, A. L., et al. (2000). PhysioBank, PhysioToolkit, and
PhysioNet. Circulation, 101(23), e215-e220. https://doi.org/10.1161/01.CIR.101.23.e215 .
License: CC-BY-4.0 ( https://physionet.org/content/ptb-xl/view-license/1.0.3/ ). Commercial
use is allowed with attribution.
## Baseline
- Strodthoff, N., Wagner, P., Schaeffter, T., & Samek, W. (2021). Deep Learning for ECG
Analysis: Benchmarks and Insights from PTB-XL. IEEE Journal of Biomedical and Health
Informatics, 25(5), 1519-1528. https://doi.org/10.1109/JBHI.2020.3022989 (the xresnet1d101
superdiagnostic macro-AUROC of 0.925 is the reference).
## Methods and code
- Fourier Neural Operator: Li, Z., et al. (2021). Fourier Neural Operator for Parametric
Partial Differential Equations. ICLR. https://arxiv.org/abs/2010.08895
- PyTorch: Paszke, A., et al. (2019). NeurIPS. https://arxiv.org/abs/1912.01703
# Model family
This is part of the FELA family from Lowdown Labs: one Fourier Neural Operator architecture
across many modalities, all CPU native and subquadratic. This repo is pushed as
`lowdown-labs/fela-ecg`. Sibling repos share no weights, so none carries a `base_model` link.
# License
Released under the Lowdown Labs Lovely License 1.0 (CC BY-NC 4.0 + Hippocratic License 3.0). See `LICENSE`.
For most LL models, a commercial license may be available; contact [Lowdown Labs](https://gimmelowdown.com/pricing).