ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

基于YOLOv11的水面垃圾检测:环境配置、训练优化与部署避坑指南

基于YOLOv11的水面垃圾检测:环境配置、训练优化与部署避坑指南 简介这是一份基于YOLOv11的水面垃圾检测系统完整说明文档面向具备一定Python基础的研究人员、环保监测及计算机视觉从业者用于解决水面漂浮物自动识别与定位问题。资源以docx文档形式呈现共1个文件压缩包大小约41KB。文档内容围绕项目完整实施流程展开涵盖环境配置、数据集准备与配置文件编写、YOLOv11模型训练、ONNX模型导出、性能评估及指标可视化、GUI界面创建等关键环节并附有关键源码样例、目录结构和注意事项。全文不仅包含项目特点、参考资料与未来改进方向还针对数据集质量、超参数调节、图像预处理等实操要点给出提醒便于读者按步骤复现并进一步优化系统。该资源已有441人学习内容精炼集中适合希望快速上手水面垃圾检测项目、了解YOLOv11落地应用流程的开发者参考。1. 水面垃圾检测为什么直接选YOLOv11先搞清楚它解决什么事一条河道巡检无人机每天拍下来几千张水面照片真正有用的检测系统不是把图片归档而是在阴天、反光、漂浮物互相遮挡的时候把矿泉水瓶、泡沫块和枯枝分清楚。基于YOLOv11的水面垃圾检测系统就是一套从数据标注到训练再到推理的完整程序和数据组合它要回答的核心问题是模型能不能稳定识别水面上的小目标垃圾以及这套流程能不能在新场景里快速复现。选YOLOv11而不是更早的版本理由很直接新模块和检测头设计让显存占用更友好同等算力下精度比上一代有可见提升。对水面垃圾这个场景来说目标不大、背景复杂任何一点精度和速度的收益都会变成巡检效率。适合动手的人是有实地采集条件、想自建检测能力的巡检团队或研究生已经有标注数据集的照着目录接上就能跑。2. YOLOv11环境配置与项目结构用两条命令跑通检测拿到整套程序和数据集之后我建议先别急着点训练。先把环境搭出一个能跑推理的最小闭环确认显卡、依赖、目录都正常再碰训练。不然模型一报错根本分不清是数据问题、代码问题还是环境问题。2.1 环境配置conda、CUDA与ultralytics版本搭配干净环境优先用conda隔离避免把系统Python搞乱。常规做法是创建一个Python 3.10的虚拟环境然后安装ultralytics库conda create -n yolo11 python3.10 -y conda activate yolo11 pip install ultralytics逻辑说明ultralytics是目前YOLO系列最常用的训练推理库YOLOv11在库里的权重名是yolo11n.pt、yolo11s.pt。这个库会把torch、torchvision以及opencv、pyyaml这些依赖一起装好速度取决于网络。装完之后不要急着开训练先确认当前机器有没有可用的NVIDIA显卡nvidia-smi pip install torch torchvision --index-url https://download.pytorch.org/whl/cu118参数说明nvidia-smi输出里能看到驱动支持的CUDA版本号。30系以上显卡装CUDA 11.8对应的torch基本够用。先手动装好CUDA版torch再装ultralytics能避免自动装上CPU版torch训练时装完发现用不了又得重来。有个常见情况是驱动装了但torch.cuda.is_available()还是False基本就是torch版本和驱动不匹配重装对应CUDA版本就能解决。import torch print(torch.cuda.is_available()) print(torch.version.cuda)这段代码从Python侧确认PyTorch能看到显卡。输出True说明环境没问题如果输出False先查驱动版本再换torch的CUDA构建版本不要盲目升最新版。2.2 项目目录让数据、权重、脚本各归其位一套完整的水面垃圾检测程序和数据拿到手第一件事是看目录结构而不是直接跑train.py。常规项目目录长这样water_garbage/ ├── data/ │ ├── images/ │ │ ├── train/ │ │ ├── val/ │ │ └── test/ │ ├── labels/ │ │ ├── train/ │ │ ├── val/ │ │ └── test/ │ └── water.yaml ├── scripts/ │ ├── train.py │ ├── predict.py │ ├── export.py │ └── eval_metrics.py ├── weights/ │ ├── yolo11n.pt │ └── best.pt ├── runs/ └── requirements.txt逻辑说明data下面是YOLO标准结构images和labels的train/val/test子目录一一对应water.yaml描述数据路径和类别名。scripts目录放四个入口脚本train负责训练predict负责对新图片推理export负责转ONNX或TensorRTeval_metrics负责把预测结果拉成统计表。weights放预训练权重和自己训练出来的best.pt。这里有个经常被忽略的细节runs目录是ultralytics自动生成的训练和推理的输出都会写进去保持不动能让每次实验记录都留在本地。我见过有人为了省磁盘手动删runs结果代码里读不到上次的模型前排练结果全没了。另外如果程序里用的是绝对路径比如/home/user/water_garbage/data换一台机器就会报路径错误拿到代码后先全局搜一下有没有写死的绝对路径有就改成相对路径。2.3 用最小命令加载模型并保存推理结果环境通了、目录理清了跑一个最小推理验证链路。用官方预训练权重和测试图片各一张from ultralytics import YOLO model YOLO(yolo11n.pt) # 官方预训练权重先验证环境 results model.predict( sourcedata/images/val, conf0.25, iou0.45, imgsz640, saveTrue, # 把画了框的结果图保存下来 save_txtTrue, # 把每个目标的类别和归一化坐标存成txt )逻辑说明YOLO(yolo11n.pt)加载预训练权重这一步能同时验证模型文件和ultralytics库版本是否兼容。source可以指向一张图或一个目录predict会遍历目录下所有图片。saveTrue把检测框画在图片上结果保存在runs/detect/predict/save_txtTrue额外生成runs/detect/predict/labels/里面每个txt对应一张图片每行是类别和坐标这是后面做结果统计的核心数据源。参数说明conf0.25表示只保留置信度大于0.25的目标框环境验证用0.25没问题正式评估时建议降到0.1看完整召回iou0.45是非极大值抑制的IoU阈值越大保留的重叠框越多imgsz640是输入分辨率后面训练时也用640保持一致效果才稳定。检查输出ls runs/detect/predict/ head -n 5 runs/detect/predict/labels/000001.txt能看到结果图和带坐标的txt说明环境、模型、数据目录全部正常。网上很多教程会把官方权重写成yolov11n.pt实际Ultralytics官方文件名是yolo11n.pt混用时加载会直接报找不到文件。提示正式项目里predict脚本优先读weights/best.pt不要每次都用官方预训练权重否则你拿着COCO模型当水面垃圾模型用检测结果基本不可用。3. 整理水面垃圾数据集训练前必须处理的三个问题数据是这套系统里最花时间的部分。水面垃圾场景没有规模很大的公开数据集很多项目都是自己飞无人机、自己标能拿到一套整理好的完整数据集相当于省掉一两个月的采集标注时间。但拿到之后也要按自己场景再检查一遍。3.1 采集与标注水面场景的特殊性决定标签怎么打水面目标有三个特点尺度小、背景杂、互相遮挡。无人机高度30米拍一张1080p图一个矿泉水瓶通常只占几十个像素地面摄像头拍出来的瓶子大一些但水面波纹和倒影会把模型搞糊涂。所以标注规则和普通物体检测不一样。我的经验是有倒影的物体只标实物本身不要把倒影一起框进去否则同一个物体会出现两个高度相关的框训练时让回归头左右摇摆被遮挡的物体标可见部分不要为了框全而把遮挡物一起框进去类别按清理方式区分比如塑料瓶、泡沫、枯枝水草、漂浮袋这四类在后续保洁船打捞时对应不同处理方式比单纯分“垃圾”和“非垃圾”实用得多。工具方面常见做法是LabelStudio或X-AnyLabeling都能直接导出YOLO格式的txt。标注时把图缩放到实际检测分辨率再标比如模型输人是640就按640看这张图能不能认出目标认不出的目标要么删掉要么单独归为难例集不要硬标一堆模型根本学不出来的像素块。3.2 整理成YOLO格式划分脚本与类别配置文件标注软件导出的格式五花八门有JSON有XML统一转成YOLO的txt格式后还要按比例划分训练集、验证集和测试集。这里给一个划分脚本import random import shutil from pathlib import Path random.seed(42) src_img Path(raw/images) src_lbl Path(raw/labels) dst_img Path(data/images) dst_lbl Path(data/labels) for split in (train, val, test): (dst_img / split).mkdir(parentsTrue, exist_okTrue) (dst_lbl / split).mkdir(parentsTrue, exist_okTrue) files list(src_img.glob(*.jpg)) list(src_img.glob(*.png)) random.shuffle(files) n len(files) for i, img_path in enumerate(files): if i int(n * 0.8): split train elif i int(n * 0.9): split val else: split test lbl_path src_lbl / (img_path.stem .txt) if not lbl_path.exists(): continue # 没有标签的图直接跳过避免训练报错 shutil.copy(img_path, dst_img / split / img_path.name) shutil.copy(lbl_path, dst_lbl / split / lbl_path.name) print(train/val/test:, len(list(dst_img.glob(train/*))), len(list(dst_img.glob(val/*))), len(list(dst_img.glob(test/*))))逻辑说明YOLO格式的标签文件名必须和图片名完全一致只是后缀从.jpg变成.txt。脚本里用随机种子固定划分结果保证每次复现时训练集会保持一致。copy代替move保留原始图片避免后面想重新划分时原始素材已经没了。然后写data/water.yamlpath: data train: images/train val: images/val test: images/test names: 0: plastic_bottle 1: foam 2: branch_weed 3: floating_bag参数说明path字段指向数据根目录train、val、test是相对path的子路径。names的ID必须和标签txt的第一列一致不能错位。这里有一个非常常见的坑把path写成data/images/train然后train又写images/train最后拼接出一个不存在的路径训练直接报错。3.3 数据增强针对漂浮物和小目标而不是套模板ultralytics训练时会自动做马赛克、翻转、HSV扰动等增强但默认参数是为COCO那种通用目标设计的水面垃圾场景建议自己调一遍。在model.train()里传augment参数或者在数据yaml里写超参都行常用的一组取值mosaic: 0.5 degrees: 10 hsv_h: 0.015 hsv_s: 0.5 hsv_v: 0.4 translate: 0.1逻辑说明mosaic从默认1.0降到0.5原因是马赛克增强把四张图拼成一张每个目标等比缩小对水面垃圾这种本身就只有几十像素的目标来说缩小之后更难学。degrees10是轻微旋转水面俯拍没有强方向性旋转范围不需要太大。hsv_h、hsv_s、hsv_v应对阴天、反光造成的色差水面反光时饱和度波动很大这几项可以让模型不那么敏感。translate0.1让目标出现位置更随机避免模型只学会在画面中央找垃圾。如果训练集里某一类样本特别少比如泡沫块只有十几个实例数据增强解决不了根本问题。这时候可以做简单的copy-paste增强把泡沫块的标注区域裁下来随机贴到没有垃圾的水面背景图上同时写入对应的txt标注。这个操作可以写脚本批量做是提升少样本类别召回率最直接的手段。4. 用YOLOv11训练水面垃圾检测模型参数、日志与第一次调优数据准备好了训练这一步反而最机械。真正考验人的是参数设置和日志解读。4.1 从预训练权重启动训练训练入口有两种命令行和Python脚本。项目里一般用脚本方式参数更集中、更好改from ultralytics import YOLO model YOLO(yolo11n.pt) model.train( datadata/water.yaml, epochs200, imgsz640, batch16, lr00.01, patience50, device0, workers4, cacheTrue, )逻辑说明YOLO(yolo11n.pt)加载的是COCO预训练权重而不是从随机权重开始训练。COCO里没有水面垃圾这些类别但预训练模型已经学会了纹理、边缘、形状的基本特征在水面数据上做迁移收敛速度和最终精度都比从头训练好得多。如果拿到的是别人在类似水面数据集上训练好的best.pt也可以用它继续训练但前提是类别配置一致。参数说明列表参数建议值说明epochs200几百到几千张图200轮足够收敛imgsz640训练分辨率小目标多时后续可以提高到1024batch16由显存决定显存不够就降到8lr00.01从预训练权重继续训练的常见初始学习率patience50验证指标50轮不提升就早停device0单卡训练直接用0cacheTrue把图片缓存进内存数据量不大时明显加速显存有限时batch降到8同时把accumulate适当调大比如accumulate2用两步梯度累积模拟batch16的效果。训练中断也不用从头跑在训练脚本里加上resumeTrue就接着上一次的checkpoint继续。4.2 训练日志loss、mAP和PR曲线怎么看训练结束后所有指标图都在runs/detect/train/results.png里对应的数值表是results.csv。很多人只看最后的mAP数字其实中间过程的信息更重要。tail -n 20 runs/detect/train/results.csv看的时候分三块box_loss是定位损失训练初期下降快后期平缓这说明框的位置在稳定下来cls_loss是分类损失如果类别不平衡后半段会有小抖动不用太紧张dfl_loss是分布损失影响框的回归精度后期还在微降说明模型在精调边框位置。另一行是mAP50和mAP50-95水面垃圾小目标多mAP50-95通常会比mAP50低不少这是正常的重点看mAP50有没有稳步抬升。典型的翻车信号是val的loss曲线在后面几轮突然反弹而train的loss还在降这是过拟合。水面垃圾数据量不大加上增强参数过拟合很常见。看到这个信号把epochs降下来或者把mosaic调低一点让模型别把训练集细节背进去。4.3 类别不平衡与漏检分析类别不平衡在水面垃圾里几乎必然出现塑料瓶和枯枝占大头泡沫和袋子可能只有零头。训练之前先统计一下每类标注数from pathlib import Path from collections import Counter counter Counter() for txt in Path(data/labels/train).glob(*.txt): for line in txt.read_text().splitlines(): parts line.split() if len(parts) 5: counter[int(parts[0])] 1 print(counter)逻辑说明读训练集所有标签统计每个类别ID出现的总次数。如果某一类只有几十个实例模型会在多数类上过拟合对少样本类别几乎不输出。简单调loss权重不是首选方案因为ultralytics对类别权重的支持有限最稳的做法是在数据层解决给少样本类别做copy-paste增强补充标注是最直接的。训练完一轮之后用验证集做一次预测保存推理结果然后专门挑置信度低于0.3的检测结果看。你会发现漏检的目标高度集中在小目标档位把这些bad case单独收集起来补标一遍再训练比盲目调参数有效得多这一步就是把预测保存下来的txt当作难例挖掘的素材。5. YOLOv11环境与训练避坑高频问题定位与修复把实际跑项目遇到的高频坑按现象、原因、解决整理成下面的清单排查问题时会快很多。5.1 训练刚启动就报Not a directory现象数据yaml写好之后训练命令一执行几秒钟就报[Errno 20] Not a directory。原因data/water.yaml里的path字段或train/val字段写错了。常见的是path写了data/images/traintrain又写了images/trainultralytics把它俩拼成一个文件路径必然报错。解决path统一指向数据根目录train/val/test只写相对子目录名。正确写法是path: data、train: images/train。检查yaml里有没有多余的空格和TabYAML对缩进敏感。5.2 训练到一半loss变成nan现象前面几十轮loss正常某个epoch开始box_loss直接变成nan后面全部乱掉。原因最常见的是学习率过高模型权重发散其次是数据里有损坏的图片或空标注txt导致某一步前向传播出现非法值。解决先查数据用脚本遍历所有图片用PIL打开一遍打不开的直接删掉或转成RGB再查labels目录所有txt文件必须至少有一行有效标注。数据处理干净之后把lr0从0.01降到0.005重跑一次同时确认batch设得不过小。RGBA四通道图片也会触发nan统一转成RGB。5.3 小目标漏检严重召回率上不去现象mAP50看着有80多但实际扫河道的视频里远处的小垃圾基本没框出来输出框都在靠近镜头的大块垃圾上。原因水面垃圾大量是十几个像素的小目标训练分辨率640时这些目标只占很小面积特征图下采样后可能只剩一个神经元在响应。另一个原因是预训练权重默认的anchor分布更偏向COCO里那种大目标。解决第一档是把训练和推理分辨率都提到1024显存不够就只提推理分辨率训练保持640效果会有明显上升。第二档是用切图推理把大图切成重叠的512或640小图分别预测再合并特别适合无人机俯拍大尺寸图片。第三档是改网络结构YOLOv11的骨干网络用的是C3k2设计常规改进思路是在骨干后面加一个跨尺度注意力模块让浅层细节特征和深层语义特征融合常见做法是在ultralytics/cfg/models/11/下新建一个yaml加入注意力层配置网上很多这类改进思路HCANet就是走跨尺度注意力融合的路线。程序包里如果内置了改进版优先用内置版本省得自己改。5.4 训练时mAP很高部署后预测效果明显变差现象runs/detect/train里mAP50有85导出模型后在新图片上一测检出数量少了一半。原因大部分时候不是模型坏了而是训练和推理配置不一致。常见的有四种推理时用的best.pt路径写错实际加载了预训练的yolo11n.pt推理时imgsz和训练时不一致推理时conf设得太高比如默认0.25把一批低置信度的小目标滤掉了训练时用test集验证而推理时换了完全不同的场景。解决推理脚本里固定model YOLO(weights/best.pt)imgsz和训练保持一致先用conf0.1跑一遍看完整召回再根据需求往上调。如果换了一批新场景图片效果下降那是数据场景覆盖问题需要补充新场景数据重训。5.5 换一台机器跑完整程序import就报错现象代码和数据拷到新机器环境装完之后运行train.py第一行from ultralytics import YOLO就报错或者运行到某个API调用时提示参数不存在。原因ultralytics版本迭代很快接口有变动。比如老版本用results.pandas().xyxy解析检测框新版本已经换成了results.boxes.xyxy旧脚本在新库上直接报废。很多完整程序包没有锁版本换机器就踩坑。解决先看项目的requirements.txt有没有锁版本没有的话先安装一个和程序编写时相近的版本。再全局搜代码里有没有老接口有就改成新版写法。最省事的做法是项目里自建一个requirements.txt把ultralytics、torch、torchvision的版本号固定下来换机器按文件装这条能省下大量排错时间。6. 从best.pt到可用系统部署、保存推理结果和验收自检6.1 常规部署与时延预估服务器端部署最省事的方式是导出ONNX然后用ONNX Runtime跑yolo export modelweights/best.pt formatonnx imgsz640 device0边缘设备部署是另一个量级的事。网上搜jetson nano部署yolov11详细步骤搜出来的流程基本都是先把模型导出成TensorRT engine再写一个小的推理脚本。导出engine命令如下yolo export modelweights/best.pt formatengine imgsz640 device0这里的关键不是命令本身而是TensorRT版本、CUDA版本、torch版本三者必须匹配版本不匹配时export会报一堆算子错误。如果只是先做验证不追求极端时延先跑ONNX Runtime就够了不要在第一步就跳到TensorRT。6.2 用预测保存的txt做验收自检模型训练完不能只看mAP。我习惯的做法是把验证集或一段新视频抽帧跑一次predict保存推理结果然后写一个小脚本从保存的txt里统计目标尺寸分布from pathlib import Path rows [] for txt in Path(runs/detect/predict/labels).glob(*.txt): for line in txt.read_text().splitlines(): parts line.split() if len(parts) ! 5: continue cls_id, cx, cy, w, h map(float, parts) rows.append((txt.stem, int(cls_id), w * h)) # 目标面积 small [r for r in rows if r[2] 0.01] # 归一化面积小于1% print(f检测到 {len(rows)} 个目标其中小目标 {len(small)} 个)逻辑说明predict保存的txt里是归一化坐标w和h的乘积就是目标占整张图的比例。把检测结果按这个比例分档能直观看到模型漏检的目标集中在哪个尺寸段。如果小目标档检出数量明显偏低就回到5.3的三档方案继续优化。这个验证方法比盯着mAP数字更贴近实际部署。我每训完一版模型都会把预测结果目录留档下次换置信度阈值重新评估时不用重新跑一遍推理直接读txt就能统计。这个习惯帮我避免了很多次重复劳动希望帮到你。本文还有配套的精品资源点击获取
返回列表