YOLOv5肺结节CT数据集:从数据准备到小目标调参实践
2026/9/12 21:50:29 网站建设 项目流程

简介:面向医学图像目标检测任务,该资源提供肺结节CT图像数据集,并按YOLOV5标准目录结构整理,标注统一为txt格式,读取后即可供YOLO系列模型直接训练,省去格式转换与目录修改步骤,便于快速投入算法迭代。数据仅包含“肺结节”一个目标类别,训练集包含220张图像及对应220个标签文件,测试集包含28张图像及对应标签,同时附带类别字典txt文件,可用于配置模型类别数,满足基础训练与验证需求。压缩包共499个文件,主体为248张jpg格式CT影像与249个txt格式标注文件,另附一个可直接运行的Python可视化脚本,随机传入一张图片即可绘制边界框并将结果保存到当前目录,有助于人工核验标注是否准确,也便于展示检测效果。整个资源包大小约5.14MB,体量小巧、目录结构清晰,适合本地快速搭建实验环境。目前已有988人学习下载,尤其适合医学影像算法研究者、目标检测方向学生以及进行项目开发或算法验证的工程师使用;同时规模适中、格式规范,也可作为深度学习初学者理解目标检测标注流程与YOLO数据组织的入门数据。

1. 拿到一份YOLOV5目录格式的肺结节CT数据集,先别急着训练

肺结节CT图像目标检测是医学影像AI里最典型的「小目标+低对比度」场景:结节在CT切片上可能只有十几像素,灰度差异又小,直接套用通用目标检测流程很容易漏检。这份数据集已经按照YOLOV5目录格式整理好,训练集220张、验证集28张,共248张CT切片图像,单类别「肺结节」,标签全部是YOLO格式的txt文件,还附带一个无需修改就能跑的可视化脚本。6MB的体积决定了它的定位不是临床级模型训练集,而是用来跑通YOLOV5从数据加载、训练到评估的完整流程,或者做迁移学习的起点。下面按数据组织、标签解析、可视化验证、训练配置和调参五个部分,把这份数据集的用法和边界一次说清。

2. 从CT切片到YOLO标签:数据组织与格式拆解

在动手训练前,先把数据目录和标注格式看清楚。YOLOV5对数据组织有约定俗成的结构,这个数据集基本沿用了通用目标检测数据集的 layout,只是内容换成了医学CT图像。

2.1 目录结构与数据集划分

常见做法是datasets/下划分imageslabels,各自再按trainval分目录。这份数据集保存为训练集datasets/images/train、验证集datasets/images/val,对应的标注文件放在datasets/labels/traindatasets/labels/val,图片和标签文件名一一对应,只是扩展名不同。展开来看是这样的:

datasets/ ├── images/ │ ├── train/ │ │ ├── R1.3.6.1.4.1.14519.5.2.1.6655.2359.111547677257119150655452340387.jpg │ │ ├── ... │ └── val/ │ ├── R1.3.6.1.4.1.14519.5.2.1.6655.2359.108523832239873578979600404354.jpg │ └── ... ├── labels/ │ ├── train/ │ │ ├── R1.3.6.1.4.1.14519.5.2.1.6655.2359.111547677257119150655452340387.txt │ │ └── ... │ └── val/ │ └── ... ├── classes.txt └── visualize.py

文件名里那一长串数字不是随机数,而是 LIDC-IDRI 这类公开肺部CT数据集中 DICOM 文件的 SOP Instance UID。用 UID 做文件名好处是跨数据集不重名,缺点是可读性差,训练日志里要定位某张图时会比较费劲。

表格统计一下数据规模:

数据划分图片数量标注txt数量类别数单张尺寸
train2202201512x512 左右
val28281512x512 左右

总大小 6MB,平均每张图片只有 25KB 左右,说明这些CT切片很可能已经做过压缩或转成JPG。真实临床DICOM单张就要几百KB到1MB,这也提醒我们:这份数据适合流程验证,不适合直接衡量模型在真实影像设备上的表现。

2.2 YOLO标注格式:归一化坐标与目标框

YOLO 格式的 txt 文件每一行表示一个目标框,格式是class x_center y_center width height。注意所有数值都相对于图片宽高做了归一化,取值在 0 到 1 之间。随便打开一个标签文件,内容会是这样:

0 0.5238 0.6114 0.0876 0.0932 0 0.7812 0.3251 0.0547 0.0612

第一列 0 是类别编号,因为只有一个类别,所以全部是 0。后面四列分别是边界框中心的 x、y 坐标以及框的宽度和高度,全部是归一化后的比例值。例如第一个框0.5238 0.6114表示目标中心点位于图片横向 52.38%、纵向 61.14% 的位置,框宽高占图片宽高的 8.76% 和 9.32%。

