hmt_ecgnet / train_binary.py
mahboobalam0's picture
Upload folder using huggingface_hub
43a9675 verified
Raw
History Blame Contribute Delete
3.56 kB
import os
import argparse
from datetime import datetime
import torch
import torch.nn as nn
from torch.utils.data import DataLoader
from tqdm import tqdm
from sklearn.metrics import roc_auc_score, f1_score
from dataset import PTBXLDataset
from models.hmt_ecgnet import HMT_ECGNet
from utils_seed import set_seed
from config import BATCH_SIZE, LR, WEIGHT_DECAY, N_EPOCHS, N_LEADS
# ---------------- ARGUMENTS ----------------
parser = argparse.ArgumentParser()
parser.add_argument("--task", choices=["mi_vs_norm", "norm_vs_abnormal"], required=True)
parser.add_argument("--seed", type=int, default=42)
parser.add_argument("--epochs", type=int, default=N_EPOCHS)
args = parser.parse_args()
def get_loader(ds, shuffle):
use_cuda = torch.cuda.is_available()
return DataLoader(
ds,
batch_size=BATCH_SIZE,
shuffle=shuffle,
num_workers=0,
pin_memory=use_cuda
)
def main():
set_seed(args.seed)
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
run_name = f"hmt_binary_{args.task}_seed{args.seed}_{datetime.now():%Y%m%d-%H%M%S}"
log_dir = os.path.join("logs", run_name)
os.makedirs(log_dir, exist_ok=True)
# ---------------- DATA ----------------
train_ds = PTBXLDataset(split="train", task="binary", binary_task=args.task)
val_ds = PTBXLDataset(split="val", task="binary", binary_task=args.task)
train_loader = get_loader(train_ds, shuffle=True)
val_loader = get_loader(val_ds, shuffle=False)
# ---------------- MODEL ----------------
model = HMT_ECGNet(num_classes=1, num_leads=N_LEADS).to(device)
print(f"Model parameters: {sum(p.numel() for p in model.parameters()):,}")
criterion = nn.BCEWithLogitsLoss()
optimizer = torch.optim.AdamW(model.parameters(), lr=LR, weight_decay=WEIGHT_DECAY)
best_auc = 0.0
for epoch in range(1, args.epochs + 1):
# -------- TRAIN --------
model.train()
train_loss = 0.0
for x, y in tqdm(train_loader, desc=f"Epoch {epoch:03d} [Train]"):
x, y = x.to(device), y.to(device).float()
optimizer.zero_grad()
logits = model(x).squeeze(1)
loss = criterion(logits, y)
loss.backward()
optimizer.step()
train_loss += loss.item()
train_loss /= len(train_loader)
# -------- VALIDATE --------
model.eval()
all_logits, all_targets = [], []
with torch.no_grad():
for x, y in val_loader:
x = x.to(device)
logits = model(x).squeeze(1)
all_logits.append(logits.cpu())
all_targets.append(y)
logits = torch.cat(all_logits)
targets = torch.cat(all_targets)
probs = torch.sigmoid(logits).numpy()
val_auc = roc_auc_score(targets.numpy(), probs)
val_f1 = f1_score(targets.numpy(), probs >= 0.5)
print(
f"Epoch {epoch:03d} | loss={train_loss:.4f} | "
f"AUROC={val_auc:.4f} | F1={val_f1:.4f}"
)
if val_auc > best_auc:
best_auc = val_auc
torch.save(
{"epoch": epoch, "model_state_dict": model.state_dict()},
os.path.join(log_dir, f"hmt_binary_{args.task}_best.pth"),
)
print(" -> Best model saved")
print("Training complete.")
if __name__ == "__main__":
main()