rakibmist/ecg-cardiac-cnn
ECG Cardiac Patient Classifier
Four-class classification of ECG scan images using three ImageNet-pretrained backbones fine-tuned with a small classification head.
Classes
Softmax index order (alphabetical, as produced by image_dataset_from_directory):
Input contract — read this
Input is a `(1, 224, 224, 3)` float32 tensor in the 0–255 range.
The training pipeline fed raw image_dataset_from_directory output straight into the backbone. A Resizing + Rescaling(1./255) block was defined in the notebook but never attached to the model graph, so the weights are adapted to 0–255 inputs.
- Do not divide by 255.
- Do not call
tf.keras.applications.resnet50.preprocess_input(or the VGG16 / EfficientNet equivalents). - Resize with bilinear interpolation to 224×224 without preserving aspect ratio.
Getting this wrong does not raise an error — it silently returns confident, wrong predictions.
Usage
import numpy as np, tensorflow as tf
from PIL import Image
from huggingface_hub import hf_hub_download
path = hf_hub_download("YOUR_USERNAME/ecg-cardiac-cnn", "ResNet50.keras")
model = tf.keras.models.load_model(path, compile=False)
img = Image.open("ecg.png").convert("RGB")
arr = np.asarray(img, dtype=np.float32) # 0-255, no rescale
arr = tf.image.resize(arr, [224, 224], method="bilinear", antialias=False)
probs = model.predict(tf.expand_dims(arr, 0))[0]
classes = ["HB", "MI", "Normal", "PMI"]
print(classes[int(np.argmax(probs))], float(np.max(probs)))Training
Adam (lr 1e-3), sparse categorical cross-entropy, 50 epochs, batch size 128, 80/20 train/test split, backbones frozen throughout. Evaluated with accuracy, weighted F1 / precision / recall, MCC, per-class ROC AUC and a confusion matrix.
Limitations and intended use
Research and educational use only. This is not a medical device, has not been clinically validated, and must not be used for diagnosis, triage, or treatment decisions. The classifier reads rendered ECG images, not raw signal data, so results depend heavily on the scan style, resolution and layout of the source dataset — expect degradation on ECGs captured or rendered differently. With frozen backbones and a 16-unit head, capacity is limited, and the held-out split was drawn from the same source dataset, so reported metrics are an optimistic estimate of real-world performance. Class balance was not corrected for.
