☰
乳腺癌YOLO数据集训练指南:从数据检查到参数调优
2026/10/6 8:10:45 网站建设 项目流程

简介:这是一份面向医学图像目标检测的YOLO格式乳腺癌数据集,包含训练集与验证集,目标类别为breast cancer。图像均为640×640分辨率RGB图片,边界框标注清晰,图像完整且前景丰富,适合用于YOLOv5等目标检测模型的训练、验证与算法研究。整个压缩包约12.87MB(7z格式),共1845个文件,其中包含922个txt标签文件、921张jpg图像,另附1个Python可视化脚本和1张预览图;标签与图像一一对应,可直接放入YOLOv5目录使用,无需额外转换。训练集共778张图片及对应标签,验证集143张图片及对应标签,数据划分明确,便于直接评估模型效果。可视化脚本随机读取一张图片即可绘制边界框并保存到当前目录,无需改动即可运行,帮助用户快速检查标注质量。目前已有1074人浏览学习,适合刚接触医学图像检测的研究者或需要现成乳腺癌检测数据集的开发者使用。

1. 单类别乳腺癌YOLO数据集:医学影像检测最省心的起点

乳腺癌检测在目标检测里是一个少见的“单类别反而更实用”的场景。你不区分肿块、钙化灶、结构扭曲的亚型,只需要回答一个问题:这块区域是不是癌变病灶。这个数据集已经按 YOLO 约定把训练集和验证集分开,标注是统一的 txt 格式,拿到手就能直接开训,等于把往常要花两三周的 DICOM 清理、格式转换、专家标注工作提前做完了。它适合两类人:做超声或钼靶影像辅助诊断的算法工程师,以及想入门医学图像目标检测但找不到干净数据集的初学者。它的核心价值在于,用最简单的数据组织方式,跑通一条可评估、可迭代的乳腺癌检测流水线。

2. 数据集内部结构与 YOLO 格式落地:先做三件不花训练时间的事

2.1 目录树与 data.yaml:模型只认这一张地图

标准的单类别 YOLO 医学检测数据集,目录结构是固定的,train 和 val 下各带 images 与 labels 两个平级文件夹:

breast_ultrasound_yolo/ ├── train/ │ ├── images/ │ │ └── case_001.jpg │ └── labels/ │ └── case_001.txt ├── val/ │ ├── images/ │ │ └── case_005.jpg │ └── labels/ │ └── case_005.txt └── data.yaml

data.yaml 是训练时的唯一地图,内容极简:

path: /datasets/breast_ultrasound_yolo train: train/images val: val/images nc: 1 names: - breast_cancer

这里的 nc 必须等于 1,names 列表只能有一个元素。我收到过一份自称“1 类别”的数据集,结果它的 data.yaml 把 nc 写成 2、names 写成 ['normal', 'cancer'],训练时 loss 一直挂在 0.7 附近下不去——因为标签 txt 里的 class_id 全是 0,模型却在努力区分两个类。拿到数据集后的第一个动作,就是打开 data.yaml 确认 nc、names 和标签文件第一列完全对得上。YOLO 训练不看目录名,只看 yaml 里的路径,path 尽量写绝对路径,避免换机器后缓存路径错乱。

再看标签文件。train/labels/case_001.txt 每行五个数字:

0 0.5123 0.4876 0.1234 0.0987

从左到右依次是 class_id、归一化中心 x、归一化中心 y、归一化宽度 w、归一化高度 h。归一化意味着除以整张图的宽高,不是像素绝对值。这份数据集的特殊之处在于:一张图通常只有 0 到 3 个框,很多图甚至是完全没有框的阴性样本。这和 COCO 那种一张图平均七八个目标的分布完全不同,后面所有参数调整都要围绕这个稀疏分布做。

2.2 标注可视化脚本:半小时内确认框是否贴边

拿到数据集的第一件事不是训练,而是把标注画出来看。这是所有排错的起点:

# check_boxes.py import cv2 import os img_file = 'train/images/case_001.jpg' txt_file = 'train/labels/case_001.txt' img = cv2.imread(img_file) h, w = img.shape[:2] with open(txt_file) as f: for line in f: c, cx, cy, bw, bh = map(float, line.split()) x1 = int((cx - bw / 2) * w) y1 = int((cy - bh / 2) * h) x2 = int((cx + bw / 2) * w) y2 = int((cy + bh / 2) * h) cv2.rectangle(img, (x1, y1), (x2, y2), (0, 0, 255), 2) cv2.imwrite('check_case_001.jpg', img)

