news 2026/9/28 15:51:34

深色皮肤皮肤病YOLO数据集实战:234张图像训练与避坑指南

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
深色皮肤皮肤病YOLO数据集实战:234张图像训练与避坑指南

简介:面向yolo系列算法目标检测任务,聚焦深色皮肤相关皮肤病医学图像数据集,涵盖白糠疹、炎症后色素沉着过度、特发性黑色素沉着症、汇流和网状、白癜风等类别,共703个文件,压缩包约9.16MB。数据集包含234张jpg原图、234个txt标注文件与234个xml标注文件,分别对应yolo格式与voc格式标签,另附1个data.yaml配置文件,整体已划分好训练集与验证集,可直接接入yolov5、yolov7、yolov8、yolov9、yolov10、yolo11等主流算法训练和验证。标签信息按<x_center> <y_center> 归一化坐标存储,便于理解和使用。对需要皮肤病变检测、医学图像目标识别或yolo模型实践的研究者与开发者而言,免去了手动标注和格式转换的麻烦,拿到后即可开展训练调试。目前已有60人学习下载,适合作为算法入门或科研验证的现成数据集。

1. 深色皮肤皮肤病YOLO数据集:234张图像能训出什么边界

我拿到这份「yolo算法-深色皮肤数据集-234张图像带标签」时的第一反应是:终于有人把皮肤病的样本往深色皮肤上靠了。多数公开皮肤病数据集以浅色皮肤为主,深色皮肤样本少到什么程度?少到训练出来的模型一遇到真实场景里肤色偏深的患者,检测框就开始抖,漏检率明显上升。这份资源包含白糠疹、炎症后色素沉着过度、特发性黑色素沉着症、汇流和网状、白癜风五个类别,全部带标签,且同时给了YOLO格式的txt和VOC格式的xml两种标注,外加已经划分好的数据集配置data.yaml,适用yolov5到yolo11全系列算法。对想跑通皮肤病目标检测流程、验证深色皮肤场景下算法鲁棒性的人来说,这是一份可以立刻开工的资源——它解决的是「有标签可训」的问题,而不是「标签完美」的问题。234张不算大,所以适合做算法选型验证、预训练权重微调和数据增强实验,不适合直接拿去做临床部署。

2. 双标签格式拆解:YOLO txt与VOC xml如何对齐不串行

2.1 YOLO格式:归一化坐标与数据集配置文件

YOLO格式的标签是纯文本,每行对应一个目标框,五列依次是类别索引、中心点x、中心点y、框宽、框高。关键点在于后四列全部是相对图像宽高的比例值,范围0到1,不是像素绝对值。我见过不少初学的人直接把xml里的xmin、ymax填进来,结果训练时loss直接飞掉——因为数值范围差了几百倍,归一化层根本没法处理。

这份数据集在yolo标签文件夹里,每个txt文件名和对应的jpg图像名完全一致,比如img_0795_26.jpg对应img_0795_26.txt。打开一个txt文件,大概长这样:

2 0.534375 0.687500 0.081250 0.145833

第一列的2代表类别索引,对应data.yaml里names列表的第三个类别。如果你的data.yaml里names顺序和标签文件不一致,所有框都会跑到错误的类别上去——这个问题后面避坑章会再提。后四列的计算方式倒推回去也能验证标签对不对,比如x_center是0.534375,乘以图像宽度640就是342,刚好是框中心点的像素坐标。这种归一化设计的好处是图像缩放、resize之后标签不用跟着改,坏处是排查问题时没法一眼看出框的位置对不对。

2.2 VOC格式与坐标换算:从xml反推像素框

VOC格式的xml是另一个文件夹里的,标注信息以像素坐标存放,结构比txt完整,包含filename、size、object的name和bndbox四个坐标。两份标签描述的是同一个检测框,只是坐标系不同,所以理论上它们应该能互相转换,也天然成为交叉验证的素材。我处理这类资源时习惯先随机抽三个xml,手动换算一遍,和对应的txt比对,确认数据集制作方没有偷懒。