一个容易踩的坑是:COCO 格式和 YOLO 格式的坐标顺序不同。COCO 是x_min y_min width height,YOLO 是x_center y_center width height,两者换算关系如下:

x_center = (x_min + x_max) / 2 / image_width y_center = (y_min + y_max) / 2 / image_height width = (x_max - x_min) / image_width height = (y_max - y_min) / image_height

如果你从其他工具拿到的是 COCO 标注,务必先做转换再喂给 YOLOV5。数据集作者已经把标签转好,这一步对使用者是透明的,但理解换算关系有助于后面排查标注错位问题。

2.3 类别字典与 classes.txt

数据集根目录下的classes.txt是类别字典文件,YOLOV5 在训练时会读取它来生成类别名列表。因为只有 "肺结节" 一类,字典内容通常是单行:

nodule

文件名可能是classes.txt,也可能被写成nodule.yaml里的names字段。如果后续要在这个数据集上增加新类别,比如把 "磨玻璃结节" 和 "实性结节" 分开,就要同时修改classes.txt和每个 label 文件的第一列编号,这是一个容易漏改的地方。我一般会在数据准备阶段写个小脚本统一校验类别编号是否越界,避免训练中途报错。这一点在下一章展开。

2.4 CT图像的小目标特性对标注的影响

CT切片的肺结节,在512x512的图像里往往只占几十个像素,对应到归一化坐标上,width 和 height 可能只有 0.02 到 0.1。这个量级说明默认的 YOLOV5 锚框设计并不一定适配。标准的 COCO 预训练模型锚框最小为 10x13,对应到 640x640 输入也就是约 1.5% 的图幅,对于更小的结节仍然会偏大。所以在这类数据上,训练流程要和自然图像目标检测有所区别,这一点会在第5章具体展开。

另外,CT图像是灰度图,很多 YOLOV5 预训练模型是在 RGB 自然图片上预训练的,训练时会把单通道复制成三通道。这不一定最优,但实践表明在小数据集上直接使用预训练特征仍然比从零训练好。如果后续有多模态需求,比如融合 PET 或 MRI,才需要考虑更换 backbone 或输入分支。

3. 训练前先看图:用可视化脚本校验标注质量

数据集的标注是人眼标注后转换的,但转换过程可能出现坐标越界、框偏移、漏标错标。训练之前必须把标注可视化一遍,这是所有目标检测项目里最值得花时间的步骤之一。

3.1 运行自带的 visualize.py

数据集作者提供了一个可视化 py 文件,放在数据集根目录,随机传入一张图片即可绘制边界框并保存到当前目录。正常使用方式是把脚本和数据放在同一个目录,在终端执行:

python visualize.py --img datasets/images/train/R1.3.6.1.4.1.14519.5.2.1.6655.2359.111547677257119150655452340387.jpg

脚本内部逻辑通常是:用 OpenCV 读取图片和同名 txt,逐行解析五个数值,用cv2.rectangle在图上画框,最后cv2.imwrite保存。运行后目录下会多出一张带框的图片,直接打开看就能快速发现标注是否有整体偏移、框大小是否明显不符合结节形态。

如果脚本接收的是图片路径,需要保证图片名和标签名严格一致;文件名里那一长串 UID 不要手动改,改短后会导致脚本找不到 txt 而报错。

3.2 自己写一个标签校验脚本

如果原作者的可视化脚本只适合单张查看,我一般会再写一个批量校验脚本,把所有训练图片和标签过一遍,检查三个问题:文件是否成对、坐标是否越界、框是否过小或太大。下面这个脚本可以直接跑,输出异常样本列表。

import os import cv2 img_dir = "datasets/images/train" label_dir = "datasets/labels/train" for img_name in os.listdir(img_dir): if not img_name.endswith(".jpg"): continue label_name = img_name.replace(".jpg", ".txt") label_path = os.path.join(label_dir, label_name) img_path = os.path.join(img_dir, img_name) # 1. 检查标签文件是否存在 if not os.path.exists(label_path): print("MISSING LABEL:", img_name) continue # 2. 检查归一化坐标是否越界 img = cv2.imread(img_path) h, w = img.shape[:2] with open(label_path) as f: for line in f: parts = line.strip().split() if len(parts) != 5: print("BAD FORMAT:", img_name, line) continue cls, xc, yc, bw, bh = parts xc, yc, bw, bh = map(float, (xc, yc, bw, bh)) if not (0 <= xc <= 1 and 0 <= yc <= 1 and 0 < bw <= 1 and 0 < bh <= 1): print("OUT OF RANGE:", img_name, line) # 3. 按反归一化检测框尺寸 box_w, box_h = bw * w, bh * h if box_w < 3 or box_h < 3: print("TOO SMALL:", img_name, box_w, box_h) print("done")

