资讯动态

皮肤病变检测数据集:YOLO与VOC双标签格式详解及训练实战

发布时间:2026/9/23 5:02:29 来源:尧图企业网站定制
简介这是一套面向皮肤病变检测的妇科皮肤病数据集覆盖黑色素、猴痘、水痘、痤疮、疣、花斑癣、粉刺、银屑病、湿疹、癣等十余类常见病灶适用于YOLO系列算法训练与验证也适合目标检测入门者练习标注格式处理。资源已按训练、验证、测试划分完毕内置data.yaml配置文件可直接用于YOLOv5、YOLOv7、YOLOv8、YOLOv9、YOLOv10、YOLO11等主流版本标签同时提供YOLO格式txt与VOC格式xml两种形式分别存放于独立文件夹txt中记录类别索引和归一化后的中心点坐标、宽高比例便于跨框架迁移和二次标注。压缩包共2000个文件以xml标注文件为主整体约169.39MB目录结构清晰图片与标签一一对应可快速定位所需样本同时data.yaml中的类别顺序与txt索引保持一致能减少训练前的配置成本。目前已有98人学习下载适合目标检测学习者和皮肤病识别研究者直接获得可训练的标注数据并快速启动实验。1. 妇科皮肤病检测的数据困境这份 4418 张带标签数据集能直接喂给 YOLO 训练做皮肤病变检测的同行应该都有体会公开数据集要么类别单一要么标注格式五花八门光是洗数据就能耗掉两三天。这份数据集覆盖黑色素、猴痘、水痘、痤疮、疣、花斑癣、粉刺、银屑病、湿疹、癣共 10 类常见皮肤病变4418 张图像全部带标签而且同时给了 YOLO 格式txt和 VOC 格式xml两套标注数据已经划分好训练集/验证集/测试集配套data.yaml配置文件意味着拿到手就能跑yolov5/yolov7/yolov8/yolov9/yolov10/yolo11任意一个版本的训练脚本。适合正在做医学影像检测、皮肤科辅助诊断、或者想拿真实多类别小目标数据集练手的人。这篇文章把数据集的目录结构、标签格式、训练参数和踩坑点全部过一遍。2. 数据集结构与双标签格式YOLO 和 VOC 到底差在哪2.1 目录布局两个标签文件夹一份数据划分这个数据集的设计思路很清晰——同一次标注生成两份不同格式的标签文件避免你在 YOLO 和 Faster R-CNN 之间切换时重新标注。解压后你会看到类似下面的核心结构dataset/ ├── images/ │ ├── train/ │ ├── val/ │ └── test/ ├── labels_yolo/ │ ├── train/ │ ├── val/ │ └── test/ ├── labels_voc/ │ ├── train/ │ ├── val/ │ └── test/ ├── data.yaml └── classes.txt注意labels_yolo和labels_voc是两个独立的顶层文件夹和images平级而不是像默认 YOLO 项目习惯那样把标签放进images对应的labels文件夹。这个设计有好处也有坑好处是 VOC 转 YOLO 或反向转换时互不干扰坑是你用yolov8训练时如果没改路径程序会默认去找images/train同级的labels/train结果一个标签都读不到。后面避坑章节会展开说。训练集、验证集、测试集的划分已经做好不需要自己再写split脚本。划分比例按图像文件名分配到三个子目录里data.yaml里已经写好了路径指向。2.2 YOLO 标签格式解析归一化坐标的计算逻辑YOLO 格式的每个 txt 文件一行对应一个目标框class x_center y_center width height四个坐标值全部是归一化比例范围 0 到 1。比如0 0.5125 0.4412 0.2234 0.3105表示类别索引为 0 的目标中心点在图像宽度的 51.25%、高度的 44.12% 处框宽度占整图宽度的 22.34%高度占整图高度的 31.05%。归一化坐标的换算公式为x_center x_abs / image_width y_center y_abs / image_height width box_width / image_width height box_height / image_height其中x_abs、y_abs是标注框中心点的像素坐标box_width、box_height是框的像素宽高。归一化的意义在于不管输入图像是 640x640 还是 1280x720标签都不需要改训练时 YOLO 会自动做 letterbox 缩放。用 Python 解析一个 YOLO 标签文件看一下# parse_yolo_label.py def parse_yolo_label(txt_path, img_w, img_h): 解析YOLO格式标签还原为像素坐标 :param txt_path: 标签txt文件路径 :param img_w: 对应图像的像素宽度 :param img_h: 对应图像的像素高度 :return: 每个目标的类别和像素bbox boxes [] with open(txt_path, r, encodingutf-8) as f: for line in f: line line.strip() if not line: continue parts line.split() cls_id int(parts[0]) x_center float(parts[1]) * img_w y_center float(parts[2]) * img_h box_w float(parts[3]) * img_w box_h float(parts[4]) * img_h x_min int(x_center - box_w / 2) y_min int(y_center - box_h / 2) x_max int(x_center box_w / 2) y_max int(y_center box_h / 2) boxes.append({class: cls_id, bbox: (x_min, y_min, x_max, y_max)}) return boxes # 使用示例 if __name__ __main__: result parse_yolo_label(labels_yolo/train/img_0828_234.txt, 640, 640) for r in result: print(r)这段脚本把归一化坐标还原成像素级 bbox方便你用 OpenCV 画框做可视化检查标注是否贴合目标边缘。img_w和img_h改成数据集里实际图像的分辨率。YOLO 格式和 VOC 格式在同一个数据集里共存但它们的坐标基准不同——YOLO 是归一化相对坐标VOC 是像素绝对坐标xmin, ymin, xmax, ymax。数据增强时如果用了 mosaicYOLO 标签会随拼接后的图重新计算VOC 则不会自动处理这也是为什么训练实测中 YOLO 格式更稳定。2.3 VOC 标签格式XML 结构与类别索引对照VOC 格式的标签文件是 XML典型内容如下annotation foldertrain/folder filenameimg_0828_234.jpg/filename size width640/width height640/height depth3/depth /size object namemelanoma/name bndbox xmin100/xmin ymin80/ymin xmax260/xmax ymax280/ymax /bndbox /object /annotationname是类别名称和classes.txt里的顺序对应。索引从 0 开始classes.txt 第 0 行对应索引 0第 9 行对应索引 9。训练时 YOLO 读的是 txt 的索引数字而非名称所以一旦 classes.txt 顺序变动所有标签全部错位——这是换类别名时最容易翻车的点。VOC 格式的bndbox里的xmin/ymin/xmax/ymax都是像素坐标如果你的图像不是正方形转成 YOLO 格式时必须按第 2.2 节的公式先读size拿到宽高再归一化。有些工具默认按 640x640 归一化如果实际图是 1280x960转出来的标签中心点全偏。3. 用 data.yaml 跑通训练从环境配置到第一个 epoch3.1 环境安装和验证YOLOv8 的 pip 安装最省事官方仓库一直在维护依赖兼容性也做得比较好# 创建虚拟环境避免污染系统Python conda create -n yolo python3.10 conda activate yolo # 安装ultralytics包yolov8/v9/v10/v11通用 pip install ultralytics # 验证安装 yolo taskdetect modecheck用 conda 单独建环境是值得养成的一个习惯。皮肤病检测项目里往往会同时装 OpenCV、scikit-learn、pandas 这些依赖版本冲突的时候虚拟环境能让你直接删掉重来不用折腾系统级的包管理器。yolo taskdetect modecheck会打印当前环境下的 CUDA 版本、GPU 是否可用、torch 版本。如果这步报了 CUDA 相关的错误先检查nvidia-smi里的驱动版本再决定是装 CPU 版还是 GPU 版 torch。数据量只有 4418 张CPU 训练不是不行但一个 epoch 可能要多等 5 到 10 倍时间。3.2 data.yaml 配置详解这个数据集自带的data.yaml是已经写好的直接打开看一眼# data.yaml # 训练、验证、测试集的图片路径 train: images/train val: images/val test: images/test # 类别数 nc: 10 # 类别名称顺序必须和classes.txt一致 names: 0: melanoma 1: mpox 2: chickenpox 3: acne 4: wart 5: tinea_versicolor 6: comedo 7: psoriasis 8: eczema 9: tineatrain/val/test路径是相对路径还是绝对路径取决于你在哪个目录下执行训练命令。建议改成绝对路径比如/home/user/dataset/images/train避免因为工作目录不同而报 FileNotFoundError。nc是类别数这份数据集固定为 10不用动。names的索引顺序千万不能乱训练出的模型输出类别就是按这个顺序排列的如果 0 和 1 对调了loss 能正常下降但预测结果全错。在训练前写一个快速校验脚本检查图片和标签是否对得上、有没有空标签文件# check_dataset.py import os from pathlib import Path def validate_dataset(img_dir, label_dir): 检查图像和标签文件是否一一对应 :param img_dir: 图像目录 :param label_dir: 标签目录 :return: 缺失标签的图像列表和空标签列表 img_files [Path(f).stem for f in os.listdir(img_dir) if f.endswith((.jpg, .jpeg, .png))] label_files [Path(f).stem for f in os.listdir(label_dir) if f.endswith(.txt)] missing [f for f in img_files if f not in label_files] extra [f for f in label_files if f not in img_files] empty_labels [] for f in label_files: file_path os.path.join(label_dir, f .txt) if os.path.getsize(file_path) 0: empty_labels.append(f) print(f图像总数: {len(img_files)}) print(f标签总数: {len(label_files)}) print(f缺失标签的图像: {missing[:10]}) # 只打印前10个 print(f多余的标签: {extra[:10]}) print(f空标签: {empty_labels[:10]}) return missing, extra, empty_labels if __name__ __main__: # 替换成你自己的路径 validate_dataset(images/train, labels_yolo/train)这一步跑完能过滤掉 90% 的路径问题。尤其是别人分享的数据集经常会出现图像比标签多几张或文件名后缀不统一jpg和JPG混用这种问题训练时不会立刻报错但 val 阶段的 mAP 会莫名偏低。3.3 训练命令与关键参数直接用yolo命令行开训YOLOv8 和 YOLO11 的入口都是一样的# 训练YOLOv8s输入图像640x640batch16训练100个epoch yolo taskdetect modetrain modelyolov8s.pt datadata.yaml epochs100 batch16 imgsz640 device0 projectruns nameskin_disease # 断点续训 yolo taskdetect modetrain modelruns/skin_disease/weights/last.pt datadata.yaml epochs100 batch16 imgsz640 device0 # 训练YOLO11s yolo taskdetect modetrain modelyolo11s.pt datadata.yaml epochs100 batch16 imgsz640model参数填预训练权重路径程序会自动下载yolov8s.pt如果想从零开始训练骨架用yolov8s.yaml而不是.pt文件。batch16在 8GB 显存的卡上刚好能跑如果你的显存只有 4GBbatch降到 8 甚至 4imgsz也可以从 640 降到 512。project和name控制输出目录结果会落到runs/skin_disease/下面。训练过程中的关键观测指标box_loss边界框回归损失正常应该持续下降如果震荡剧烈说明学习率太大或 batch 太小cls_loss分类损失下降速度比 box_loss 慢是正常的mAP50和mAP50-95验证集上的精度指标mAP50-95 比 mAP50 更严格因为它统计了不同 IoU 阈值下的平均精度每个 epoch 结束会打印当轮最佳模型是否更新best.pt就是 val 上表现最好的权重训练 100 个 epoch 后runs/skin_disease/目录下会生成best.pt、last.pt、confusion_matrix.png、results.png等文件。其中results.png包含 loss 曲线、PR 曲线、F1 曲线是判断模型是否过拟合的第一手材料。4. 验证与预测跑通推理全流程4.1 在测试集上做批量验证训练完成后要做的第一件事是在测试集上跑验证而不是直接去预测单张图# 验证模型的最终效果 yolo taskdetect modeval modelruns/skin_disease/weights/best.pt datadata.yaml splittest # 指定输出目录 yolo taskdetect modeval modelruns/skin_disease/weights/best.pt datadata.yaml splittest projectruns nameval_skinsplittest告诉程序用data.yaml里test字段指向的目录做验证不写默认用val。跑完会输出一张完整指标表包含每个类别的precision、recall、mAP50、mAP50-95。这份数据集有个特点——10 类病变里黑色素和湿疹的数量可能比其他类别多而猴痘、花斑癣这类相对少见样本不均衡会让mAP50虚高。你需要重点看每个类别的单独指标而不是只盯平均值。如果某个类别的recall明显低于其他类大概率是该类别训练样本太少解决方法放在后面进阶章节。4.2 单张图像推理与结果可视化对单张图像做推理关键是要把置信度阈值调到合理范围# 单张图像推理 yolo taskdetect modepredict modelruns/skin_disease/weights/best.pt sourcedataset/images/test/img_0828_234.jpg conf0.25 iou0.45 saveTrue # 整个目录批量推理 yolo taskdetect modepredict modelruns/skin_disease/weights/best.pt sourcedataset/images/test/ conf0.25 saveTrue # 不保存标注框的原始图只输出结果 yolo taskdetect modepredict modelruns/skin_disease/weights/best.pt sourcedataset/images/test/ conf0.25 save_txtTrue save_confTrueconf0.25是置信度阈值低于 0.25 的框会被过滤掉。皮肤病变检测里如果目标是筛查建议调到 0.1 到 0.15宁可多检出不放过如果目标是辅助诊断0.3 以上更稳妥因为低置信度框通常对应正常皮肤纹理的误检。iou0.45是 NMS 的 IoU 阈值两个框重叠超过这个比例就保留置信度高的那个。皮肤病变边界往往不规则标注框和预测框的重叠率天然比常规目标低iou可以放宽到 0.5。如果保存了save_txtTrue预测结果会以 YOLO 格式写入runs/detect/predict/labels/目录每一行是class_id conf x_center y_center width height方便你写脚本做后续统计。4.3 混淆矩阵和 PR 曲线怎么读训练输出的confusion_matrix.png和PR_curve.png不能只看一眼就跳过。混淆矩阵的行是真实类别列是预测类别对角线上的数字越大越好。你重点看两类错误一是某两类之间互相误检严重比如痤疮和粉刺它们外观上本来就很像二是背景被误检为正类最后一列数值偏高说明模型把正常皮肤纹理也当成了病灶。PR 曲线越靠近右上角precision 和 recall 都接近 1说明模型在该类别上越可靠。如果曲线尾部有个明显下坠的拐点意味着提高阈值会极快地损失召回率。对于皮肤病检测来说recall 通常比 precision 更重要——漏检一个病灶的后果比误检一个严重得多。# evaluate_metrics.py import pandas as pd # 读取results.csv这是训练过程自动生成的 df pd.read_csv(runs/skin_disease/results.csv) # 查看最后10个epoch的mAP走势 print(df[[epoch, metrics/mAP50(B), metrics/mAP50-95(B)]].tail(10)) # 找出mAP50最高的epoch best_epoch df.loc[df[metrics/mAP50(B)].idxmax(), epoch] print(f最佳mAP50出现在epoch {best_epoch})这个小脚本能帮你快速定位模型最优权重落在哪个 epoch如果最佳 mAP 出现在最后一个 epoch说明 100 轮可能还没收敛可以加训如果最佳出现在中间但后面持续下降说明过拟合已经发生best.pt才是你要的权重。5. 避坑指南训练皮肤病变数据集的五个常见问题5.1 训练时报错找不到标签文件现象执行训练命令后立刻报错提示unable to find label file for image或者 loss 一直为 0。原因data.yaml里的路径写法问题。这份数据集的标签不在默认的labels/目录下而是在labels_yolo/和labels_voc/两个独立文件夹里。YOLO 训练程序默认在图像同级目录下找labels/你如果不改配置直接跑它找不到任何标签文件。解决# 方案一建立软链接 ln -s /path/to/dataset/labels_yolo /path/to/dataset/images/train/labels # 方案二在data.yaml里直接指定label路径ultralytics不直接支持 # 推荐方案直接把labels_yolo改名为labels并放入images对应目录我一般直接在项目目录下执行cd dataset mkdir -p labels cp -r labels_yolo/* labels/然后把训练数据从images/train/改成dataset/根目录的方式让 images 和 labels 同级但数据结构能被程序识别。更彻底的方案是把labels_yolo目录复制成每个images子目录下的labels子目录。5.2 训练正常但 mAP 极低可能类别索引错位现象loss 正常下降但 val 时 mAP50 始终在 0.1 左右徘徊。原因classes.txt的类别顺序和data.yaml里的names顺序不一致。比如 classes.txt 第 0 行是melanomadata.yaml 里第 0 个名字却是acne模型学的类别和验证时对不上。解决检查classes.txt和data.yaml的names是否逐行对应。# check_classes.py with open(classes.txt, r) as f: classes_txt [line.strip() for line in f if line.strip()] import yaml with open(data.yaml, r) as f: data_yaml yaml.safe_load(f) names_yaml [data_yaml[names][i] for i in range(len(classes_txt))] print(classes.txt顺序:, classes_txt) print(data.yaml顺序:, names_yaml) print(是否一致:, classes_txt names_yaml)如果发现不一致以 classes.txt 为准改 data.yaml或者反过来但两边必须严格一致。5.3 显存不够OOM 错误现象训练到第几个 iteration 时直接崩掉报CUDA out of memory。原因batch16、imgsz640在 8GB 显存以下的卡上会爆显存。皮肤病变图像通常包含大量细节如果你把imgsz调到 768 或更高想要提升小目标检测效果显存压力更大。解决先降到 batch8 试跑再逐步调整。yolo taskdetect modetrain modelyolov8s.pt datadata.yaml epochs100 batch8 imgsz640 device0 # 还是OOM就换模型规模 yolo taskdetect modetrain modelyolov8n.pt datadata.yaml epochs100 batch8 imgsz640yolov8n是 nano 版本参数量只有 s 的 1/3 左右精度损失有限但显存占用大幅降低。如果目标是先跑通流程再追求精度nano 版本是更明智的起点。5.4 小目标漏检为皮肤病变调整 anchor现象训练结果里黑素色、水痘这类目标面积占比很小的类别 recall 特别低大目标类别正常。原因皮肤病变图像的病灶面积小相对整张图来说占比往往低于 1%YOLO 默认 anchor 是为 COCO 数据集设计的小目标 anchor 数量不足。解决训练时开启自适应 anchor 计算。# 在data.yaml同级目录新建一个配置或者在命令行加参数 # 默认就比较有效的是让程序自己算 yolo taskdetect modetrain modelyolov8s.pt datadata.yaml epochs100 batch16 imgsz640 anchorTrueYOLOv8 之后的版本自动根据数据集计算 anchor不需要手动指定但如果你发现小目标 mAP 特别低可以把imgsz从 640 提到 960前提是显存够小目标对应的像素数会变大检测难度降低。5.5 过拟合训练集损失低但验证集 mAP 不涨现象训练集 loss 持续下降但 val 的 mAP 到某个 epoch 后不再上升甚至下降。原因4418 张图不算多模型学完训练集特征后开始在噪声上过拟合。尤其皮肤病类别间外观相似度高湿疹和癣在肉眼和模型眼里都像更容易把背景纹理学进去。解决增加数据增强和正则化。yolo taskdetect modetrain modelyolov8s.pt datadata.yaml epochs100 batch16 imgsz640 \ hsv_h0.015 hsv_s0.7 hsv_v0.4 \ degrees15 translate0.1 scale0.5 fliplr0.5 \ weight_decay0.0005hsv_h调整色相偏移对皮肤病变这种颜色敏感的检测任务要保守一点0.015 已经足够degrees15允许 15 度以内的旋转皮肤图像的方向性不强但旋转太多会引入不真实的形变。weight_decay从默认值调高到 0.0005可以缓解过拟合但不至于欠拟合。6. 进阶针对十类皮肤病变的调优策略与项目复盘参数层面默认训练能拿到可用的best.pt但如果你想把 mAP 再往上提需要针对皮肤病变的特性做三件事。第一是样本不均衡处理。十类症状里黑色素、痤疮、湿疹的样本量往往远超猴痘、花斑癣。训练时可以用class_weight参数给低频类别更大的损失权重或者用脚本做离线复制增强——把猴痘、花斑癣、癣这几类的图片做水平翻转、小角度旋转、亮度抖动来扩样。高频类别的样本量不动避免模型对它们过拟合。第二是数据增强参数调优。皮肤病变检测对颜色变化高度敏感hsv_h不宜超过 0.02因为病变和正常皮肤的色差是核心特征色相偏移太强会把模型学到的颜色判别彻底打乱。degrees旋转建议控制在 10 度以内超过这个范围图像内容不再符合临床采集场景。translate平移 0.1 到 0.15 有助于模型关注病变区域而非图像固定位置的纹理。第三是多尺度训练。皮肤病灶大小差异很大黑色素可能占据整张图的 30%而痤疮单点只有几个像素。用Rectangular训练让程序自动按 batch 内图像的最长边做多尺度缩放而不是统一拉成 640x640可以减少小目标和图像边缘的形变失真。我自己的习惯是每次换数据集都会先跑一个 20 epoch 的快速验证看results.png的 loss 曲线初段走势确认数据路径、类别数、锚点适配都没问题再跑完整 100 epoch。否则一次失败的完整训练往往浪费几个小时最后还得从头调参数。另一个值得做的事情是保留一份完整的环境依赖快照。训练这个数据集时装的每个包最好pip freeze requirements.txt存档。项目隔几个月再回来复现的时候新环境里各库版本已经更新了好几轮没有快照就只能逐个排雷。对我来说这份数据集最省心的地方是它把标签格式和数据集划分都做好了让我能把精力放在调参上而不是造轮子。如果你也在做皮肤病变检测相关的课题这份资源能让你跳过数据准备阶段直接进入训练和优化环节希望帮到你。本文还有配套的精品资源点击获取

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价