ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

糖尿病肾病检测数据集解读:VOC+YOLO格式与YOLOv8训练实践

2026/9/23 20:52:00 拓冰建站 浏览量
糖尿病肾病检测数据集解读:VOC+YOLO格式与YOLOv8训练实践 简介面向医学影像智能分析场景的糖尿病肾病检测数据集提供五个类别的目标检测标注类别覆盖 mild-DR、moderate-DR、normal、proliferation-DR、severe-DR包含轻、中、重度及增殖期病变与正常对照适合需要训练 YOLO 系列或基于 Pascal VOC 格式检测模型的研究人员、算法工程师与学生。压缩包内共 2000 个文件其中 xml 标注文件占 1999 个另含 1 个使用说明 txt文件组织清晰便于按图片编号定位对应标注。资源包整体大小约 44.31MB轻量易下载可快速用于本地或云端 GPU 环境的实验迭代。数据集同步提供 VOC 标准 xml 与 YOLO 格式 txt 两种标注省去自行转换的麻烦拿到后即可划分训练集和验证集直接开展 DR 分级检测模型的训练、验证与评估。目前已有 138 人学习/下载尤其适合医学影像目标检测方向的课程设计、毕业设计或横向课题研究。1. 糖尿病肾病检测数据集4122 张标注图到底能帮你省下多少标注工时做病理图像目标检测的人都有过这种经历模型结构不是瓶颈标注才是。肾小球、肾小管、间质这些结构在 HE 染色切片上密集且形态相似一个熟练的标注员标一张 512×512 的病理图也要 10 到 15 分钟标完还要第二个人复核。所以当我看到「糖尿病肾病检测数据集VOCYOLO格式4122张5类别.7z」这个压缩包时第一反应不是它能不能用而是它替我省掉了最枯燥的那段工时。这个数据集的价值在于图片已经按目标检测的标准格式标注好了VOC 的 xml 和 YOLO 的 txt 双份并存可以直接接进 YOLOv5/YOLOv8 的训练管线不用再拿 LabelImg 重新描框。适合谁用做医学图像目标检测的算法工程师、病理 AI 方向的研究生、以及想用公开数据跑通检测基线的人。需要注意的是双格式不是冗余它正好给了你一条交叉验证的路径。2. 拆开 7z 看数据结构VOC 与 YOLO 双格式的对应关系和解压细节2.1 Windows 与 Linux 下解压 7z命令、中文编码和完整性校验拿到这个压缩包第一步不是急着解压而是先确认它是完整的。7z 是分块压缩格式下载过程中断、存储介质坏道都可能让压缩包内部数据出错。常见的做法是先用测试模式跑一遍完整性校验而不是直接解压到一半报错。Windows 下用 7-Zip 打开压缩包后选中文件点击「测试」按钮即可Linux 下用 p7zip 的命令行先7z t再7z x# 先测试压缩包完整性返回 Everything is Ok 再继续 7z t 糖尿病肾病检测数据集VOCYOLO格式4122张5类别.7z # 测试通过后解压到指定目录-o 后面不要留空格 7z x 糖尿病肾病检测数据集VOCYOLO格式4122张5类别.7z -o./dn_dataset解压参数说明t是 test 模式只校验 CRC 不做解压x是 extract-o指定输出目录。这里有个小坑——如果压缩文件是 Windows 上创建的包内的中文文件名在 Linux 下解压可能变成乱码因为 7z 在 Windows 下默认用本地编码GBK存文件名而 Linux 默认用 UTF-8 解释。遇到乱码我一般会在解压后立即执行ls看一眼目录名如果出现之类的字符就用convmv -f gbk -t utf8 -r批量转一次或者干脆用 Python 的 py7zr 指定编码解压。这个细节不处理后面写训练脚本时路径引用全是坑。解压完成后别急着删压缩包。我习惯先把压缩包留到模型训练跑通之后再清理因为一旦训练时报「找不到图片」或「标注错位」重新解压一份比从备份里翻要快得多。2.2 VOC 的 xml 与 YOLO 的 txt同一张图的两种坐标表达解压之后你会看到这套数据集的典型组织方式一个Annotations目录存 VOC 格式的 xml一个labels目录存 YOLO 格式的 txtJPEGImages目录放原始图片。同一张图对应两个标注文件内容等价但坐标表达方式完全不同这是理解整个数据集的核心。VOC 格式的 xml 里存的是像素绝对坐标标注一个目标长这样annotation filenamedn_001.jpg/filename size width1024/width height768/height depth3/depth /size object nameglomerulus/name bndbox xmin132/xmin ymin201/ymin xmax358/xmax ymax427/ymax /bndbox /object /annotation而 YOLO 格式的 txt 只有一行五个数字含义是「类别序号、中心点 x、中心点 y、宽度、高度」并且全部做了归一化值域在 0 到 1 之间0 0.2393 0.4089 0.2207 0.2943VOC 到 YOLO 的转换逻辑是固定的cx (xmin xmax) / 2 / widthw (xmax - xmin) / width每个坐标都除以图片的宽或高。这个数据集同时给你两种格式意味着你自己写转换脚本时可以拿它自带的 YOLO txt 作为「标准答案」来验证转换逻辑是否正确。我拿到数据集的第一天就会做这件事随机挑 10 张图自己写脚本把 xml 转成 txt再和数据集自带的 txt 逐行对比坐标误差超过 0.001 就说明哪个环节有问题。这比直接在训练时踩坑要省事得多。2.3 5 个类别先别急着训先搞清每类是什么、框得准不准「5 类别」这个信息在标题里只是一句话但对训练结果影响极大。糖尿病肾病的病理检测常规关注的组织学结构一般是肾小球、肾小管、间质、血管以及硬化或纤维化区域这类病变结构。不同数据集对类别的定义会有差异有的把「硬化肾小球」单独拆成一类有的合并进「肾小球」有的把「间质炎症」和「间质纤维化」分成两类有的统一叫「间质病变」。所以拿到数据集后第一件事是找到类别定义文件——通常是classes.txt或者数据集说明文档里的类别列表——确认这 5 类到底是什么、在图上长什么样。我一般会做一次「标注质量抽检」用 OpenCV 或 PIL 把标注框画到原图上生成一批带框预览图自己肉眼过一遍 100 张左右。看三件事框和目标的贴合度是紧贴边界还是松垮、有没有漏标大量明显目标医学图像里密集的小目标很容易漏、以及类别之间是不是存在混淆比如把萎缩的肾小管标成了间质。这一步看起来费时间但它决定了你后面所有训练和评估的可信度。我见过有人拿到数据集直接开训mAP 出来很高一画框才发现标注本身就偏了半个目标等于模型学的是错位标注的分布。3. 用 YOLOv8 在本地跑通糖尿病肾病检测数据集配置与训练命令3.1 把 4122 张图组织成 YOLO 训练目录images 与 labels 的对应关系YOLO 系列训练自己的数据集目录结构是硬约束images和labels必须平级且各自下面分train和val子目录同一张图的图片和标注文件名要完全一致不含扩展名。这个数据集自带 YOLO 格式标注但标注文件可能全在labels根目录下没有按训练验证分开需要你自己切分。常见做法是写一个 Python 脚本做三件事把图片和标注按 8:1:1 划分到 train/val/test校验每张图都有对应的 txt最后生成一个 data.yaml 配置文件。切分时要注意如果文件名前缀里有病例编号要按病例分组切分而不是按单张图随机切。道理后面讲这里先记住结论。import os import random import shutil random.seed(42) images sorted(os.listdir(JPEGImages)) random.shuffle(images) n_train int(len(images) * 0.8) n_val int(len(images) * 0.1) split { train: images[:n_train], val: images[n_train:n_train n_val], test: images[n_train n_val:], } for phase, files in split.items(): os.makedirs(fdataset/images/{phase}, exist_okTrue) os.makedirs(fdataset/labels/{phase}, exist_okTrue) for img in files: stem os.path.splitext(img)[0] # 如果标注缺失直接跳过并打印避免训练时静默出错 if not os.path.exists(flabels/{stem}.txt): print(fmissing label: {stem}) continue shutil.copy(fJPEGImages/{img}, fdataset/images/{phase}/{img}) shutil.copy(flabels/{stem}.txt, fdataset/labels/{phase}/{stem}.txt)这段脚本的逻辑说明先按文件名排序后随机打乱固定随机种子保证可复现按 8:1:1 切分训练集 3298 张左右、验证集 412 张左右复制文件而不是移动保留原始数据作为后悔药。脚本里最关键的是那句missing label检查——YOLO 训练时如果某张图没有标注文件它会被静默跳过你不会立刻发现但会发现自己明明有 4122 张图训练时却只用了 3800 张。3.2 最小训练脚本从 yolov8s 预训练权重起步的参数选择目录组织好之后写一个最小可跑的 YOLOv8 训练脚本。我用 Ultralytics 的 Python API 多一些比命令行好调参也方便训练完直接做验证。from ultralytics import YOLO # 从 COCO 预训练的 s 权重起步比从零开始收敛快很多 model YOLO(yolov8s.pt) model.train( datadataset/data.yaml, epochs120, imgsz640, batch16, patience25, device0, workers8, pretrainedTrue, )参数说明imgsz640是速度和精度的折中如果你的显卡显存有余量这个数据集可以试 800 甚至 960对检测小目标有明显帮助patience25表示验证集指标连续 25 个 epoch 不提升就早停医学数据集通常不大硬跑满 120 轮大概率过拟合batch16在 16GB 显存上比较稳显存不够就降到 8workers8是数据加载线程数Windows 上如果报错就改成 0。类别名称不用写进脚本data.yaml 里统一配置。关于权重选择我想多说一句yolov8n 是最快的但对病理图像这种目标小、语义细的场景n 的特征提取能力明显不足mAP 通常比 s 低 3 到 5 个点。我一般从 s 起步如果推理速度不是瓶颈直接用 m。先跑通一条完整链路再考虑换大模型而不是一上来就调最大的。3.3 第一次验证mAP50 与 mAP50-95 在医学检测里该怎么解读训练结束或早停后模型会自动把最好的权重存成best.pt。用它对验证集做一次完整评估输出的是 Precision、Recall、mAP50、mAP50-95 四项。很多初学者只看 mAP50这在医学检测里是不够的甚至会产生误导。简单说mAP50 只要求预测框和真实框的 IoU 超过 0.5 就算命中这对大目标很宽容但对肾小球、小病灶这类目标框偏了半个目标尺寸 IoU 可能还有 0.5视觉上却已经明显不准了。mAP50-95 是 IoU 从 0.5 到 0.95 每隔 0.05 算一次 mAP 再取平均它惩罚的是「框不贴合目标边界」的预测。所以做病理检测我更关注 mAP50-95。如果它比 mAP50 低一大截说明框的位置精度不够可能是标注边界松垮也可能是小目标特征丢失两个方向都要排查。验证脚本只有几行from ultralytics import YOLO model YOLO(runs/detect/train/weights/best.pt) metrics model.val(datadataset/data.yaml, splitval) print(metrics.box.map50) # mAP50 print(metrics.box.map) # mAP50-95跑完之后先别急着看数字高兴或沮丧用model.predict在验证集上随机抽 50 张图把框画出来存成图片一张一张看。医学图像数据集的指标通常会虚高因为病变区域相对背景纹理复杂模型很容易学到「有纹理就框」的粗暴模式指标好看实际不可用。画图这一步不花多少时间但它能直接暴露模型是在看形状还是看纹理。4. 五个类目标大小悬殊时怎么办增强策略与损失函数侧的调整4.1 病理图像的小目标问题32 倍下采样后肾小球还剩几个像素YOLOv8 的主干网络会对输入图片做 32 倍下采样意味着一个 640×640 的输入最深层的特征图只有 20×20。在这个尺度上一个 32×32 像素的小目标只占 1 个像素特征基本丢失。糖尿病肾病病理图里肾小球直径可能只有几十像素间质里的细小病变更小。所以这类数据集训练时普遍会遇到小目标召回率低的问题。解决办法有几个层次。第一是提高输入分辨率imgsz从 640 调到 800 或 960相当于把小目标放大了再送进网络这是最直接有效的手段代价是显存和训练时间增加第二是利用 YOLOv8 的 P3 层浅层高分辨率特征图它在小目标检测上起主要作用不要为了省显存把模型输入压得太小第三是数据增强阶段的 mosaic 操作——它会把四张图缩放到各占四分之一再拼成一张这等于把小目标又缩小了对本来就只有几十像素的目标是雪上加霜。所以对这类数据集我会把 mosaic 的概率从默认的 1.0 降到 0.5 左右给小目标留一些「原始大小」的训练样本。4.2 对 HE 染色病理图颜色增强要克制参数调法通用目标检测里颜色扰动是标配——随机改亮度、饱和度、色相帮助模型对光照变化鲁棒。但病理图不一样HE 染色苏木精-伊红染色的颜色本身就是诊断依据细胞核染成蓝紫色胞浆和间质染成粉红色。如果训练时对色相做大幅度随机扰动等于在告诉模型「颜色不重要」但临床上颜色恰恰重要——染色偏蓝或偏粉会影响病理医生的判读也会影响模型的判断。我对这类数据集的增强参数设置比较保守一般关掉色相扰动饱和度也只做小幅调整model.train( datadataset/data.yaml, epochs120, imgsz800, batch8, patience25, hsv_h0.0, # 关闭色相扰动HE 染色颜色有诊断意义 hsv_s0.2, # 饱和度只做 ±20% 扰动模拟不同批次染色差异 hsv_v0.3, # 亮度扰动保留应对切片曝光不均 fliplr0.5, flipud0.5, # 病理切片没有方向性上下翻转安全 mosaic0.5, mixup0.2, )参数说明hsv_h0.0是这一组参数里最重要的一项。病理切片的染色色调是稳定的生物学特征不是随机的环境噪声不该被当成数据增强的对象。fliplr和flipud都开 0.5 是合理的因为病理切片不存在「朝上」和「朝下」的语义区别。mosaic 降到 0.5 的考量前面说过是为了避免小目标被过度缩小。mixup 我只开 0.2意思意思——它对病理图像的增益不稳定开大了反而让模型学出重影特征。4.3 类别不平衡先用脚本数框再决定采样和权重5 个类别在 4122 张图里的数量几乎不可能均匀。肾小管可能是最多的某个病变类别可能只有前者的十分之一。如果直接训练多数类会主导损失函数少数类的召回率会非常难看。所以我拿到数据集的第一件事除了前面说的标注质量抽检就是统计每个类别的目标数量from collections import Counter import glob counter Counter() for txt in glob.glob(labels/train/*.txt): for line in open(txt): cls int(line.split()[0]) counter[cls] 1 total sum(counter.values()) for cls, cnt in sorted(counter.items()): print(fclass {cls}: {cnt} ({cnt / total:.2%}))这段代码统计每个类别在训练集中的标注框数量。看到分布后我一般分三种情况处理最少的类别占比低于 5%我会先试着对这类样本做过采样——把包含它的图片复制几份加入训练集如果某个类别特别难学我会把它的框挑出来单独看确认是标注问题还是形态差异太大最后才会考虑在损失函数侧调权重常见做法是在训练脚本里配置cls这个损失系数。不要一上来就调损失函数权重那是黑匣子操作不好控制先解决数据层面的不平衡。5. 训练糖尿病肾病模型的 5 个避坑记录从解压报错到 mAP 虚高5.1 7z 解压报错「密码正确但 CRC 失败」先查编码和内存现象解压这个 7z 压缩包时7-Zip 提示密码正确但解压到某个文件时报CRC Failed或Data Error直接中断。如果你反复确认过密码无误问题基本不在密码而在压缩包本身或运行环境。我在 Linux 服务器上遇到过两次一次是压缩包通过网盘下载不完整一次是解压到 FAT32 格式的移动硬盘上遇到超过 4GB 的单个文件。原因是FAT32 文件系统不支持超过 4GB 的单个文件解压大体积图片或标注文件时会写入失败甚至静默损坏。解决方法是先7z t测试完整性再把解压目标放到 NTFS、exFAT 或 ext4 分区。如果测试阶段就报错老老实实重新下载不要尝试用修复工具去赌运气。5.2 训练时大量图片没有标签xml 的 filename 和磁盘对不上现象训练日志里显示的训练图片总数比预期少几百张或者某些图片的标签全为空。原因是多文件数据集里容易出现这种问题有的 xml 里filename写的和磁盘文件名大小写不一致比如IMG_001.JPG和img_001.jpg或者写了完整路径而脚本只取 basename。我自己写批量处理脚本时踩过这个坑后来固定用「只比对文件 stem忽略扩展名大小写」的规则。排查命令很简单find labels/train -name *.txt | wc -l find images/train -name *.jpg | wc -l两个数字对不上就写一段 Python 遍历文件名做差集打印出所有「有图无标」和「有标无图」的样本。解决后重新切分数据集不要手工去改标注文件的名字。5.3 Loss 变成 NaN检查损坏图片和越界的归一化坐标现象训练到第 20 到 30 个 epoch 时loss 突然变成 NaN之后整个训练过程指标全部异常。如果你确认学习率没有异常最常见的原因是输入数据里混进了脏数据。病理数据集的图片可能包含损坏的 JPEG、带 Alpha 通道的 PNG或者转换时被错误地存成了单通道灰度图。YOLO 读取这类图片后某些增强操作比如颜色扰动会在空通道上计算出 NaN 梯度。另一个常见原因是 YOLO 标注坐标越界归一化的cx、cy、w、h不在 [0, 1] 区间或者w、h出现 0。排查脚本可以直接写import glob import cv2 import numpy as np for img_path in glob.glob(images/train/*.jpg): img cv2.imread(img_path) if img is None or img.ndim ! 3: print(fbad image: {img_path})我遇到一例最隐蔽的情况是一张图被保存成了 4 通道 PNGYOLO 读取没问题但imgsz缩放到 640 后通道数不匹配loss 在某个 epoch 突然爆炸。这种问题只会在特定随机种子下复现很难追最省事的办法是训练前对整个数据集做一次图片可用性检查把非三通道的图片全部转成 RGB 再入训练集。5.4 mAP 不低但大图上框位漂移置信度门限与 NMS 要重调现象验证集 mAP 有 0.85 以上但把模型跑到未裁剪的大图上推理时同一目标被框了三四次且框位偏移明显。原因是训练时的 mAP 是在标注尺寸的图片上算的大图推理时目标尺度变化模型给出的框置信度分布完全不同。病理图像目标密集且互相粘连默认的置信度门限 0.25 会放出一堆低置信度预测框默认的 NMS IoU 阈值 0.45 又太严格导致重叠目标被重复保留。常见做法是在推理阶段做两组对比conf0.15和conf0.3各跑一遍看哪组结果更干净。对这类疾病检测我一般把iou0.5往上提到 0.6让 NMS 更宽容一些允许高重叠的同类框合并再配合 nms 后的重复框过滤逻辑处理效果比训练阶段调参数更直接。5.5 验证集 mAP 虚高同一病例切片的泄漏问题现象训练时 mAP50 到了 0.92你觉得模型已经收敛得很好一换成外部数据测试立刻掉到 0.6 以下。这种断崖式下跌最常见的原因是数据泄漏。如果切分数据集时是随机按单张图切分的同一患者的不同切片可能同时出现在训练集和验证集里。这些切片虽然视野不同但染色风格、组织结构特征高度相似模型记住的是「这张切片来自哪个病例」而不是「肾小球长什么样」。验证时碰到眼熟的切片指标当然高。解决办法前面提过如果文件名里带病例编号切分按编号分组如果不带编号也应该用聚类的方式按图像特征分组切分。这是医学图像检测里最值得警惕的一个问题因为它的「高指标」具有欺骗性让你对模型的实际泛化能力产生误判。6. 用滑窗推理压测训练结果不依赖额外标注的模型回归验证法6.1 在大图上滑窗推理把切片重新拼回去YOLOv8 训练时的输入是 640 或 800 的方形图但实际的病理全切片图像WSI动辄几万像素直接整图喂给模型会爆显存。最常见的做法是滑窗推理把大图切成有重叠的 patch 分别检测检测结果转换回原图坐标再做一次全局 NMS 合并重叠框。我验证模型时会写这样的脚本def slide_infer(model, big_img, crop640, stride480, conf0.25): h, w big_img.shape[:2] boxes [] for y in range(0, h - crop 1, stride): for x in range(0, w - crop 1, stride): patch big_img[y:y crop, x:x crop] res model(patch, confconf, verboseFalse)[0] for b in res.boxes: cx, cy, bw, bh b.xywh[0].tolist() boxes.append([ x cx - bw / 2, y cy - bh / 2, x cx bw / 2, y cy bh / 2, b.conf.item(), int(b.cls) ]) return boxes这里stride480是 patch 大小的 75%保证目标跨越切片边界时至少在两个 patch 内完整出现一次。滑窗的步长不能等于 crop 大小否则在切缝上的目标会被截断成两半两边都检测不出来。全局合并时我会把坐标还原后的框全部收集起来再做一次 NMS。这一步虽然代码逻辑简单但能暴露训练指标看不出的问题模型对边界截断目标是否敏感、对大图上的小目标是否有稳定的检出能力。6.2 旋转一致性测试只用现有数据就能发现过拟合最后一关我会做一个不依赖外部标注的回归测试把验证集里的每张图旋转 90 度、180 度、270 度后重新推理再把预测框旋转变换回原图坐标和原图上的预测结果对比。理论上病理切片的方向是任意的模型对同一个目标的检测结果不应随旋转而改变。如果某次旋转后目标消失或类别改变说明模型学到的是方向相关的伪特征——比如染色不均造成的纹理方向性。这个测试不需要额外标注数据实现成本很低却能直接暴露过拟合。具体做法是对一张图分别推理四次把后三次的框坐标做逆变换然后计算同一目标在不同方向下的检出率。如果某个类别的旋转一致性低于 80%我就会回头检查这个类的标注质量或者考虑在训练时加大旋转增强的比例。这已经是我训完医学检测模型后的固定习惯它比反复看 mAP 曲线更能告诉我模型是「真的会了」还是「碰巧对了」。希望这个思路能帮你在自己的数据集上少走一段弯路。本文还有配套的精品资源点击获取