这段脚本的逻辑很简单,但很实用。第一段检查图片和标签是否成对,排查漏转换或漏复制;第二段把归一化坐标还原到像素尺寸,标记出那些在 512x512 图上小于 3 像素的框。小于 3 像素的目标即使人眼也需要放大才能确认,通常需要和医生确认是否保留。如果你的数据集里结节的真实最小直径都在 5 像素以上,那么这些过小的框多半是标注噪声,可以剔除。

如果发现框整体偏移,大概率是图像预处理时做了裁剪,但标签没有同步变换。这类问题在可视化阶段暴露得越早,后面浪费的 GPU 时间越少。

如果要扩展到多类标注,脚本里的cls变量还可以用来统计每个类别的目标数量分布。比如想知道结节大小分布,可以把所有标签的bwbh收集起来画直方图,看是不是集中在 0.05 附近。这种分布信息在决定锚框和输入分辨率时非常有用。

3.3 标签异常类型与处理方式

异常现象可能原因处理方式
标签文件缺失文件复制遗漏重跑划分脚本,补全对应 txt
坐标出现大于1或小于0标签转换未归一化将像素坐标除以图片宽高
框绘在图像边缘但比例合理原标注框越界被裁剪裁剪时 clamp 坐标到 [0,1]
尺寸异常小结节直径过小或标注误差与医学背景人员确认后决定保留或剔除

这里重点提一下“坐标越界”的处理。很多工具在标注时会把框扩展到图像边缘之外,转换脚本如果没有 clamp,就会留下负数或大于1的值。这种数据直接训练,YOLOV5 的损失函数虽然不会崩溃,但会给出大量负样本,拉低召回。建议统一按x = min(max(x, 0), 1)的方式裁剪,而不是直接把这些样本删掉,因为边缘结节本身就是肺结节检测的重要场景。

4. 用YOLOv5训练肺结节检测:配置与命令

数据检查通过后,就是标准 YOLOV5 流程。这里以官方 ultralytics/yolov5 仓库为例,版本分支选 v6.0 之后的版本都可以,因为数据接口不变。关键是写好 data.yaml 和数据路径。

4.1 准备数据集配置文件 data.yaml

YOLOV5 通过一个 yaml 文件告诉训练脚本图片和标签在哪里、有多少类。打开nodule.yaml,内容如下:

train: datasets/images/train val: datasets/images/val nc: 1 names: ['nodule']

注意trainval写的是images目录路径,YOLOV5 会自动把路径中的images替换成labels来寻找标签文件。所以标签目录名必须保持和 images 下的划分一致,否则会直接报assertion error找不到标签。这一点经常有人搞错:有人把train字段写成 labels 路径,结果数据加载器在 labels 下再找 labels,自然找不到。

如果你把数据集放在了自定义目录,可以在 yaml 里写绝对路径,也可以写相对路径,以你执行训练命令的当前目录为基准。我倾向于用绝对路径,避免换终端后路径失效。

4.2 训练命令与超参数选择

进入 yolov5 仓库目录,安装依赖后执行:

python train.py \ --data /path/to/nodule.yaml \ --weights yolov5s.pt \ --img 640 \ --batch 16 \ --epochs 100 \ --device 0

参数含义如下:

  • --data:上一步配置的数据集文件,指定类别和路径。
  • --weights:预训练权重。数据量很小,用 COCO 的 yolov5s 做迁移学习能显著提升收敛速度和最终精度。
  • --img:输入尺寸,640 是 YOLOV5 默认值,CT 原图是 512x512,用 640 会在训练时先 resize 到 640,会轻微拉伸。由于 YOLOV5 默认启用 letterbox 填充,不会改变宽高比,所以可以接受。
  • --batch:批量大小,6MB 的小数据集可以先从 16 开始,根据显存调整。如果显存只有 8G,--batch 8更稳妥。
  • --epochs:小数据集建议 100 起步。由于样本少,训练很快,一个 100 epoch 的流程在单张 3090 上十几分钟就能跑完。
  • --device:指定 GPU,没有 GPU 可以去掉,用 CPU 训练 248 张图也能跑,但速度慢很多。

小数据集上我建议再加几个参数:

python train.py \ --data /path/to/nodule.yaml \ --weights yolov5s.pt \ --img 640 \ --batch 16 \ --epochs 100 \ --patience 20 \ --save-period 10

--patience 20表示 20 个 epoch 内 mAP 没有提升就提前结束,防止过拟合;--save-period 10每 10 个 epoch 保存一次 checkpoint,方便观察中间状态。这两个参数在长训练里很实用。

表格里是几个影响较大的超参数参考值:

超参数建议值说明
--img640可尝试 768 提升小目标召回
--batch8-16根据显存调整
--epochs100-300样本少,参考 loss 曲线
--weightsyolov5s.pt迁移学习
--hypdata/hyps/hyp.scratch-low.yaml小数据集可选用低增强策略