脚本逻辑只有一步:把 txt 里的归一化坐标还原成像素坐标。最容易写错的是顶点计算——左上角 x 是(cx - bw/2) * w,不能直接拿cx * w当左上角,否则框整体偏移半个框宽。乳腺病灶在超声图里多是低回声类圆形区域,矩形标注必然会框进一小圈正常组织,这是 YOLO 类水平框检测器的固有代价,不算法错误。但如果框只有病灶的一半,或者把周围一大片腺体全包进来,这种标注必须回头找数据方核对。

抽 train 和 val 各 20 张图跑一遍这个脚本,能发现三类问题:框和病灶错位、两张图误共用同一组坐标、图像被旋转 90 度导致框整体歪掉。最后一种在医学影像里格外常见,DICOM 自带的 Orientation 标签在转 JPG 时常常被忽略,转出来的人眼看上去是正的,实际像素矩阵已经是旋转过的。

2.3 数据泄露检查:同病例出现在两端是最大隐患

乳腺数据集的坑不在类别不平衡,在数据泄露。一个病人的多张超声切面如果同时落在训练集和验证集,模型记住的不是“癌变的普遍模式”,而是“这个人的乳房纹理”。推理时换一个新病人,性能立刻掉一截。

检查手法非常直接:

ls train/images | sed 's/_[0-9]*\.jpg//' | sort -u > train_cases.txt ls val/images | sed 's/_[0-9]*\.jpg//' | sort -u > val_cases.txt comm -12 train_cases.txt val_cases.txt

comm -12 输出的 case_id 就是同时出现在两端的病例,一个都不能留。这条命令依赖命名规范:如果文件名是 case_001_view1.jpg 这类,sed 能正确抽出 case_id;如果是纯数字文件名,就只能去翻数据表或元数据。我建议收到数据集的第一小时就做这一步,比训练一晚上再发现指标虚高划算得多。

注意:数据泄露检查不是走形式。验证集指标虚高的模型上线后必然翻车,而翻车在医学场景里是要担责任的。

检查的第二件事是阴性图占比。单类别检测不存在类别不平衡,但存在图像级不平衡:大量图像没有病灶框。训练集里的阴性图教会模型“不要乱出框”,这没毛病;但验证集如果阴性图占比畸高,Precision 会被抬得很虚。理想情况下,验证集的阳性图占比应该贴近真实筛查场景的阳性率,这个数字通常在 10% 到 30% 之间,而不是 50% 以上。

3. YOLO 训练乳腺癌检测模型:最小命令与五个必调参数

3.1 跑通训练的最小命令

用 ultralytics 的 YOLOv8 或 YOLO11,环境只需一个pip install ultralytics。训练命令:

yolo detect train \ data=/datasets/breast_ultrasound_yolo/data.yaml \ model=yolov8n.pt \ epochs=200 \ imgsz=640 \ batch=8 \ device=0

model=yolov8n.pt会自动加载 COCO 预训练权重到当前目录。训练开始后,终端会按轮打印 box_loss、cls_loss、Precision、Recall 和 mAP50。第一次跑通,只盯两件事:box_loss 是否在稳步下降,Recall@0.5 是否在逐步上升。如果 box_loss 降了、Recall 不动,优先怀疑标注框和病灶边缘严重不齐,回到第 2.2 节的可视化脚本查一遍。训练结束后,runs/detect/train/weights/ 下会有 best.pt 和 last.pt 两个权重,乳腺癌检测我基本只取 best.pt,last.pt 留给断点续训用。

关于 imgsz,我一般先用 640 跑一个 baseline,同时统计验证集病灶的像素尺寸分布。把 batch 从默认 16 改到 8,不是玄学:乳腺数据集通常只有几百到几千张图,batch=16 时一个 epoch 只有几十步,BN 统计量波动大,配合 0.002 的低学习率更容易稳。

3.2 五个必调参数:单类别医学图像和 COCO 就是不一样

YOLO 的默认参数是按 COCO 自然图像调的,用在乳腺数据上至少有五个要改。下表是我在乳腺超声和钼靶数据上常用的起点值:

