资讯动态

YOLOV5舰船检测实战:从anchor聚类到切片推理的完整调优指南

发布时间:2026/9/10 5:32:21 来源:尧图企业网站定制
简介基于YOLOV5的舰船目标检测项目包面向计算机视觉研究者和深度学习开发者可快速搭建从数据集准备、模型训练、性能评估到部署验证的完整流程适用于海事监控、港口管理、海上搜救等场景。压缩包共含2000个文件整体大小约456.66MB其中1165个XML标注文件与786个TXT标签文件构成可直接训练的数据集23个Python脚本负责训练、验证、绘图等核心逻辑19个YAML文件用于模型与数据配置5个Shell脚本辅助环境初始化和任务执行2个Markdown文档提供使用说明。目录结构清晰便于系统学习。已有95人学习下载适合具备一定深度学习基础、希望快速上手YOLOv5目标检测的读者可通过源码与配置理解模型参数对精度和速度的影响或在自定义数据集上复现完整训练流程。1. 海洋场景里的目标检测YOLOV5 要解决的不只是“框出来”一张海面影像丢给检测模型要它把货轮、渔船、快艇一个个框出来看起来只是目标检测的一个普通分支。实际做起来你会发现舰船目标和 COCO 里的猫狗汽车完全不同船身宽扁、长宽比极端遥感视角下可能只占几十个像素海浪纹理和浮标又会制造大量假正例。训练一个“能跑”的模型只要半天训练一个漏检率可控、误检能解释的模型需要把 anchor、数据格式、训练参数和推理策略都按场景单独过一遍。这篇内容就把这条路完整走通讲清楚从 YOLOV5 模型选型、聚类 anchor到准备舰船数据集、配置训练超参数再到用切片推理解决小目标漏检的每一步。新手可以照着命令跑通全流程有经验的工程师可以直接拿走调优参数和排错清单。2. YOLOV5 网络结构与舰船目标的 anchor 设定思路2.1 从 CSPDarknet 到 PANet舰船检测为什么吃多尺度特征YOLOV5 的骨干网络是 CSPDarknet核心模块是 C3跨阶段部分连接配合 SPPF 做多尺度池化把主干最后几层的特征拼接起来。颈部网络用的是 PANet 结构自顶向下和自底向上两条路径交替融合特征最终输出三张不同步长的特征图。这个设计直接影响舰船检测的成败舰船在画面里的尺寸跨度极大近景可见光视频里一艘货轮可能占满半个画面卫星遥感图里一艘渔船只有十几个像素。三种步长对应不同的感受野20×20 的格子负责大目标40×40 负责中目标80×80 负责小目标PANet 的跨层连接让浅层细节信息能传导到深层语义输出。特征图尺寸步长适合的目标尺度舰船场景对应情况80×808小目标8~32 像素遥感切片里的小型渔船、浮标干扰40×4016中目标32~128 像素近岸航道里的中型货船20×2032大目标128 像素以上港口停靠的大型集装箱轮不同规模的模型变体在舰船检测场景里的取舍也遵循同一原则YOLOv5s 参数量约 7.2M显存占用小、推理快适合边缘端和实时处理YOLOv5m 和 l 在召回率上明显提升适合离线做高精度遥感筛查。我的建议是先用 s 跑通数据流程确认误检来源后再决定是否升级模型而不是直接上最大的 x 版本训练和推理成本都会可控得多。2.2 舰船宽高比与 anchor 校正kmeans 聚类脚本YOLOV5 的默认 anchor 是在 COCO 数据集上聚类得来的落到舰船上会产生一个明显问题COCO 目标长宽比集中在 1:1 附近而舰船在水平框标注下经常出现 1:3、1:5 甚至更极端的比例。默认 anchor 与真实框的 IoU 偏低导致回归头要额外学一个较大的偏移量收敛慢且小目标容易漏。YOLOV5 训练时会自动调用autoanchor逻辑重新聚类如果聚类结果与默认 anchor 的适应度差距超过阈值它会在训练启动时自动替换。但要精确控制这个环节我一般会在训练前用脚本单独做一次聚类把结果写进模型配置文件。import numpy as np from tqdm import tqdm def iou_distance(boxes, anchors): 计算每个真实框与每个anchor的IoU距离用于kmeans聚类 intersections np.minimum(boxes[:, 0], anchors[:, 0]) * np.minimum(boxes[:, 1], anchors[:, 1]) unions boxes[:, 0] * boxes[:, 1] anchors[:, 0] * anchors[:, 1] - intersections return 1.0 - intersections / unions def kmeans_anchor(boxes, k9, max_iter300): 对归一化宽高做聚类返回按面积排序的anchor数组 n len(boxes) idx np.random.choice(n, k, replaceFalse) centroids boxes[idx] for _ in range(max_iter): dist iou_distance(boxes, centroids) labels np.argmin(dist, axis1) new_centroids np.array([boxes[labels i].mean(axis0) for i in range(k)]) if np.allclose(new_centroids, centroids): break centroids new_centroids return centroids[np.argsort(centroids[:, 0] * centroids[:, 1])]脚本输入是数据集中所有标注框的宽度和高度数组输出 9 个 anchor按面积从小到大排列对应三种尺度的特征图每组 3 个。聚类时要注意先把标注框的宽高从像素值转为相对输入尺寸的归一化值否则大图数据会完全支配聚类结果。得到 anchor 后把models/yolov5s.yaml里的anchors字段替换为新值同时在训练命令里加--noautoanchor避免训练启动时被覆盖。2.3 输入分辨率继续用 640 还是拉大图像尺寸YOLOV5 官方默认输入是 640×640这个尺寸在舰船检测里需要重新审视。如果你的数据来自可见光视频监控640 通常够用因为目标在画面中占比不小如果数据来自遥感影像或无人机航拍原图可能大到 4000×4000直接缩放到 640 会把大量小目标压成 3~5 个像素无论怎么调 anchor 都救不回来小目标检测的基础前提已经不存在了。常见做法是把大图按滑动窗口切成 640 或 1024 的子图再送入模型训练和推理。这样做的代价是训练样本数量倍增但舰船场景的收益非常直接目标在子图里的相对尺寸恢复到可识别范围。切图时的重叠率一般设 10%~20%避免目标恰好被切在窗口边缘。训练阶段也可以开启--multi-scale让模型在每 10 个 batch 随机切换输入尺寸模拟不同成像高度下的目标尺度变化对遥感舰船这种尺度分布极广的任务有明显提升。3. 舰船检测数据准备公开数据集、格式转换与验证集划分3.1 数据从哪来公开数据集与自建数据的取舍舰船检测没有像 COCO 那样统一规模的开源基准实际项目里通常从三个方向凑数据。第一是学术公开数据集HRSC2016 包含大量垂直视角遥感舰船图像但它的标注是旋转框需要转换SeaShips 是海面可见光视频帧目标为货船等常见船型标注是水平框接入 YOLOV5 更直接。第二是航运监控视频抽帧这种方式最贴近实际部署场景但需要自己做清洗和标注。第三是网络公开的港口卫星图只建议用来补充困难样本比如近岸背景、密集停靠场景。数据质量上最容易踩的坑是类别失衡。舰船检测的负样本不只是完全没有船的纯海面还包括海浪纹理、白色浪花、浮标、防波堤这些“长得像船”的区域。训练集里至少要保留 15%~20% 这样的难负样本否则模型会在推理阶段疯狂误报。类别定义也要提前想清楚只分ship一类最稳妥如果项目要求区分货轮和渔船要保证每个子类至少有 1000 个以上的实例否则分类头的 loss 根本收敛不了。3.2 XML 标注转 YOLO 格式归一化与越界处理YOLOV5 需要的标签格式是纯文本每行代表一个目标class x_center y_center width height所有值都归一化到 0~1。从标注工具导出 XMLVOC 格式或 JSONLabelMe 格式后必须写一个转换脚本。下面是处理 VOC 风格 XML 的完整代码import xml.etree.ElementTree as ET import os def convert_voc_to_yolo(xml_file, out_file, class_map): 将VOC格式XML标注转为YOLO格式TXT处理越界和空标注 tree ET.parse(xml_file) root tree.getroot() img_w int(root.find(size/width).text) img_h int(root.find(size/height).text) lines [] for obj in root.iter(object): cls_name obj.find(name).text if cls_name not in class_map: continue cls_id class_map[cls_name] box obj.find(bndbox) x1 float(box.find(xmin).text) y1 float(box.find(ymin).text) x2 float(box.find(xmax).text) y2 float(box.find(ymax).text) x1 max(0, min(x1, img_w)) y1 max(0, min(y1, img_h)) x2 max(0, min(x2, img_w)) y2 max(0, min(y2, img_h)) if x2 x1 or y2 y1: continue x_center (x1 x2) / 2 / img_w y_center (y1 y2) / 2 / img_h w (x2 - x1) / img_w h (y2 - y1) / img_h lines.append(f{cls_id} {x_center:.6f} {y_center:.6f} {w:.6f} {h:.6f}) with open(out_file, w) as f: f.write(\n.join(lines)) class_map {ship: 0} # 类别名到id的映射必须从0开始逻辑说明先读取原图宽高作为归一化分母然后遍历所有标注框把坐标裁剪到图像范围内。舰船标注经常出现框的一个角超出图像边界的情况如果不裁剪归一化后的坐标可能大于 1训练时模型会按错误位置回归。转换完成后用find labels -name *.txt -size 0检查是否有空标注文件空文件在训练时会导致loss计算异常最好直接删除对应图片或给一个极小的背景权重。3.3 验证集划分别让同一艘船同时出现在训练集和验证集视频抽帧数据有个隐蔽问题同一艘船在连续几十帧里都出现如果随机打乱划分训练集和验证集会包含高度相似的画面验证指标虚高到 90% 以上上线后真实场景表现却很差。正确做法是按时间或场景划分把视频片段按时间段切块整个块的帧只进入训练集或验证集遥感图像则按地理区域划分避免同一片港口的不同切图出现在两侧。划分比例建议 8:1:1验证集和测试集各取 10%。若数据总量少于 2000 张验证集至少要保证有 100 张否则 mAP 的置信区间太大调参时看不出真实差异。4. YOLOV5 训练舰船模型环境配置、参数表与多尺度训练建议4.1 环境配置与 GPU 需求YOLOV5 训练要不要 GPU答案是明确的需要。CPU 不是不能跑只是舰船数据通常伴随大量高频背景纹理batch size 小、训练轮数多纯 CPU 训练几百张图一个 epoch 要几十分钟完全不具备实践可操作性。显存 6GB 的入门级显卡可以跑yolov5s加 batch size 88GB 以上可以把 batch 拉到 16训练效率明显改善。没有本地 GPU 时云厂商的按量付费实例是最常见的选择单卡 T4 就能满足 s 和 m 模型的微调需求。conda create -n yolo python3.8 conda activate yolo pip install torch torchvision --index-url https://download.pytorch.org/whl/cu118 git clone https://github.com/ultralytics/yolov5.git cd yolov5 pip install -r requirements.txt代码说明前三行创建 Python 3.8 环境并安装带 CUDA 11.8 的 PyTorch--index-url指定了 PyTorch 官方预编译 wheel 的地址避免 pip 默认安装到 CPU 版本。如果你的显卡驱动较新也可以把cu118换成cu121。requirements.txt里包含numpy、opencv-python、matplotlib等训练依赖一次装完。环境配置完成后用python -c import torch; print(torch.cuda.is_available())验证 CUDA 是否可用输出True才继续往下走。4.2 数据配置文件与目录结构YOLOV5 用 YAML 文件描述数据集路径和类别信息训练前必须把目录结构调整成官方预期的格式。一个完整的舰船数据目录长这样datasets/ship/ ├── images/ │ ├── train/ # 训练图片 │ └── val/ # 验证图片 ├── labels/ │ ├── train/ # 与训练图片同名的TXT标注 │ └── val/ └── ship.yaml # 数据配置文件path: ../datasets/ship train: images/train val: images/val nc: 1 names: [ship]配置说明path是数据集根目录可以用绝对路径也可以用相对 YOLOV5 目录的路径train和val是相对于path的子目录。nc是类别数names按顺序列出类别名索引从 0 开始与标签文件里的第一列数字一一对应。这里最容易犯的错是names顺序和训练时标签不一致比如标注时ship是第 0 类配置里却写成了[boat, ship]模型会学到完全错位的映射。4.3 训练命令与关键超参数python train.py \ --data ship.yaml \ --weights yolov5s.pt \ --batch-size 16 \ --epochs 100 \ --img 640 \ --multi-scale \ --cache \ --name ship_experiment各参数的含义和舰船场景下的建议值如下表参数作用舰船检测建议--batch-size每轮迭代的样本数受显存限制显存不足时降到 8优先保证梯度稳定--epochs训练轮数迁移学习 100 轮起步小数据集可到 150--img训练输入尺寸遥感切片用 640近景视频可用 960--multi-scale启用多尺度随机输入强烈建议开启模拟不同成像高度--cache预加载图像到内存数据集小于 5000 张时开启显著加速--weights预训练权重用yolov5s.pt做迁移学习不使用随机初始化训练命令对应的超参数文件默认是data/hyps/hyp.scratch-low.yaml里面定义了学习率、权重衰减系数、数据增强强度。舰船检测里值得手动改两项hsv_h控制色调增强舰船目标本身颜色特征较弱可以保持默认flipud是上下翻转增强垂直视角遥感图像可以打开水平视角的水面图像建议关闭因为船体的倒影会让模型学到错误的上文关系。4.4 训练曲线与评价指标怎么读训练结束后进入runs/train/ship_experiment/目录打开results.png重点看三件事。第一train/box_loss和train/cls_loss是否持续下降并在后 20 轮趋于平缓如果曲线还在明显下降就说明训练轮数不够。第二metrics/mAP_0.5和metrics/mAP_0.5:0.95的差距如果 mAP_0.5 很高但 mAP_0.5:0.95 很低说明模型虽然能框住目标但框的定位精度差大概率是标注框不贴合船体轮廓或回归头训练不充分。第三val/recall如果明显低于val/precision说明漏检是主要问题优先去处理小目标和难负样本而不是调低置信度阈值。验证阶段用官方脚本输出详细的评价指标python val.py \ --data ship.yaml \ --weights runs/train/ship_experiment/weights/best.pt \ --img 640 \ --task val \ --verbose输出的Confusion Matrix图会按类别给出漏检和误检的统计这是定位模型问题的最直接工具。图中对角线的值代表正确检测比例舰船检测里要特别关注“background行”如果模型把大量背景预测成舰船说明负样本不够或置信度阈值偏低。5. 舰船检测落地的 3 个调优技巧切片推理、阈值调整与模型导出5.1 小目标漏检用 SAHI 做滑动窗口推理遥感或无人机影像直接缩放输入模型时小目标在降采样过程中丢失是不可避免的。与其在训练阶段强行提高分辨率不如在推理阶段用滑动窗口切片每个子图独立检测后合并结果。这个流程可以自己实现也可以直接用 SAHI 库它内置了切片推理、结果合并和可视化对 YOLOV5 有现成接口。from sahi import AutoDetectionModel from sahi.predict import get_sliced_prediction model AutoDetectionModel.from_pretrained( model_typeyolov5, model_pathruns/train/ship_experiment/weights/best.pt, confidence_threshold0.3, image_size640, ) result get_sliced_prediction( aerial_harbor.jpg, model, slice_height640, slice_width640, overlap_height_ratio0.2, overlap_width_ratio0.2, )参数说明slice_height和slice_width决定切图尺寸建议与模型训练输入一致overlap_height_ratio是切片间的重叠比例设 0.1~0.2 可以避免目标被切断但重叠过大会导致同一艘船被重复检测后处理合并压力变大。对只有十几个像素的小目标可以先把切片尺寸降到 416配合重叠 0.25 使用召回率提升明显。5.2 用混淆矩阵调整置信度阈值与 NMS 参数舰船场景的误检来源通常是有规律可循的。海面强反光区域容易产生细长虚假框港口堆场的集装箱纹理容易被识别为船体。面对这类问题优先调整置信度阈值和 NMS IoU 阈值而不是重新训练。验证集上把conf_thres从默认 0.25 逐步提高到 0.35、0.45、0.55对比每档的 precision 和 recall。追求高召回的场景搜救、船位监管适合 0.25追求低误报的场景自动过闸、港口统计适合 0.4 以上。NMS 的iou_thres默认 0.45舰船密集停靠时目标互相遮挡过高的 IoU 阈值会合并相邻船只这个值可以降到 0.35代价是同一条船可能出现重复框再用按类别合并的策略收敛。另外可以开启--augment做 TTA测试时增强对可见光视频里的中等舰船目标能稳定提升 1~2 个百分点的 mAP但对遥感小目标提升有限且推理耗时成倍增加实时场景谨慎使用。5.3 导出 ONNX/TensorRT 并验证部署一致性调优完成后要把模型导出成部署格式这一步的关键是保证导出模型的推理结果和 PyTorch 原版一致否则前期的调参全部失去意义。python export.py \ --weights runs/train/ship_experiment/weights/best.pt \ --include onnx \ --dynamic导出完成后用onnxruntime读取模型对验证集图片推理与 PyTorch 输出逐图对比mAP 偏差一般应控制在 0.01 以内。如果发现偏差较大优先检查--dynamic参数是否引入动态轴问题以及输入图像的归一化方式是否与训练时一致。边缘端部署时在 Jetson 设备上再把 ONNX 转成 TensorRT精度还会有一点点下降通常也在可接受范围内。最后把置信度阈值和 NMS IoU 阈值原样写入部署配置与训练验证时的后处理参数保持一致。本文还有配套的精品资源点击获取

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价