训练过程中看到终端打印类似Epoch gpu_mem box_obj cls ...的信息,主要关注box_lossobj_loss是否整体下降,以及每个 epoch 结束时的mAP@0.5。如果 loss 反复震荡不下降,优先检查学习率,YOLOV5 默认学习率 0.01,在小数据集上可以降到 0.001 试试。

--multi-scale参数可以每 10 轮随机变化一次输入尺寸,范围是--img的 0.5 到 1.5 倍。对小目标检测有一定帮助,因为它等于把目标按不同比例呈现给模型。但在这个数据集上,我建议先关闭,因为样本量太少,多尺度会增加训练不稳定性;等基线跑通后再开启对比效果。

4.3 评估输出与结果文件

训练结束后,runs/train/exp目录下会生成weights/best.ptresults.pngconfusion_matrix.png等。验证集只有 28 张,指标波动会很大,使用best.pt而不是last.pt是关键。可以用下面命令在验证集上单独评估:

python val.py \ --data /path/to/nodule.yaml \ --weights runs/train/exp/weights/best.pt \ --img 640 \ --conf-thres 0.001 \ --iou-thres 0.6

注意--conf-thres设为 0.001 是为了在验证时统计所有可能的目标框,避免因为置信度阈值过高而遗漏低置信度漏检。真正做推理时再使用 0.25 或 0.5。

评估结果里mAP@0.5mAP@0.5:0.95要分开看。肺结节这类小目标,mAP@0.5 可能在 0.7 以上,但 mAP@0.5:0.95 往往低不少,因为 IoU 阈值提高后,框位置稍有偏差就判为不匹配。这并不完全代表模型差,而是小目标定位精度本来就难。

如果你需要把训练好的模型导出为 ONNX 或 TensorRT 做推理,可以使用export.py。但要注意,导出的模型输入尺寸固定,最好用训练时的--img一致的值,否则精度会下降。这个小数据集的实验价值就在于此:你能在几小时内快速验证一套端到端流程是否可行。

5. 小目标调参:锚框、数据增强与验证技巧

肺结节检测的难点不在类别区分,而在「目标太小」。248 张图、单类别,默认 COCO 锚框可能不是最优。这一章给三个可落地的技巧。

5.1 用 autoanchor 重算锚框

YOLOv5 会根据数据集自适应锚框,训练时会自动计算(也可以禁用)。小数据集上建议先用utils/autoanchor.py工具重新计算:

python utils/autoanchor.py --data nodule.yaml --img 640

它会统计所有标签的宽高分布,输出新的锚框建议。如果输出的锚框与默认值差别较大,可以在yolov5s.yaml中手动替换anchors字段,再重新训练。注意 autoanchor 的结果要放到模型 yaml 里,而不是 data yaml 里。这一步对肺结节这种尺寸变化大的目标很有用,因为 CT 结节直径从 3mm 到 30mm 都有,对应像素差异接近 10 倍,固定锚框覆盖不全。

如果重算锚框后 mAP 反而下降,可以保留默认锚框,因为对于数据量极小的场景,预训练锚框携带的分布先验可能比数据统计更可靠。此时--noautoanchor参数可以强制关闭自动锚框计算。

5.2 降低 mosaic 增强对医学小目标的影响

YOLOv5 默认开启 mosaic 增强,将四张图拼接成一张。对普通目标检测是好事,但对肺结节来说,拼接后每个结节被进一步缩小,容易变成 2-3 像素的噪声。我一般会在小目标场景把 mosaic 概率从 1.0 降到 0.5 甚至关闭,方法是在训练命令里指定 hyp 文件:

python train.py --data nodule.yaml --hyp hyp.scratch-low.yaml --epochs 100

然后编辑hyp.scratch-low.yaml中的mosaic: 0.5mosaic: 0.0。同时保留轻微尺度抖动scale: 0.5,帮助模型适应不同大小的结节。如果之后发现正样本数量太少,还可以开启copy_paste,但它对小目标的增益不明显,反而增加训练时间,不建议优先尝试。

5.3 用特征图或结果图确认漏检原因

训练完成后,用detect.py在验证集上输出带框图片,重点看假阴性样本。对于漏检的结节,检查它周围是否有血管截面或其他高密度组织干扰。如果某几个固定位置漏检,往往是标注问题而非模型问题,回到第 3 章的可视化脚本复查那几张图。另一个办法是打印results.png中的 P、R 曲线,观察 Recall 是否在低 confidence 区间有突然下跌,如果有,说明漏检集中在小目标上,可以考虑提高输入分辨率或者重新调整锚框。

清理未标注的近空白样本或去除异常小的标注后重训练,通常能稳定提升 1-2 个点的 mAP。这种反复验证标注质量的过程,比盲目调超参数更值得做。

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

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

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

立即咨询