ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

Trash-ICRA19数据集+YOLO:海洋漂浮物检测从训练到部署

Trash-ICRA19数据集+YOLO:海洋漂浮物检测从训练到部署 简介面向目标检测与海洋环境监测的Trash-ICRA19标注数据集压缩包内含1144张真实海洋场景图像和对应数量的XML标注文件标注框信息完整可直接供给YOLO系列模型进行训练与交叉验证免去自行采集与标注的耗时环节。资源包整体26.21MB共2288个文件jpg原图与xml标签一一对应文件命名采用固定前缀与帧号组合便于按需抽取样本、划分训练集和测试集。配套代码以参数化编程方式组织检测类别、输入尺寸、置信度阈值等关键超参数集中在配置区修改便捷且注释密集可帮助使用者快速理解从数据载入到模型评估的每个环节。作者为资深算法工程师长期从事目标检测与图像处理仿真资源面向计算机、电子信息工程、数学等专业学生特别适合课程设计、期末大作业或毕业设计。当前已有259人学习下载可在较短时间内完成从数据解读到模型验证的完整实践。1. 海洋漂浮物检测为什么我劝你先拿这份数据集起步做YOLO目标检测的同行应该都有同感模型结构、训练脚本、调参技巧现在到处都能找到真正卡住人的往往是数据集。尤其是海洋漂浮物检测这个方向公开数据集少、标注质量参差不齐很多做水下机器人、近岸监控、河道治理项目的团队光在数据上就要耗掉两三个星期。Trash-ICRA19 Dataset这份海洋检测数据集提供了1144张已经标注好的图像标注文件直接对应YOLO训练格式拿来就能跑通训练流程。这对想快速验证检测方案、或者做毕业设计、比赛Demo的从业者来说能省掉的脏活累活相当可观。这份数据集的适用人群很明确已经接触过YOLO、但缺一份干净数据来跑通流程的人以及需要快速评估YOLO在海洋垃圾检测场景下能打到什么精度的团队。它的价值不在于模型创新而在于把「数据准备」这个最枯燥的环节直接跳过让注意力集中在数据清洗、训练参数调优和部署验证上。下面要讲的就是用这份数据集从零跑通YOLO训练的全过程包括格式校验、训练配置、精度评估和几个我实际踩过的坑。2. 先搞清楚这份数据集的底细标注格式与目录结构2.1 解压后先别急着训练按这套流程检查文件拿到压缩包后第一件事不是直接扔进训练脚本而是确认标注格式和图像是否对应。常见做法是先解压到固定目录然后用脚本扫一遍图像和标注文件的名称匹配情况。Trash-ICRA19这份数据集的标注格式和历史版本有关系有些版本是Pascal VOC的XML有些是经过转换的TXT纯文本格式标题里明确说了「已标注直接使用」通常指的是已经转成YOLO需要的TXT格式但解压后必须亲自验证。# 解压并检查目录结构 mkdir -p trash_icra19 cd trash_icra19 unzip ../Trash-ICRA19_dataset.rar -d . # 统计图像数量和标注文件数量 echo 图像数量: $(ls images/*.jpg 2/dev/null | wc -l) echo 标注数量: $(ls labels/*.txt 2/dev/null | wc -l) # 找出没有对应标注的图像 for img in images/*.jpg; do base$(basename $img .jpg) if [ ! -f labels/$base.txt ]; then echo 缺少标注: $img fi done这段脚本的逻辑很直接先确认图像是jpg格式然后按文件名前缀去labels目录找同名txt。如果发现有图像找不到对应标注说明数据集在打包或传输过程中有丢失需要补全或剔除这些样本否则训练时会在加载数据阶段报错。这里有个细节值得注意标注文件的命名必须和图像完全一致不包括扩展名部分YOLO的Dataset类就是按这个规则去找标注的。2.2 TXT标注内容怎么读类别ID、归一化坐标和边界框YOLO格式的TXT标注每一行代表一个目标物体包含5个字段类别ID、归一化后的中心点x坐标、中心点y坐标、归一化后的宽度、归一化后的高度。数值全部在0到1之间坐标是相对于图像宽高的比例。Trash-ICRA19数据集的类别一般是按照比赛设定来的常见的是对塑料瓶、罐子、渔网等不同垃圾类别做区分但具体类别数量和ID映射需要查看压缩包内是否附带了类别说明文件。# 读取一个标注文件并可视化解析 def parse_yolo_label(label_path, img_width, img_height): boxes [] with open(label_path, r) as f: for line in f: parts line.strip().split() if len(parts) ! 5: print(f格式异常: {label_path} - {line}) continue class_id int(parts[0]) cx, cy, w, h map(float, parts[1:]) # 还原为像素坐标 x1 (cx - w / 2) * img_width y1 (cy - h / 2) * img_height x2 (cx w / 2) * img_width y2 (cy h / 2) * img_height boxes.append((class_id, x1, y1, x2, y2)) return boxes这里的解析逻辑在排查标注问题时特别有用。打印出来的坐标还原后如果能用OpenCV在原图上画框并保存就能直观看到标注是否准确、有没有偏移或漏标。这个验证步骤虽然简单但能避免训练一个标注错乱的模型属于典型的「花10分钟省10小时」的操作。2.3 我为什么建议你按训练集/验证集7:3重新划分Trash-ICRA19原始数据集在发布时可能已经划分好了训练集和测试集但很多拿到手的人发现直接训练会遇到验证精度和实际效果对不上的情况。原因通常是测试集分布和训练集差异较大或者原始划分中出现了图像数据泄露。我的做法是拿到手后不管原始划分自己重新按7:3的比例随机划分训练集和验证集确保两者来自同一分布。import os import random from shutil import copyfile random.seed(42) # 固定随机种子保证每次划分结果一致 images sorted(os.listdir(images)) random.shuffle(images) split_idx int(len(images) * 0.7) train_imgs images[:split_idx] val_imgs images[split_idx:] for split, img_list in [(train, train_imgs), (val, val_imgs)]: os.makedirs(fdata/{split}/images, exist_okTrue) os.makedirs(fdata/{split}/labels, exist_okTrue) for img in img_list: copyfile(fimages/{img}, fdata/{split}/images/{img}) label_file img.replace(.jpg, .txt) if os.path.exists(flabels/{label_file}): copyfile(flabels/{label_file}, fdata/{split}/labels/{label_file})随机种子设置成固定值是为了可复现性。重新划分还有一个额外的好处可以顺便把类别分布打印出来确认每个类别的样本量是否均衡。如果某个类只有几十个样本训练时AP会明显偏低这时候要考虑类别权重或者数据增强策略。这一步虽然改动不大但对后续训练效果的稳定性影响很大。3. 训练前必须处理的三个细节类别文件、数据增强与模型选型3.1 类别文件和数据配置文件怎么写到YOLO能直接读YOLO的训练需要两个文件一个是类别名称文件每行一个类别名另一个是数据集配置文件指明训练集、验证集路径和类别数量。写这两个文件看起来简单但路径写错、类别顺序和标注ID对不上是新手最常见的翻车点。Trash-ICRA19如果原始标注里类别ID是连续从0开始的那直接按顺序写类别名就行如果不是就需要先统计标注文件里实际出现的类别ID再决定类别文件的顺序。# 统计所有标注文件里出现过的类别ID cat labels/*.txt | awk {print $1} | sort -n | uniq -c # 把类别ID和出现次数打印出来确认类别范围统计结果能直接告诉你类别数量是不是从0到N-1连续分布。如果中间有跳号比如出现了类别ID 3但没有任何ID 2的样本YOLO训练时会把3当成第三个类别导致错位。解决方式是写一个小脚本把所有标注的类别ID重新映射为连续值然后按映射关系生成类别文件。3.2 YOLOv8还是YOLOv5这份数据集的性价比选择Trash-ICRA19只有1144张图属于小样本数据集。用太大的模型如YOLOv8x或者YOLOv5x训练出来精度未必高反而容易过拟合。我的经验是从YOLOv8s或YOLOv5s起步参数量适中在单张消费级显卡上训练一轮只要几分钟。如果验证集上的mAP达到预期再往上换模型如果没达到往上换也不会有效果问题可能出在数据本身。# 使用YOLOv8s训练指定数据配置和训练轮数 yolo detect train \ modelyolov8s.pt \ datatrash_icra19.yaml \ epochs80 \ imgsz640 \ batch16 \ device0 \ projecttrash_models \ nametrash_yolov8s这里的关键参数是imgsz640这是YOLO系列最常用的输入分辨率精度和速度的平衡点比较好。batch16在显存不够时可以往下调4GB显存用8也能跑。epochs80在小数据集上足够收敛再多就会出现验证精度不再上升甚至过拟合的情况。训练完成后weights/best.pt就是验证集上表现最好的权重文件。3.3 数据增强策略小数据集不靠增强就等着过拟合1144张图像对YOLO来说确实不多尤其对于海洋这种环境相对单一的场景模型很容易记住背景而不是学习目标特征。我的做法是在训练配置里打开默认增强的同时针对性增加两项随机HSV扰动和随机平移缩放。Trash-ICRA19里很多图片是在不同光照条件下拍摄的水面光照变化是模型泛化能力的主要威胁HSV扰动正好能模拟不同天气和时段的光线变化。# 在训练命令里显式指定增强参数 yolo detect train \ modelyolov8s.pt \ datatrash_icra19.yaml \ epochs80 \ imgsz640 \ batch16 \ hsv_h0.015 \ hsv_s0.7 \ hsv_v0.4 \ degrees5.0 \ translate0.1 \ scale0.5 \ fliplr0.5hsv_v0.4的意思是亮度扰动范围在正负40%以内对于水下拍摄的昏暗图像可以适当加大到0.5。degrees5.0限制旋转角度因为水面垃圾的朝向虽然任意但旋转太多会让模型学会错误的空间先验。scale0.5控制缩放比例模拟目标远近变化。增强参数不是越大越好过大的扰动会让模型学不到稳定的特征这是训练时需要通过验证集精度来反复校准的。4. 跑通训练流程从第一个Epoch到验证集评估4.1 最小训练命令不调任何参数先出一版Baseline拿到数据集后我习惯先不改任何超参数用YOLO官方默认配置跑一版Baseline。这个Baseline的意义在于给后续所有调参提供一个对照基准没有它你后面改任何一个参数都无法判断到底是变好了还是变坏了。跑Baseline之前先确认数据配置文件里的路径是绝对路径还是相对路径YOLO两种都支持但相对路径在切换工作目录时容易出问题。# trash_icra19.yaml 最小配置示例 path: /path/to/trash_dataset # 数据集根目录 train: train/images # 训练图像相对路径 val: val/images # 验证图像相对路径 names: 0: plastic_bottle 1: can 2: fishing_net这个配置文件大概是这样的结构。names字典里的类别顺序必须和标注文件里的类别ID一一对应如果类别文件写错训练不会报错但验证时的mAP会非常低因为模型预测的类别和真实类别错位了。跑Baseline时我一般会把epochs改成50左右因为默认的100轮在1144张图上跑完时间太长而前面30轮精度就已经基本定型。4.2 训练日志里到底该看哪几个指标训练过程中终端会滚动输出每一轮的loss、精度和速度。很多人盯着box_loss看觉得loss降了就是好模型其实对于目标检测来说box_loss降到一定程度后基本不再变化真正需要关注的是验证集上的mAP50和mAP50-95。mAP50是IOU阈值取0.5时的平均精度比较宽容mAP50-95是多个IOU阈值下的平均更严格也是当前学术界的标准评估指标。Trash-ICRA19的类别之间难易程度差别很大塑料瓶好检渔网因为形状不规则、经常半透明检测难度高得多所以单看总体mAP看不出问题要按类别看AP曲线。# 训练结束后直接用best.pt在验证集上重新评估 yolo detect val \ modeltrash_models/trash_yolov8s/weights/best.pt \ datatrash_icra19.yaml \ imgsz640 \ batch16评估完成后会输出一份详细的每类别AP报告。看到某个类别的AP明显低于其他类别就需要回到数据集检查这一类别的标注数量和质量。渔网这类目标经常存在边界不清的情况标注的框可能偏大或偏小这属于标注框质量导致的精度天花板调模型参数无法解决。4.3 过拟合还是欠拟合怎么根据日志和训练曲线判断在验证集上观察到的典型过拟合现象是训练loss持续下降验证loss在第30轮左右开始回升mAP也随之下降或停滞。1144张图像的数据集出现过拟合非常正常不用慌两个手段可以压住一是加强数据增强把scale和degrees调大二是早停在验证loss开始回升的轮次保存权重而不是跑到最后。YOLO命令行里没有直接内置早停参数但ultralytics框架会在训练时自动保存每个epoch的最佳权重所以即便过拟合best.pt也代表验证集上最佳的模型状态。欠拟合的表现则是训练和验证的loss都降不下去mAP徘徊在低位。这时候要检查的不是增强参数而是标注质量问题。常见的情况是标注框和目标实际轮廓不贴合或者目标太小在640分辨率下只有十几个像素模型很难提取有效特征。遇到小目标较多的数据可以考虑把imgsz提高到960但训练时间会相应增加需要权衡。5. 避坑指南Trash-ICRA19使用过程中的五个血泪教训5.1 解压后标注文件为空原因多半是rar压缩包内目录嵌套拿到压缩包解压后发现labels目录下全是0字节的空文件或者整个labels目录不存在但压缩包列表里明明有标注文件名。出现这种现象一般不是数据集本身缺文件而是rar包内还有一层子目录直接解压到当前目录时图像和标注被分到了不同层级的目录里。解决方法是先看完整目录树确认标注文件的真实路径然后统一移动到预期的目录结构下。不要嫌麻烦跳过这一步训练脚本遇到空标注文件时不会报错而是默认该图为背景图导致总训练样本数虚高但实际有效目标很少mAP结果会非常离谱。5.2 类别ID不连续导致类别错位前面提过统计类别ID的问题这里说一个我实际遇到过的坑。某次训练时mAP50-95只有0.12排查了很久最后发现标注文件里类别ID从0到4但ID 2出现的次数为0而类别文件里写的是0到3一共4个类别。YOLO框架读取标注时按数字索引类别ID 3的文章会被当成ID 2的类别来训练AP全部乱套。这时候不能用原始ID直接训练必须先做类别映射压缩成连续ID。# 重新映射类别ID为连续值 import os from collections import defaultdict id_mapping {} new_id 0 for fname in os.listdir(labels): with open(flabels/{fname}, r) as f: for line in f: old_id int(line.strip().split()[0]) if old_id not in id_mapping: id_mapping[old_id] new_id new_id 1 # 统计结果old_id - new_id 的映射 print(id_mapping)有了映射关系后遍历所有标注文件把第一列替换掉同时生成对应顺序的类别名称文件。这个坑的隐蔽性在于训练过程完全正常loss下降也正常但最终精度评测时才发现类别张冠李戴。5.3 图像分辨率差异大导致训练和推理效果不一致Trash-ICRA19的原始图像来源可能是多个设备分辨率跨度从几百像素到几千像素都有。YOLO训练时通过letterbox方式统一缩放到640这个没问题但推理时如果输入图像的宽高比不一样缩放后目标的相对大小会变化。更隐蔽的问题是某些高分辨率图像里的小目标缩小后可能只有2到3个像素模型在训练阶段根本学不到这个目标。我的处理方式是训练前统计所有图像的长宽分布把极端尺寸的图像单独剔出来或者做裁剪。如果你要部署到实时视频监控场景还需要考虑推理时用的分辨率要和训练时一致否则精度会掉。使用TensorRT或其它加速方案时分辨率不匹配引发的精度下降往往不是模型问题而是预处理配置问题。5.4 数据集版权与学术用途的实际边界Trash-ICRA19来源是ICRA 2019的机器人比赛数据集本身以学术用途为主。如果你用这份数据训练模型做商业项目部署需要确认原始发布方的许可证条款有些版本只允许学术研究。这一条看起来和训练无关但涉及工程项目交付时必须提前确认不能等模型上线了才发现有合规问题。另外公开数据集往往存在标注噪声特别是边界框标注的一致性不够训练出的模型在真实复杂海洋环境中的泛化能力有限建议在目标水域自采一批数据做微调。5.5 训练100轮和训练300轮最优权重可能出现在完全不同的位置小数据集上训练轮数的影响很大。我在一份类似规模的数据集上跑过对比100轮训练的最优权重出现在第78轮300轮训练的最优权重出现在第95轮后面就过拟合了。表面上看多跑没坏处因为框架会自动保存最优权重但多出来的训练时间算浪费了。如果时间预算紧建议先跑50轮看验证集mAP的拐点位置再决定要不要加训别一上来就按默认的300轮跑。6. 验证与进阶从mAP到可视化、再到实际场景部署6.1 用best.pt对验证集做可视化推理对比训练结束不代表工作结束mAP数字高只能说明在验证集上表现好但实际效果需要肉眼确认。一个简单有效的验证方法是随机抽20张验证集图像跑一遍推理把预测框画在图上和真实标注框对比检查有没有漏检、误检、框偏移这些问题。找一张水面反光强烈或者目标贴着水面的图观察模型的表现往往一眼看出过拟合还是泛化能力不足。from ultralytics import YOLO import cv2 model YOLO(trash_models/trash_yolov8s/weights/best.pt) results model.predict(val/images/001.jpg, conf0.25, saveTrue)conf0.25是置信度阈值实际部署时根据场景调整。做可视化验证时保持阈值一致才能和训练时的验证结果对比。如果发现预测框大量出现在反光区域说明模型学习到了水面纹理而不是目标特征需要回到数据增强阶段增加对反光区域的抑制或补充负样本。6.2 导出ONNX再转TensorRT部署环节的分辨率坑训练验证通过后部署是下一步。YOLO官方训练产出的weights/best.pt是PyTorch格式直接放到生产环境跑效率不高。最常见的部署链路是先导出ONNX再转成TensorRT的engine文件。导出时有一个关键参数要特别注意keep_fp16。如果你在训练时用了FP16混合精度导出时也保FP16精度避免精度损失。yolo export modeltrash_models/trash_yolov8s/weights/best.pt formatonnx imgsz640导出时imgsz必须和训练时的分辨率一致否则转出来的模型在推理时会有一个额外的预处理步骤间接增加延迟。转到TensorRT后输入图像的预处理环节在代码里也要保持一致尤其是letterbox的填充方式和缩放比例这一步出错会导致部署端的检测框整体偏移。6.3 部署方案选型单路监控还是多路并发实时检测实际项目里的部署需求各不相同有的场景是岸边固定摄像头一路视频流做实时检测有的是水面上无人机巡检需要离线分析拍摄的视频。单路实时检测的资源开销不大消费级显卡或者Jetson开发板都能跑但如果是监控系统拉RTSP流需要并发的路数越多对显存和推理时间的约束就越严格。常见做法是用DeepStream或者自研的推流管道把RTSP拉流、解码、缩放、推理、结果上抛做成多线程流水线。在Jetson这类边缘设备上YOLOv8s的FP16推理可以达到20到30毫秒一帧满足单路实时需求。多路并发时显存会先成为瓶颈因为每一路decode出来的帧缓冲和预处理后的Tensor都要占显存。这里有个血泪经验不要为每路视频单独创建一个YOLO模型实例共用同一个engine用线程或队列做并发推理显存占用会小得多吞吐量反而更高。6.4 模型在真实场景效果不如验证集找数据分布差异最后说一个大家都会遇到的问题模型在Trash-ICRA19验证集上mAP有0.6但部署到真实水域后检测率明显下降。这不是模型训练有问题而是数据分布差异。比赛数据集中目标通常比较清晰、占据画面比例较大真实场景的垃圾可能只有几十像素、被水草遮挡、有雾或反光干扰。常见做法有两个方向一是在目标水域采集一定量真实图像用训练好的模型做伪标注后加入训练集微调二是调整检测逻辑比如拉低置信度阈值、增加帧间跟踪来过滤误检。后一种方案依赖跟踪算法短期见效快但本质上还是要靠补充数据来提升模型的泛化能力。Trash-ICRA19这份数据集适合快速验证整个检测链路但真正做工程项目时我只是把它当作预训练基础而不是最终训练数据的全部。这个习惯让我避免了多次因为数据集单一导致的模型翻车那些所谓「无用」的数据准备工作其实才是最终效果的最大变量。希望这些经验和踩坑记录能帮你节省一些时间也祝你在这个方向上少走弯路。本文还有配套的精品资源点击获取
返回列表