
简介本资源为糖尿病肾病视网膜病变检测数据集面向医学图像处理、眼底病变识别方向的算法工程师与深度学习研究者可用于目标检测模型的训练、验证与竞赛实践。数据集采用Pascal VOC与YOLO双格式标注包含4122张jpg图片每张图片均配有对应的VOC格式xml文件与YOLO格式txt文件标注类别共5类分别为mild-DR、moderate-DR、normal、proliferation-DR、severe-DR覆盖糖尿病视网膜病变的轻、中、重度及增殖期分级。压缩包为7z格式内含2000个文件以1999个xml标注文件和1个说明用txt为主整体约44.31MB目录结构清晰便于直接接入主流检测框架进行训练与评估。目前已有139人学习下载适合需要快速获取标注完备、类别均衡的眼底病变数据集的读者可省去自行标注与格式转换的时间成本专注于模型调优与实验对比。1. 4122 张眼底图、5 类 DR 分级这份 VOCYOLO 双格式数据集到底能干什么眼底糖网筛查这个方向公开数据一直是个尴尬事。想跑检测模型要么去啃几万张的竞赛集标注格式还得自己转要么找小样本凑合类别又不够细。这份 4122 张的糖尿病肾病检测数据集走的是另一条路——它把 5 个 DR 分级类别直接标好同时给了 Pascal VOC 的 xml 和 YOLO 的 txt 两套标注jpg 原图、xml、txt 三者数量严格对齐都是 4122。类别名是mild-DR、moderate-DR、normal、proliferation-DR、severe-DR从正常到增殖期一条线拉通。它适合谁一是想快速验证 YOLO 系列在自己环境里能不能跑通眼底检测的工程师二是做医学图像课程设计、需要现成标注又不想从零标的学生三是拿它当预训练或对比基线、再往私有数据上迁移的算法同学。不适合谁指望它直接上临床的——4122 张的规模做研究够用做产品远远不够。下面按「拿到手怎么用 → 参数怎么设 → 哪里会翻车」的顺序拆开讲。2. 双格式标注怎么选VOC 与 YOLO 的转换逻辑和目录结构2.1 为什么同一批图要给两套标注Pascal VOC 和 YOLO 的差别本质是坐标表达方式不同。VOC 的 xml 存的是绝对像素坐标xmin/ymin/xmax/ymax还带filename、size、object等一堆元信息YOLO 的 txt 存的是归一化后的class_id cx cy w h每行一个目标没有图片尺寸信息全靠训练时读原图反推。给两套格式的好处很直接VOC 适合做数据审查、可视化、转 COCO 或别的框架YOLO 格式可以直接喂给 ultralytics 系的训练脚本省掉转换步骤。但要注意这份数据集不包含分割路径的 txt 文件也就是说它只做检测框不做实例分割。如果你的任务是分割这份数据得自己补 mask别指望现成的。常见做法是先用 VOC 的 xml 做一轮标注质量抽查确认框没跑偏、类别没错再转成 YOLO 格式训练。反过来也行但 xml 里信息更全审查阶段更顺手。2.2 目录结构长什么样解压后典型结构是这样文件名以实际为准这里按常见组织方式示意firc_shenbing_dataset/ ├── 使用前必读.txt ├── JPEGImages/ # 4122 张 jpg 原图 │ ├── firc_shenbing_1063.jpg │ └── ... ├── Annotations/ # 4122 个 VOC xml │ ├── firc_shenbing_1063.xml │ └── ... └── labels/ # 4122 个 YOLO txt ├── firc_shenbing_1063.txt └── ...使用前必读.txt别跳过里面通常写了类别顺序、命名规则、有没有空标注图。类别 id 的映射关系必须和 txt 里的数字对上否则训练出来全是错类。这份数据的 5 类按摘要给的顺序常见映射是class_id类别名含义0mild-DR轻度糖网1moderate-DR中度糖网2normal正常3proliferation-DR增殖期糖网4severe-DR重度糖网提示这个映射不是官方强制有的整理者会按字母序或别的顺序排。动手前一定打开一个 txt 和一个 xml 对照确认 id 和类别名的对应关系别照搬上面的表。2.3 用脚本核对三份文件是否对齐拿到数据集第一件事不是训练是核对。jpg、xml、txt 三者数量都是 4122但数量相等不代表文件名一一对应。跑一段脚本查一遍import os img_dir firc_shenbing_dataset/JPEGImages xml_dir firc_shenbing_dataset/Annotations txt_dir firc_shenbing_dataset/labels def stems(d, ext): return {os.path.splitext(f)[0] for f in os.listdir(d) if f.endswith(ext)} imgs stems(img_dir, .jpg) xmls stems(xml_dir, .xml) txts stems(txt_dir, .txt) print(图片数:, len(imgs)) print(xml 数:, len(xmls)) print(txt 数:, len(txts)) print(图片有但 xml 缺:, imgs - xmls) print(xml 有但图片缺:, xmls - imgs) print(图片有但 txt 缺:, imgs - txts)逻辑说明用文件名主干去掉扩展名做集合运算能直接暴露「有图没标注」或「有标注没图」的情况。参数上img_dir、xml_dir、txt_dir按你解压后的真实路径改。如果三个差集都为空说明对齐没问题可以进下一步如果有差集先手动处理掉再训练否则 YOLO 训练时会因为找不到对应 label 直接报错或静默跳过。3. 从零跑通 YOLO 训练数据配置、类别文件和启动命令3.1 生成 train/val 划分和 data.yamlYOLO 训练不认 VOC 那套目录需要按images/labels分 train、val 两套再写一个data.yaml指向它们。先划分import os, random, shutil src_img firc_shenbing_dataset/JPEGImages src_lbl firc_shenbing_dataset/labels dst yolo_dataset random.seed(42) names [os.path.splitext(f)[0] for f in os.listdir(src_img) if f.endswith(.jpg)] random.shuffle(names) split int(len(names) * 0.8) train_names, val_names names[:split], names[split:] for subset, subset_names in [(train, train_names), (val, val_names)]: os.makedirs(f{dst}/images/{subset}, exist_okTrue) os.makedirs(f{dst}/labels/{subset}, exist_okTrue) for n in subset_names: shutil.copy(f{src_img}/{n}.jpg, f{dst}/images/{subset}/{n}.jpg) shutil.copy(f{src_lbl}/{n}.txt, f{dst}/labels/{subset}/{n}.txt) print(train:, len(train_names), val:, len(val_names))逻辑说明random.seed(42)固定随机种子保证每次划分一致方便复现。8:2 是常见比例4122 张里约 3297 张训练、825 张验证。参数上如果类别分布很不均比如normal特别多、proliferation-DR特别少建议改成按类别分层抽样别纯随机否则验证集里某些类可能一张都没有。接着写data.yamlpath: ./yolo_dataset train: images/train val: images/val names: 0: mild-DR 1: moderate-DR 2: normal 3: proliferation-DR 4: severe-DRpath是数据集根目录train/val是相对路径。names的 id 必须和 txt 里的 class_id 严格一致这是最容易翻车的地方——id 错一位模型学出来的全是错的。3.2 启动训练与关键参数用 ultralytics 的 YOLOv8 起训一条命令yolo detect train \ datadata.yaml \ modelyolov8n.pt \ epochs100 \ imgsz640 \ batch16 \ lr00.01 \ patience20 \ projectruns/dr \ namebaseline参数逐个说modelyolov8n.pt是最小的 nano 版先用它验证流程通不通别一上来就上 x 版显存和时间都吃不消。imgsz640是默认输入尺寸眼底图如果分辨率很高缩到 640 会丢小病灶细节可以试 1024但显存翻倍。batch16按显存调8G 显存跑 640 一般能到 16跑 1024 就得降到 4 或 8。lr00.01是初始学习率小数据集上偏大容易震荡可以降到 0.001。patience20是早停20 轮没提升就停省时间。训练起来后盯两个东西一是runs/dr/baseline/results.csv里的mAP50和mAP50-95二是混淆矩阵。医学数据类别不平衡时normal的 AP 往往虚高真正要看的是proliferation-DR和severe-DR这两类的召回它们样本少、最容易漏检。3.3 验证与推理训练完在验证集上跑一遍yolo detect val \ modelruns/dr/baseline/weights/best.pt \ datadata.yaml \ imgsz640单张图推理看效果yolo detect predict \ modelruns/dr/baseline/weights/best.pt \ sourcefirc_shenbing_dataset/JPEGImages/firc_shenbing_1063.jpg \ conf0.25 \ saveTrueconf0.25是置信度阈值医学场景宁可多报也别漏报的话可以降到 0.1代价是误检变多。这一步主要是肉眼确认框的位置和类别对不对别只看数字指标。4. 避坑与排查这份数据集上最容易翻车的五件事4.1 类别 id 对不上训练全错现象训练 loss 正常下降但验证时混淆矩阵里类别全乱normal被预测成mild-DR。 原因data.yaml里的names顺序和 txt 文件里的 class_id 不一致。有的整理者按字母序排有的按严重程度排摘要给的顺序不一定等于文件里的顺序。 解决打开任意一个 txt看第一列数字再打开对应 xml 看object/name两者对照确定映射。确认后写死到data.yaml别凭记忆。4.2 空标注图导致训练报错现象训练启动后报IndexError或某张图labels为空。 原因4122 张里可能有极少数图没有目标框对应的 txt 是空文件。YOLO 对空 label 的处理在不同版本里不一致有的直接跳过有的报错。 解决先扫一遍空 txtimport os empty [f for f in os.listdir(firc_shenbing_dataset/labels) if os.path.getsize(os.path.join(firc_shenbing_dataset/labels, f)) 0] print(空标注文件:, empty)如果数量少直接从训练集里剔除如果数量多说明这批图本身可能有问题得回头查标注流程。4.3 图片尺寸和坐标越界现象可视化时框跑到图外面或者训练时警告coordinates out of range。 原因VOC 转 YOLO 时归一化算错或者原图被裁剪过但 xml 没更新。归一化公式是cx (xminxmax)/2/widthw (xmax-xmin)/width分母用错就会越界。 解决写个校验脚本遍历所有 txt检查每行后四个数是否都在 0~1 之间import os bad [] for f in os.listdir(firc_shenbing_dataset/labels): with open(ffirc_shenbing_dataset/labels/{f}) as fp: for i, line in enumerate(fp): parts line.strip().split() if len(parts) ! 5: bad.append((f, i, 字段数不对)); continue vals list(map(float, parts[1:])) if any(v 0 or v 1 for v in vals): bad.append((f, i, 坐标越界)) print(异常行数:, len(bad))4.4 类别不平衡导致小类漏检现象proliferation-DR和severe-DR的召回率极低模型几乎全预测成normal和mild-DR。 原因5 个类别在 4122 张里分布不均重度样本天然少标准交叉熵会让模型偏向多数类。 解决训练时加类别权重或用copy_paste、mosaic这类增强多造小类样本。ultralytics 里可以在data.yaml同级配cls权重也可以换 focal loss。更直接的办法是过采样小类图片但注意别过拟合。4.5 验证集泄漏进训练集现象验证指标高得离谱mAP50 到 0.95 以上但换一批新图就崩。 原因同一患者的左右眼、或同一张图的增强版本同时出现在 train 和 val 里造成信息泄漏。 解决划分时按患者 id 或图片前缀分组别按单张随机分。这份数据文件名是firc_shenbing_xxxx这种编号如果编号连续代表同一来源就得按编号段划分而不是逐张 shuffle。5. 进阶把 VOC 直接转 COCO、做分层抽样和指标复核5.1 VOC 转 COCO 备用有些框架比如 mmdetection吃 COCO 格式转一份备用不亏import os, json import xml.etree.ElementTree as ET xml_dir firc_shenbing_dataset/Annotations classes [mild-DR, moderate-DR, normal, proliferation-DR, severe-DR] coco {images: [], annotations: [], categories: []} for i, c in enumerate(classes): coco[categories].append({id: i, name: c}) ann_id 1 for idx, f in enumerate(os.listdir(xml_dir)): tree ET.parse(os.path.join(xml_dir, f)) root tree.getroot() w int(root.find(size/width).text) h int(root.find(size/height).text) img_id idx 1 coco[images].append({id: img_id, file_name: root.find(filename).text, width: w, height: h}) for obj in root.findall(object): name obj.find(name).text cls_id classes.index(name) b obj.find(bndbox) xmin float(b.find(xmin).text); ymin float(b.find(ymin).text) xmax float(b.find(xmax).text); ymax float(b.find(ymax).text) coco[annotations].append({ id: ann_id, image_id: img_id, category_id: cls_id, bbox: [xmin, ymin, xmax - xmin, ymax - ymin], area: (xmax - xmin) * (ymax - ymin), iscrowd: 0}) ann_id 1 json.dump(coco, open(coco_annotations.json, w))逻辑说明COCO 的 bbox 是[x, y, w, h]和 VOC 的[xmin, ymin, xmax, ymax]差一个减法别写错。area用于评估时区分大小目标。参数上classes顺序必须和 YOLO 的names一致否则两套格式对不上。5.2 分层抽样划分前面提过纯随机划分在类别不平衡时会翻车这里给个分层版本import os, random from collections import defaultdict lbl_dir firc_shenbing_dataset/labels random.seed(42) # 按主类别分组 groups defaultdict(list) for f in os.listdir(lbl_dir): stem os.path.splitext(f)[0] with open(os.path.join(lbl_dir, f)) as fp: lines fp.readlines() if not lines: continue main_cls lines[0].split()[0] groups[main_cls].append(stem) train, val [], [] for cls, items in groups.items(): random.shuffle(items) cut int(len(items) * 0.8) train items[:cut] val items[cut:] print(train:, len(train), val:, len(val))逻辑说明按每张图的主类别第一个框的类别分组再在组内 8:2 划分保证每个类在验证集里都有代表。参数上如果一张图有多个类别取第一个框只是近似更严谨的做法是按类别出现次数加权但工程上够用了。5.3 指标复核别只看 mAP训练完拿到best.pt除了 mAP至少再看三样每类的 precision/recall、混淆矩阵、以及按类别分组的 PR 曲线。医学检测里severe-DR和proliferation-DR的召回比整体 mAP 重要得多因为漏掉一个重度患者代价远大于多报一个。我一般会在验证脚本里单独把这两类的 recall 打出来低于 0.7 就回去查数据分布和增强策略而不是急着调模型结构。从那以后我每次拿到新数据集都强制先跑一遍文件对齐校验和类别 id 对照再动训练脚本。这份 4122 张、5 类的 VOCYOLO 双格式数据流程跑通不难难的是别在 id 映射和划分泄漏上栽跟头。希望帮到你。本文还有配套的精品资源点击获取