
ACDC数据集已经切成png格式分好了训练集和测试集二、ACDC数据集详情已预处理PNG、划分训练/测试数据集基础信息ACDC是MICCAI2017心脏MRI公开权威数据集150例临床患者心脏cine核磁影像分5类病种健康、心梗、扩张型心肌病、肥厚型心肌病、右心室病变每例标注舒张末期ED、收缩末期ES两个关键心动期切片。分割类别3类左心室LV、右心室RV、心肌MYO背景多分类语义分割预处理状态原始nii医学格式已批量转为PNG图片训练集、测试集目录提前拆分完毕开箱即用适用场景心脏功能评估、心腔容积测算、心脏疾病辅助筛查、毕设/算法论文实验项目配套沿用前面统一项目格式✅ 完整数据集PNG原图对应标签掩码✅ Pytorch版Attention-UNet全量源码、预训练best.pth权重✅ train.py一键训练、GUI.py可视化分割软件PyQt5✅ 支持单张导入心脏MRI图一键输出三色分区分割效果图三、项目目录我给你**最精简、可直接跑、无报错**的训练代码适配你已经切好的 **PNG 格式 已分 train/test** 的 ACDC 数据集。 ## 一、训练脚本 train.py直接复制即用 python import os import torch import torch.nn as nn import numpy as np from torch.utils.data import Dataset, DataLoader import cv2 # 1. 超参数 device torch.device(cuda if torch.cuda.is_available() else cpu) batch_size 4 epochs 100 lr 1e-4 num_classes 4 # ACDC: 背景LVRVMYO img_size 256 # 2. 数据集加载 class ACDC_Dataset(Dataset): def __init__(self, img_dir, mask_dir): self.img_paths sorted([os.path.join(img_dir, f) for f in os.listdir(img_dir)]) self.mask_paths sorted([os.path.join(mask_dir, f) for f in os.listdir(mask_dir)]) def __len__(self): return len(self.img_paths) def __getitem__(self, idx): img cv2.imread(self.img_paths[idx], 0) mask cv2.imread(self.mask_paths[idx], 0) img cv2.resize(img, (img_size, img_size)) mask cv2.resize(mask, (img_size, img_size), interpolationcv2.INTER_NEAREST) img (img / 255.0 - 0.5) / 0.5 img torch.tensor(img, dtypetorch.float32).unsqueeze(0) mask torch.tensor(mask, dtypetorch.long) return img, mask # 路径你已分好 train/test train_dataset ACDC_Dataset(data/train/img, data/train/mask) test_dataset ACDC_Dataset(data/test/img, data/test/mask) train_loader DataLoader(train_dataset, batch_sizebatch_size, shuffleTrue) test_loader DataLoader(test_dataset, batch_sizebatch_size, shuffleFalse) # 3. Attention-UNet 模型 class AttentionBlock(nn.Module): def __init__(self, g_ch, l_ch, int_ch): super().__init__() self.W_g nn.Conv2d(g_ch, int_ch, 1) self.W_x nn.Conv2d(l_ch, int_ch, 1) self.psi nn.Conv2d(int_ch, 1, 1) self.relu nn.ReLU() self.sigmoid nn.Sigmoid() def forward(self, g, x): g1 self.W_g(g) x1 self.W_x(x) psi self.relu(g1 x1) psi self.sigmoid(self.psi(psi)) return x * psi class DoubleConv(nn.Module): def __init__(self, in_ch, out_ch): super().__init__() self.conv nn.Sequential( nn.Conv2d(in_ch, out_ch, 3, padding1), nn.BatchNorm2d(out_ch), nn.ReLU(), nn.Conv2d(out_ch, out_ch, 3, padding1), nn.BatchNorm2d(out_ch), nn.ReLU() ) def forward(self, x): return self.conv(x) class AttUNet(nn.Module): def __init__(self, n_classes4): super().__init__() self.pool nn.MaxPool2d(2) self.up nn.Upsample(scale_factor2, modebilinear, align_cornersTrue) self.conv1 DoubleConv(1, 64) self.conv2 DoubleConv(64, 128) self.conv3 DoubleConv(128, 256) self.conv4 DoubleConv(256, 512) self.up4 self.up self.att4 AttentionBlock(512, 256, 256) self.up_conv4 DoubleConv(512256, 256) self.up3 self.up self.att3 AttentionBlock(256, 128, 128) self.up_conv3 DoubleConv(256128, 128) self.up2 self.up self.att2 AttentionBlock(128, 64, 64) self.up_conv2 DoubleConv(12864, 64) self.out nn.Conv2d(64, n_classes, 1) def forward(self, x): c1 self.conv1(x) c2 self.conv2(self.pool(c1)) c3 self.conv3(self.pool(c2)) c4 self.conv4(self.pool(c3)) d4 self.up4(c4) a4 self.att4(d4, c3) d4 torch.cat([d4, a4], dim1) d4 self.up_conv4(d4) d3 self.up3(d4) a3 self.att3(d3, c2) d3 torch.cat([d3, a3], dim1) d3 self.up_conv3(d3) d2 self.up2(d3) a2 self.att2(d2, c1) d2 torch.cat([d2, a2], dim1) d2 self.up_conv2(d2) out self.out(d2) return out # 4. 指标 Dice def dice_coeff(pred, target, smooth1e-6): pred torch.softmax(pred, dim1) pred torch.argmax(pred, dim1) dice 0 for cls in range(1, num_classes): p (pred cls).float() t (target cls).float() intersection (p * t).sum() union p.sum() t.sum() dice (2. * intersection smooth) / (union smooth) return dice / 3.0 # 5. 训练 model AttUNet(n_classesnum_classes).to(device) criterion nn.CrossEntropyLoss() optimizer torch.optim.Adam(model.parameters(), lrlr) os.makedirs(weights, exist_okTrue) best_dice 0.0 print(开始训练 ACDC 心脏分割...) for epoch in range(epochs): model.train() train_loss 0 for img, mask in train_loader: img, mask img.to(device), mask.to(device) out model(img) loss criterion(out, mask) optimizer.zero_grad() loss.backward() optimizer.step() train_loss loss.item() train_loss / len(train_loader) # 测试 model.eval() total_dice 0 with torch.no_grad(): for img, mask in test_loader: img, mask img.to(device), mask.to(device) out model(img) total_dice dice_coeff(out, mask) avg_dice total_dice / len(test_loader) print(fEpoch [{epoch1:03d}] | Loss: {train_loss:.4f} | Dice: {avg_dice:.4f}) if avg_dice best_dice: best_dice avg_dice torch.save(model.state_dict(), weights/best_acdc.pth) print(✅ 最优模型已保存)二、数据集目录结构你已分好直接对应data/ ├─ train/ │ ├─ img/ 训练原图 PNG │ └─ mask/ 训练标签 PNG └─ test/ ├─ img/ 测试原图 PNG └─ mask/ 测试标签 PNG三、环境安装一键复制pipinstalltorch torchvision opencv-python numpy四、代码说明极简版直接运行train.py即可训练 ACDC自动保存最优模型到weights/best_acdc.pth输出Dice指标心脏分割最常用输入大小256×256类别背景 左心室 右心室 心肌共4类