尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

基于YOLOv8的妇科皮肤病检测:数据集构建与模型训练全流程

基于YOLOv8的妇科皮肤病检测:数据集构建与模型训练全流程 简介面向yolo系列算法目标检测任务的妇科皮肤病数据集覆盖黑色素瘤、猴痘、水痘、痤疮、疣、花斑癣、粉刺、银屑病、湿疹、癣共10类皮肤问题适合医学图像检测研究、皮肤病辅助诊断模型训练以及yolo系算法的教学实战。数据集已按训练/验证/测试划分好并附带data.yaml配置文件可直接接入yolov5、yolov7、yolov8、yolov9、yolov10、yolo11等主流版本进行训练与验证免去自行标注和分集的繁琐流程。压缩包总计2000个标注文件以xml标注为主同时提供yolo格式的txt标签和voc格式的xml标签分别存放于不同文件夹坐标信息均采用归一化的中心点与宽高表示便于不同工具链读取和转换。资源整体约169.39MB结构清晰文件命名规范适合快速上手实验。目前已有98人学习下载对于需要标准医学皮肤病检测数据集的开发者或研究者而言是一个完整且开箱可用的训练资源。1. 用YOLO做妇科皮肤病检测先看数据再谈模型4418张图像、十类妇科皮肤病变标签放到yolo目标检测流程里第一件事不是调参而是确认标签粒度。黑色素、猴痘、水痘、痤疮、疣、花斑癣、粉刺、银屑病、湿疹、癣这十类很多在早期外观上只差一个色泽环和边界形态全局分类网络容易把多病灶图像判成一类而YOLO把每个病灶框出来再做分类更贴近皮肤科医生的读图方式。不过妇科部位图像的光照、姿势、遮挡差异远大于公共数据集训练时既要防模型记住背景也要防类别不平衡导致少数类被吞掉。下面按数据准备、标签转换、训练参数、损失排查、推理迁移这条yolo目标检测流程展开引用的命令和脚本用YOLOv8为例。2. 妇科皮肤病数据集的构成与YOLO标签格式转换拿到压缩包并解压后先不要急着训练。打开标签文件确认它是COCO JSON、Pascal VOC XML还是Ultralytics的txt。妇科皮肤病数据集里的“黑色素”可能是色素痣也可能是黑色素瘤“猴痘”和“水痘”的疱形态接近标注规范直接决定后面几十轮训练是否白跑。2.1 十类皮肤损伤的标注目标定义下表按标题中的顺序给出一个通用映射具体以解压后的names文件或类别编号为准类别ID标签名常见外观特征0melanoma不对称、边缘不规则、色泽不均1monkeypox凸起水疱或脓疱周围红晕2chickenpox小而密集的水疱疱壁薄3acne红肿丘疹常伴脓头4wart表面粗糙的丘疹5tinea_versicolor边界清楚、颜色不一斑片6comedone黑头或白色闭合性粉刺7psoriasis红色斑块有银白色鳞屑8eczema红斑、苔藓化、边界不清9ringworm环形红斑中央脱屑注意类别ID必须从0开始连续编号。如果原JSON里category_id从1开始转换时要统一减一如果原标签里顺序和标题顺序不一致先写一个小字典映射到新ID不要直接用原ID。2.2 从原始标注到YOLO txt标签的转换脚本常见做法是拿到COCO JSON标注一个image_id对应一张图一个annotation对应一个框。下面的脚本把它转成YOLO训练用的txt标签转换思路和KITTI标注转YOLO时用的坐标归一化完全一致。import json from pathlib import Path from collections import defaultdict def coco_to_yolo(coco_path: str, output_dir: str) - None: with open(coco_path, encodingutf-8) as f: coco json.load(f) img_info {img[id]: img for img in coco[images]} img_annos defaultdict(list) for ann in coco[annotations]: img_annos[ann[image_id]].append(ann) out Path(output_dir) out.mkdir(exist_okTrue) for img_id, anns in img_annos.items(): info img_info[img_id] w, h int(info[width]), int(info[height]) name Path(info[file_name]).stem lines [] for ann in anns: cat ann[category_id] - 1 # 原ID从1开始则减1 x, y, bw, bh ann[bbox] # 左上角坐标和宽高 # 裁剪到画面内部避免越界 x2 min(x bw, w) y2 min(y bh, h) x max(x, 0) y max(y, 0) bw, bh x2 - x, y2 - y if bw 2 or bh 2: # 过滤过小目标 continue cx (x bw / 2) / w cy (y bh / 2) / h nw bw / w nh bh / h lines.append(f{cat} {cx:.6f} {cy:.6f} {nw:.6f} {nh:.6f}) (out / f{name}.txt).write_text(\n.join(lines), encodingutf-8)这段代码的要点是category_id - 1用来把COCO从1开始的类别号转为YOLO从0开始bbox的四个值是[x, y, width, height]其中x, y是框左上角归一化使用图像宽高w, h做分母。bw 2的条件过滤掉只有几个像素的小框这类框往往是人手标注的噪声强行保留会让box_loss抖动。如果原标注是XML文件把ann[bbox]换成解析bndbox后的xmin, ymin, xmax, ymax公式不变只需要先把x2-x算出宽高。2.3 数据集目录结构与类别映射表YOLO训练时不会自动识别图片和标签的关联它要求图片放在images/train、images/val同名txt放在labels/train、labels/val。目录结构如下gynecological_skin/ ├── images/ │ ├── train/ │ └── val/ ├── labels/ │ ├── train/ │ └── val/ └── gynecological_skin.yaml对应的data.yaml按下面的写法填写path: /absolute/path/to/gynecological_skin train: images/train val: images/val names: 0: melanoma 1: monkeypox 2: chickenpox 3: acne 4: wart 5: tinea_versicolor 6: comedone 7: psoriasis 8: eczema 9: ringworm如果原始压缩包没有划分train和val可以先用train_test_split切分固定随机种子保证可复现from sklearn.model_selection import train_test_split import glob, os, shutil imgs sorted(glob.glob(raw/images/*.jpg)) train, val train_test_split(imgs, test_size0.2, random_state42) for split, paths in [(train, train), (val, val)]: os.makedirs(fgynecological_skin/images/{split}, exist_okTrue) os.makedirs(fgynecological_skin/labels/{split}, exist_okTrue) for p in paths: name os.path.basename(p) stem os.path.splitext(name)[0] shutil.copy(p, fgynecological_skin/images/{split}/{name}) label fraw/labels/{stem}.txt if os.path.exists(label): shutil.copy(label, fgynecological_skin/labels/{split}/{stem}.txt)test_size0.2在4418张图上大约留出884张验证图比例合适random_state42保证重复执行时切分结果不变。复制标签文件时如果找不到同名txt说明原始标注漏标这种图片要么补标要么移出训练集。3. 训练YOLOv8妇科皮肤病模型的关键参数把4418张图喂给YOLOv8之前先决定用哪个模型体和优化策略。YOLOv8把anchor箱交给网络自适应学习省掉了YOLOv5里手动聚类锚框的步骤对病灶这种长宽比不固定的目标更省事。3.1 为什么选YOLOv8而不是更早版本从yolo算法发展角度看YOLOv8使用C2f结构替换C3模块特征融合阶段对小目标更友好同时内置了mosaic、mixup、hsv扰动等数据增强不用额外写增强代码。妇科皮肤病图像里病灶相对周围皮肤对比度不高多尺度特征是否丰富直接决定小水疱能不能被找到。这里用yolov8n.pt作为起点不会因为模型过大导致显存不足训练一轮的时间较短方便快速验证标签质量。如果显存足够可以换成yolov8s.pt精度通常会提升1到2个点。3.2 yolov8训练自己的数据集的命令与yaml配置安装ultralytics后直接用命令行启动训练pip install ultralytics yolo train datagynecological_skin.yaml \ modelyolov8n.pt \ epochs120 \ imgsz640 \ batch16 \ lr00.001 \ optimizerAdamW \ patience20 \ cos_lrTrue \ device0data指向2.3节写的yamlmodel填预训练权重路径YOLOv8会下载对应参数epochs120对4418张图像来说足够配合早停不会浪费太多时间。关键参数如下表参数建议值说明imgsz640原图分辨率如果超过两倍建议先归一化到640小水疱多可上调到768batch16显存小于8G时降到8同时把lr0降到0.0005lr00.001使用预训练权重时的常用初始值optimizerAdamW小数据集上AdamW收敛比SGD稳patience20验证集指标连续20轮不升就早停cos_lrTrue余弦退火减少后期震荡训练过程中日志和断点会保存在runs/detect/train/。每次跑新实验前建议手动改一下project或name比如projectruns_skin nameexp03避免覆盖上一轮的权重。如果一轮训练后发现验证集mAP很低先检查标签有没有错位而不是盲目加epoch。3.3 小样本类别不平衡的处理4418张图不是平均分配给10个类别。常见分布是痤疮、湿疹、癣样本偏多猴痘、黑色素偏少。先统计每个类别的框数量再决定要不要做增强。from pathlib import Path import collections def count_boxes(label_dir): counter collections.Counter() for txt in Path(label_dir).glob(*.txt): for line in txt.read_text().splitlines(): if line.strip(): counter[int(line.split()[0])] 1 return counter counts count_boxes(gynecological_skin/labels/train) print(counts)如果某个类的框数少于另一个类的一个零头比如monkeypox总共不到50个框模型很难学到稳定的特征。常见做法是仅对少类图像做离线增强然后把这些增强副本追加到训练集中import cv2 from pathlib import Path from albumentations import Rotate, RandomBrightnessContrast few_images [raw/images/001.jpg] # 从上一段统计中挑出少类图片 for img_path in few_images: img cv2.imread(img_path) rotated Rotate(limit10, p1.0)(imageimg)[image] bright RandomBrightnessContrast(limit0.2)(imagerotated)[image] out Path(augmented) / Path(img_path).name cv2.imwrite(str(out), bright)增强副本复制时标签txt也要复制成同名文件。注意不要用垂直翻转私密部位图像上下翻转后会改变解剖结构的方向语义模型容易学到错误特征水平翻转在皮肤科通常可接受。复制数量控制在原样本的1到2倍过量复制会让训练每个epoch都反复看同一张图局部过拟合反而拉低验证集AP。4. 读懂yolo损失函数并排查训练异常训练跑到几十轮后不能只看mAP有没有涨。YOLOv8输出的损失曲线隐藏了很多标签质量和数据分布的信息学会读它排错会快很多。4.1 YOLOv8损失曲线的几个分量yolo损失函数由三部分组成box_loss使用CIoU衡量预测框与真实框的位置误差cls_loss使用BCEWithLogitsLoss做多标签分类dfl_loss处理边界框分布的离散化误差。结果目录里的results.csv记录了每个epoch的训练和验证分量import pandas as pd import matplotlib.pyplot as plt df pd.read_csv(runs/detect/train/results.csv) df.columns [c.strip() for c in df.columns] plt.plot(df[epoch], df[train/cls_loss], labeltrain_cls) plt.plot(df[epoch], df[val/cls_loss], labelval_cls) plt.legend() plt.savefig(cls_curve.png)第一行读入的列名会带大量前导空格必须strip一次再取列。重点看验证集分类损失它比train/cls_loss更早暴露过拟合。如果val/cls_loss在前10轮快速下降后突然回升说明模型开始记忆皮肤纹理和光影这种时候首先要降低lr0其次是减少mosaic概率或关闭mixup。4.2 标注漏检与标签噪声的排查妇科皮肤病数据集中有些图像只框了最大的病灶旁边的小丘疹没框。这种漏标对YOLO的伤害比错标更大因为漏检区域会变成假负样本模型被迫学会“这里没有目标”。先用一张图一个框的统计把异常图片找出来from pathlib import Path box_counts [] for txt in Path(gynecological_skin/labels/val).glob(*.txt): c sum(1 for line in txt.read_text().splitlines() if line.strip()) box_counts.append((txt.name, c)) for name, c in sorted(box_counts, keylambda x: x[1])[:20]: if c 0: print(name, c)这份代码会列出验证集里标签完全为空的图片。如果一张图里确实一个病灶都没有它作为背景样本没问题但更多情况是漏标打开对应图片看一遍就知道。另一种常见错误是所有标签的框宽高都等于原图尺寸这说明原始的bbox用的可能是中心点坐标[cx, cy, w, h]被误读成了[x, y, w, h]转换时要把前半段做x cx - w/2的偏移。4.3 用验证集PR曲线决定阈值和增强策略训练结束后跑一次标准验证yolo val modelruns/detect/train/weights/best.pt \ datagynecological_skin.yaml \ conf0.25 \ iou0.5conf0.25是判断正负样本的置信度阈值iou0.5是NMS和mAP计算时的IoU阈值。验证输出会生成PR_curve.png和confusion_matrix.png。看混淆矩阵时注意黑色素类和疣类是否互相误检这两类颜色接近如果互相混淆很严重考虑给它们补充边界更清晰的难例样本。val/cls_loss很低但mAP不高往往不是训练问题而是数据集类别定义重叠。临床上湿疹和银屑病早期本就难以区分让模型输出上保留这两个类还是合并成一个“红斑鳞屑类”需要和标注者确认。如果决定合并第三个类别对应的txt里的class数字也会变这是调整标签而不是调整网络结构简单改映射文件比重新训练更快。5. 用训练好的YOLO权重做妇科皮肤病推理与迁移训练完成后best.pt不只是用来做检测也可以作为新数据集的预训练权重减少从头训练的成本。5.1 单张图像推理Python脚本加载权重并输出每个框的类别、置信度和坐标from ultralytics import YOLO model YOLO(runs/detect/train/weights/best.pt) results model.predict(sourcetest.jpg, conf0.3, imgsz640, saveTrue) for r in results: for cls, conf, xyxy in zip(r.boxes.cls, r.boxes.conf, r.boxes.xyxy): print(model.names[int(cls)], round(float(conf), 2), xyxy.tolist())conf0.3比默认0.25高适合对假阳性敏感的筛查场景imgsz640必须和训练一致否则会先resize再推理影响小病灶定位。saveTrue会把画了框的结果图存到runs/detect/predict/方便直接和原图做对比。5.2 新增类别时保留旧病种的微调技巧妇科皮肤病数据集经常会补一批新的标记图像进来比如新增“脂溢性皮炎”。直接在best.pt上从头训练会覆盖旧类别。常见做法是冻结backbone的前10层让底层特征保持不变只更新检测头最后再解冻整个网络做低学习率精调yolo train datagynecological_skin_v2.yaml \ modelruns/detect/train/weights/best.pt \ freeze10 \ epochs50 \ lr00.0005freeze10代表冻结模型前10层这一步能大幅降低新类别对旧类别特征的破坏。迁移阶段建议把旧数据保留20%到30%参与训练相当于场景回放防止灾难性遗忘发生。如果新增类别和已有类别外观很相似比如“脂溢性皮炎”和“湿疹”都表现为红斑不要把它们分到两个太近的类可以在标注阶段先合并成一个父类等新样本积累到每类100个框以上再拆开。训练完成后用5.1的脚本跑一遍旧类别的验证集图片逐一确认旧病种的检出没有明显退化。本文还有配套的精品资源点击获取
返回列表