ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

915张痤疮图像VOC+YOLO双格式数据集:目标检测训练与避坑指南

915张痤疮图像VOC+YOLO双格式数据集:目标检测训练与避坑指南 简介痤疮检测数据集面向皮肤科辅助诊断、医学图像识别方向的算法开发者与高校学生用于训练和验证单类别目标检测模型。资源采用Pascal VOC与YOLO双格式标注包含915张jpg图片及一一对应的915个xml文件和915个txt文件标注类别为cuochuang共11807个矩形框全部由labelImg工具人工绘制可直接接入YOLO系列或VOC兼容框架进行训练。压缩包为7z格式共约2000个文件以txt标签、xml标注和jpg图像为主整体约31.74MB体积轻便便于快速下载与本地部署。目前已有206人学习下载适合作为医学小目标检测的入门练手数据帮助读者省去自行采集与标注的成本快速搭建训练流水线并验证模型在真实皮肤图像上的检测效果。1. 915 张痤疮图像、11807 个标注框这份 VOCYOLO 双格式数据集到底能干什么手上有一批皮肤科图像想跑一个痤疮检测的 baseline结果卡在第一步——没有标注。自己标 900 多张图按每张 10 个框算就是近万个框labelImg 点到手酸还不一定标得一致。这份firc_cuochuang_231系列数据集解决的就是这个前置问题915 张 jpg 原图配套 915 个 Pascal VOC 格式 xml 和 915 个 YOLO 格式 txt单类别cuochuang总框数 11807平均每张图约 12.9 个目标。标注工具是 labelImg规则就是矩形框没有分割掩码也没有关键点。它适合谁做皮肤检测方向的学生、想验证 YOLO 系列模型在小目标密集场景下表现的工程师、需要一份现成标注数据做迁移学习起点的从业者。不适合谁想要分割任务、想要多类别比如同时区分炎性和非炎性、想要保证模型精度的——数据集本身明确声明不对训练权重精度作任何保证它只提供标注。换句话说这是一份「省掉标注时间」的原料不是「拿来就能发论文」的成品。下面按「格式怎么读 → 怎么转 → 怎么训 → 坑在哪」的顺序拆开讲。2. VOC 与 YOLO 双格式拆解xml 和 txt 到底怎么对应2.1 两种格式的坐标体系差异Pascal VOC 的 xml 用的是绝对像素坐标xmin/ymin/xmax/ymax直接对应图像上的像素位置读的时候不需要知道图像尺寸。YOLO 的 txt 用的是归一化中心点坐标每行class_id cx cy w hcx、cy、w、h 都是相对于图像宽高的 0 到 1 之间的小数。这两个格式放在同一个压缩包里意味着你可以直接用 YOLO 的 txt 训练也可以用 xml 转成 COCO 或别的格式省了一次转换。关键点在于这份数据集的 txt 里 class_id 只有一个值 0对应类别名cuochuang。如果你后续要合并别的数据集类别索引冲突是第一个要处理的问题。常见做法是建一个统一的classes.txt把cuochuang放在固定位置合并时重映射 id。2.2 目录结构与文件命名规律压缩包解压后通常是这样的结构cuochuang_dataset/ ├── JPEGImages/ # 915 张 jpg │ ├── firc_cuochuang_1.jpg │ ├── firc_cuochuang_2.jpg │ └── ... ├── Annotations/ # 915 个 VOC xml │ ├── firc_cuochuang_1.xml │ └── ... └── labels/ # 915 个 YOLO txt ├── firc_cuochuang_1.txt └── ...文件名严格一一对应firc_cuochuang_231.jpg对应firc_cuochuang_231.xml和firc_cuochuang_231.txt。这个命名一致性很重要——如果你用脚本做 train/val 划分直接按文件名匹配就行不需要额外维护映射表。我一般会先跑一遍完整性检查确认三个目录的文件名集合完全一致缺一个都会在训练时炸掉。2.3 用 Python 快速校验标注一致性拿到数据集第一件事不是急着训练而是校验。下面这段脚本检查三件事jpg 和 xml 是否配对、xml 里的框是否越界、txt 行数和 xml 的 object 数是否一致。import os import xml.etree.ElementTree as ET from PIL import Image IMG_DIR cuochuang_dataset/JPEGImages XML_DIR cuochuang_dataset/Annotations TXT_DIR cuochuang_dataset/labels def check_dataset(): imgs {os.path.splitext(f)[0] for f in os.listdir(IMG_DIR) if f.endswith(.jpg)} xmls {os.path.splitext(f)[0] for f in os.listdir(XML_DIR) if f.endswith(.xml)} txts {os.path.splitext(f)[0] for f in os.listdir(TXT_DIR) if f.endswith(.txt)} # 1. 文件名配对检查 print(jpg 缺 xml:, imgs - xmls) print(xml 缺 jpg:, xmls - imgs) print(txt 缺 xml:, xmls - txts) mismatch 0 for name in sorted(imgs xmls txts): img_path os.path.join(IMG_DIR, name .jpg) xml_path os.path.join(XML_DIR, name .xml) txt_path os.path.join(TXT_DIR, name .txt) w, h Image.open(img_path).size tree ET.parse(xml_path) root tree.getroot() objs root.findall(object) with open(txt_path) as f: lines [l for l in f.readlines() if l.strip()] # 2. 框数量一致性 if len(objs) ! len(lines): print(f{name}: xml {len(objs)} 框 vs txt {len(lines)} 框) mismatch 1 # 3. 越界检查 for obj in objs: bbox obj.find(bndbox) xmin int(bbox.find(xmin).text) ymin int(bbox.find(ymin).text) xmax int(bbox.find(xmax).text) ymax int(bbox.find(ymax).text) if xmin 0 or ymin 0 or xmax w or ymax h: print(f{name}: 越界框 ({xmin},{ymin},{xmax},{ymax}) 图像 {w}x{h}) print(f框数不一致文件数: {mismatch}) check_dataset()逻辑说明先做集合差集找出缺失配对再逐文件比对 xml 的 object 数量和 txt 行数。越界检查用图像实际尺寸做边界因为 VOC 的坐标是绝对像素直接和宽高比就行。参数方面如果你的数据集路径不同改三个目录常量即可。跑完如果输出全是空集合和 0说明数据干净可以进入下一步。3. 从 VOC 到 YOLO 训练划分、配置与启动3.1 训练集验证集划分的两种策略915 张图不算多划分方式直接影响验证集的可信度。常见做法是 8:1:1 或 8:2但痤疮图像有个特点同一患者的图像可能连续拍摄如果随机划分训练集和验证集里出现同一患者的相似图像验证指标会虚高。我一般会先按文件名前缀或拍摄批次做分组再在组间划分。这份数据集的文件名是firc_cuochuang_数字顺序编号没有患者 ID所以只能按编号随机划分但建议固定随机种子保证可复现。import os import random import shutil random.seed(42) IMG_DIR cuochuang_dataset/JPEGImages LBL_DIR cuochuang_dataset/labels OUT_DIR dataset_split names sorted([os.path.splitext(f)[0] for f in os.listdir(IMG_DIR) if f.endswith(.jpg)]) random.shuffle(names) n len(names) n_train int(n * 0.8) n_val int(n * 0.1) 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(): img_out os.path.join(OUT_DIR, images, split) lbl_out os.path.join(OUT_DIR, labels, split) os.makedirs(img_out, exist_okTrue) os.makedirs(lbl_out, exist_okTrue) for name in items: shutil.copy(os.path.join(IMG_DIR, name .jpg), os.path.join(img_out, name .jpg)) shutil.copy(os.path.join(LBL_DIR, name .txt), os.path.join(lbl_out, name .txt)) print(split, len(items))逻辑说明random.seed(42)固定种子保证每次划分一致。8:1:1 的比例在 915 张下大约是 732/91/92。复制而不是移动保留原始数据不动。参数上如果你想做交叉验证把random.shuffle换成 KFold 的逻辑即可但小数据集下 5 折训练成本不低一般 8:2 够用。3.2 YOLO 数据配置文件写法YOLO 系列v5/v8/v11的 data yaml 结构基本一致关键是nc和names要和 txt 里的 class_id 对齐。这份数据集只有一类所以nc: 1names: [cuochuang]。# cuochuang.yaml path: /absolute/path/to/dataset_split train: images/train val: images/val test: images/test nc: 1 names: 0: cuochuang注意path用绝对路径train/val/test用相对路径。如果你用的是 YOLOv8命令行直接yolo detect train datacuochuang.yaml modelyolov8n.pt epochs100 imgsz640。YOLOv5 则是python train.py --data cuochuang.yaml --weights yolov5n.pt --epochs 100 --img 640。模型选 nano 还是 small取决于你的显存和精度要求——915 张图用 nano 就够跑 baseline想压榨精度再上 s。3.3 训练参数中容易忽略的三个值第一个是imgsz。痤疮目标普遍偏小640 是默认值但如果你的原图分辨率远大于 640缩小后小框可能只剩几个像素。建议先统计一下 xml 里框的宽高分布如果大量框小于 32 像素考虑用 1024 或切片推理。第二个是batch。小数据集下 batch 太大会导致一个 epoch 迭代次数太少梯度更新不足。915 张图batch16 大约 57 个 iteration/epoch比较合理。第三个是lr0。默认 0.01 对 nano 模型没问题但如果你从预训练权重微调可以降到 0.001 避免破坏已有特征。这些值没有绝对标准跑一次看 loss 曲线和 mAP 再调。4. 避坑与排查标注数据落地时最容易翻车的五件事4.1 现象训练时提示 “No labels found”原因通常是 YOLO 找不到 txt 文件或者 txt 路径和图像路径不匹配。YOLO 默认会在图像同目录下找同名 txt或者按 data yaml 里的labels字段找。这份数据集的 txt 在独立labels/目录如果你划分后没有同步复制 txt就会报这个。解决确认dataset_split/labels/train/下有和images/train/同名的 txt。用ls images/train | wc -l和ls labels/train | wc -l对比数量。4.2 现象mAP 一直是 0 或者极低原因可能是类别索引错位。txt 里 class_id 是 0但 data yaml 里names写成了从 1 开始或者nc写成了 2。另一个常见原因是归一化坐标算错了——如果你自己转过格式cx 除了宽而不是除宽或者忘了除。解决随便打开一个 txt确认每行第一个数字是 0后面四个数都在 0 到 1 之间。再检查 yaml 的nc: 1和names: {0: cuochuang}。4.3 现象验证集 loss 震荡mAP 忽高忽低原因验证集太小。91 张图的验证集每张图约 13 个框总共约 1180 个框统计波动大。加上如果划分时相似图像泄漏到验证集指标会虚高然后骤降。解决增大验证集比例到 2:8或者做 5 折交叉验证取平均。另外固定随机种子不要每次训练重新划分。4.4 现象小框检测不到大框正常原因下采样倍率导致小目标特征丢失。YOLO 的 P3 特征图 stride 是 8如果框在原图上只有 10 像素到 P3 就剩 1 个多像素网络很难学。解决提高输入分辨率到 1024或者用 SAHI 做切片推理。训练时开启mosaic增强也能缓解但注意 mosaic 对小目标有时会引入噪声。4.5 现象xml 能读但 txt 是空的原因转换脚本在写 txt 时如果框坐标计算出 NaN 或者超出 0-1 范围有些脚本会直接跳过该行导致 txt 为空。这份数据集是官方提供的双格式理论上不会出现但如果你自己重新生成过 txt就要检查。解决用第 2 章的校验脚本跑一遍看框数一致性。如果 xml 有 13 个框而 txt 只有 10 行说明有 3 个框在转换时被丢弃需要回溯转换逻辑。5. 进阶用法用这份数据做迁移学习和切片推理的实操技巧5.1 从 COCO 预训练权重微调的策略直接拿 COCO 预训练的 YOLO 权重在这份数据上微调比从头训练收敛快得多。但 COCO 的 80 类里没有cuochuang所以分类头需要重新初始化。常见做法是冻结 backbone 前几层只训 neck 和 head跑 20 个 epoch 后再解冻全部微调。YOLOv8 里可以用freeze10参数冻结前 10 层。yolo detect train datacuochuang.yaml modelyolov8s.pt epochs50 imgsz1024 freeze10 batch8逻辑说明freeze10冻结前 10 层imgsz1024提升小目标召回batch8因为分辨率提高显存占用大。跑完 50 epoch 后再用freeze0跑 30 epoch 全量微调。这套流程我在多个小数据集上验证过比直接全量微调 mAP 高 3 到 5 个点。5.2 切片推理处理高分辨率原图如果原图是 3000x4000 这种手机拍摄尺寸直接缩到 640 会丢失大量小框。SAHISlicing Aided Hyper Inference的思路是把原图切成重叠的小块每块单独推理再合并。对这份数据集如果测试图也是高分辨率切片推理能显著提升小框召回。from sahi import AutoDetectionModel from sahi.predict import get_sliced_prediction model AutoDetectionModel.from_pretrained( model_typeyolov8, model_pathruns/detect/train/weights/best.pt, confidence_threshold0.25, devicecuda:0 ) result get_sliced_prediction( test_image.jpg, model, slice_height640, slice_width640, overlap_height_ratio0.2, overlap_width_ratio0.2 ) result.export_visuals(export_diroutput/)参数说明slice_height/width是切片尺寸一般和训练分辨率一致overlap是重叠比例0.2 表示相邻切片有 20% 重叠避免边缘目标被切断。confidence_threshold设 0.25 是召回优先后续可以再调。这套流程的代价是推理时间成倍增加但小目标场景下值得。5.3 验证模型是否真的学到了痤疮特征训练完不要只看 mAP。我习惯做两件事一是用 Grad-CAM 可视化热力图看模型关注的是不是皮损区域而不是背景二是拿几张训练集里没有的、不同光照条件的图做推理看框是否稳定。如果热力图集中在图像边缘或者均匀分布说明模型可能学到了数据集偏差比如拍摄设备的固定水印或者光照模式。从那以后我每次拿到新数据集都强制先跑一遍完整性校验和可视化抽样确认标注和图像对齐再开训。这份 915 张的痤疮数据集标注一致性不错双格式省了转换步骤适合快速搭 baseline。希望帮到你。本文还有配套的精品资源点击获取
返回列表