首页 / 资讯中心 / 文章详情

YOLO肺结节检测数据集:5000张CT标注与训练全流程

YOLO肺结节检测数据集:5000张CT标注与训练全流程 ★ FEATURED ARTICLE
简介这份YOLO肺结节目标检测数据集面向医学影像检测方向的算法学习者与研究者提供真实场景下的高质量肺结节图片可用于YOLO系列模型的训练与验证。资源包共2000个文件以1986个xml标注文件为主另含少量html说明文档、txt列表与py脚本压缩包约77.56MB标注由labelimg完成同时提供voc、coco和yolo三种格式标签分别存放于不同文件夹可直接对接主流检测框架。配套内容还包含数据集划分脚本可按需生成训练集、验证集与测试集并附有Windows与Linux环境搭建及训练教程帮助读者从环境配置到模型训练完整跑通流程。目前已有403人学习下载适合希望快速上手肺结节检测任务、减少数据准备成本的读者参考使用。1. 从一批肺结节 CT 片子说起这套 YOLO 数据集到底能省掉多少标注功夫手里有一批肺部 CT 影像想跑一个肺结节目标检测模型最耗时的环节从来不是调网络结构而是把几千张片子的结节位置一个个框出来、再转成训练框架认的格式。这套 YOLO 肺结节目标检测数据集就是冲着这个痛点来的5000 张真实场景图片用 labelImg 标注同时给出 VOCxml、COCOjson、YOLOtxt三种格式标签分文件夹放好拿到手就能直接喂给 YOLO 系列。它还附了环境搭建、训练教程和三个数据集划分脚本Windows 和 Linux 两套流程都覆盖了。适合谁刚入门 YOLO 想找个真实医学场景练手的人或者手头有检测任务、想先拿一份标注质量过关的数据把 pipeline 跑通再换自己数据的从业者。下面我按「数据长什么样 → 怎么划分 → 怎么训 → 坑在哪」拆一遍。2. 三种标签格式与目录结构先搞清 VOC、COCO、YOLO 各存了什么拿到压缩包别急着解压完就开训先把标签格式和目录结构理清楚否则后面划分脚本一跑路径对不上报错能让你查半天。这一章讲清楚三种格式的差异、各自适用场景以及怎么用脚本把它们读进来验证一遍。2.1 VOC、COCO、YOLO 三种标注格式的本质区别同样是「一个框」三种格式记录方式完全不同这也是很多人第一次接触时最容易懵的地方。VOC 格式是每张图对应一个同名 xml 文件框的信息写在object节点里坐标是左上角xmin,ymin和右下角xmax,ymax的绝对像素值类别名写在name里。它的好处是可读性强labelImg 默认就存这个缺点是文件多、解析慢。COCO 格式是整份数据集一个 json里面images、annotations、categories三个大数组框的坐标是[x, y, width, height]绝对像素category_id是数字。它适合做评测和跨框架迁移但单看 json 很难肉眼核对。YOLO 格式是每张图一个同名 txt每行一个目标格式是class_id x_center y_center width height后四个全是归一化到 0~1 的相对值。它最紧凑训练时读取最快但归一化坐标一旦算错框会整体偏移而且肉眼不容易发现。格式存储方式坐标类型类别表示典型用途VOC每图一个 xml绝对像素字符串名labelImg 原生、可读核对COCO单 json绝对像素数字 id评测、跨框架迁移YOLO每图一个 txt归一化相对值数字 idYOLO 系列直接训练提示三种格式的类别顺序不一定一致。VOC 里是字符串名COCO 和 YOLO 里是数字 id转换或混用时务必先确认classes.txt或categories的顺序否则会出现「框对了但类别全错」的玄学现象。2.2 用一段脚本把三种格式读进来做一致性校验在正式划分之前我习惯先写个小脚本把三种格式各读一遍确认图片数量、标注数量、类别集合能对上。这一步花五分钟能省掉后面几小时的排查。import os import json import xml.etree.ElementTree as ET # 三个标签目录按实际解压路径改 VOC_DIR Annotations # xml 所在 COCO_JSON annotations.json # coco 单文件 YOLO_DIR labels # txt 所在 IMG_DIR images # 图片所在 # 1. 统计图片 imgs [f for f in os.listdir(IMG_DIR) if f.lower().endswith((.jpg, .png, .jpeg))] print(图片数量:, len(imgs)) # 2. 统计 VOC 标注与类别 voc_classes set() voc_count 0 for f in os.listdir(VOC_DIR): if not f.endswith(.xml): continue voc_count 1 tree ET.parse(os.path.join(VOC_DIR, f)) for obj in tree.getroot().findall(object): voc_classes.add(obj.find(name).text) print(VOC 标注文件数:, voc_count, 类别:, voc_classes) # 3. 统计 COCO 类别 with open(COCO_JSON, r, encodingutf-8) as fp: coco json.load(fp) coco_classes {c[id]: c[name] for c in coco[categories]} print(COCO 类别:, coco_classes, 标注数:, len(coco[annotations])) # 4. 统计 YOLO 类别 id yolo_ids set() yolo_count 0 for f in os.listdir(YOLO_DIR): if not f.endswith(.txt): continue yolo_count 1 with open(os.path.join(YOLO_DIR, f)) as fp: for line in fp: if line.strip(): yolo_ids.add(int(line.split()[0])) print(YOLO 标注文件数:, yolo_count, 类别 id:, yolo_ids)逻辑说明先数图片再分别数三种标签最后把类别集合打印出来对比。参数上VOC_DIR、COCO_JSON、YOLO_DIR、IMG_DIR四个路径按你解压后的实际目录改别照抄。跑完如果发现 VOC 类别是{nodule}COCO 是{0: nodule}YOLO 的 id 只有{0}那就说明三套标签是一致的可以放心往下走。如果数量对不上先别划分回去查是不是有图片漏标或者标签文件名和图片名不匹配。2.3 目录结构建议划分前先规整成标准布局原始压缩包里三种格式是分文件夹放的但划分脚本通常期望一个更规整的布局。我一般会整理成这样再跑脚本dataset/ ├── images/ # 所有图片 ├── Annotations/ # VOC xml ├── labels/ # YOLO txt ├── annotations.json # COCO ├── classes.txt # 类别名一行一个 └── ImageSets/ # 划分脚本输出目录classes.txt很关键很多划分和训练脚本都靠它确定类别数和顺序。肺结节这个场景一般就一个类写一行nodule即可。整理好之后图片名和标签名必须严格一一对应除了扩展名这是后面所有脚本能跑通的前提。3. 三个划分脚本怎么用训练集、验证集、测试集的切分逻辑与参数数据集划分看着简单其实是最容易埋雷的一步。划分比例、是否分层、随机种子、输出路径任何一个没处理好都会导致训练时验证指标虚高或者直接找不到文件。这一章把压缩包里三个划分脚本的用途、调用方式和参数讲透。3.1 三个脚本分别解决什么问题压缩包里给了三个划分脚本名字不同用途也不同别混着用。第一个是「训练集、验证集、测试集划分脚本图片标签划分写入新文件夹.py」它做的是三路划分并且会把图片和标签实际复制到新的 train/val/test 文件夹里适合你想物理隔离三份数据的情况。第二个是「训练集、验证集划分脚本图片标签划分写入新文件夹.py」只切 train 和 val 两路同样复制文件适合数据量不大、不需要单独测试集的场景。第三个是「split_train_val生成ImageSets下txt文件划分脚本.py」它不复制图片只在ImageSets下生成train.txt、val.txt这类索引文件里面写图片路径。YOLO 官方训练流程更常用这种索引方式省磁盘、改划分也方便。选哪个取决于你的训练框架怎么读数据。用 Ultralytics 的 YOLO通常用索引 txt 就够了如果你用的是自己写的 dataloader可能更习惯物理分文件夹。3.2 三路划分脚本的调用与参数调整以三路划分脚本为例核心逻辑是读所有图片名打乱后按比例切分再把图片和对应标签复制过去。调用前先看脚本头部的配置区。# 划分脚本核心参数区按实际脚本变量名对照修改 import os import random import shutil random.seed(42) # 固定随机种子保证可复现 train_ratio 0.7 # 训练集比例 val_ratio 0.2 # 验证集比例 # 剩下 0.1 自动归测试集 IMG_SRC images # 原图目录 LABEL_SRC labels # YOLO txt 目录 OUT_ROOT split_dataset # 输出根目录 for split in [train, val, test]: os.makedirs(os.path.join(OUT_ROOT, images, split), exist_okTrue) os.makedirs(os.path.join(OUT_ROOT, labels, split), exist_okTrue) names [os.path.splitext(f)[0] for f in os.listdir(IMG_SRC) if f.lower().endswith((.jpg, .png, .jpeg))] random.shuffle(names) n len(names) n_train int(n * train_ratio) n_val int(n * val_ratio) splits { train: names[:n_train], val: names[n_train:n_train n_val], test: names[n_train n_val:] } for split, items in splits.items(): for name in items: # 复制图片扩展名按实际改 shutil.copy(os.path.join(IMG_SRC, name .jpg), os.path.join(OUT_ROOT, images, split, name .jpg)) # 复制标签 shutil.copy(os.path.join(LABEL_SRC, name .txt), os.path.join(OUT_ROOT, labels, split, name .txt)) print(split, len(items))逻辑说明random.seed(42)是后悔药固定种子后每次划分结果一致方便复现实验。train_ratio和val_ratio按需改医学数据量不大时常见 7:2:1 或 8:1:1。IMG_SRC、LABEL_SRC、OUT_ROOT三个路径按你的目录改。脚本跑完会打印每份的数量三个数加起来应该等于总图片数对不上就说明有图片没有对应标签被跳过了。参数上要特别注意扩展名。脚本里写死了.jpg如果你的图片是.png复制那一步会直接报文件不存在。稳妥做法是把扩展名也做成可配置或者先统一转成 jpg。3.3 生成 ImageSets 索引的脚本与 YOLO 训练配置对接如果你走索引路线用第三个脚本生成train.txt、val.txt。它不复制文件只写路径速度快很多。# 生成的 ImageSets 目录结构 ImageSets/ ├── train.txt # 每行一个图片路径如 images/xxx.jpg ├── val.txt └── test.txt生成之后在 YOLO 的data.yaml里对接path: /abs/path/to/dataset train: ImageSets/train.txt val: ImageSets/val.txt test: ImageSets/test.txt nc: 1 names: [nodule]逻辑说明path是数据集根目录train/val/test指向索引 txtnc是类别数肺结节单类就写 1names顺序必须和classes.txt一致。这里最常见的翻车是路径写成相对路径但训练时工作目录变了导致找不到文件。我一般直接写绝对路径省心。注意索引 txt 里如果写的是相对路径是相对于path还是相对于运行目录不同版本行为可能不同。拿不准就写绝对路径或者先跑一个 epoch 看能不能读到数据。3.4 划分比例与随机种子的取舍划分比例没有标准答案但有几个经验值。数据量 5000 张这个级别7:2:1 比较稳验证集留 1000 张足够评估。如果类别极不平衡比如小结节样本很少纯随机划分可能导致某个子集里几乎没有正样本这时候要做分层抽样按类别比例切。压缩包里的脚本是纯随机遇到不平衡场景需要自己改。随机种子建议固定尤其是你要对比不同模型或不同超参时划分必须一致否则指标波动你分不清是模型变了还是数据变了。我见过有人每次训练都重新随机划分然后纳闷为什么同样的配置结果差好几个点这就是典型的没固定种子。4. 环境搭建与训练Windows 和 Linux 两套流程的关键差异压缩包里给了 Windows 和 Linux 两套环境搭建和训练教程还有 Ubuntu 安装教程。这一章不重复教程里的每一步而是把两套流程里最容易出问题的地方挑出来讲尤其是 CUDA、PyTorch、Ultralytics 版本匹配这几个老生常谈但每次都有人栽的环节。4.1 Windows 环境搭建CUDA 与 PyTorch 版本对齐Windows 上搭 YOLO 环境翻车重灾区是 CUDA 版本、显卡驱动、PyTorch 版本三者不匹配。正确顺序是先看显卡驱动支持的最高 CUDA 版本再选对应的 PyTorch。# 1. 查看显卡驱动支持的 CUDA 版本 nvidia-smi # 右上角 CUDA Version 就是驱动支持的上限 # 2. 建虚拟环境conda 为例 conda create -n yolo python3.10 -y conda activate yolo # 3. 按 nvidia-smi 显示的版本装 PyTorch # 假设显示 CUDA 12.1去 PyTorch 官网找对应命令例如 pip install torch torchvision --index-url https://download.pytorch.org/whl/cu121 # 4. 验证 GPU 可用 python -c import torch; print(torch.cuda.is_available())逻辑说明nvidia-smi显示的 CUDA Version 是驱动能支持的最高版本不是你必须装的版本装低一点通常也能用。torch.cuda.is_available()返回 True 才算成功。如果返回 False八成是装成了 CPU 版或者版本不匹配卸载重装。虚拟环境一定要建别在 base 里折腾否则依赖冲突能让你重装系统。4.2 Linux/Ubuntu 环境搭建权限与依赖的坑Linux 上流程类似但多了权限和系统依赖的问题。Ubuntu 装完显卡驱动后同样先nvidia-smi确认。常见坑是 conda 装完 PyTorch 后torch.cuda.is_available()为 False原因往往是驱动没装好或者装了开源驱动 nouveau。# 确认驱动 nvidia-smi # 如果没输出或报错检查是否装了官方驱动 ubuntu-drivers devices # 按推荐版本安装例如 sudo apt install nvidia-driver-535 # 装完必须重启 sudo reboot逻辑说明ubuntu-drivers devices会列出推荐驱动版本按推荐的装最稳。装完驱动一定要重启不重启nvidia-smi可能还是报错。另外 Linux 下如果用了 conda注意LD_LIBRARY_PATH有时会干扰 CUDA 库加载遇到诡异报错可以先unset LD_LIBRARY_PATH试试。4.3 用案例配置改自己的数据集data.yaml 与模型选择教程里给的是案例配置换成肺结节数据集主要改两处data.yaml和模型配置文件里的类别数。# data.yaml path: /abs/path/to/split_dataset train: images/train val: images/val test: images/test nc: 1 names: [nodule]# 训练命令以 Ultralytics YOLO 为例 yolo detect train datadata.yaml modelyolov8n.pt epochs100 imgsz640 batch16逻辑说明model用预训练权重起步收敛快很多。imgsz是输入尺寸肺结节在 CT 上通常不大640 是常见起点如果小结节多可以试 1024但显存和速度要权衡。batch按显存调爆显存就减半。epochs100 起步看验证指标是否还在降再决定加不加。训练日志里重点看mAP50和mAP50-95前者宽松后者严格医学检测更该关注后者。4.4 训练过程监控与中断恢复训练跑起来后别干等盯几个信号。loss 不降反升可能是学习率太大或者标注有问题mAP 一直上不去可能是数据量不够或者类别定义有误。Ultralytics 默认会在runs/detect/train下存权重和日志中断了可以用resume接着跑。# 中断后恢复训练 yolo detect train resume modelruns/detect/train/weights/last.pt逻辑说明resume会从last.pt恢复优化器状态和 epoch比重新加载权重接着训更完整。前提是原来的runs目录还在。我一般训练前先确认磁盘空间够权重文件加上日志跑几百 epoch 也能占几个 G。5. 避坑与排查标注、划分、训练里最常见的五类翻车这一章全是血泪经验每条按「现象 → 原因 → 解决」写遇到问题直接对号入座。5.1 训练报错找不到标签文件现象训练启动后报No labels found或者images and labels count mismatch。原因图片名和标签名不一致或者data.yaml里的路径指向了图片目录但标签在另一个目录YOLO 默认按同名规则找标签。解决先跑第 2.2 节的一致性校验脚本确认每张图都有同名 txt。如果标签和图片不在同一级目录检查data.yaml的路径配置必要时把标签和图片放到对应结构下。5.2 框整体偏移或尺寸不对现象训练能跑但预测出来的框位置明显偏或者框特别大特别小。原因YOLO 格式要求归一化坐标如果转换时用了绝对像素没除以宽高或者 VOC 转 YOLO 时把xmax,ymax当成了宽高框就会错。解决抽查几个 txt确认后四个值都在 0~1 之间。如果大于 1说明没归一化。VOC 转 YOLO 的正确公式是x_center(xminxmax)/2/widthwidth(xmax-xmin)/width别搞反。5.3 验证集指标虚高现象验证集 mAP 很高但拿新数据一测就崩。原因划分时没有固定随机种子或者训练集和验证集有重复图片导致验证集泄漏。解决固定random.seed划分后去重确认 train 和 val 没有交集。另外检查是不是同一张图的不同增强版本同时进了训练和验证。5.4 CUDA out of memory现象训练中途报显存不足。原因batch或imgsz太大或者没释放上一次的缓存。解决先减batch再考虑减imgsz。训练前torch.cuda.empty_cache()清一下。如果还是不够用梯度累积模拟大 batch。5.5 类别 id 从 1 开始导致全错现象训练不报错但预测类别全是背景或者错位。原因VOC 转 YOLO 时类别 id 从 1 开始编号而 YOLO 要求从 0 开始。解决转换时统一减 1或者检查classes.txt和实际 txt 里的 id 是否从 0 开始。这个坑很隐蔽因为训练不会报错只是结果不对。6. 进阶技巧用预训练权重和分层抽样把肺结节检测效果再拉一档数据划分和训练跑通只是及格线想把肺结节检测做到能用还有两个技巧值得花时间一是用好预训练权重和迁移学习二是针对小结节做分层抽样和尺寸适配。先说预训练权重。肺结节数据集 5000 张说多不多从零训容易过拟合。常见做法是加载 COCO 预训练的 YOLO 权重冻结 backbone 先训几轮再解冻全量微调。冻结阶段学习率可以设大一点解冻后调小。我一般分两段前 20 epoch 冻结lr00.01后 80 epoch 解冻lr00.001。这样收敛比从头训快最终 mAP 通常也高几个点。# 第一阶段冻结 backbone yolo detect train datadata.yaml modelyolov8n.pt epochs20 freeze10 lr00.01 # 第二阶段解冻微调 yolo detect train datadata.yaml modelruns/detect/train/weights/last.pt epochs80 lr00.001freeze10表示冻结前 10 层具体层数看模型结构backbone 一般在前十几层。这个参数不是越大越好冻太多反而限制拟合能力。再说分层抽样。肺结节有大有小纯随机划分可能让验证集里全是大结节指标好看但没意义。改进做法是按结节面积分档每档按比例抽到 train/val/test。实现上先读每个 YOLO txt 算框面积分箱后再切分。这样验证集能覆盖各种尺寸指标更可信。最后是输入尺寸。640 对小结节可能不够结节在 CT 上可能只占几十像素缩到 640 后更小。如果显存允许试 1024 甚至 1280配合rect训练减少填充。代价是速度慢但医学检测对召回更敏感值得。从那以后我每次拿到新数据集都强制先跑一遍一致性校验、固定种子划分、再抽查几个标注框的归一化值这三步走完才开训。希望帮到你。本文还有配套的精品资源点击获取
阅读完成 · 觉得有帮助?
咨询建站