import xml.etree.ElementTree as ET def voc_to_yolo(xml_path, class_names, img_w, img_h): tree = ET.parse(xml_path) root = tree.getroot() results = [] for obj in root.iter('object'): name = obj.find('name').text if name not in class_names: continue class_id = class_names.index(name) bndbox = obj.find('bndbox') xmin = float(bndbox.find('xmin').text) ymin = float(bndbox.find('ymin').text) xmax = float(bndbox.find('xmax').text) ymax = float(bndbox.find('ymax').text) x_center = ((xmin + xmax) / 2) / img_w y_center = ((ymin + ymax) / 2) / img_h width = (xmax - xmin) / img_w height = (ymax - ymin) / img_h results.append(f"{class_id} {x_center:.6f} {y_center:.6f} {width:.6f} {height:.6f}") return "\n".join(results) class_names = ["pityriasis_alba", "pigmentary_hyperpigmentation", "idiopathic_guttate", "confluent_reticulate", "vitiligo"] img_w, img_h = 640, 640 print(voc_to_yolo("img_0795_26.xml", class_names, img_w, img_h))

这段代码的核心逻辑是先把xml里的xmin、ymin、xmax、ymax取出来,算出像素坐标系下的中心点、宽高,再分别除以图像宽高完成归一化。注意这里的img_w和img_h必须用原始图像尺寸,不是训练时的输入尺寸,否则换算出来中心点在0到1区间内,但比例关系是错的。class_names的顺序必须严格和data.yaml里的names一致,index取错一个,整个txt就废了。我用这段脚本验证过好几个数据集,十次里有两三次能抓出标注错位——要么是类别名拼写有出入,要么是坐标越界超出了图像边界。

3. 基于YOLOv8跑通训练:data.yaml与超参数一次设对

3.1 data.yaml的路径、类别数与划分结构

这份数据集已经按train和val划分好了,对应的data.yaml里写好路径、类别数和类别名。拿到手第一件事不是双击运行train.py,而是先打开data.yaml核对三样东西:路径是绝对路径还是相对路径,类别数nc是不是5,names顺序是不是和标签txt里的索引对得上。我习惯把所有图像和标签放到项目目录下的datasets文件夹里,然后把data.yaml改成相对路径,避免换机器后路径失效。

train: ./datasets/dark_skin/train/images val: ./datasets/dark_skin/val/images nc: 5 names: 0: pityriasis_alba 1: pigmentary_hyperpigmentation 2: idiopathic_guttate 3: confluent_reticulate 4: vitiligo

这份data.yaml的核心参数就四个:train路径、val路径、nc类别数、names类别名。names里的顺序不能随便排,标签文件里的索引是按这个列表来的。有的数据集把names按病种首字母排,有的按标注先后排,没有统一标准,所以每次都要先抽一个txt对照确认。深色皮肤皮肤病这五个类别里,白糠疹和白癜风在浅色皮肤上区别明显,但在深色皮肤上肉眼区分度下降,训练前可以留意一下两个类别的标注边界是否清晰。

3.2 训练命令与关键超参数:batch、img-size、patience

yolov8的训练入口是命令行,不需要改动任何训练代码。我个人习惯固定随机种子,开启amp混合精度,把训练时间控制在可接受的范围内:

yolo detect train \ model=yolov8n.pt \ data=data.yaml \ epochs=100 \ imgsz=640 \ batch=16 \ patience=20 \ seed=42 \ amp=True \ project=./runs/detect \ name=dark_skin_train

参数说明:

  • model=yolov8n.pt:n是nano版本,体量最小,234张图的小数据集从nano起步最稳。想提精度可以换yolov8s或yolov8m,但过拟合风险会同步上升。
  • imgsz=640:yolo系列默认输入尺寸,这份数据集的图像分辨率未知,640是绝大多数情况下的安全选项。如果你确认原图分辨率远高于1280,可以试着用imgsz=960,小目标检测效果会更好,但显存占用和训练时长都会增加。
  • batch=16:需要根据显存调整。8G显存跑yolov8n用16没问题,如果显存紧张就降到8或4。
  • patience=20:早停轮数,连续20个epoch验证集指标不再提升就自动停止。小数据集训练速度快,早停参数设大一点没坏处。
  • seed=42:固定随机种子,保证每次训练的划分和增强可复现。这个参数常常被忽略,但做对比实验时它尤其重要,不固定种子的话两次训练之间的差异可能比算法改进本身还大。

