共计 2607 个字符,预计需要花费 7 分钟才能阅读完成。
Chest X-ray14 数据集实战指南:从数据预处理到模型训练全流程解析
背景介绍
Chest X-ray14 数据集是医学影像分析领域的重要基准数据集,包含 112,120 张标注了 14 种常见胸部疾病的 X 光图像。该数据集由美国国立卫生研究院 (NIH) 发布,具有以下特点:

- 规模大且标注全面:覆盖 14 种病理标签,包括肺不张、心脏肥大、肺实变等
- 多标签特性:单张图像可能同时存在多个病理状态
- 现实世界数据:包含不同医院采集的图像,存在设备差异
- 类别不平衡:某些疾病样本量较少
数据准备
数据下载
使用 wget 命令下载数据集(约 40GB):
wget https://nihcc.app.box.com/v/ChestXray-NIHCC/file/219427872344
解压数据集
unzip images_001.zip -d chest_xray14
# 重复解压所有分卷
数据集目录结构
chest_xray14/
├── images/ # 所有 DICOM 格式图像
│ ├── 00000001_000.png
│ └── ...
└── Data_Entry_2017.csv # 包含图像路径和标签
图像加载示例
from PIL import Image
import pandas as pd
# 加载标注文件
df = pd.read_csv('chest_xray14/Data_Entry_2017.csv')
# 图像加载函数
def load_image(img_path):
try:
img = Image.open(f'chest_xray14/images/{img_path}')
return img.convert('RGB') # 统一转换为 RGB 格式
except Exception as e:
print(f"Error loading {img_path}: {e}")
return None
数据预处理
医学影像标准化
- 像素值归一化:DICOM 图像通常有 12-16 位深度,需要归一化到 0 - 1 范围
- 尺寸统一:将图像 resize 到统一尺寸(如 224×224)
- 窗宽窗位调整:增强特定组织的可视性
import cv2
import numpy as np
def preprocess_image(img, target_size=(224,224)):
# 转换为 numpy 数组
img_array = np.array(img)
# 归一化
img_normalized = (img_array - img_array.min()) / (img_array.max() - img_array.min())
# 调整大小
img_resized = cv2.resize(img_normalized, target_size)
return img_resized
处理类别不平衡
from sklearn.utils.class_weight import compute_class_weight
# 计算类别权重
labels = df['Finding Labels'].str.get_dummies(sep='|')
class_weights = compute_class_weight('balanced', classes=np.unique(labels), y=labels.values.argmax(axis=1))
模型训练
基础 CNN 模型
import torch
import torch.nn as nn
import torch.optim as optim
class ChestXrayCNN(nn.Module):
def __init__(self, num_classes=14):
super().__init__()
self.features = nn.Sequential(nn.Conv2d(3, 32, kernel_size=3, padding=1),
nn.ReLU(),
nn.MaxPool2d(2),
nn.Conv2d(32, 64, kernel_size=3, padding=1),
nn.ReLU(),
nn.MaxPool2d(2)
)
self.classifier = nn.Sequential(nn.Linear(64*56*56, 128),
nn.ReLU(),
nn.Linear(128, num_classes)
)
def forward(self, x):
x = self.features(x)
x = torch.flatten(x, 1)
x = self.classifier(x)
return torch.sigmoid(x) # 多标签分类使用 sigmoid
训练循环
model = ChestXrayCNN()
criterion = nn.BCELoss()
optimizer = optim.Adam(model.parameters(), lr=0.001)
# 自定义数据加载器
class ChestXrayDataset(torch.utils.data.Dataset):
# 实现__len__和__getitem__方法
pass
dataset = ChestXrayDataset(df)
train_loader = torch.utils.data.DataLoader(dataset, batch_size=32, shuffle=True)
for epoch in range(10):
for images, labels in train_loader:
outputs = model(images)
loss = criterion(outputs, labels.float())
optimizer.zero_grad()
loss.backward()
optimizer.step()
避坑指南
- 数据加载优化:
- 使用多进程数据加载
- 预加载部分数据到内存
-
考虑使用 LMDB 等高效存储格式
-
内存不足处理:
- 减小 batch size
- 使用梯度累积
-
尝试混合精度训练
-
标签噪声处理:
- 使用标签平滑(Label Smoothing)
- 采用鲁棒损失函数
- 考虑半监督学习方法
进阶建议
- 迁移学习:
- 使用预训练的 ImageNet 模型作为特征提取器
-
尝试医学专用预训练模型如 CheXNet
-
多标签处理:
- 使用二元交叉熵而非交叉熵损失
- 考虑标签相关性建模
-
尝试图神经网络捕获标签关系
-
模型解释性:
- 使用 Grad-CAM 生成热力图
- 分析模型关注区域是否合理
思考题
- 如何处理 X 光图像中不同设备导致的域偏移问题?
- 当某些疾病样本极少时,除了重采样还有哪些数据增强策略?
- 如何设计一个能同时预测疾病和定位病灶的端到端模型?
正文完
发表至: 未分类
近一天内
