686. PhysioNet - Digitization of ECG Images | physionet-ecg-image-digitization
感谢组织者举办这场有趣的比赛!以下是我们方法的总结。
我们的解决方案基于一个端到端 (End-to-End, E2E) 深度学习 pipeline,直接从 ECG 图像预测 ECG 时间序列信号。关键的洞察是将图像分割与信号 refinement 结合在一个可微分的 pipeline 中。
ECG 图像 (阶段 1 预处理)
│ [H=1280, W=5600, C=3]
↓
阶段 2: UNet 分割 (4 通道软 mask)
│ [H=1280, W=5600, C=4]
│ ← 辅助损失 1: 分割 BCE 损失
↓
可微分质心提取 (mask → 1D 信号)
│ [C=4, L=10250]
│ ← 辅助损失 2: 信号质心 L1 损失
↓
阶段 3: 1D ResUNet refinement
│ [C=4, L=10250]
│ ← 主要损失:L1 + SNR 损失
↓
重采样集成 (decimate_fir + polyphase + linear)
│ [C=4, L=fs×10] (例如 5000 for fs=500Hz)
↓
最终 ECG 信号 (12 leads)
这是一个关键组件,实现了端到端训练:
# 对于每一列,计算概率分布的加权质心
y_coords = torch.arange(H).view(1, 1, H, 1)
prob_sum = seg_prob.sum(dim=2) + eps
centroid_y = (seg_prob * y_coords).sum(dim=2) / prob_sum
# 将像素位置转换为 mV
signal_mv = (base_y_position - centroid_y) / y_scale
这允许梯度从信号损失流回分割网络。
结合分割和信号损失,并进行调度加权:
# 早期训练:专注于分割
# 后期训练:转向信号质量
seg_weight = seg_start + (seg_end - seg_start) * progress
signal_weight = sig_start + (sig_end - sig_start) * progress
loss = seg_weight * seg_bce_loss + signal_weight * (l1_loss + snr_loss)
增强对于泛化至关重要:
| 增强方法 | 概率 | 影响 |
|---|---|---|
| 水平翻转 (Horizontal Flip) | 0.5 | +0.6 dB (最大改进!) |
| 灰度 (Grayscale) | 0.2 | 帮助应对颜色变化 |
| 亮度/对比度 (Brightness/Contrast) | 0.3 | 对光照的鲁棒性 |
| JPEG 压缩 (JPEG Compression) | 0.2 | 处理低质量扫描 |
| 切割 (Cutout) | 0.2 | 处理遮挡/损坏 |
| 高斯噪声 (Gaussian Noise) | 0.2 | 处理传感器噪声 |
水平翻转增强出人意料地有效 (+0.6 dB),可能是因为它使有效训练数据翻倍,并帮助模型学习方向不变的特征。
我们训练了多个具有不同配置的模型:
| 模型 | Encoder | 阶段 3 | 水平翻转 | LB 分数 (无重采样集成) |
|---|---|---|---|---|
| m009 | ResNet34 | resunet1d (d=4) | 0.0 | 20.02 |
| m010 | EfficientNet-B3 | resunet1d (d=4) | 0.0 | 20.21 |
| m013 | ResNet34 | resunet1d (d=4) | 0.5 | 20.64 |
| m014 | EfficientNet-B3 | resunet1d (d=4) | 0.5 | 20.84 |
| m018 | EfficientNet-B3 | resunet1d (d=5) | 0.5 | 20.87 |
| m020 | EfficientNet-B4 | resunet1d (d=4) | 0.5 | 20.61 |
models = ['m009', 'm010', 'm013', 'm014', 'm018', 'm020']
weights = [0.05, 0.1, 0.2, 0.25, 0.25, 0.15]
基于单模型性能的加权平均,并对不同架构给予轻微的多样性奖励。
一个微妙但有效的技术:在将模型输出长度转换为目标采样频率时,集成多种重采样方法。
ensemble_methods = ['decimate_fir', 'polyphase', 'linear']
不同的重采样算法会引入不同的伪影(尤其是在信号边缘)。对它们进行平均可以消除特定方法的伪影。
非常感谢 @hengck23 提供的优秀公开 notebooks!我们的阶段 1 预处理完全基于 hengck23 的工作,这为我们的 pipeline 提供了基础。阶段 1 提供的干净、标准化图像对于有效训练我们的 E2E 模型至关重要。
同时也感谢 Kaggle 社区在整个比赛期间提供的富有洞察力的讨论。