YOLO直肠息肉检测数据集:txt与xml双标注解析及训练避坑指南
简介面向直肠息肉检测场景的YOLO格式数据集专为医学图像目标检测任务设计既适合刚接触目标检测的初学者快速搭建训练流程也适合研究人员在此基础上进行算法改进与对比。包体共19795个文件其中包含7804张jpg原图、7161个xml标注文件与4830个txt标签文件xml对应VOC格式、txt为YOLO格式可直接适配不同版本的YOLO及主流检测框架省去繁琐的格式转换工作。数据集中图像涵盖原始样本与数据增强样本可扩充训练数据量有助于提升模型在真实场景中的泛化能力。压缩包整体约177.21MB解压后即可直接用于模型训练与验证。目前已有1146人学习下载对于缺乏标注数据或希望快速验证检测算法的医学影像学习者而言是一份即取即用的合格数据集能显著减少数据准备时间使学习者聚焦模型设计与调优。1. YOLO直肠息肉检测数据集先看懂txt与xml双标注再谈训练在直肠息肉检测的实际项目里真正劝退人的不是模型选型而是数据标注没吃透。这份YOLO直肠息肉检测数据集把每张内镜图片同时给出txt和xml两种标签txt是YOLO训练直接吃的归一化坐标xml是VOC习惯的绝对像素框图片命名里的_Aug后缀代表经过增强的衍生样本。对单类息肉检测这类任务它最大的价值是省掉了格式迁移的重复劳动摆好目录、写好yaml就能在YOLOv5或YOLOv8上跑通。适合消化道内镜AI辅助诊断的工程师、复现目标检测流程的研究生以及刚接触YOLO训练的新手。不过拿到数据先别急着训练。txt和xml双格式意味着给了两边互相验证的机会我习惯先把标注全部扫一遍确认没有空标签和越界坐标再动训练命令省掉后期大量排错时间。下面按我实际拆这套数据的顺序从标注格式讲到训练、避坑和部署。2. 数据集结构与标注格式txt归一化坐标和xml绝对像素的对照2.1 文件命名与_Aug增强版本从哪来打开数据集目录最先看到的是图片文件名的规律IM_3901_Aug.jpg、IM_1534_Aug.jpg、IM_28_Aug.jpg。这里IM是原始内镜图像编号Aug是augmentation的缩写。这批_Aug后缀的图片通常是在原始图像上做了翻转、旋转、亮度对比度扰动后生成的目的是让模型看到同一病灶在不同姿态、不同光照下的表现提升泛化能力。对内镜图像来说这格外重要因为肠道环境里有暗角、高光反光、褶皱阴影真实形态变化很大。在动手之前先核对图片与标注文件的数量对应关系。图片、txt、xml三者之间只要数量对不上或者同名文件缺失训练时就会报数据集读取错误。用脚本快速扫一遍能省下半天排查时间import glob, os imgs sorted(glob.glob(images/*.jpg)) txts sorted(glob.glob(labels_txt/*.txt)) xmls sorted(glob.glob(labels_xml/*.xml)) print(f图片数量: {len(imgs)} txt标签: {len(txts)} xml标签: {len(xmls)}) names_img {os.path.basename(f).replace(.jpg, ) for f in imgs} names_txt {os.path.basename(f).replace(.txt, ) for f in txts} names_xml {os.path.basename(f).replace(.xml, ) for f in xmls} print(缺txt的图片:, names_img - names_txt) print(缺xml的图片:, names_img - names_xml)这段脚本的逻辑是先按扩展名分别收集三类文件再去掉扩展名做集合比对。集合差集能直接列出哪些图片缺少标注哪些标注文件没有对应图片。对这类带增强版本的数据集我还会额外检查原始图与增强图是否都存在——如果只有IM_28_Aug.jpg而没有IM_28.jpg说明发布方只放了增强子集这也影响后续训练验证集划分时的分组策略。2.2 txt标签一行五个数字的YOLO格式YOLO系列的txt标注每行代表一个目标格式是五个数值类别编号class_id、中心点归一化横坐标cx、中心点归一化纵坐标cy、归一化宽w、归一化高h。归一化的含义是所有坐标都除以图片自身的宽和高因此数值范围在0到1之间如果标注框恰好贴住图片边缘理论最大值会接近1但超出1就属于越界标注模型训练时容易产生梯度震荡。用一段Python快速读取任意一个txt标签可以看到具体结构label_path labels_txt/IM_28_Aug.txt with open(label_path, r) as f: lines f.readlines() for line in lines: parts line.strip().split() if len(parts) 5: cls, cx, cy, w, h parts cx, cy, w, h float(cx), float(cy), float(w), float(h) print(f类别编号: {cls}) print(f中心点归一化: ({cx:.4f}, {cy:.4f})) print(f宽高归一化: ({w:.4f}, {h:.4f}))上面这段的核心逻辑是按空格拆分每行前一个字段是类别编号后四段转成浮点数。对单类息肉检测cls通常为0。这里必须注意归一化的宽高是相对整张图的比例不是像素值。要把它换算回像素框必须乘以图像的实际宽和高。这也是新手最容易踩坑的地方——把归一化值当成像素坐标直接画框画出来的框位置天差地别。2.3 xml标签VOC风格框和转换关系xml标签采用VOC格式结构比txt更直白根节点下有size节点记录图像宽高然后每个object节点对应一个目标里面用bndbox子节点保存min、ymin、xmax、ymax四个绝对像素坐标。xml的好处是信息完整既能知道目标类别名又能直接拿到像素框缺点是占空间大读取速度比txt慢。很多发布方同时给txt和xml就是让使用者按自己的习惯任选。用Python解析xml并把它和txt坐标做交叉验证是判断数据集标注质量最有效的办法import xml.etree.ElementTree as ET from PIL import Image img Image.open(images/IM_28_Aug.jpg) W, H img.size print(f图像尺寸: {W} x {H}) tree ET.parse(labels_xml/IM_28_Aug.xml) root tree.getroot() size root.find(size) xml_W int(size.find(width).text) xml_H int(size.find(height).text) print(fxml记录尺寸: {xml_W} x {xml_H}) for obj in root.findall(object): name obj.find(name).text box obj.find(bndbox) xmin int(box.find(xmin).text) ymin int(box.find(ymin).text) xmax int(box.find(xmax).text) ymax int(box.find(ymax).text) print(f类别: {name}, 像素框: ({xmin}, {ymin}, {xmax}, {ymax}))这段脚本先读取图像真实尺寸再去xml里取size节点两者不一致就说明图片被改过尺寸但标注没更新。接着遍历每个object取出bndbox的四个绝对坐标。我一般还会把txt归一化坐标反向换算和xml的像素框对照IoU低于0.9就要重点排查具体换算脚本会在避坑章节给出。这一步的作用相当于给数据集做体检体检不过关后面训练再久也是事倍功半。3. 用YOLOv8把数据跑起来目录组织、yaml配置与训练参数3.1 训练验证集拆分与目录结构确认标注质量之后接下来就是把数据组织成YOLO训练的标准目录。YOLOv8默认的目录约定是datasets下按数据集名分目录内部再分images和labels两个大分支底下各建train和val子目录。图片和标签文件的主文件名必须保持一致txt放labels里jpg放images里。这么做的好处是框架自动按同名文件去匹配图片和标签不需要额外写映射文件。由于数据集里同时存在原始图和_Aug增强图拆分时不能简单用随机函数。我习惯的做法是先从文件列表里提取原始编号按编号分组后再拆保证同一来源的增强样本全部进训练集或全部进验证集后面避坑章节会解释原因。这里先给出基本拆分脚本import os, shutil from sklearn.model_selection import train_test_split image_dir images label_dir labels_txt base_names [f for f in os.listdir(image_dir) if f.endswith(.jpg)] train_names, val_names train_test_split( base_names, test_size0.2, random_state42 ) for split, names in [(train, train_names), (val, val_names)]: img_out fpolyps/images/{split} lbl_out fpolyps/labels/{split} os.makedirs(img_out, exist_okTrue) os.makedirs(lbl_out, exist_okTrue) for img_name in names: stem os.path.splitext(img_name)[0] shutil.copy( os.path.join(image_dir, img_name), os.path.join(img_out, img_name) ) shutil.copy( os.path.join(label_dir, f{stem}.txt), os.path.join(lbl_out, f{stem}.txt) )这段脚本用train_test_split按8:2划分random_state固定成42保证每次运行结果一致。复制图片时同步复制同名txt标签确保两个目录始终一一对应。如果内存充足我更倾向直接在命令行里用shutil移动而不是复制能省一半磁盘空间。但作为初始流程先copy一份保留原始数据更稳妥毕竟后面要反复试验各种预处理。3.2 data.yaml单类目标检测的配置要点目录结构搭好后需要写一个data.yaml告诉YOLOv8训练数据在哪、类别有几个、类别名是什么。这个文件是整个训练流程的枢纽路径写错了或者类别数不对训练过程会以各种诡异方式翻车。对息肉检测这种单类任务配置很简洁# polyps.yaml path: ./polyps train: images/train val: images/val nc: 1 names: [polyp]这里path是数据集根目录train和val相对路径对应上面脚本建好的子目录。nc代表类别数量息肉检测只有一类所以是1。names列表里写类别名顺序必须和txt标签里的类别编号一致——编号0对应names[0]。如果数据集里还有病理类型细分比如“腺瘤性息肉”“增生性息肉”nc就要改成对应数值names也要同步扩展。这个文件的坑集中在相对路径和绝对路径混用YOLOv8里path用相对路径时train和val就不要再加数据集根目录前缀了。3.3 训练命令和关键超参数配置就绪后训练命令比想象中直接。以YOLOv8为例命令行里指定data、model、epochs、imgsz、batch五个参数就能启动yolo train datapolyps.yaml modelyolov8n.pt epochs100 imgsz640 batch8参数含义分别是data指定yaml配置model指定预训练权重或模型结构epochs是训练轮数imgsz是输入图片分辨率batch是batch size。对于息肉检测我通常第一轮用imgsz640、batch8先跑通流程确认loss正常下降后再根据显存情况把imgsz提到768或960试一次。原因是肠道息肉在整张内镜图里占比偏小分辨率越高对小目标越友好但显存占用也随之上升。训练过程中值得盯的指标有三处训练loss、验证mAP50、以及训练结束时的混淆矩阵。loss下降但mAP不涨大概率是标注噪声过大或者模型容量不够mAP50高但mAP50-95低说明框定位精度一般需要更大输入尺寸或更好的正则手段。我一般让tensorboard或wandb开着实时曲线前20轮就能判断模型有没有在学东西不用傻等100轮结束。4. 避坑指南直肠息肉检测训练中的五个翻车现场4.1 增强图像标注框漂移现象训练到中后期loss卡在0.04到0.07之间不再下降验证集上框经常压着息肉边界或者框住肠壁褶皱阴影。原因_Aug增强图片在生成时标注框没有跟随图像一起变换。比如图像旋转了15度目标框仍用原始坐标直接写回txt相当于给训练集系统性掺入了错标样本。模型在矛盾标注里反复震荡损失自然降不下去。解决抽样对比IM_28.jpg和IM_28_Aug.jpg的坐标换算关系用图像变换矩阵反推旋转后框的位置确认是否出现系统性偏移。如果确认是增强时未同步更新标注就删掉错标样本只保留坐标正确的增强版本。以后自己生成增强数据用albumentations这类库时一定要带上BboxParams同步变换这是正规解法。4.2 txt与xml坐标混用现象同一张图用txt解析出的框和用xml解析出的框位置差很远训练时验证mAP忽高忽低但训练loss看起来正常。原因txt的cx是中心点坐标除以图宽xml的xmin是左上角绝对像素值。有人写代码时把txt的归一化值当像素值直接用或者把xml的xmin当成中心坐标两种格式的语义完全不是一回事混用后目标框整体平移半个图宽。解决用下面的换算脚本在训练前批量验证坐标一致性from PIL import Image img_path images/IM_28_Aug.jpg W, H Image.open(img_path).size with open(labels_txt/IM_28_Aug.txt, r) as f: cls, cx, cy, w, h f.readline().strip().split() cx, cy, w, h float(cx), float(cy), float(w), float(h) pixel_w, pixel_h w * W, h * H tx_min int(cx * W - pixel_w / 2) tx_ty int(cy * H - pixel_h / 2) tx_x_max int(cx * W pixel_w / 2) tx_y_max int(cy * H pixel_h / 2) print(ftxt转像素框: ({tx_min}, {tx_ty}, {tx_x_max}, {tx_y_max}))这段脚本把txt归一化坐标换算成像素框输出结果和xml的bndbox直接比较重叠不达标就说明格式转换有bug。从那以后我每次拿到新数据集都会先把这张检查表跑完再开始训练。4.3 类别数误设导致权重加载报错现象加载预训练权重时直接报错Error(s) in loading state_dict for DetectionModel训练能启动但mAP一直为0或者推理输出维度异常。原因YOLO预训练权重基于COCO的80类模型检测头最后一层的卷积输出维度是80。息肉数据集只有一类nc1权重文件的类别相关层参数个数对不上。还有人在data.yaml里漏改nc沿用默认80导致类别编号越界或预测维度错乱。解决data.yaml里明确写nc: 1names只留polyp一个。更稳妥的做法是用yolov8n.yaml而不是yolov8n.pt作为model参数让框架从结构定义开始构建再配合pretrainedTrue加载预训练参数系统会自动跳过维度不匹配的层。4.4 小目标漏检imgsz与模型尺寸的选择现象验证集mAP50看着有0.85以上放到真实内镜视频里息肉框总是框住半个病灶还把黏膜反光当目标。原因肠道息肉在画面中占比很小默认imgsz640时小目标经过多次下采样后特征已经很弱加上内镜反光区域和病灶颜色接近容易误检。评估指标高是验证集难度偏低真实场景分布一变化就露馅。解决训练时把imgsz调到768或960显存不够就优先换大模型到m或者减少batch。推理时把conf阈值降到0.15到0.2配合NMS的iou阈值调整把低置信度候选框也召出来人工确认。这个组合对内镜场景非常有效代价是推理速度下降需要按实际硬件权衡。4.5 验证集信息泄漏增强图与原图重叠现象验证mAP高得离谱但换到外部公开图片检测效果惨不忍睹典型的过拟合信号。原因原始图和增强图同属一个场景如果IM_28.jpg分到训练集IM_28_Aug.jpg也留在训练集而验证集里其他样本又都来自同一原始图族模型等于变相背过了验证集的纹理信息指标虚高。解决拆分时按原始文件名中的编号分组把IM_28相关的所有图片看成一整组整组进训练集或整组进验证集。具体实现是在文件名解析时提取IM_后面的数字作为分组key用GroupKFold或按组列表划分替代直接随机拆分。5. 评估与部署mAP验证、ONNX导出和端侧实测5.1 验证集指标怎么看训练结束后用YOLOv8自带的验证命令在测试集上跑一遍得到结果yolo detect val modelruns/detect/train/weights/best.pt datapolyps.yaml conf0.001这里把conf设到0.001是为了最大化召回评估阶段宁可多框不要漏框mAP计算会通过精度召回曲线综合判定。对息肉检测我重点看两个指标mAP50反映最基本的定位能不能打中病灶mAP50-95反映框的定位精度。如果前者在0.85以上而后者低于0.4说明框不紧、位置偏移大优先怀疑标注框本身的边界不够准确。5.2 ONNX导出和实测筛选精度满意后把模型导出成ONNX格式做端侧部署验证yolo export modelruns/detect/train/weights/best.pt formatonnx imgsz640 opset12opset指定算子集版本旧设备跑不起来时降到11或12。导出后用onnxruntime加载推理验证一下onnx和pt的输出差异是否在误差范围内。我每次导出完都会跑一张验证图对比推理结果确保导出流程没破坏模型结构再进入具体部署环节。做完这一整套流程我对数据集质量、模型最佳参数和部署链路都有了底。这份资源里txt和xml双格式的标注很适合拿来验证自己的坐标转换逻辑_Aug增强样本也给了练手清洗脏数据的机会。从那以后我每次拿到新数据集都强制先跑一遍标注体检脚本、再做分组拆分、最后才动训练命令这个习惯帮我避开过至少五次标注格式导致的无效训练。希望帮到你祝复现顺利。本文还有配套的精品资源点击获取