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

资讯详情

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

YOLO实例分割数据集校验与训练:水体标注的完整实践指南

YOLO实例分割数据集校验与训练:水体标注的完整实践指南 简介这是一份面向实例分割任务的专业标注资源包含446张航拍或环境监测图像其中训练集390张、验证集38张、测试集18张所有图像均以YOLO格式的多边形坐标点勾勒水体区域类别单一但边界精确适合用于环境监测、农业灌溉规划、洪水风险分析及遥感与AI交叉领域的研究与教学。压缩包共894个文件以JPG图像和TXT标注文件为主体分别提供原始画面与多边形坐标标注另有YAML配置文件和DOCX说明文档总大小27.97MB目录结构清晰便于直接接入主流深度学习框架训练实例分割模型。目前已有99人学习下载素材源于真实环境标注质量较高可帮助开发者省去繁重的标注环节快速启动水体分割项目或作为基准数据集验证算法效果。1. 水体实例分割数据集单类别任务为什么也要认真做数据校验无人机巡河、农田灌溉监测、洪涝风险评估这类任务里最常见的检测对象就是水体。这个水体实例分割数据集把场景收敛得很干净446 张图片按 390/38/18 划分训练、验证、测试集YOLO 多边形标注类别只有 waterbodies 一类。单类别往往让人以为“很好训”拆开才发现坑全在数据侧坐标归一化与图片尺寸是否匹配、文件名里的处理痕迹、验证集偏小导致的指标波动。下面按“先校验、再可视化、后训练”的顺序把这个数据集从 zip 解压到出指标走一遍适合环境监测、遥感分割方向的人直接照着复现。2. 数据集结构解析从 zip 压缩包到 YOLO 标注文件解压是第一步但很多人解压完就直接开训结果 data.yaml 路径写错或者标注文件没配对浪费一两个小时。先把结构看清再谈训练。2.1 解压后的目录结构与文件名规律先建目录解压再扫一遍骨架mkdir -p waterbody unzip 水体实例分割数据集_20251116_162130.zip -d waterbody find waterbody -maxdepth 2 -type d | sort-d waterbody指定解压目标目录避免压缩包把文件散在当前目录find -maxdepth 2 -type d只列两层以内的目录先确认有没有 train / valid / test 三块。常见结构是每块下面各放 images 和 labels 两个目录图片在 images同名 txt 在 labels。这里要特别说一个容易忽略的细节图片文件名形如6523918299_jpg.rf.8e33be32a299662cb15077cc0eb78ea0.jpg中间那段_jpg.rf.是在线标注平台导出时的常见处理痕迹说明图片在标注前被统一预处理过通常含缩放或重命名。看到这种后缀先别急着把图片另存或者手工改尺寸因为你一旦二次缩放图片txt 里存的归一化坐标就和你手里的图片对不上了。接着检查图片和标注是否一一对应ls waterbody/train/images | wc -l ls waterbody/train/labels | wc -l两个数字应当相等。差一个要么缺标注 txt要么某张 txt 找不到对应的图。这个小检查花不了十秒却能避免后面数据加载时报 0 images。2.2 txt 标注文件一行一个实例坐标全部归一化随便挑一张图对应的标注文件看内容head -n 3 waterbody/train/labels/6523918299_jpg.rf.8e33be32a299662cb15077cc0eb78ea0.txt内容大致是这样的每行是一个独立的水体实例0 0.5132 0.6121 0.5286 0.6130 0.5347 0.6223 0.5120 0.6315第一列是类别编号这里是 0对应 names 数组里的第 0 个类waterbodies后面每两个浮点数是一组多边形顶点坐标。坐标全部归一化x 用像素列值除以图片宽度y 用像素行值除以图片高度所以正常范围是 0 到 1只有贴着图像边缘的实例会出现接近 0 或 1 的值。顶点数最少 3 组三角形多的到几十组都是正常的。点越密水体边界勾勒越细致YOLO 系列分割模型对密集点位的学习成本会略高但边界精度更好。YOLO 格式的便利处在于不用自己写解析器训练脚本直接读转成 mask 的环节框架内部处理掉了。想快速知道某张图有几个水体实例数 txt 行数就行一行一个实例。这个数据集是典型的单类别多实例形态一张航拍图里出现两三个水塘或一段河流是常态训练时正样本分布比较均匀。2.3 三块划分的比例390/38/18验证集小带来的问题训练集 390 张、验证集 38 张、测试集 18 张比例大概是 10.3 : 1 : 0.5。验证集只有训练集的十分之一这个比例在小数据集里很常见但也要清醒认识它的副作用验证集越小val loss 和 mAP 的波动越大单轮指标并不能完全反映模型真实水平。所以建议是训练过程按 val 做早停但不要拿 val 的每轮数值做精细比较训练结束再用测试集评估一次。如果只是做课程设计或基准测试想获得更稳定的评价可以把 valid 和 test 合并成 57 张重新划分或者干脆做 5 折交叉验证——数据量小训练成本低每折几十个 epoch 就能跑完。提示拿到数据集先做一次 images 与 labels 一一对应的清单检查再写训练配置。否则 YOLO 加载数据时报 0 images排错往往比事先检查更费时间。这个数据集的适用场景很明确环境监测与水资源管理、农业灌溉规划、洪涝风险评估、GIS 与遥感的交叉研究。单类别的好处是背景干扰可控坏处是类别单一后模型容易把“看起来像水”的东西都圈进来这一点在第 5 章详细讲。3. 数据验证与可视化训练前花十分钟省三个小时排错YOLO 对数据格式的校验其实很宽容宽容到标注有问题也不会立刻报错而是等你训完一轮、看指标不对劲才开始排查。与其事后翻车不如训练前用脚本做三件事格式体检、可视化抽查、分布统计。3.1 用 Python 脚本做标注格式体检先把训练集里的每个 txt 过一遍检查字段数量、坐标范围、图片对应关系。脚本不长但能挡住大部分低级错误import os train_img waterbody/train/images train_lbl waterbody/train/labels for name in sorted(os.listdir(train_lbl)): if not name.endswith(.txt): continue img_file os.path.join(train_img, name.replace(.txt, .jpg)) if not os.path.exists(img_file): print(f[缺图] {name} 没有对应 jpg) continue with open(os.path.join(train_lbl, name)) as f: lines f.readlines() for row, line in enumerate(lines): parts line.strip().split() if len(parts) 7: # 类别 3 组顶点至少 7 个字段 print(f[点数过少] {name} 第{row}行只有 {len(parts)} 个字段) continue coords [float(v) for v in parts[1:]] if not all(-0.05 v 1.05 for v in coords): print(f[越界] {name} 第{row}行 坐标范围异常)脚本逻辑有三段先按文件名把 txt 的 .txt 换成 .jpg去 images 目录里找对应图片找不到就输出缺图再按行拆分字段正常至少要有 1 个类别编号加 3 组坐标也就是最少 7 个字段少于这个数说明多边形的点被吃掉了最后检查坐标是否落在合理区间。越界检查这里特意放了一点余量-0.05 到 1.05。因为有些多边形贴合图像边缘时标注工具会给出极靠近边界甚至轻微越界的点这在训练时 YOLO 的增强操作里也会产生。但超出 -0.1 或 1.1 就要警惕多半是图片被二次缩放、坐标没跟着换算。3.2 把标注画回图片上一眼看出是否错位脚本检查只能发现格式错误发现不了语义错误。比如多边形整体往右偏了 20 个像素坐标值依然在合法范围内只有画出来才能看到。这一步用 OpenCV 直接把多边形画回原图import cv2 import numpy as np def draw_seg(img_path, txt_path): img cv2.imread(img_path) h, w img.shape[:2] with open(txt_path) as f: for line in f: p line.strip().split() pts np.array(p[1:], dtypefloat).reshape(-1, 2) # 每两个数还原为一个点 pts[:, 0] * w # 反归一化x 乘回图片宽度 pts[:, 1] * h # y 乘回图片高度 cv2.polylines(img, [pts.astype(np.int32)], True, (0, 0, 255), 2) return img反归一化是最关键的一步txt 里的坐标乘以的是“这张图读取出来的真实宽高”。如果标注是按 640 尺寸导出的而实际图片是 1024画出来必然错位这也是很多人可视化发现 mask 偏了的根源。cv2.polylines的第二个参数包了一层中括号因为函数接受的是多边形数组[pts]表示画一组多边形True表示首尾闭合最后两个参数是颜色和线宽。批量挑十来张图跑一遍重点看水体岸线是否贴合、有没有把相邻水域连成一个实例、有没有漏标。这一步机器替代不了值得花时间。3.3 类别统计与实例分布预判训练难度最后跑一个统计脚本看类别分布和每张图的实例数这两个数会影响训练配置from collections import Counter cls_counter Counter() inst_per_img [] for name in os.listdir(train_lbl): with open(os.path.join(train_lbl, name)) as f: lines f.readlines() inst_per_img.append(len(lines)) for line in lines: cls_counter[line.split()[0]] 1 print(类别分布:, cls_counter) print(实例数/图 平均:, sum(inst_per_img) / len(inst_per_img)) print(最多实例数:, max(inst_per_img))类别分布如果只有 class 0说明标注体系是干净的如果出现其他数字后面 data.yaml 里的 nc 和 names 就要相应调整。平均实例数直接反映正样本密度平均 1~2 个实例时大多数图只有一个小水塘模型能学到的上下文有限训练时背景占比高loss 收敛会慢一些平均 3 个以上时样本分布更健康模型泛化会好一些。把这三步走完数据集的可信度心里就有数了。接下来写配置、开训练。4. 用 YOLO 生态跑通训练配置、参数与指标解读数据校验通过后进入训练环节。这个数据集是单类别、小规模用 YOLOv8-seg 的 nano 模型起步性价比最高跑通后再根据结果决定要不要换更大的模型。4.1 data.yaml路径用绝对路径names 对齐类别编号先写数据集配置文件这是 YOLO 系列的标准入口path: /home/user/waterbody # 建议填绝对路径避免工作目录不同导致加载失败 train: train/images val: valid/images test: test/images nc: 1 names: 0: waterbodiespath是数据集的根目录train、val、test这三项拼接在 path 后面指向 images 目录YOLO 会自动去同级的 labels 目录找对应 txt。nc为类别数这个数据集只有 1 类。names里的索引顺序必须和标注文件第一列的类别编号一致标注里是 0names 就要把 0 映射到 waterbodies写反了训练不会报错但结果全错。路径这里我吃过亏用相对路径换一个终端工作目录训练直接 0 images。后来一律在 yaml 里写绝对路径省掉大半路径相关的翻车。4.2 训练命令与超参数选择配置就绪后训练命令本身不复杂yolo segment train \ datawaterbody.yaml \ modelyolov8n-seg.pt \ epochs120 \ imgsz640 \ batch8 \ device0 \ projectruns \ namewaterbody_seg \ cacheTruemodelyolov8n-seg.pt用的是 nano 分割模型预训练权重覆盖了 COCO 上的通用分割特征迁移到水体数据集上收敛快446 张图的规模nano 已经足够想追求更高精度可以换成yolov8m-seg.pt但显存占用和训练时间都会涨一截。epochs120对单类别 390 张训练图是合理的区间太少欠拟合太多过拟合后面早停机制兜底。imgsz640是输入分辨率如果原始航拍图分辨率远高于 640 且水体边界细节重要可以试imgsz1280但显存消耗接近翻倍。batch8在 8GB 显存上比较稳显存 4GB 就降到batch2。cacheTrue把 446 张图一次性加载进内存省去每轮磁盘 IO小数据集非常划算内存紧张时再关掉。训练过程中不用频繁打断观察两个东西终端每轮打印的Box和Seg指标以及 runs 目录下生成的 loss 曲线。如果 train/loss 降得很快但 val/loss 先降后升就是过拟合信号第 5 章会讲怎么处理。4.3 训练产物与指标先看 mAP50再抠 mAP50-95训练结束后指标解释要注意区分两个 mAP指标含义这个数据集的参考区间Seg mAP50预测 mask 与真值的 IoU 超过 0.5 即判定正确0.85 以上说明粗边界可用Seg mAP50-95IoU 阈值从 0.5 到 0.95 的平均单类别小数据集常见 0.5~0.6val/loss验证损失反映泛化趋势与 train/loss 持续背离说明过拟合mAP50 高而 mAP50-95 低说明模型把水体位置找对了但边界轮廓不够精细。这个数据集聚类标注、且训练图只有 390 张mAP50-95 落在 0.5~0.6 之间是正常水平想往上提优先加大 imgsz其次是补标注点位密度。产物目录 runs/waterbody_seg 下面最值得看的是 val 子目录里的预测可视化图val_batch*_pred.jpg和confusion_matrix.png。前者把模型输出的 mask 直接画在图上错漏一眼可见后者对单类别任务来说主要看背景会不会被误判成水体。最后用测试集做一次离线评估yolo segment val \ modelruns/waterbody_seg/weights/best.pt \ datawaterbody.yaml \ splittest测试集只有 18 张满足一次性评估的用途就够了别反复拿它调参否则测试集的信息会泄漏到模型选择里。5. 避坑手册单类别实例分割最容易踩的五个翻车点以下五条来自实际的拆解过程每一条都是先看到现象再反查根因最后给解决路径。单类别的坑和多样本的坑不一样主要集中在小数据过拟合和格式错位这两类上。5.1 标注画出来整体偏移或变形先查图片尺寸是否被二次处理现象用第 3 章的 draw_seg 函数可视化mask 明显错位要么整体向右下偏移要么形状被拉伸。原因文件名的_jpg.rf.后缀说明图片在线标注时经过预处理很多标注平台默认会 Resize 到固定尺寸再让标注员操作。如果拿到手之后又对图片做了统一缩放比如为了拼接数据集txt 里存的归一化坐标没有同步更新就会和当前图片尺寸失配。解决训练前随机挑 5 张图用 draw_seg 画出来核对不要对数据集手动做任何二次缩放让 YOLO 在训练时按 imgsz 参数自己缩放。如果确认被二次处理过需要重新按当前图片宽高换算出标注并做一遍坐标校验。5.2 train/loss 降得漂亮val 指标像玄学一样跳过拟合与验证集噪声叠加现象train/loss 降到 0.1 以下val/loss 从第 40 轮开始反弹Seg mAP 每轮上下波动超过 0.05看起来像随机数。原因390 张训练图太少模型从第 40 轮开始记忆训练图的背景纹理同时验证集只有 38 张样本方差大两个因素叠加后指标就非常不稳。解决epochs 压到 100 以内开启增强参数让模型不那么容易背图比如degrees15控制旋转、fliplr0.5做水平翻转早停的 patience 设 20 轮。另外要提醒38 张验证集本身的波动就不小小幅震荡不代表模型坏了看整体趋势而不是单轮峰值。5.3 预测 mask 清一色矩形分不清 box 和分割多边形现象训练出的 mask 输出全是方方正正的块水体弧线边界完全丢失。原因标注 txt 被当作检测框格式处理或者数据预处理管线只取了多边形的 4 个顶点把圆滑边界强行简化成了矩形。解决回到 txt 看字段数。合法的分割实例至少是class x1 y1 x2 y2加第三组点也就是 7 个字段如果每行只有 5 个字段class x1 y1 x2 y2那不是分割标注而是检测框模型应该用yolo detect而不是yolo segment。如果只有 4 组点但确实来自多边形标注可以用四点四边形让 YOLO 学但要明白边界精度上限就在那了想提升还得补点位。5.4 几乎相同的两次训练mAP 能差 0.1小数据集方差大现象两次训练命令完全一样只是随机种子不同最终 test 集 mAP 相差超过 0.1。原因390 张训练图对模型来说信息量有限模型初始化、增强顺序、数据加载顺序都会影响最终落点这是小数据集的固有方差不是代码 bug。解决训练命令里加seed42固定随机种子保证结果可复现报告指标时不要只报最好一次多次运行取中位数更诚实最终结论以 test 集为准val 集数字只用来做模型选择。5.5 训练日志显示 0 images路径或标注文件没对上现象train dataset: 0 images甚至刚启动就退出没有任何指标输出。原因data.yaml 里path和train拼接出来的目录不存在或者 labels 目录里没有放和图片同名的 txtYOLO 在 labels 里找不到任何一个标注就认为数据集是空的。解决先用绝对路径重写 yaml再用下面这条命令检查缺标注的情况python -c from pathlib import Path; imgsPath(waterbody/train/images); lblsPath(waterbody/train/labels); miss[i.stem for i in imgs.glob(*.jpg) if not (lbls/(i.stem.txt)).exists()]; print(miss[:10])把两个目录的 stem 一一对比缺 txt 的图片名会列出来。如果缺的是个别几张多半是从别的数据集拼过来时漏拷贝了如果全部缺失说明 labels 目录路径写错了。排查最快的方法就是先确认目录树长什么样别急着改训练参数。6. 进阶用法mAP 之外把单类别分割用在面积估算上6.1 用 mask 像素占比估算水体面积mAP 回答的是“模型找得准不准”但实际项目更常问“水体面积有多大”。比如洪涝评估里要的是淹没面积不是一个框或一个分数。做法是先把 best.pt 对目标图跑推理导出 mask再统计二值图里水体的像素占比。先跑推理yolo segment predict \ modelruns/waterbody_seg/weights/best.pt \ sourceriver_test.jpg \ save_txtTrue \ save_dirruns/predictsource指定待推理图片save_txtTrue会输出预测的坐标 txtsave_dir控制输出目录。再写一个短脚本统计占比import cv2 pred cv2.imread(runs/predict/river_test_mask.png, 0) ratio (pred 127).sum() / pred.size print(水体像素占比: %.3f % ratio)ratio 是 mask 像素占全图的比例。已知航拍影像的空间分辨率后水体面积约等于ratio × 图幅覆盖面积。需要注意如果影像不是正射视角而是倾斜航拍计算面积会有透视误差别直接拿比值当绝对面积。6.2 转成 COCO 格式做跨框架对比如果想在 mmdetection 或 Detectron2 里复现YOLO seg 格式需要转换成 COCO 的 annotation 结构。常见做法是写一个转换脚本遍历 labels 下的 txt将归一化坐标乘回原图宽高得到多边形点数组再按 COCO 格式打包成 segmentation、area、bbox。area 用多边形面积公式shoelace计算bbox 用多边形外接矩形。转换后用 pycocotools 做一次合法性校验重点确认每个多边形至少 3 个点、坐标不越界、area 非负。这类脚本社区里有很多现成版本但坐标归一化基准也就是按原图宽高还是按标注平台 Resize 后的尺寸必须在你自己的脚本里写对这是唯一容易翻车的地方。这份数据集拆下来最大的感受是单类别并不意味着简单它只是把多类别之间的混淆问题换成了“边界精度”和“小数据过拟合”这两个更隐蔽的坑。从那以后我每次拿到数据集都强制跑一遍格式校验脚本再谈训练这个习惯帮我避开七成以上的翻车希望帮到你。本文还有配套的精品资源点击获取
返回列表