参数COCO 常用默认乳腺数据推荐调整原因
imgsz640512~800病灶常小于 32 像素,分辨率不够直接压没
batch16~328灰度图被复制成 3 通道,显存占用和彩色图差不多
epochs100150~300数据量小,需要更多轮次慢慢收敛
lr00.010.001~0.003医学图纹理差异小,学习率太大会震荡
mosaic1.00.25 或 0拼接增强会切碎病灶上下文,小病灶直接消失

lr0 是我改动后收益最明显的参数。乳腺超声图的背景结构高度相似,梯度方向一致,0.01 的默认学习率很容易第一轮就把预训练权重冲坏,表现为前 10 轮 loss 不降反升。降到 0.002 并配合 cosine lr,让最后 20 个 epoch 缓慢收敛,效果通常比大学习率跑满 300 轮还稳。

mosaic 是另一个大坑。YOLOv8 默认开启 Mosaic 增强,把四张图裁开再拼成一张,但乳腺病灶本来可能只有几十个像素,拼图过程中病灶被切掉一半是常态,模型学到的是残破病灶而不是完整病灶。第一轮我一般设mosaic=0.25,后面如果小目标漏检严重,直接改成 0。

3.3 轮数与早停:小数据集别迷信 patience

YOLO 自带早停机制,默认 patience=50,验证集指标 50 轮不涨就停。但在医学小数据集上,验证集指标抖动比 COCO 大得多,经常第 30 轮涨一点、第 45 轮又跌回去,50 轮不动的判断很容易提前刹车。我一般显式设patience=50,但前提是学习率已经降到 0.002 附近;如果 lr 还是默认的 0.01,早停反而容易停在一个次优点上。

另一个冷知识:best.pt 是按验证集 mAP50 选的。mAP50 是通用目标检测的主指标,但乳腺癌检测更关心召回率。所以训练结束后,我会用 best.pt 再跑一遍验证集,把 conf 阈值放到 0.15 到 0.2 重新统计一次 Recall,那个数字才是模型真实能力的上限。具体怎么找阈值,第 5 章单独讲。

4. 乳腺影像训练踩坑记录:5 条现象、原因与排查步骤

4.1 现象:box_loss 降到了 0.3,验证集 mAP 始终接近零

原因排查后通常是标注文件里混入了错误的 class_id。数据提供方导标注时可能沿用了旧表,txt 里 class_id 既有 0 又有 1,而 data.yaml 的 nc 是 1。模型收到两个类别标签,训练 loss 照常下降,但验证时类别预测一半概率落空,mAP 自然接近零。

解决的第一步是查脏数据:

grep -rE '^[1-9]' train/labels/ | head -40

任何第一列不是 0 的行都是脏标注。如果确认这个数据集就是单类别,直接批量改写:

import os for root, _, files in os.walk('train/labels'): for fn in files: p = os.path.join(root, fn) lines = open(p, encoding='utf-8').readlines() fixed = [] for line in lines: parts = line.split() if parts and parts[0] != '0': parts[0] = '0' fixed.append(' '.join(parts) + '\n') if fixed != lines: open(p, 'w', encoding='utf-8').writelines(fixed) print('fixed:', fn)

这个脚本只做一件事:把所有非 0 的 class_id 统一改成 0,不动框坐标。改完重训前再跑一次第 2.3 节的病例泄露检查,因为很多脏文件其实是同一个病例的重复导出。

4.2 现象:微钙化簇几乎全漏,大肿块全部能检出

这是乳腺钼靶最常见的失败模式。YOLO 的下采样步长是 8/16/32,病灶在最后几层特征图上至少要占一个网格位置,太小就直接被跳过去。先量化问题有多大:

import cv2, glob for txt in glob.glob('val/labels/*.txt'): img_file = txt.replace('/labels/', '/images/').replace('.txt', '.jpg') img = cv2.imread(img_file) if img is None: continue h, w = img.shape[:2] for line in open(txt): c, cx, cy, bw, bh = map(float, line.split()) pw, ph = int(bw * w), int(bh * h) if pw < 32 or ph < 32: print(f'{txt}: {pw} x {ph} px')