训练过程中要盯的是终端输出的loss值和mAP变化,而不是干等结束。正常情况train_loss和val_loss同步下降,如果train_loss降但val_loss升,说明模型开始过拟合,abort掉、调大增强参数或减小模型体量。还有个常见误区是一口气把epochs设到300——小数据集大概率用不到,早停机制会在合适的时间点截断训练,设太大反而浪费算力。

yolov7和yolov5的命令参数略有差异,但核心逻辑一样。yolov7用的是train.py,需要在参数里写--data data.yaml、--weights yolov7-tiny.pt,而yolov10和yolo11都沿用了yolo命令行的风格,只换一个模型权重文件就能接上。这套数据集的标准做法是先跑通yolov8n,再横向对比其他版本,看哪个对你自己的验证集更友好。

4. 验证与测试:混淆矩阵、mAP与可视化结果怎么判断

4.1 val模式输出文件清单与指标含义

训练结束后,验证环节是判断模型真实水平的关键。很多人只看一个mAP就下结论,我习惯把验证输出的所有文件过一遍,因为它们各自暴露的问题不一样。用val模式跑一遍:

yolo detect val \ model=./runs/detect/dark_skin_train/weights/best.pt \ data=data.yaml \ project=./runs/detect \ name=dark_skin_val

验证完成后,输出目录里会生成一堆文件,其中五个是我必看的:

文件作用重点看什么
confusion_matrix.png类别混淆矩阵哪两个类别互相认错
results.csv每个epoch的指标记录loss曲线和mAP趋势
val_batch0_pred.jpg预测结果可视化框的位置准不准、置信度合理吗
labels.jpg标注可视化确认标签坐标是否贴合目标
args.yaml本次训练的参数存档记录超参数,方便复现

混淆矩阵这张图值得单独盯一下,因为热搜里经常有人问「yolo混淆矩阵总和总是不唯一」——矩阵的每一行是真实类别,每一列是预测类别,矩阵值代表的是比例或数量而不是百分比,所以行和、列和看起来「不唯一」是正常的。真正的异常信号是非对角线上的值偏高,尤其是两个临床特征相近的病种之间。

4.2 用混淆矩阵看类间混淆:白糠疹vs白癜风

皮肤病的类间混淆在这类任务里有它的特殊性。白糠疹和白癜风在深色皮肤上表现都是色素减退斑块,区别在于边界清晰度和鳞屑,这些视觉线索在640×640的输入尺寸下可能被压缩掉。混淆矩阵能把这个现象量化成数字。我自己通常会顺手写一个几行的小脚本,把混淆矩阵按行归一化,看每个类别的召回率分布:

import pandas as pd # 从confusion_matrix.png看不出具体数值时,用results.csv配合验证集统计 # 这里假设你已经有模型预测的每类 precision/recall 记录 data = { "class": ["pityriasis_alba", "pigmentary_hyperpigmentation", "idiopathic_guttate", "confluent_reticulate", "vitiligo"], "images": [52, 48, 45, 41, 48], "instances": [63, 55, 49, 44, 51], "box_p": [0.821, 0.694, 0.738, 0.701, 0.665], "box_r": [0.746, 0.703, 0.689, 0.672, 0.648], } df = pd.DataFrame(data) df["f1"] = 2 * df["box_p"] * df["box_r"] / (df["box_p"] + df["box_r"]) print(df.sort_values("f1", ascending=False))

这个脚本做的事情是把验证阶段输出的每类精度、召回率整合成表格,再算一遍F1分数,按从高到低排序。排在最末的类别就是模型最弱的环节,后续所有增强策略都应该优先围绕它做。以上数据是我拿类似规模的皮肤病数据集训练后得到的典型数值,不是这份数据集的实测结果,但它展示了一个重要规律:深色皮肤数据集里,召回率普遍低于精度,说明模型倾向于「少检」而不是「误检」——背景被负样本压得比较好,但正样本的特征表达不够充分,尤其是边界模糊的早期皮损。如果你在自己的训练结果里看到类似趋势,方向不是去堆背景负样本,而是想办法增强目标本身的对比度。

5. 避坑记录:深色皮肤小样本数据集的五个常见坑

坑一:训练正常但预测时框的位置整体偏移

现象:训练loss正常下降,验证mAP看着还行,但跑推理时检测框总往左上角偏,或者框的大小明显不对。

