@freeCodeCamp: 训练医学影像模型应从理解数据开始,而非仅仅选择架构。在此教程中…
摘要
来自freeCodeCamp的教程,讲解如何使用MONAI构建乳腺超声图像肿瘤分割管道,强调在模型选择之前进行数据剖析。
查看缓存全文
缓存时间: 2026/07/24 19:17
训练医学影像模型应该从了解数据开始,而不是仅仅选择架构。
在本教程中,Lakshmi 将展示如何使用 MONAI 构建一个针对乳腺超声图像的肿瘤分割流水线。
你将分析数据,训练一个 U-Net,使用 Dice 分数进行评估,并分析失败模式。
https://freecodecamp.org/news/how-to-train-a-tumor-segmentation-model-on-ultrasound-data-with-monai/…
如何使用 MONAI 在超声数据上训练肿瘤分割模型
来源:https://www.freecodecamp.org/news/how-to-train-a-tumor-segmentation-model-on-ultrasound-data-with-monai/ 如何使用 MONAI 在超声数据上训练肿瘤分割模型大多数分割教程都是从选择模型、将图像输入模型、调整超参数直到指标提升开始的。但这跳过了通常最重要的步骤:理解数据。
在本教程中,我们将首先分析数据集,然后让这些观察结果驱动 MONAI 分割流水线中的每一个设计决策。
我们将涵盖的内容:
- 本教程适合谁? (https://www.freecodecamp.org/news/how-to-train-a-tumor-segmentation-model-on-ultrasound-data-with-monai/#heading-who-is-this-for)
- 关于数据集 (https://www.freecodecamp.org/news/how-to-train-a-tumor-segmentation-model-on-ultrasound-data-with-monai/#heading-about-the-dataset)
- 什么是 MONAI,为什么使用它? (https://www.freecodecamp.org/news/how-to-train-a-tumor-segmentation-model-on-ultrasound-data-with-monai/#heading-what-is-monai-and-why-use-it)
- 什么是 Dice? (https://www.freecodecamp.org/news/how-to-train-a-tumor-segmentation-model-on-ultrasound-data-with-monai/#heading-what-is-dice)
- 第一部分 — 建模前分析数据 (https://www.freecodecamp.org/news/how-to-train-a-tumor-segmentation-model-on-ultrasound-data-with-monai/#heading-part-1-data-profile-before-modeling) - 类别平衡决定损失函数 (https://www.freecodecamp.org/news/how-to-train-a-tumor-segmentation-model-on-ultrasound-data-with-monai/#heading-class-balance-drives-the-loss) - 患者数量决定数据划分 (https://www.freecodecamp.org/news/how-to-train-a-tumor-segmentation-model-on-ultrasound-data-with-monai/#heading-patient-counts-drive-the-split)
- 第二部分 — 构建流水线 (https://www.freecodecamp.org/news/how-to-train-a-tumor-segmentation-model-on-ultrasound-data-with-monai/#heading-part-2-building-the-pipeline) - 单一配置对象 (https://www.freecodecamp.org/news/how-to-train-a-tumor-segmentation-model-on-ultrasound-data-with-monai/#heading-a-single-config-object) - 按患者分组的数据划分 (https://www.freecodecamp.org/news/how-to-train-a-tumor-segmentation-model-on-ultrasound-data-with-monai/#heading-the-patient-grouped-split) - 根据数据快照选择的变换 (https://www.freecodecamp.org/news/how-to-train-a-tumor-segmentation-model-on-ultrasound-data-with-monai/#heading-transforms-chosen-by-the-snapshot) - 模型、损失函数和评估指标 (https://www.freecodecamp.org/news/how-to-train-a-tumor-segmentation-model-on-ultrasound-data-with-monai/#heading-model-loss-and-metric)
- 解读结果 (https://www.freecodecamp.org/news/how-to-train-a-tumor-segmentation-model-on-ultrasound-data-with-monai/#heading-reading-the-results)
- 预测结果可视化 (https://www.freecodecamp.org/news/how-to-train-a-tumor-segmentation-model-on-ultrasound-data-with-monai/#heading-prediction-visualization)
- 失败模式比平均值更重要 (https://www.freecodecamp.org/news/how-to-train-a-tumor-segmentation-model-on-ultrasound-data-with-monai/#heading-the-failure-modes-matter-more-than-the-average)
- 下一步去哪里 (https://www.freecodecamp.org/news/how-to-train-a-tumor-segmentation-model-on-ultrasound-data-with-monai/#heading-where-to-go-next)
- 要点总结 (https://www.freecodecamp.org/news/how-to-train-a-tumor-segmentation-model-on-ultrasound-data-with-monai/#heading-takeaway)
- 参考文献 (https://www.freecodecamp.org/news/how-to-train-a-tumor-segmentation-model-on-ultrasound-data-with-monai/#heading-reference)
本教程适合谁?
本教程假设你熟悉 Python 以及训练神经网络的基本知识。它会解释 MONAI 特有的部分(如字典变换、DiceCELoss、DiceMetric)以及医学影像术语(如 BI-RADS、低回声、按患者分组交叉验证),并在出现时进行说明。不需要超声领域的先验知识。
关于数据集
数据集是 BUS-BRA (https://www.kaggle.com/datasets/orvile/bus-bra-a-breast-ultrasound-dataset),这是一个公开的乳腺超声图像集合,包含活检证实的标签和肿瘤分割掩码。
每张图像都带有良性/恶性标签、BI-RADS(乳腺影像报告和数据系统)分类(放射科医生的怀疑评分,范围从2到5)、组织学字符串以及一个二值肿瘤掩码。数据集中附带的 CSV 文件还包含了预定义的交叉验证折。
任务是二值分割:将肿瘤与背景分离。BUS-BRA 包含来自1064名患者的1875张B型乳腺超声图像,这些图像由巴西一家癌症研究所的四台扫描仪采集。
BUS-BRA 数据集示例:一张乳腺超声图像、其对应的二值肿瘤分割掩码,以及掩码叠加在原始图像上的效果图。## 什么是 MONAI,为什么使用它?
MONAI(Medical Open Network for AI)是一个专门为医学影像构建的开源 PyTorch 框架。它是一个领域特定的层,位于 PyTorch 之上:你仍然编写标准的 PyTorch 训练循环,但 MONAI 提供了医学影像特有的组件,这样你就不必自己构建了。
它为你提供:
- 变换:用于医学数据的变换,支持加载 DICOM 和 NIfTI 等格式、标准化强度、调整大小和扩增,所有这些都在一个基于字典的流水线中完成,确保图像及其掩码保持同步。
- 网络架构:医学分割中常用的网络(U-Net、UNETR、SegResNet 等),可直接实例化。
- 损失函数和评估指标:专为分割设计的损失和指标,包括基于 Dice 的损失和 Dice 评估指标。
结果是更少的样板代码和更小的图像与掩码配准错误的风险。
什么是 Dice?
Dice(Dice 相似系数)衡量两个区域的重叠程度。在分割中,它将模型预测的掩码与真实掩码进行比较,并返回一个0到1之间的分数:0表示完全不重叠,1表示完全匹配。
公式是:
Dice = 2 × (重叠区域) / (预测区域 + 真实区域)
分子中的“2×”确保了即使分母两边都计算了重叠像素,分数仍保持在0到1之间。
在本教程中,它扮演两个角色:
- 作为评估指标,Dice 是运行评分的方式。验证 Dice 为0.876意味着预测的肿瘤掩码与真实掩码平均重叠约88%。
- 作为损失函数(
DiceCELoss),基于 Dice 的项是模型训练的目标。这对于类别不平衡问题很重要:因为 Dice 衡量的是重叠程度而不是逐像素的正确性,模型不能通过将所有像素标记为背景来获得高分。一个小肿瘤和大肿瘤一样重要,因此模型被迫去实际找到肿瘤区域。
第一部分 — 建模前分析数据
第一步是数据分析。它读取每张图像和掩码一次,并回答一系列问题,这些问题的答案决定了流水线必须如何构建。运行这些检查只需几秒钟,并为后续工作节省大量猜测。
下面的快照总结了直接影响流水线设计的属性。我们将让这些观察结果决定工作流的每一步。
| 快照测量的内容 | 数值 | 它迫使什么 |
|---|---|---|
| 不同的图像分辨率 | 数百种不同的 (宽度, 高度) 对 | 图像必须调整到固定大小才能批量处理 |
| 类别平衡 | 背景:前景 ≈ 10.6:1 | 普通的逐像素损失可能会收敛到主要预测背景,因为仅凭这样做就能在这个不平衡数据集上获得高像素精度。 |
| 每张图像亮度 | 数据集中差异很大 | 强度归一化应属于变换流水线的一部分 |
| 患者 vs. 图像 | 1064名患者,1875张图像(左右视图配对) | 数据划分必须按患者分组,否则同一个人会泄露到训练集和验证集中 |
| 掩码组件 | 每张掩码都是一个单连通区域 | 一个包含多个不连通块的预测很可能是错误的 |
| 像素格式 | 图像为8位灰度,掩码为1位二值 | 加载为单通道,加载后将掩码二值化 |
其中两个点值得仔细关注,因为它们决定了两个最重要的决策。
类别平衡决定损失函数
肿瘤很小。在整个数据集中,背景像素数量是肿瘤像素数量的十倍以上。
使用普通二值交叉熵训练的模型可以通过将所有像素标记为背景来达到约91%的像素准确率。这个高数字反映的是不平衡,而不是模型找到肿瘤的能力。
解决方案是使用一个奖励与真实肿瘤区域重叠的损失函数,这直接指向 Dice。
BUS-BRA 数据集中前景与背景像素的条形图比较。背景像素数量约为肿瘤像素的10.6倍,说明了严重的类别不平衡。### 患者数量决定数据划分
图像数量少于患者数量,因为许多患者同时提供了左侧和右侧的扫描。如果随机划分将一个患者的左侧扫描放在训练集,右侧扫描放在验证集,则验证分数会因泄露而虚高。
数据集作者已经解决了这个问题:CSV 文件中提供了一个 K5P 列:这是一个5折划分,其中 P 代表按患者分组(patient-grouped),这意味着来自同一患者的所有图像都会进入同一折。重复使用它比手动重新构建相同的分组更安全。
有了这些答案后,流水线就有了构建的规范。
第二部分 — 构建流水线
下面所有内容都使用 MONAI 进行分割相关的工作:变换、数据集封装、网络、损失函数和评估指标。
单一配置对象
流水线从一个数据类中读取所有参数。下游没有任何硬编码的常量,因此重新运行使用不同折或图像大小的实验只需一次编辑。
`` from dataclasses import dataclass from typing import Tuple, Optional from pathlib import Path
@dataclass class TrainConfig: data_root: Optional[Path] = None fold_column: str = “K5P” # 按患者分组的5折(开发集) val_fold: int = 1 # 用作验证集的 K5P 折 test_column: str = “HOP” # 按患者分组的留出分区 test_group: int = 1 # 保留为测试集的 HOP 值
image_size: Tuple[int, int] = (256, 256)
batch_size: int = 16
lr: float = 1e-3
epochs: int = 30
use_amp: bool = True # 混合精度
ckpt_path: str = "best_model.pt"
cfg = TrainConfig() ``
上面的代码定义了一个 TrainConfig 数据类,包含流水线所需的每个设置:折列以及要验证的折、目标图像大小、批量大小、学习率、轮次、混合精度开关以及保存最佳模型的路径。通过一次创建 cfg,后面的每一步都可以从一个地方读取其设置。
按患者分组的数据划分
划分使用两个预定义的列。HOP(留出分区)保留一个患者不重叠的切片作为测试集,直到最后才使用。在剩余的开发集中,一个 K5P 折作为验证集,另外四个作为训练集。简短的断言确认没有患者出现在多个划分中。
`` dev_df = manifest[manifest[cfg.test_column] != cfg.test_group] test_df = manifest[manifest[cfg.test_column] == cfg.test_group]
train_df = dev_df[dev_df[cfg.fold_column] != cfg.val_fold] val_df = dev_df[dev_df[cfg.fold_column] == cfg.val_fold]
没有患者可以出现在多个划分中
for a, b in [(train_df, val_df), (train_df, test_df), (val_df, test_df)]: assert not (set(a[“Case”]) & set(b[“Case”])), “患者泄露” ``
上面的代码首先分离出 HOP 测试集,然后将剩余的开发行划分为验证集(选定的 K5P 折)和训练集(其余部分)。然后检查每对划分中是否共享了患者 Case。如果有任何一个共享,断言会立即失败。
根据数据快照选择的变换
MONAI 的字典变换操作于按名称键("image" 和 "label")的记录,并对两者应用匹配的操作。每一步都回答了第一部分数据分析的发现。
`` from monai.transforms import ( Compose, LoadImaged, EnsureChannelFirstd, ScaleIntensityd, AsDiscreted, Resized, RandFlipd, EnsureTyped, ) import torch
base = [ LoadImaged(keys=[“image”, “label”], reader=“PILReader”, image_only=True), EnsureChannelFirstd(keys=[“image”, “label”]), ScaleIntensityd(keys=“image”), # 亮度分散 AsDiscreted(keys=“label”, threshold=0.5), # 干净的 {0, 1} 掩码 Resized(keys=[“image”, “label”], # 数百种尺寸 spatial_size=cfg.image_size, mode=(“bilinear”, “nearest”)), ]
train_transforms = Compose(base + [ RandFlipd(keys=[“image”, “label”], prob=0.5, spatial_axis=1), # 水平翻转 EnsureTyped(keys=[“image”, “label”], dtype=torch.float32), ]) val_transforms = Compose(base + [ EnsureTyped(keys=[“image”, “label”], dtype=torch.float32), ]) ``
上面的代码构建了一个共享的基础步骤列表:加载 PNG、将通道移到前面、将图像缩放到 [0, 1]、二值化掩码,并将两者调整到 256×256。然后将该列表封装到两个流水线中。训练流水线添加了随机水平翻转,而验证流水线没有,因此评估时始终看到原始图像。
水平翻转是一种简单的扩增方法,可以保持该数据集中的解剖合理性。更激进的扩增方法,如大角度旋转或弹性变形,应仔细验证,因为它们可能会扭曲临床上有意义的结构。
图像使用双线性插值以保持强度梯度,而掩码使用最近邻插值,以便类别标签严格保持为0或1。在掩码上使用双线性插值会在物体边界处产生人为的标签值。
模型、损失函数和评估指标
网络是 MONAI 的 UNet,具有一个输入通道(灰度)和一个输出通道(肿瘤 logit)。损失函数是类别平衡分析所指出的那个。
U-Net 由一个编码器和一个解码器组成:编码器在逐渐变粗的分辨率下捕获上下文,解码器重建精细的空间细节。跳跃连接将高分辨率特征直接从编码器传递到解码器,这使得 U-Net 在边界重要的医学分割中特别有效。
`` from monai.networks.nets import UNet from monai.losses import DiceCELoss from monai.metrics import DiceMetric from monai.transforms import Activations, AsDiscrete
model = UNet( spatial_dims=2, in_channels=1, out_channels=1, channels=(16, 32, 64, 128, 256), strides=(2, 2, 2, 2), num_res_units=2, ).to(device)
loss_fn = DiceCELoss(sigmoid=True) # Dice 处理不平衡;CE 平滑梯度 metric = DiceMetric(include_background=True, reduction=“mean”) post_pred = Compose([Activations(sigmoid=True), AsDiscrete(threshold=0.5)]) ``
上面的代码创建了 U-Net(五个分辨率级别,一个输入和一个输出通道)并将其移动到 GPU。然后定义了围绕它的三个部分:损失函数、验证评估指标以及一个 post_pred 步骤,该步骤通过应用 sigmoid 并在0.5处进行阈值处理,将模型原始输出转换为干净的0/1掩码。
DiceCELoss 结合了两个项。Dice 部分在前景区域上是尺度不变的,因此小肿瘤和大肿瘤一样重要,
相似文章
@aigclink: 最近在参与国内某头部医院检验科训练一个垂直细分医疗模型,分享一些个人观点,给AI+医疗领域的从业者一些建议(觉得有用拿走、觉得没用底下留言喷): 1、医疗领域最核心的是数据,国内的公立及三甲医院基本上数据不出医院的,所以细分领域AI落地有…
作者分享参与国内头部医院训练垂直医疗模型的个人观点,指出医疗数据不出医院、本地化部署成本高、付费意愿弱等核心挑战,并建议与硬件厂商绑定。同时认为通用医疗模型(如百川)已表现良好。
部分信息分解作为资源受限深度神经网络训练中脑肿瘤分割的多对比3D MRI选择策略
本文提出了一种部分信息分解框架,用于选择最具信息量的MRI对比对,以使用轻量级3D U-Net进行脑肿瘤分割,在保持性能的同时降低计算成本。
@HuggingModels: 你是否曾想要一个能够‘看到’医学图像并回答相关问题的人工智能?这个模型,llava-medical-8B-clip-vit-…
本文介绍了 llava-medical-8B-clip-vit-stage2,这是一个专为医疗保健领域微调的专用视觉语言模型,使人工智能能够解读 X 光和 MRI 等医学图像并回答相关问题。
TwinTrack:医学影像分割的事后多标注者校准
# 论文页面 - TwinTrack:医学影像分割的事后多标注者校准 来源:[https://huggingface.co/papers/2604.15950](https://huggingface.co/papers/2604.15950) ## 摘要 TwinTrack 框架通过将集成概率事后校准为经验平均人类响应,解决胰腺癌分割中的模糊性,在多标注者基准上提升校准指标。
从数据分析到肿瘤委员会:一种基于证据的多智能体工作流用于肿瘤学特征提取
论文评估了一个可配置的多智能体系统(nMAS),用于从碎片化的临床文档中提取结构化的肿瘤学数据,与基线模型相比取得了高性能。