宫颈癌YOLOv5检测数据集训练全攻略:格式拆解、调参与避坑
简介面向目标检测与医学影像识别学习者的宫颈癌YOLOv5检测数据集定位为可直接投入模型训练与验证的YOLO格式数据包。数据按YOLOv5标准文件夹保存cancer单一类别训练集816张、验证集216张图像为640×640 RGB大分辨率图片病灶目标偏小适合小目标检测、医疗影像筛查等场景。包内共2000个文件以txt标注文件、jpeg图像和1个Python可视化脚本为主7z压缩包约180.22MBtxt对应边界框标签jpeg为原始病灶图像可视化脚本无需修改即可随机抽图绘制边界框并输出结果。已有29人学习浏览。下载后无需额外标注或格式转换可直接划分训练/验证数据进行YOLOv5训练。1. 宫颈癌YOLOv5检测数据集为什么它值得直接拿来训练做医疗影像目标检测的开发者大多卡在同一个位置模型结构早就熟了YOLOv5的权重也能跑通公开数据集但一换到宫颈癌筛查场景数据就找不到。要么是公开数据带着水印和重复切片要么只有几百张图根本不敢拿来训练要么是标注格式混乱到要自己写一周转换脚本。这还只是数据层面到了训练阶段还有类别不平衡、样本重复、标注框过小这些暗坑。标题里这套宫颈癌YOLOv5检测数据集解决的正是这一段从「有idea」到「有模型」之间最耗时的问题训练集和验证集齐整、YOLO格式规整、标注信息完整。我按「先看数据组成 → 再讲训练前调整 → 然后跑通YOLOv5训练与验证 → 最后聊排错和进阶验证」的顺序来拆这个数据集怎么用。适合两类人一是做宫颈细胞学或病理切片目标检测的研究生和算法工程师想省掉数据预处理的时间直接跑基线二是医疗AI公司里负责数据管线的工程师需要一份结构规范的YOLO数据集来评估标注质量和模型可行性。读完你可以直接按步骤把训练跑起来也能避掉我在类似数据集上踩过的坑。2. 数据集结构拆解训练、验证、标签、类别一一对应2.1 目录结构与YOLO格式的对应关系拿到数据集第一件事不是解压就跑而是先看清楚目录结构。这个数据集的根目录一般长这样cervical_yolo/ ├── images/ │ ├── train/ # 训练集图像通常占 80% 左右 │ └── val/ # 验证集图像通常占 20% 左右 ├── labels/ │ ├── train/ # 与 images/train 一一对应的标签文件 │ └── val/ # 与 images/val 一一对应的标签文件 ├── classes.txt # 类别清单 └── dataset.yaml # YOLOv5 训练所需配置文件这里最关键的是 labels 目录和 images 目录必须同名同数量。每张img_001.jpg必须对应一个img_001.txt。缺一个训练时 YOLOv5 会直接跳过图像而且只在日志里出现一行警告不仔细看根本发现不了。我第一次拿这类数据集训练时就是没核对对应关系训练完看 mAP 只有 0.1排查半天才发现训练集里有几张图没标签被静默跳过了。每个 txt 文件内容是 YOLO 格式的检测标注一行代表一个目标框class_id x_center y_center width height四个数值都是相对于图像宽高的比例值范围在 0 到 1 之间。比如某一行的内容是1 0.53125 0.46875 0.06250 0.05729表示类别 id 为 1 的目标中心点在图像横向 53.1%、纵向 46.9% 的位置框宽为图像宽度的 6.25%框高为图像高度的 5.73%。这种格式的好处是与图像分辨率解耦换分辨率不用重新标注缺点是对坐标精度敏感转格式时小数点截断就会影响 IoU 计算后面讲踩坑会细说。2.2 classes.txt 里的类别定义与类别平衡评估categories 文件的命名会因为标注习惯不同略有差异有的叫classes.txt有的叫labels.txt或者class_names.txt内容都是一行一个类名。宫颈癌检测数据集常见的类别定义有按细胞类型分的如normal、ascus、lsil、hsil也有按病灶区域分的如normal、lesion、cancer本文这套数据集具体怎么定义以解压后看到的classes.txt为准。查看类别信息后要顺手统计一下每个类别的样本数量。可以用下面的 Python 脚本import os from collections import Counter def count_classes(labels_dir, classes_file): with open(classes_file, r, encodingutf-8) as f: class_names [line.strip() for line in f.readlines()] counter Counter() total_boxes 0 for file in os.listdir(labels_dir): if not file.endswith(.txt): continue with open(os.path.join(labels_dir, file), r, encodingutf-8) as f: for line in f: parts line.strip().split() if len(parts) 5: cls_id int(parts[0]) counter[cls_id] 1 total_boxes 1 print(总标注框数:, total_boxes) for cls_id in range(len(class_names)): print(f{class_names[cls_id]} (id{cls_id}): {counter[cls_id]} 个框) # 输出每张图的平均框数判断标注密度 img_count len([f for f in os.listdir(labels_dir) if f.endswith(.txt)]) print(f平均每图框数: {total_boxes / img_count:.2f}) count_classes(./labels/train, ./classes.txt)这个脚本是「拿到 YOLO 数据集先做体检」的第一步。输出的类别分布有几个值得注意的指标最高类和最低类的数量差距是否在一个数量级以上决定训练时要不要加 class weights平均每图框数低于 1 说明大部分图没有目标或标注稀疏模型容易学成背景检测器标注框总数去重后是否合理可以去重一次看看重复框占比这在前面我用过的类似医疗数据集中是一个高频问题。2.3 验证集的标注覆盖度与训练-验证泄露风险验证集最容易出问题的地方不是数量不够而是覆盖度和独立性。理想的验证集应该覆盖所有类别并且在图像层面与训练集完全隔离——同一患者的不同视野图不能同时出现在训练和验证里。但这个数据集是否在患者级做了划分从目录结构上看不出来需要自己验证。一个实用的做法是检查验证集的图像哈希是否与训练集有重合import hashlib import os def file_hash(filepath): h hashlib.md5() with open(filepath, rb) as f: for chunk in iter(lambda: f.read(8192), b): h.update(chunk) return h.hexdigest() train_imgs [os.path.join(./images/train, f) for f in os.listdir(./images/train)] val_imgs [os.path.join(./images/val, f) for f in os.listdir(./images/val)] train_hashes set(file_hash(f) for f in train_imgs) overlap [f for f in val_imgs if file_hash(f) in train_hashes] print(f训练-验证图像重合数量: {len(overlap)})同样要对标注框做内容级检查比如检查验证集的标注框大小分布。医疗影像目标检测中标注框过小是常态但验证集里如果大量框的宽高都小于 0.05AP 计算时会被当作无效结果。这两步检查最好在训练前做完等模型训完再发现验证集有问题等于白跑一轮。3. 训练前的数据调整三个绕不开的准备工作3.1 坐标格式校验与损坏图像处理YOLO 格式的标注文件是纯文本任何一个字段出错YOLOv5 训练时要么报错要么把这个框忽略掉。最常见的问题有三类坐标越界大于 1 或小于 0、坐标顺序错乱xyxy 格式混入 xywh、浮点精度过低。校验脚本我会这么写import os def validate_label_file(label_path, img_width, img_height): errors [] with open(label_path, r, encodingutf-8) as f: for line_num, line in enumerate(f, 1): parts line.strip().split() if len(parts) ! 5: errors.append(f第{line_num}行字段数不为5: {line}) continue try: cls_id int(parts[0]) x_center float(parts[1]) y_center float(parts[2]) w float(parts[3]) h float(parts[4]) except ValueError: errors.append(f第{line_num}行存在非数值: {line}) continue # 类别 id 越界 if cls_id 0: errors.append(f第{line_num}行类别id为负: {line}) # 坐标范围检查 if not (0 x_center 1 and 0 y_center 1): errors.append(f第{line_num}行中心坐标越界: {line}) # 宽高检查 if w 0 or h 0 or x_center - w/2 0 or x_center w/2 1 or y_center - h/2 0 or y_center h/2 1: errors.append(f第{line_num}行框超出图像边界: {line}) return errors校验完成后还要检查图像文件本身能否被正常读取。用 OpenCV 或 PIL 批量读一遍重点看有没有损坏的 JPEG、截断的 PNG、灰度图混入彩色图、EXIF 旋转信息不一致。这些在公开数据里概率不大但医疗影像导出过程中常见。某个开放宫颈数据集翻车过因为部分图像是 16 位深度的 TIF 混在 JPEG 里YOLOv5 默认的cv2.imread会把 16 位图读成 8 位信息直接丢掉部分细粒度特征就没了。3.2 数据增强策略选择与医学图像的约束YOLOv5 自带增强管线hyp.scratch.yaml里hsv_h、hsv_s、hsv_v控制颜色增强translate、scale、fliplr控制几何增强。但医学图像的增强策略和自然图像有本质区别不能直接用默认值。对于宫颈癌筛查数据我的建议是颜色增强幅度降低到默认的一半hsv_h从 0.0138 降到 0、hsv_s从 0.678 降到 0.3 左右、hsv_v从 0.36 降到 0.2。原因在于宫颈细胞学的染色方案巴氏染色、液基薄层制片有标准化的颜色范围过度增强颜色会让模型学到错误的染色特征几何增强里的fliplr0.5可以保留左右翻转对细胞形态没有语义影响但scale0.5不要开太大因为很小的标注框经过大尺度缩放会变成几个像素甚至无效框。旋转增强是另一个需要小心的点。病理切片的拍摄角度随机适度旋转的泛化收益在 1 到 2 个百分点之间但超过 30 度的旋转会改变细胞核的相对排列方向如果类别定义中包含方向相关的形态学特征旋转就会制造伪样本。用hyp.scratch.yaml时把degrees设置在 15 以内比较合理。3.3 数据集的 train-val 划分合理性复核标题说包含完整训练与验证集但「完整」不等于「合理」。拿到的划分比例通常是 8:2需要确认两点一是验证集的困难样本占比不能太低如果验证集全是典型样本训练时 mAP 虚高换到真实场景就掉点二是验证集里不能有训练集图像的缩放、裁剪版本。实际操作中我一般会统计验证集里标注框宽高的 P50 和 P10 分位判断它是否覆盖了小目标区间import os import numpy as np def get_box_percentiles(labels_dir): sizes [] for f in os.listdir(labels_dir): if not f.endswith(.txt): continue with open(os.path.join(labels_dir, f)) as fh: for line in fh: parts line.strip().split() if len(parts) 5: continue w float(parts[3]) h float(parts[4]) # 取框尺寸为边长 sizes.append((w h) / 2) arr np.array(sizes) return np.percentile(arr, [10, 50, 90]) train_pct get_box_percentiles(./labels/train) val_pct get_box_percentiles(./labels/val) print(f训练集框边长分位 P10/P50/P90: {train_pct}) print(f验证集框边长分位 P10/P50/P90: {val_pct})如果两者的尺度分布差异过大比如训练集 P10 超过 0.1 而验证集 P10 在 0.03说明验证集的困难程度高于训练集训练时 loss 会降得不错但 mAP 上不去。这种时候不是模型的问题是数据集划分的问题重新划分或者换一个按尺度分层抽样的划分策略才靠谱。4. 用 YOLOv5 训练宫颈癌检测模型完整命令与参数4.1 环境准备与数据集配置文件的改写YOLOv5 对硬件的要求不算苛刻一张 8GB 显存的显卡就能训练小尺寸模型但训练宫颈癌这类细节纹理数据集图像分辨率一旦超过 640显存会迅速吃紧。训练前先把数据集配置文件写好# cervical_dataset.yaml train: ./cervical_yolo/images/train val: ./cervical_yolo/images/val # test: 如果提供了测试集可以加上 nc: 4 # 修改为数据集实际的类别数 names: [ normal, ascus, lsil, hsil ] # 以 classes.txt 内容为准顺序必须一致这里的train和val推荐写绝对路径避免相对路径在不同的工作目录下解析失败。nc必须与classes.txt的行数严格相等names的顺序就是类别 id 的映射顺序从 0 开始。很多数据集的 classes.txt 顺序和训练时的 id 不匹配如果拿classes.txt里第 0 行是 normal就要确保names数组里第 0 个也是 normal不一致会导致评估时混淆矩阵完全错位。4.2 训练启动命令与关键参数拆解YOLOv5 的训练入口是train.py启动命令我一般按这个模板python train.py \ --data cervical_dataset.yaml \ --weights yolov5s.pt \ --img 640 \ --batch 16 \ --epochs 100 \ --cache ram \ --name cervical_yolo_run \ --project ./runs \ --exist-ok \ --patience 20每条命令的参数在这个场景下的考虑是--weights yolov5s.pt用 COCO 预训练权重做迁移学习比随机初始化收敛快很多医学图像和自然图像虽然在特征层面差异大但底层边缘、纹理滤波器的共享还是有效的。如果显存够可以用yolov5m.pt换一点精度显存只有 6GB 的卡老老实实用yolov5s和--img 640。--img 640是输入分辨率。原始数据集如果是 1920×1080 级别的视野图640 能保留主要特征但会丢失细粒度细胞核细节。建议先用 640 跑通基线然后用--img 800或者--img 1024做对比实验看 mAP 提升幅度是否值得显存开销。--batch 16在 8GB 显存上属于安全值。batch size 如果太小小于 8BatchNorm 的统计量会不稳定在医疗数据这种类别不平衡的场景里会让少数类的梯度方向噪声变大。--patience 20是早停参数超过 20 个 epoch 验证集没有提升就自动结束。训练流程默认会保存 best.pt 和 last.pt最后用 best.pt 做验证。4.3 多种模型规模的效果对比与选择建议不要只训一个模型就交差。同样是这个数据集yolov5s和yolov5l在精度上的差距通常有 3 到 7 个 mAP 点但推理速度会相差 2 到 3 倍。如果场景是离线分析病理切片用大模型换精度是划算的如果是实时辅助筛查速度才是刚需。以「先 s 后 l」的顺序做对比训练是比较常见的做法# 小模型快速验证数据质量 python train.py --data cervical_dataset.yaml --weights yolov5s.pt --img 640 --batch 16 --epochs 60 --name cerv_s_baseline # 大模型精调 python train.py --data cervical_dataset.yaml --weights yolov5l.pt --img 640 --batch 8 --epochs 100 --name cerv_l_finetune--batch 8是因为大模型显存占用翻了一倍以上。训练完成后对比两个模型的results.csv里验证集的mAP_0.5和mAP_0.5:0.95如果 s 模型已经达到业务阈值就没必要上 l。我见过不少团队把小模型训出 0.6 的 mAP 后直接上线实际效果也不错因为宫颈癌检测场景里召回率比精确率更关键——漏掉一个可疑细胞比多标几个正常区域严重得多。4.4 训练日志观察loss 曲线和 mAP 曲线的正常形态训练过程中通过runs/cervical_yolo_run/results.csv观察指标主要看 box_loss 和 mAP 的关系。正常的形态是前 10 个 epoch 内 box_loss 快速下降mAP_0.5 从 0.1 爬到 0.3 左右20 到 30 个 epoch 之间 mAP 开始进入平台期之后即使 mAP_0.5 不再涨mAP_0.5:0.95 也还会有缓慢上升说明边界框回归还在优化。如果出现 mAP 在某个 epoch 突然掉到接近 0 然后恢复通常是训练时 batch size 太小遇到梯度爆炸或者学习率在 cosine 调度后期降得过快。用--cos-lr默认开启的情况下把--lr0 0.01改为0.005可以缓解。如果 box_loss 降得很快但 mAP 始终在 0.2 以下大概率是标注框与真实目标不匹配——有的框可能标在了背景区域有的漏标了同一目标这类问题不是超参能解决的要回数据。5. 训练与验证中的避坑指南五条血泪经验5.1 图像尺寸必须统一否则锚框计算失真现象训练时损失很低但验证时 mAP 忽高忽低同一份权重多次验证结果波动超过 3 个点。原因数据集里混有不同分辨率的图像YOLOv5 虽然会自动缩放但如果原图比例差异大比如 4:3 和 16:9 混着来letterbox 填充区域比例不同锚框匹配时背景占比变化导致预测置信度不稳定。解决训练前把图像统一缩放到相同长宽比的安全做法是预处理后再训练用--img参数固定输入以外还要确保dataset.yaml的train路径指向的图像本身比例接近。如果批次内图像长宽比跨度大把rectTrue加进启动命令让 YOLOv5 按批次内最长边做矩形训练尽量减少填充。5.2 标注框过小导致的数值不稳定现象训练中obj_loss降不下去始终在 0.04 以上震荡输出层的小目标分支权重一直偏高。原因宫颈细胞图像里存在大量小于 16×16 的标注框相对 640 输入这些框在特征金字塔的浅层分支上对应的特征图区域只有 1×1 左右负样本梯度占比过大。解决我在这类数据集上习惯的做法是检查所有标注框的像素尺寸分布如果 P10 分位的框边长低于 8 像素优先用--img 1024提高输入分辨率。如果显存不够就把--multi-scale打开让模型周期性切换 0.5 到 1.5 倍缩放等效提升小目标分辨率覆盖。另外在hyp.scratch.yaml的box损失权重从 0.05 降到 0.03能让模型更多关注类别和置信度预测小目标框回归压力降低。5.3 类别不平衡导致验证集精度虚高现象总的 mAP_0.5 超过 0.85但每类单独看少数类比如 hsil 阳性细胞的 AP 只有 0.1 附近。原因多数类样本占比超过 90%模型整体精度被多数类拉高少数类几乎没学到有效特征。验证时如果验证集的类别分布和训练集一样偏斜总 mAP 会非常具有欺骗性。解决不要在验证集上只看总 mAP必须用--save-conf输出置信度文件后逐类计算 PR 曲线。我在这类不平衡数据上的建议是对少数类做离线复制增强或者改用--cls参数提高类别损失权重一般从默认 0.5 提到 0.8 到 1.0。也可以尝试给少数类单独做模型蒸馏用多数类模型作为 teacher在特征层面指导学生模型学习少数类的表征。5.4 训练集和验证集泄露的隐蔽形式现象训练时 mAP 达到 0.95 以上但换到任何真实外部测试集都断崖式掉到 0.4 以下且人工抽查预测结果时发现模型对同一视野的不同截图输出完全不同的检测框。原因数据划分时没有按患者或病例做拼接查重导致同一个病例的不同视野图分散在训练和验证集里模型实际是记住了病例特征而不是检测语义。解决唯一可靠的做法是自己重新划分一个患者粒度的验证集。正常来说拿到数据集后先做图级查重再做患者级查重比较稳妥具体做法是统计图像的文件名前缀如果前缀包含患者编号就按编号分组后重新按组划分 train/val。如果这个数据集的文件名是随机哈希无法从文件名判断患者归属那就只能从图像内容层面做感知哈希去重把相似度超过 0.95 的图像对标记出来确保训练集和验证集不跨组。5.5 验证阶段设备差异导致的 NaN现象训练好的模型在本地 CUDA 上推理正常部署到 CPU 机器或另一块显卡时报 NaN 或输出空的检测结果。原因权重文件本身没问题出问题的是模型结构里使用了不兼容的某些算子或者验证机器上 OpenCV 版本太旧对某些格式的 JPEG 解码丢数据。解决先固定验证环境用同一个 Docker 镜像或 conda 环境。我在类似项目里遇到过cv2.imread在两台机器上返回 None 的情况换成PIL.Image.open做验证时读图再转成 BGR 数组给模型推理能避免大部分坑。如果遇到了全图推理为 NaN大概率是精度溢出把输入图先转成float32并做np.clip到 0-255 范围再归一化。6. 从训练到部署验证数据集的真实泛化能力和后续提点技巧训练完之后验证集的 mAP 只能说明拟合程度真实泛化能力要看外部验证。我养成了一个习惯拿这个数据集训出的模型再去找一份与此数据集来源不同但标注目标语义相近的宫颈细胞图像数据集跑一遍推理统计检测框的类别置信度分布和误检类型。如果外部数据集的精度只比验证集低 5 个点以内说明模型学到了语义特征而不是背景特征如果掉点超过 15 个点大概率是验证集与训练集存在隐藏的相关性要回到第 5 章的方法重新划分数据。另一个实用的验证方法是做 CAM 可视化。YOLOv5 虽然不像分类网络那样直接输出热力图但可以对检测分支的高层特征图做梯度加权查看类别激活区域是否集中在细胞核周围。这个方法不需要额外的库用 PyTorch 的 hooks 就能实现。如果激活区域覆盖到整个细胞质而不是细胞核说明模型的注意力被背景染色特征干扰了这时候需要检查增强策略里的色彩扰动是否导致了颜色混淆。更进一步的提点方向有两个。第一是使用 YOLOv5 的--evolve模式做超参数搜索。以这段数据的训练成本看单次训练几十个 epoch 在单卡上可以接受用进化算法跑两轮约 50 次训练重点搜索lr0、lrf、box、cls几个参数组合通常能比默认超参提升 2 到 4 个 mAP_0.50.95。第二是针对宫颈癌检测的特定类别关系做后处理比如 hsil 和 lsil 在形态上存在连续性模型容易把同一细胞在帧间判别为不同类别可以在输出层之后加一个时序或空间平滑模块利用相邻检出框的类别概率做投票修正。最后是一个我踩过很多次的小教训不要在同一个数据集上反复迭代模型而是一次性把数据质量检查做扎实再开始调模型。宫颈癌检测这种类别边界模糊的任务数据标注偏差对模型上限的影响远超模型结构的选择花三天清洗数据比花三周试网络结构有效得多。希望这篇笔记能帮你把时间花在真正有价值的地方。本文还有配套的精品资源点击获取