如果小框占比超过 30%,第一选择不是换模型,而是提高输入分辨率。imgsz 从 640 升到 800,小病灶的像素面积能多出五成以上,代价是显存和推理时间各涨约三成。第二选择是关掉 Mosaic,小病灶在拼接图中更容易失踪。第三选择是检查验证集标注里有没有把小病灶和大病灶混在同一张图的不同层级,导致回归目标互相干扰。

这些手段都试过还漏,就得承认当前数据自己有一个分辨率天花板。这时应该去要更高分辨率的原始图像,或者做全幅切片推理,而不是继续调置信度阈值。

4.3 现象:推理结果里同一病灶出现十几个重叠框

重复框大概率是 NMS 之前候选框没有被有效抑制,常见原因一是推理时 conf 设太低,二是 iou 阈值设得太小。先看每张图输出多少框:

yolo detect val \ model=runs/detect/train/weights/best.pt \ data=/datasets/breast_ultrasound_yolo/data.yaml \ conf=0.25 iou=0.45 \ save_txt=True

单类别乳腺影像一张图正常情况下最多 4 到 5 个框,超过 10 个就是 NMS 出了问题。解决方法是把推理的 iou 提高到 0.5 到 0.6,让重叠框被压得更狠。

但也有一种例外必须排除:标签文件本身就带了重复框。标注工具卡顿、鼠标双击,同一个框被保存两次很常见。去重脚本:

# dedup_boxes.py seen = {} for line in open('val/labels/case_005.txt'): key = tuple(round(float(v), 4) for v in line.split()) seen.setdefault(key, line) open('val/labels/case_005.txt', 'w').writelines(seen.values())

对每个标签文件都跑一遍,然后用第 2.2 节的可视化脚本复查,能消除一批来源不明的重复框。

4.4 现象:验证集指标反而比训练集好,心里不踏实

验证指标优于训练集,先别高兴。常见原因有三个:第一是数据泄露,同病例的图进了双端,模型相当于开卷考;第二是验证集阴性图占比过高,Recall 虚高、Precision 缺少参考意义;第三是训练时增强开得太猛,训练图像被 Mosaic 和旋转折腾得面目全非,训练集上误差大,验证集用的是原始图所以指标好看。

排查顺序:先跑第 2.3 节的 comm 命令确认没有病例重叠,再统计 val 目录的阳性图占比,最后把训练集增强前后的图像各抽几张并排看。如果只是 Mosaic 过猛,把 mosaic 调成 0.25 或 0 重新训练,验证集和训练集的差距会收敛到合理范围。

4.5 现象:推理时把正常腺体、钙化点当成癌框出来

单类别模型的假阳性在医学图像里最恼人。原因是乳腺正常组织的密集纹理和早期癌灶在灰度上非常接近,模型没见过足够多“难负样本”。排查顺序:先把推理置信度从默认 0.25 提到 0.5,观察漏检率是否还能接受;如果 Recall 掉得厉害,回头检查训练集里有没有把“边界不清的良性组织”也标成了阳性——这属于标注问题,不是模型问题。最后再考虑难负样本挖掘:把验证集里假阳性最高的那批图挑出来,确认没有病灶后加入训练集,让模型学会拒绝这些纹理区域。

5. 验证集评估不看 mAP50:筛查场景的指标组合与置信度调优

5.1 mAP50 之外,乳腺癌检测真正该看的是 Recall

YOLO 训练输出的指标有 Precision、Recall、mAP50、mAP50-95。通用目标检测以 mAP50 为主评,但医学筛查里漏掉一个癌的代价远大于误报一次,所以乳腺癌检测的第一指标应该是 Recall@0.5——也就是在默认 conf=0.25 下,模型能找回多少比例的真实病灶。如果 R 低于 0.85,这个模型离辅助诊断还有距离。

指标通用目标检测乳腺癌检测
mAP50主指标参考指标
Recall@0.5重要首选指标
Precision重要次要,但要控住
F2 score少用更贴近场景
漏检率不大关注首要关注

这张表不是标准答案,而是提醒你评估前先想清楚业务目标。做筛查场景,R 要大于 0.9;做辅助标注场景,P 要大于 0.7。同一个模型在不同的 conf 阈值下会落在 PR 曲线的不同位置,所以光看训练日志里那一行数字远远不够。

5.2 用 PR 曲线找最佳置信度阈值

