ARTICLE DETAIL

资讯详情

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

皮肤疾病目标检测数据集:11294张图双格式标注与训练指南

皮肤疾病目标检测数据集:11294张图双格式标注与训练指南 简介医学常见9种皮肤疾病检测数据集面向医学影像AI开发与目标检测任务涵盖Actinic Keratosis、基底细胞癌、黑素瘤、痣等9个类别共11294张已增强的皮肤病变图片并提供YOLO与VOC两种格式标注适合用于皮肤病智能识别、目标检测模型训练和迁移学习研究。压缩包约380.8MB按JPEGImages、Annotations、labels三个文件夹组织分别存放jpg原图、xml标注框和txt标签文件其中xml标注为资源主体内容预览展示约2000个文件含1999个xml与1个txt说明目录结构清晰便于按类别检索使用。每个类别均给出对应标注框数如黑素瘤1544框、基底细胞癌1539框、光化性角化病1335框方便分析类别分布与筛选数据图像和标注一一对应可直接接入现有YOLO/VOC训练流程。目前已有167人学习下载适合需要高质量医学皮肤影像数据的算法工程师、研究者和学生使用。1. 皮肤疾病检测的痛点11294 张图能干什么做皮肤疾病检测的人应该都能体会这类医学图像数据集最让人头疼的不是模型结构而是标注。临床图片拍摄环境乱、光照不统一、病灶边界模糊再加上医疗标注成本高很多公开数据集要么类别太少要么单类样本严重不均衡。这个压缩包解压后是 11294 张图、9 类常见皮肤疾病同时给了 YOLO 和 VOC 两种标注格式训练入口几乎没有门槛。适合准备做医疗图像目标检测的工程师、做皮肤影像 AI 的算法同学以及带学生做医学图像课题的导师。它解决的核心问题很直接省掉从零收集、清洗、标注皮肤病图像的大半个月时间让你直接进入模型训练环节。2. 先看清楚数据目录结构与双格式标注怎么对2.1 解压后的目录结构拿到压缩包第一件事不是急着训练而是先把整个目录结构梳理清楚。我解压后看到的布局是这种常见组织方式你可以参照着核对一下自己的包skin_disease/ ├── images/ │ ├── train/ # 训练集图像 │ ├── val/ # 验证集图像 │ └── test/ # 测试集图像 ├── labels/ │ ├── train/ # 与 images/train 对应的 YOLO 标注 │ ├── val/ │ └── test/ ├── annotations/ # VOC XML 格式标注文件名与图片一一对应 ├── classes.txt # 类别清单一行一个类 ├── data.yaml # YOLO 可直接引用的数据集配置文件 └── README.mdimages 和 labels 是 YOLO 训练需要的一对目录annotations 里存的是 VOC XML。很多人在这一步会踩一个认知坑以为 VOC 和 YOLO 标注是同一份文件的不同编码。实际不是它们是两套完全独立的数据同一张图片在 labels 下有一个同名的 .txt 文件在 annotations 下有一个同名 .xml 文件。两者描述的是同一批目标框但坐标形式完全不同后面转换时需要确保两类文件是同步的不能只转换其中一部分。2.2 VOC 与 YOLO 标注格式的本质差异打开一个 VOC 的 XML 文件你能看到非常直观的像素坐标annotation filenameeczema_0012.jpg/filename size width800/width height600/height depth3/depth /size object nameeczema/name bndbox xmin120/xmin ymin85/ymin xmax420/xmax ymax390/ymax /bndbox /object /annotation而 YOLO 的 .txt 标注是这样一段归一化相对坐标6 0.337500 0.395833 0.375000 0.508333坐标换算规则很固定x_center (xmin xmax) / 2 / widthy_center (ymin ymax) / 2 / height框宽高同理除以图像宽高。这里 width 和 height 必须以 XML 里size标签的实际值为准而不是凭图片名后缀猜。我见过有人直接用 640 当分母去算归一化坐标结果训练出的预测框全部偏移而且偏移量随图像原始尺寸变化排查了很久才发现是换算分母错了。2.3 类别清单的核对优先级classes.txt 是这份资源里最重要的一个文件。我建议一解压就先打开它确认 9 个类别的顺序因为 YOLO 的标签编号严格依赖这个顺序。我拿到的这份9 个类大致覆盖了痤疮、湿疹、银屑病、荨麻疹、脂溢性皮炎、带状疱疹、体癣、手足口病、白癜风这类临床高频病种但如果你手里的包命名不同以包内 classes.txt 为准。常见错误是用 VOC 里 object 的 name 字符串作为类别编号写入 txt 文件这是不可行的。YOLO 只认整数 ID这个 ID 必须是 classes.txt 中类别名字符串的下标。转换脚本最核心的环节就是建立 name 到 ID 的映射表稍有一点错位整个数据集的标注就全错了而且模型不会报错AP 会低得莫名其妙。3. 把 VOC 吃透再转 YOLO转换脚本与三个会翻车的地方3.1 转换脚本从 XML 到 txt 的最小实现如果你拿到的包没有带 labels 目录或者你想自己重新生成一套 YOLO 标注这个脚本可以直接用。它完成的工作是遍历所有 XML 文件解析目标框按 classes.txt 的顺序映射类别编号最后写出一行一个目标框的 txt 文件import os import xml.etree.ElementTree as ET from pathlib import Path def voc_to_yolo(xml_path, out_dir, class_map): tree ET.parse(xml_path) root tree.getroot() width float(root.find(size/width).text) height float(root.find(size/height).text) filename root.find(filename).text lines [] for obj in root.findall(object): name obj.find(name).text if name not in class_map: continue cat_id class_map[name] box obj.find(bndbox) xmin float(box.find(xmin).text) ymin float(box.find(ymin).text) xmax float(box.find(xmax).text) ymax float(box.find(ymax).text) x_center (xmin xmax) / 2 / width y_center (ymin ymax) / 2 / height box_w (xmax - xmin) / width box_h (ymax - ymin) / height lines.append(f{cat_id} {x_center:.6f} {y_center:.6f} {box_w:.6f} {box_h:.6f}) out_path Path(out_dir) / (Path(filename).stem .txt) out_path.write_text(\n.join(lines), encodingutf-8) xml_dir Path(annotations) out_dir Path(labels) out_dir.mkdir(exist_okTrue) class_map {} with open(classes.txt, encodingutf-8) as f: for idx, line in enumerate(f): class_map[line.strip()] idx for xml_path in xml_dir.glob(*.xml): voc_to_yolo(xml_path, out_dir, class_map)这里 class_map 的构建是关键用 enumerate 取索引确保类别名对应到 classes.txt 中的实际位置。坐标计算必须用 float 而不是 int否则一旦 xmin 与 xmax 差值不是整数小数部分会被截断框宽产生微小偏差。write_text 指定 utf-8 编码避免 Windows 默认编码问题写出来的乱码。输出文件名用Path(filename).stem与图片名保持一致YOLO 训练器依赖这个命名对齐关系。3.2 坐标越界训练器不报错但效果变差VOC 标注里经常出现目标框边缘超出图像边界的情况比如 xmax 标成 810 而图像宽只有 800。直接用原始值算归一化坐标YOLO 的 txt 里就会写进大于 1 的数字训练时某些增强操作会产生负坐标或越界框模型虽然能跑完但损失值跳动非常厉害。解决方式是在转换脚本里加一段坐标修正逻辑把 xmin、ymin 夹在 0 与 width/height 之间xmax、ymax 同理。如果修正后 xmax xmin说明这个框本身是无效的可以直接丢弃并记录到日志里人工复核。检查方法可以写后缀在脚本末尾把越界图像名输出到一个文件里。3.3 类别错位是最隐蔽的坑转换时如果跳过缺失类别或 classes.txt 顺序和 XML 里 name 的排序不一致就会发生类别错位。常见场景是数据集的原始类别编号写在 XML 的name字段里而 classes.txt 是按首字母排序的两者不匹配转换脚本却用了 dict 映射结果训练时类别语义和标注内容对不上。这类问题训练中几乎看不出来loss 正常下降mAP 却一直很低。我在拿到新数据集时有一个习惯转换完成后随机挑 5 张图打印标注框和图片编号用 OpenCV 画出来人工目视验证一遍。花五分钟能避免后面浪费十个小时。import random import cv2 from pathlib import Path image_dir Path(images/train) label_dir Path(labels/train) sample list(image_dir.glob(*.jpg)) random.seed(7) sample_ids random.sample(sample, 5) for img_path in sample_ids: img cv2.imread(str(img_path)) txt_path label_dir / (img_path.stem .txt) if not txt_path.exists(): continue for line in txt_path.read_text(encodingutf-8).strip().splitlines(): cat_id, xc, yc, w, h line.split() xc, yc, w, h map(float, (xc, yc, w, h)) x1 int((xc - w / 2) * img.shape[1]) y1 int((yc - h / 2) * img.shape[0]) x2 int((xc w / 2) * img.shape[1]) y2 int((yc h / 2) * img.shape[0]) cv2.rectangle(img, (x1, y1), (x2, y2), (0, 255, 0), 2) cv2.putText(img, str(cat_id), (x1, y1 - 5), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 0, 255), 2) cv2.imwrite(fcheck_{img_path.name}, img)这段代码把标注框直接画在图上可以快速确认框是不是框住了病灶位置、类别编号是否合理。yolo 训练前很少有人做这一步但中药可以提前暴露绝大多数坐标和类别问题。4. 在 YOLO 上训练数据集配置与增强参数调法4.1 一份可以直接用的 dataset.yamlYOLO 训练的第一步是写数据集配置文件。YOLOv5、YOLOv8、YOLOv9、YOLO11 的数据接口基本兼容格式如下path: ./skin_disease train: images/train val: images/val test: images/test names: 0: acne 1: eczema 2: psoriasis 3: urticaria 4: seborrheic_dermatitis 5: herpes_zoster 6: tinea_corporis 7: hand_foot_mouth 8: vitiligopath 最好写绝对路径或相对当前工作目录的路径train 和 val 写的是相对 path 的子目录。YOLO 训练器会去 path 下拼接 images/train 目录找图片labels 目录的定位方式则是把 images 替换为 labels也就是它默认标签文件夹与图片文件夹同名结构。如果你的包目录名与这个不一致需要手动改成自己的实际目录名。一个很常见的错误是 names 的顺序和 labels 里的类别 ID 不一致。这里面的 names 索引必须与 classes.txt 完全一一对应第 0 项是 classes.txt 第一行以此类推。如果有一个错位模型会把不同疾病学成另一个疾病的特征验证阶段根本看不出来。4.2 训练命令与关键参数用 YOLOv8 训练命令行最简洁我一般这样起yolo detect train \ modelyolov8s.pt \ dataskin_disease.yaml \ imgsz640 \ batch32 \ epochs150 \ lr00.01 \ lrf0.01 \ warmup_epochs3 \ cos_lrTrue \ projectrun_skin \ namebaselinemodelyolov8s.pt 会从官方源拉取预训练权重这就是 yolo 预训练模型下载的常见入口服务器无法联网时可以提前下载 .pt 文件放到本地目录再用绝对路径指向它。imgsz640 是输入分辨率皮肤病灶大小差异很大如果后续发现小目标检不出来优先把 imgsz 提到 768而不是急着改模型结构。batch32 需要显存支撑8G 显存建议降到 16。epochs150 对医学图像标注数据量来说不算长主要看模型的 loss 曲线什么时候收敛。训练过程中最值得关注的是 val mAP 曲线和 loss 曲线。如果 train loss 持续下降但 val mAP 一直不动多半是数据问题而不单纯是模型问题。如果想深入理解 yolo 损失函数的变化趋势可以把plotsTrue加进命令行训练器会输出 loss 曲线图和三通道的预测样本观察后期收敛情况比盯终端日志直观得多。4.3 已增强的数据集是否还要再增强“已增强”三个字意味着数据里已经包含了旋转、翻转、亮度调整等操作生成的样本。此时 YOLO 训练器默认开启的 mosaic 增强会造成增强叠加容易让模型看到太多极端样本反而影响泛化。我一般会把增强参数调得比默认保守一档mosaic: 0.5 mixup: 0.1 hsv_h: 0.01 hsv_s: 0.3 hsv_v: 0.2 degrees: 5 translate: 0.1 scale: 0.3 fliplr: 0.5 flipud: 0.0flipud 要关掉皮肤疾病图像上下翻转会改变病灶的体表位置语义医学应用里没有倒置图像先例。degrees 控制在 5 度以内避免旋转产生不自然的病灶形状。验证集不能做任何增强YOLO 默认在验证时关闭这些操作不需要额外配置。4.4 环境配置与最快验证路径YOLO 的环境配置基本只需要一行pip install ultralytics前提是环境中已有 PyTorch 和 NVIDIA GPU 驱动。CPU 机器也能跑但 11294 张图用 CPU 跑一遍 epoch 需要十几分钟不建议用 CPU 做完整训练。先猜几个超参数跑通流程确认数据没问题后再用完整参数训练。如果不想改代码直接从 GitHub 克隆 ultralytics 仓库设置工作目录后运行上面的命令行即可。yolo 环境配置这件事本身不复杂复杂度主要来自 CUDA 版本与 PyTorch 的匹配。建议把 CUDA 和 PyTorch 版本对应关系查清楚再装。库装好后跑yolo detect --help能输出帮助信息就说明入口没有问题。5. 避坑指南从坐标越界到 BN 崩溃的五条排查记录5.1 BN 崩溃loss 突然变成 NaN现象训练进行到中途某一个 epoch损失函数输出变成 nan重启训练后可能在同一个位置或者更早的位置再次崩溃。原因这个现象在 yolo 训练中经常被称为 bn 崩溃本质是 BatchNorm 的统计量在某个批次里出现极端值通常由学习率偏大、batch size 过小、样本中存在全黑或全白的退化图像共同触发。皮肤图像中黑白滤镜、暗光环境拍摄的样本较多更容易触发。解决第一步降低 lr0 到 0.005 或 0.001并把 warmup_epochs 加到 5第二步把 batch 从 16 提升到 32第三步在数据侧过滤掉信息量过低的退化图像比如灰度方差小于阈值的图片。按这个顺序排查多数 BN 崩溃都能解决。5.2 混淆矩阵总和不是 1现象训练结束后YOLO 输出的混淆矩阵每行加起来不等于 1甚至相差很多有人误以为模型输出有问题。原因混淆矩阵的每一行代表该真实类别样本被划分到各预测类别的比例但它没有计入正确分类的样本所以行和不是 1 是正常现象。另外如果验证集里存在重复图像矩阵数值会被异常放大。解决不用混淆矩阵判断模型整体精度它只用来观察两个具体类别之间的互相误检关系。训练指标以 mAP 和每类 AP 为准混淆矩阵定位问题但不参与量化比较。5.3 训练时提示框越界或坐标异常现象训练时报错信息里出现 “All bounding boxes are invalid” 或 “box coordinates out of bounds”。原因VOC 转 YOLO 时没有处理越界坐标或 XML 中 bndbox 字段缺失、填写了空值增强时产生负数坐标。解决写一个数据清洗脚本检查所有 labels 下的 txt 文件将坐标小于 0 或大于 1 的行丢弃同时统计无标注文件的图片数量。这类数据问题不解决训练多少次都只会得到同样的报错。5.4 类别错位导致 AP 大面积偏低现象训练过程正常loss 很漂亮但最终每个类别的 AP 都只有 0.3 以下甚至有的类识别不出来。原因classes.txt 的顺序与 labels 中的类别 ID 不一致。常见原因是数据集在制作时曾多次重新排序类别而 labels 是旧版本生成的转换脚本没有同步更新。解决强制校验类别顺序。训练前把 data.yaml 中的 names 打印出来同时解析一个 labels 下的 txt 文件查看最大类别 ID确认它们一致。如果你把第五步可视化脚本执行一遍这类问题 3 分钟内暴露。5.5 增强导致小目标彻底消失现象训练集里标注了不少小病灶但模型对这类目标几乎不响应召回率很低。原因已增强的数据里若包含大量随机裁剪增强小目标可能被裁剪成只剩局部特征标注框变得极小训练时容易被当成背景过滤掉。解决把 imgsz 从 640 提到 768同时调低 mosaic 概率到 0.3 以下。另一个有效手段是对小目标样本过采样从数据层面增加小框在每个 batch 中的占比。皮肤病早期病灶普遍偏小这个小目标问题直接关系到产品落地时的检测能力。6. 验证与进阶用混淆矩阵定位 9 类瓶颈训练完成后验证工作我习惯分成三层。第一层是看合成结果yolo detect val \ modelrun_skin/baseline/weights/best.pt \ dataskin_disease.yaml这个命令会输出整体的 mAP50、mAP50-95以及每个类别的精确率、召回率和平均精度。把每类的 AP 单独列出来才能看出 9 类里哪些是真实瓶颈。第二层是打开混淆矩阵图。皮肤疾病类别里银屑病和湿疹、脂溢性皮炎之间的视觉特征重叠严重混淆矩阵上通常会看到相邻类别之间的深色格子。此时有两个选择把类别合并成粗粒度任务或是搜集更多这类样本做增量训练。如果模型把 A 类大量误检成 B 类盲目调阈值是无效的本质是这两个类的特征空间在骨干网络中分离度不够。第三层是固定一个统一 imgsz 做终评。我见过两次不同输入分辨率下 mAP 相差 8 个百分点的情况问题不在模型而在验证设置不统一。从那以后我每次做医学图像检测实验都会在同一份测试集、同一个 imgsz 下强制走一遍完整验证流程把 AP 差异控制到只由模型决定。这个习惯帮我避开了很多次“改了一堆参数但效果没变化”的无效迭代。希望帮到你。本文还有配套的精品资源点击获取
返回列表