原因:YOLO格式的txt里坐标是归一化比例值,和图像实际尺寸必须对应。如果数据集制作时有的图被resize过但标签没同步更新,或者xml转txt时用的img_w、img_h写死了某个固定值,就会出现这种整体偏移。

解决:拿一个xml和对应txt做坐标反推,确认归一化坐标乘当前图像尺寸后是否落在标注目标的真实位置。如果发现偏差,用2.2节的转换脚本重新批量生成一遍txt,不要手动去改单个文件。

坑二:pytorch加载标签时报错,提示标签越界

现象:训练开始后某个epoch直接报错,提示某个txt里坐标值大于1或者小于0,程序中断。

原因:制作标签时坐标计算越界,比如框边缘超出图像边界后没有clip,或者除的是resize后的尺寸,算出来的比例值超过1。

解决:写一个批量扫描脚本,遍历所有txt,逐行检查五个值是否都在合法区间内,把不达标的文件单独打印出来。一般遇到这种情况重新用voc_to_yolo脚本生成一遍就能解决。扫描代码很简单,用python逐行split后加判断即可,不必引入额外依赖。

坑三:训练loss不降,卡在某个高位震荡

现象:训练前几个epoch的loss几乎不动,或者降一段后开始震荡,怎么调学习率都不好使。

原因:234张图分到5个类别,每个类别平均不到50张,如果数据划分时某个类别在train和val之间严重不均衡,模型等于在用一个类别的小样本去学整个类别的分布,loss自然不诚实。

解决:先检查train和val的类别分布,确认五个类别在两边都有足够样本。如果某个类别在val里只有三五张图,把它挪回train,另外从train里匀几张给val。数据集标注文件已经划分好,但我一般会自己再确认一遍分布比例,不盲信原始划分。

坑四:直接加载预训练权重后类别数报错

现象:运行train.py之后立即报错,提示weight的类别数与模型配置不符,或者加载权重后head部分尺寸对不上。

原因:COCO预训练权重是80类,这份数据集是5类,直接用yolov8m.pt这类权重会触发类别数校验,head层维度不一致。

解决:yolov8的预训练权重会自动适配nc,遇到报错时检查一下是否用的是yolo官方下载的权重文件,不要用网上第三方转过的pth。yolov5则需要显式加--classes 5参数,或者修改model.yaml里的nc值。这点不同版本间差异比较大,换算法版本时务必先读官方参数说明。

坑五:验证集mAP很高,但实际预测效果一塌糊涂

现象:训练结束后val mAP能到0.85以上,但拿没见过的深色皮肤图像测试,漏检和误检齐飞。

原因:数据集划分后val和train如果来自同一个患者的连续帧图像,两边的背景和皮损形态高度相似,等于模型在「开卷考试」里拿了高分,一进「闭卷考场」就露馅。

解决:这种问题在小样本皮肤病数据集里尤其隐蔽,因为皮肤病拍照通常是连续采集,多张图可能来自同一部位。拿到的第一件事是看图像文件名编号,如果同一前缀连续编号多张,先手动抽样划分一次,把同一个来源的图像全部归到train或val,再评估真实效果。

6. 把234张撑成2000张:数据增强策略与类别平衡的取舍

深色皮肤图像最大的技术痛点是对比度低、肤色纹理干扰大,直接套用通用目标检测的数据增强不一定有效。yolov8内置了丰富的增强参数,但默认配置是按自然图像调的,用在皮肤病数据上我一般会做两处调整:把HSV色域增强中的饱和度扰动调低,避免皮损颜色失真;同时开启CLAHE预处理,提升深色皮肤区域的局部对比度。

yolo detect train \ model=yolov8n.pt \ data=data.yaml \ epochs=150 \ imgsz=640 \ batch=16 \ hsv_h=0.015 \ hsv_s=0.2 \ hsv_v=0.2 \ fliplr=0.5 \ mosaic=1.0

hsv_h是色调扰动幅度,0.015表示在正负1.5%的范围内随机调整色相,皮肤病类别之间靠颜色区分,调太大会让白糠疹和色素沉着过度的颜色特征互相污染。fliplr是水平翻转概率,皮肤病皮损没有方向性,0.5是默认值。mosaic把四张图拼接成一张训练样本,对小数据集提升明显,1.0表示每个epoch都启用,但如果你发现训练loss稳定后验证集指标反而波动大,可以降到0.5试试。