训练结束后,runs/detect/train/ 下会生成 val/PR_curve.png,这是找 conf 阈值的决策图。曲线上的每一个点对应一个候选框 score 阈值,默认 conf=0.25 在曲线上的位置偏向右下。如果只追求高召回,把 conf 降到 0.15,但 Precision 会掉;反过来,要保证 P 大于 0.6,就到曲线上找对应位置,那个点的横坐标就是你要用的 conf 阈值。

要把这个操作量化,可以跑一次推理,再把预测结果重新做阈值搜索:

import json preds = json.load(open('runs/detect/val/predictions.json')) # predictions.json 里的每条记录包含 image_id / bbox / score / category_id for t in [0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7]: tp, fp, fn = 0, 0, 0 # 这里按 t 过滤 preds,然后和真实框做 IoU 匹配 # IoU > 0.5 且类别正确为 TP,否则为 FP,GT 未匹配到则为 FN # 算出当前阈值下的 recall 和 precision,记录到一张表里

这段代码骨架想说明的思路是:训练日志里的指标固化了 conf=0.25,但实际上线时的置信度阈值可以按场景重新选。手动补全 IoU 匹配逻辑后,你会得到一张“阈值-R-P”对照表,再结合筛查场景要的 Recall 下限,直接读出该用哪个 conf。

5.3 分析错误样本的收敛模式,而不只是看指标数字

评估的最后一步是可视化错误样本。验证时开启 save_txt 和 save_conf,预测结果会按图存成 txt。我习惯把假阴性样本单独挑出来看:它们到底是微钙化簇还是大肿块?是低对比度图还是被伪影覆盖的图?如果假阴性全部集中在微小病灶,说明输入分辨率不够,回到 imgsz 而不是调阈值;如果假阳性都集中在正常腺体高回声区,说明需要加难负样本。

这里还要提醒一句:只有一个 train 和 val 的数据集,val 指标只能说明模型在这套数据分布上表现如何。真要考虑上线,最好再收集一批来自另一家机构、另一台设备的外部数据做双盲验证,否则 val 指标再高也只是内部自评。医学图像的设备差异、采集参数差异会对模型性能造成明显影响,这是数据分布问题,不是调参能完全解决的。

6. 数据增强与迁移学习:把单类别数据集的潜力逼出来

6.1 针对乳腺影像的增强开关

YOLO 内置增强里,hsv_h、hsv_s、hsv_v 对乳腺灰度图基本没有正面意义,图上没有真实色彩,随机色偏只会制造伪彩色噪声。fliplr 对乳腺图像有用,左右乳在解剖结构上对称,水平翻转等于免费扩充数据;flipud 不建议开,上下翻转会破坏解剖方向。Mosaic 在第 3.2 节已经说过,先给 0.25,等模型下采样到合适分辨率后才考虑调回 0。

我常用的训练命令:

yolo detect train \ data=/datasets/breast_ultrasound_yolo/data.yaml \ model=yolov8n.pt \ imgsz=640 batch=8 epochs=300 \ lr0=0.002 mosaic=0.25 \ hsv_h=0.0 hsv_s=0.0 hsv_v=0.0 \ fliplr=0.5 flipud=0.0 \ patience=50

注意 hsv 全关、fliplr 留 0.5、flipud 是 0。这些开关直接放在训练命令里,比改配置文件更直观,重跑时一眼能看到这轮用了什么增强。

6.2 两阶段迁移学习:先冻结 backbone,再解冻微调

针对只有一两千张图的乳腺数据集,我现在的习惯是两阶段训练:先用冻结 backbone 的方式跑 50 轮,让检测头和 neck 先学会粗定位;再解冻全部层,把学习率降到 0.0005 左右跑 100 轮,让模型慢慢去精修病灶纹理。第一阶段的权重用 COCO 预训练模型,第二阶段再加载第一阶段的 best.pt 继续训。这个做法比从头直接全层微调稳定得多,尤其当数据集里不少图只有一个小病灶时,先用粗定位锚住目标,后面细调不会把预训练特征冲散。

做医学检测这一年多,我最大的教训就是收到任何数据集的第一动作永远不是提交训练任务,而是可视化标注、查病例泄露、统计病灶尺寸分布。这三件不花训练时间的事,帮我省下的排错时间比训练本身还多。希望帮到你。

本文还有配套的精品资源,点击获取

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询