简介:本资源为面向YOLO系列目标检测算法的深色皮肤病变图像数据集,适用于皮肤科辅助诊断、医学图像识别等方向的算法训练与验证,适合具备一定深度学习基础的目标检测学习者使用。压缩包共703个文件,包含234张jpg图像、234个txt标签、234个xml标签及1个data.yaml配置文件,整体约9.16MB,已按训练与测试需求划分完毕,可直接投入模型训练。标签覆盖白糠疹、炎症后色素沉着过度、特发性黑色素沉着症、汇流和网状、白癜风等类别,同时提供YOLO格式与VOC格式两套标注,YOLO格式采用归一化中心点与宽高比例,便于适配yolov5、yolov8、yolov9、yolov7、yolov10及yolo11等主流框架。目前已有60人学习下载,读者可借助该数据集快速搭建深色皮肤病变检测实验,省去标注与格式转换环节,专注模型调参与效果对比。
1. 深色皮肤数据集为什么让通用 YOLO 模型集体翻车
如果你拿 COCO 或 VOC 上预训练的 YOLO 权重,直接去检测深色皮肤上的色素性皮损,大概率会得到一个很尴尬的结果:要么整张图一个框都不出,要么把正常皮肤纹理当成病灶框出来。这不是模型太弱,而是训练分布里根本没有这类样本。深色皮肤上的白糠疹、炎症后色素沉着过度、特发性黑色素沉着症、汇流和网状型皮损,在 RGB 空间里的对比度远低于浅色皮肤上的同类病变,边缘梯度弱、颜色通道差异小,通用检测头学到的“病灶=高对比度斑块”这个先验直接失效。
这个标题对应的是一份 234 张图像、带标签、聚焦深色皮肤色素异常的数据集,目标是用 YOLO 系列算法做多类别皮损检测。它解决的不是“能不能检测皮肤病”,而是“在深色皮肤这个特定子域上,小样本、多类别、低对比度场景怎么把 YOLO 跑出可用精度”。适合两类人:一类是手里有类似临床图像、想验证 YOLO 在低对比度小样本上边界的算法工程师;另一类是做皮肤影像辅助分析、需要快速判断这个方向值不值得投入的产品侧同学。234 张这个量级,注定不能走“大力出奇迹”的路线,选型、增强、标签策略比调 backbone 更关键。
2. 234 张图、5 类色素病变:YOLO 选型与标签体系怎么定
2.1 为什么优先选 YOLOv8n 或 YOLOv11n 而不是大模型
234 张图像,按 8:1:1 切分,训练集不到 190 张。这个量级下,YOLOv8x、YOLOv11l 这类大模型参数量动辄五六千万,训练时几个 epoch 就能把训练集背下来,验证集 mAP 却纹丝不动,典型的过拟合。我一般会从 nano 或 small 起步,参数量控制在 300 万以内,配合强增强先把 baseline 跑出来。如果 nano 欠拟合(训练 loss 降不下去),再往 small 升一档,而不是直接跳 large。
另一个现实约束是显存。深色皮肤图像如果原始分辨率在 2000×3000 以上,直接 resize 到 640 会丢掉皮损边缘的细微纹理。常见做法是先把长边缩到 1280 做一次推理验证,确认病灶在缩小后仍可辨认,再决定训练输入尺寸。nano 模型在 1280 输入下,单卡 8G 显存也能跑 batch=4,这是它能落地的前提。
2.2 五个类别的标签命名与合并策略
标题里列了白糠疹、炎症后色素沉着过度、特发性黑色素沉着症、汇流和网状、白癜风。这里有个坑:汇流和网状更像形态描述,不是独立疾病实体,它可能和特发性黑色素沉着症同时出现在一张图上。如果强行拆成五个互斥类别,标注员会在同一区域反复纠结,标签一致性直接崩掉。
我的处理方式是先做一轮标签审计,统计每个类别的框数量和共现频率。如果“汇流和网状”与“特发性黑色素沉着症”共现超过 30%,就把它降级为属性而不是类别,最终保留四个检测类别。标签文件用 YOLO 标准格式,每行class_id x_center y_center width height,坐标全部归一化到 0~1。下面这段脚本用来检查标签里有没有越界框和空标签文件:
import os from pathlib import Path label_dir = Path("labels/train") img_dir = Path("images/train") issues = [] for lbl in label_dir.glob("*.txt"): img_name = lbl.stem + ".jpg" if not (img_dir / img_name).exists(): issues.append(f"孤儿标签: {lbl.name}") continue lines = lbl.read_text().strip().splitlines() if len(lines) == 0: issues.append(f"空标签: {lbl.name}") continue for i, line in enumerate(lines): parts = line.split() if len(parts) != 5: issues.append(f"字段数错误 {lbl.name}:{i}") continue cls, x, y, w, h = parts vals = list(map(float, [x, y, w, h])) # YOLO 归一化坐标必须在 0~1,越界说明标注工具导出异常 if any(v < 0 or v > 1 for v in vals): issues.append(f"坐标越界 {lbl.name}:{i} -> {vals}") if float(w) <= 0 or float(h) <= 0: issues.append(f"宽高非正 {lbl.name}:{i}") print(f"共发现 {len(issues)} 个问题") for it in issues[:20]: print(it)这段脚本做三件事:检查标签和图像是否一一对应、检查空标签、检查归一化坐标是否越界。参数上,label_dir和img_dir要按你实际的数据划分改;越界判断用 0~1 而不是像素值,是因为 YOLO 训练时读的是归一化坐标,越界框会在数据加载阶段被静默裁剪,训练日志里看不出来,只能靠离线检查抓。跑完如果问题数超过总标签数的 5%,先别急着训练,回去修标注。
2.3 数据划分要按“图像来源”分层而不是随机切
234 张图如果来自多个采集批次或不同设备,随机切分会让同一批次的图同时出现在训练和验证集,验证 mAP 虚高。我一般按图像来源做分层抽样:先给每张图打一个 source_id,再按 source_id 分组切分,保证验证集里的来源在训练集里也出现过,但具体图像不重叠。这样验证集才能反映模型对新个体的泛化,而不是对新批次的记忆。
3. 从零跑通训练:配置文件、增强参数与最小命令
3.1 数据集 YAML 与类别映射
YOLO 训练入口认一个 dataset.yaml,里面写清路径、类别数和类别名。路径建议用绝对路径,相对路径在不同工作目录下容易翻车。下面是一个可直接改的模板:
# dataset.yaml path: /data/skin_dark # 数据集根目录 train: images/train val: images/val test: images/test nc: 4 # 类别数,按标签审计后的结果改 names: 0: pityriasis_alba # 白糠疹 1: post_inflammatory_hyperpigmentation # 炎症后色素沉着过度 2: idiopathic_melanosis # 特发性黑色素沉着症 3: vitiligo # 白癜风nc必须和 names 的条目数一致,否则训练启动时会报索引越界。names 的顺序要和标签文件里的 class_id 严格对应,改顺序等于把标签全部打乱。我见过有人为了“看起来整齐”重排 names,结果模型把白癜风学成了白糠疹,这种错误在混淆矩阵里才看得出来,训练 loss 完全正常。
3.2 针对低对比度皮损的增强参数
默认增强对深色皮肤低对比度病灶不够用。我一般会显式调这几个参数:hsv_v调到 0.5 左右,让模型对亮度变化更鲁棒;hsv_s调到 0.7,因为色素沉着的核心区分度在饱和度通道;degrees控制在 10 以内,皮损方向没有语义,但大角度旋转会引入黑边;mosaic保持 1.0,小样本下 mosaic 相当于免费扩增。下面是最小训练命令:
yolo detect train \ data=/data/skin_dark/dataset.yaml \ model=yolov8n.pt \ imgsz=1280 \ epochs=200 \ batch=4 \ hsv_h=0.015 hsv_s=0.7 hsv_v=0.5 \ degrees=10 translate=0.1 scale=0.5 \ mosaic=1.0 mixup=0.1 \ patience=30 \ project=runs/skin_dark name=exp01imgsz=1280是为了保住皮损边缘细节,代价是显存和训练时间翻倍,8G 卡上 batch 只能给到 4。patience=30表示验证 mAP 连续 30 个 epoch 不升就早停,小样本下这个值别设太小,否则模型还没收敛就被掐掉。mixup=0.1是轻度混合,再高会让低对比度病灶互相叠加,反而更难学。跑之前先用yolo detect train ... epochs=1做一次冒烟测试,确认数据路径和标签能正常加载,别等跑了三小时才发现 val 集是空的。
3.3 训练过程中该盯哪几个指标
小样本训练,loss 曲线好看不代表模型有用。我重点看三个东西:验证集的 mAP50 是否在 50 个 epoch 后还在缓慢爬升、混淆矩阵里有没有某个类别被整体预测成背景、以及每类的 recall 是否严重不均衡。深色皮肤数据集最常见的现象是白糠疹和白癜风这两类低对比度病灶 recall 明显低于另外两类,因为它们的边界在特征图上响应最弱。如果出现这种情况,先别加 epoch,回去检查这两类的标注框是不是普遍偏大或偏小,标注框和实际病灶边缘差 10 个像素,在 1280 输入下就是 20 个特征点的偏移,足够让检测头学偏。
4. 深色皮肤检测的避坑清单:5 个我踩过的坑
4.1 坑一:验证集 mAP 很高,换一批图全漏检
现象是训练日志里 mAP50 到 0.8,拿几张新采集的图一跑,一个框都没有。原因是数据划分时同一来源的图被随机分到了训练和验证集,模型记住的是这批图的采集特征而不是病灶特征。解决方式是回到 2.3 节的分层切分,按 source_id 分组,验证集只放训练集里出现过的来源,但图像不重叠。改完划分后 mAP 通常会掉 10~20 个点,那才是真实水平。
4.2 坑二:把“汇流和网状”当独立类别,标注一致性崩了
现象是同一张图两个标注员给出的框差异巨大,训练时 loss 震荡。原因是这个类别本质是形态描述,和特发性黑色素沉着症高度重叠。解决方式是做共现统计,共现超过阈值就合并或降级为属性。合并后类别数从 5 降到 4,标注一致性明显提升,训练 loss 也稳了。
4.3 坑三:输入尺寸直接拉到 1920,显存爆了还怪模型
现象是 batch 只能设 1,训练极慢,还频繁 OOM。原因是深色皮肤图像原始分辨率高,1920 输入下 nano 模型的特征图也很大。解决方式是先用 1280 跑通,确认精度可接受再考虑升分辨率;如果必须 1920,改用梯度累积模拟大 batch,而不是硬扛显存。
4.4 坑四:增强开太猛,低对比度病灶被“增强没了”
现象是训练 loss 正常下降,但验证集 recall 一直上不去。原因是 hsv_v 和 mixup 开太大,低对比度病灶在增强后和背景融为一体。解决方式是把 hsv_v 从默认往上调但不超过 0.5,mixup 控制在 0.1 以内,并且每加一个增强参数就单独跑一次对比,别一次性全开。
4.5 坑五:标签里混入了非目标类别的框
现象是模型总在某些正常皮肤区域出框。原因是标注时把一些边界模糊的正常纹理也标成了病灶。解决方式是做一轮标签复核,把置信度低的框单独拉出来人工过一遍,宁可少标也不要错标。小样本下,一个错标框对 loss 的影响被放大好几倍。
5. 小样本深色皮肤检测的进阶技巧:从能跑到能用
234 张图想跑到“能用”,单靠一次训练不够。我一般会做两件事:第一件是用训练好的模型在验证集上跑推理,把高置信度但标签里没有的检测框导出,人工确认后作为补充标签加入训练集,这叫自训练式半监督,能把有效样本量提升 20%~30%。第二件是冻结 backbone 做微调,先用通用权重训 50 个 epoch,再解冻最后两层用低学习率(比如 1e-4)训 100 个 epoch,让模型在保留通用特征的同时适配深色皮肤的低对比度分布。
验证方法上,别只看 mAP。我习惯按类别分别算 recall,再画一张每类 recall 随置信度阈值变化的曲线。深色皮肤数据集里,白糠疹和白癜风这两类往往需要把置信度阈值从默认 0.25 降到 0.15 才能把 recall 拉起来,代价是误检增加。这个取舍没有标准答案,取决于你的下游是“宁可错报”还是“宁可漏报”。如果是辅助筛查,倾向高 recall;如果是自动报告,倾向高 precision。
最后一个具体技巧:推理时把输入尺寸设成和训练一致,别训练 1280 推理 640。深色皮肤病灶在缩小一半后,边缘梯度可能直接消失,模型输出会变得极不稳定。我吃过这个亏,训练日志一切正常,部署时忘了改推理尺寸,线上漏检率翻了三倍,排查了一整天才定位到。现在我的习惯是训练脚本和推理脚本共用同一个 imgsz 变量,从源头杜绝不一致。希望帮到你。
本文还有配套的精品资源,点击获取