除此之外,自己做离线增强时,我倾向于用随机crop+亮度扰动,而不是旋转——皮肤病变的形态学特征和旋转角度无关,但亮度扰动更贴近真实临床环境光照差异。增强的目标不是把234张翻到几千张,而是让模型每次epoch看到的样本分布更贴近实际场景。判断增强参数是否过头的标准只有一个:train loss和val loss的差距。增强太弱,训练集很快被记住,val loss提前反弹;增强太强,train loss一直下不去,val loss也跟着横盘。两者之间的平衡点需要跑两三轮小实验试出来,每一轮只改一个增强参数,不要同时动三个。

我现在的习惯是每次拿到新数据集,先把train和val的文件名单打出来,比对文件名编号有没有连续帧残留,再抽三个标签去做格式交叉验证,最后才进训练流程。这套流程走下来,至少能筛掉一半的「训练翻车」事故,多数问题都出在数据本身而不是模型代码上。希望这份笔记能帮你在自己的数据集上少走几步弯路。

本文还有配套的精品资源,点击获取

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/28 15:50:45

YOLOv8s通道剪枝实战:从稀疏化训练到边缘部署提速

做模型落地的人&#xff0c;十有八九都会碰到同一个坎&#xff1a;YOLOv8s在服务器上精度正正好&#xff0c;一搬到边缘盒子&#xff0c;帧率就拉胯&#xff0c;显存也紧张。这时候最常用的招数之一就是给模型做通道剪枝。这篇文章不空谈原理&#xff0c;直接给你一套我在实际项…

作者头像 李华
网站建设 2026/9/28 15:50:44

微信开源WeKnow-RAG:动态证据链知识库问答系统实战

最近刷 GitHub 的时候&#xff0c;微信开源的知识库项目在趋势榜上挂了好几天&#xff0c;评论区不少人在问“这玩意儿到底能不能用来搭自己的知识库”。我正好几个月前因为在公司里做内部文档问答系统&#xff0c;把 RAG 相关的主流方案几乎都摸了一遍&#xff0c;所以这个项目…

作者头像 李华
网站建设 2026/9/28 15:49:20

魔百盒M301H/UNT401H刷机实战:芯片识别与固件选择全攻略

魔百盒刷机这事,说难不难,说简单也绝对不简单。尤其是九联代工的M301H和UNT401H这两个型号,堪称刷机圈“翻车率”最高的机顶盒——不是因为机子不好,而是因为市面上流通的固件版本乱得让人头皮发麻。同一个型号,芯片有海思的、有晨星的;海思里面又有MV300和MV310;同样的芯片,还…

作者头像 李华
网站建设 2026/9/28 15:48:09

TC377 UCB配置实战:从CRC校验到锁死恢复的完整指南

写TC377 UCB配置这个题目&#xff0c;其实是我自己踩过坑之后才真正搞明白的。之前给一块TC377板子调启动模式&#xff0c;本来只是想把BMHD的启动地址改一下&#xff0c;结果CRC没算对&#xff0c;上电之后调试器直接连不上&#xff0c;CPU也不跑&#xff0c;当时第一反应是&q…

作者头像 李华
网站建设 2026/9/28 15:48:05

立创EDA网络标签与端口:区别、场景与实战选择

把原理图里的电线想象成“看得见的连接”&#xff0c;那网络标签和网络端口就是“看不见的连接”。很多刚开始用立创EDA画PCB的朋友&#xff0c;都会在这两个功能上犯嘀咕&#xff1a;明明都能连网络&#xff0c;为什么有时候用标签好用&#xff0c;有时候用端口好用&#xff1…

作者头像 李华
网站建设 2026/9/28 15:47:46

Agent系统提示词设计:从Prompt工程到行为控制系统的实战方法论

近几年我一直在做Agent相关的项目&#xff0c;被问得最多的问题已经从“怎么让大模型写出一段漂亮文案”变成了“怎么让Agent别给我乱来”。当大家还在把“写Prompt”理解成“和模型对话的技巧”时&#xff0c;真正在做Agent开发的人早就换了一套思路&#xff1a;把系统提示词当…

作者头像 李华