☰
基于改进YOLOv5的船舶目标检测:从训练到部署的完整方案
2026/9/29 15:12:41 网站建设 项目流程

简介:这份文档面向计算机视觉与智能交通方向的研究者、研究生及算法工程师,聚焦复杂海况与多目标场景下船舶检测精度与鲁棒性不足的问题,系统梳理了基于改进Yolov5算法的完整研究思路。内容从研究背景与国内外现状切入,依次展开图像预处理与特征提取、Yolov5原理与流程、船舶识别技术及多种检测算法对比,并重点阐述数据增强策略、卷积层与池化层优化、注意力机制引入以及正负样本损失与类别不平衡问题的调整方案,最后给出数据集准备、训练验证设置、性能指标与结果对比分析。资源为单个docx文档,压缩包约80KB,目录结构完整、章节层次清晰,涵盖理论基础、算法改进与实验设计三大模块,可作为船舶目标检测课题的参考范本与写作模板。目前已有47人学习,适合需要快速把握改进Yolov5落地路径、对照实验流程查漏补缺的读者。

1. 船舶目标检测为什么绕不开 YOLOv5:一份能直接复现的改进方案

做内河航道监控或者港口卡口项目的同行大概率都遇到过这个场景:水面反光、船体与岸线颜色接近、小目标渔船在 1080P 画面里只占几十个像素,拿通用 COCO 预训练的检测器直接跑,漏检和误检能把后处理逻辑逼疯。这份《基于改进Yolov5算法的船舶目标检测研究》文档,核心就是围绕上述痛点,在 YOLOv5 的骨干、颈部、损失函数和后处理环节做针对性改造,并给出完整的训练、验证、部署链路。它适合两类人:一类是正在做船舶、水面目标检测的算法工程师,想找一份可对照的改进基线;另一类是刚接触 YOLOv5、想拿一个垂直场景把「训练自己的数据集」全流程走通的学生或转行者。文档不是纯理论推导,重点落在改进点怎么落到代码、参数怎么调、指标怎么涨。下面我按「改进思路 → 环境与数据 → 训练调参 → 部署验证 → 避坑」的顺序拆开讲,能抄的代码和参数我都尽量给全。

2. 改进点拆解:从骨干到后处理,每一处改在哪

2.1 为什么选 YOLOv5 而不是 YOLOv8 或 Faster R-CNN

先回答选型问题。船舶检测的典型约束是:边缘设备算力有限(Jetson、瑞芯微、昇腾边缘盒子都常见)、要求实时(25 FPS 以上)、小目标多。Faster R-CNN 两阶段精度够但速度上不去,YOLOv8 虽然新,但很多工业现场的推理框架(比如早期版本的 TensorRT 插件、某些国产 NPU 工具链)对 v5 的算子支持更成熟,踩坑少。YOLOv5 的工程化程度高,export.py一行命令能出 ONNX、TensorRT、OpenVINO 多种格式,这对「yolov5部署」这个高频需求非常关键。所以这份文档选 v5 作为基线,不是保守,是工程权衡。

改进方向通常集中在四处:一是骨干网络替换或加注意力,提升水面反光下的特征提取;二是颈部结构改进,增强小目标的多尺度融合;三是损失函数换成 CIOU 或 EIOU,改善回归精度;四是后处理里针对密集船只做 NMS 优化。文档里这几块都有涉及,下面逐个说怎么落地。

2.2 骨干与注意力改进的代码落点

YOLOv5 的骨干定义在models/common.py和models/yolo.py,改骨干最稳妥的方式是新增模块而不是直接改原文件,避免破坏预训练权重加载。常见做法是在common.py里加一个 CBAM 或 SE 模块,然后在yolov5s.yaml的 backbone 里插入。

# models/common.py 中新增通道注意力模块 import torch import torch.nn as nn class SEBlock(nn.Module): """通道注意力:对每个通道做全局池化后学习权重""" def __init__(self, c1, r=16): super().__init__() c2 = max(1, c1 // r) # 压缩比 r 控制参数量,船舶场景 16 比较稳 self.avg = nn.AdaptiveAvgPool2d(1) self.fc = nn.Sequential( nn.Linear(c1, c2, bias=False), nn.ReLU(inplace=True), nn.Linear(c2, c1, bias=False), nn.Sigmoid() ) def forward(self, x): b, c, _, _ = x.size() y = self.avg(x).view(b, c) y = self.fc(y).view(b, c, 1, 1) return x * y.expand_as(x) # 逐通道加权

逻辑说明:SEBlock 先做全局平均池化把空间信息压成一个通道描述符,再用两个全连接层学通道间依赖,最后 Sigmoid 出权重乘回原特征。参数r是压缩比,船舶数据集类别少、纹理单一,r 取 16 比默认的 8 更不容易过拟合。插入位置建议放在 backbone 的 C3 模块之后,而不是每个卷积后面都加,否则推理耗时涨得比精度快。

改完 yaml 后必须验证权重加载是否正常,跑一句:

python models/yolo.py --cfg models/yolov5s_se.yaml

如果报RuntimeError: Error(s) in loading state_dict,说明新增层的 key 和预训练权重对不上,这是正常的,用--weights yolov5s.pt --cfg 新yaml训练时 YOLOv5 会自动跳过不匹配的层,但你要确认跳过的层数和你新增的层数一致,否则就是 yaml 写错了。

2.3 颈部与损失函数的配合

颈部改进常见的是把 PANet 换成 BiFPN 或者加一个专门的小目标检测头。文档里如果提到多尺度融合增强,落地时要注意:加检测头会改变输出张量数量,后处理和解码逻辑都要跟着改。损失函数方面,YOLOv5 默认用 CIOU,船舶长宽比差异大(货船细长、渔船短粗),换成 EIOU 对宽高比回归更友好。改的地方在utils/loss.py的ComputeLoss类里,把 CIOU 替换成 EIOU 的实现即可,注意保持box_loss的归一化方式不变,否则学习率要重调。

提示:改损失函数后第一件事是拿小批量数据过拟合,看 loss 能不能降到接近 0,降不下去说明实现有 bug,别急着上全量训练。

3. 环境配置与数据集准备:把「训练自己的数据集」跑通

3.1 环境配置的版本锁定

「yolov5环境配置」是搜索量极高的词,也是翻车重灾区。核心矛盾是 PyTorch、CUDA、torchvision 三者版本必须对齐。我一般用 conda 建独立环境,锁定一套经过验证的组合:

conda create -n ship_yolo python=3.8 -y conda activate ship_yolo # CUDA 11.3 对应的 torch 1.12.1,这个组合在 30 系卡上最稳 pip install torch==1.12.1+cu113 torchvision==0.13.1+cu113 \ --extra-index-url https://download.pytorch.org/whl/cu113 # 再装 YOLOv5 依赖,注意 requirements.txt 里的版本别乱升 pip install -r requirements.txt

参数说明:Python 3.8 是兼容性最好的版本,3.10 以上有些旧版 numpy 会出问题;torch 1.12.1 配 cu113 在 RTX 3060/3090 上实测稳定。装完必须验证:

python -c "import torch; print(torch.cuda.is_available(), torch.version.cuda)"

输出True 11.3才算过。如果输出 False,八成是驱动版本低于 CUDA 要求,或者装成了 CPU 版 torch,重装即可。

3.2 船舶数据集的标注与格式转换

船舶数据来源一般是公开数据集(如 Seaships、Singapore Maritime Dataset)加自己采集的监控截图。标注用 labelImg 或 X-AnyLabeling,存成 YOLO 格式:每张图对应一个 txt,每行class x_center y_center width height,全部归一化到 0~1。目录结构必须严格按下面来,否则训练脚本找不到文件:

datasets/ship/ ├── images/ │ ├── train/ # 训练图 │ └── val/ # 验证图 ├── labels/ │ ├── train/ # 对应 txt │ └── val/

然后写数据配置文件data/ship.yaml:

path: ../datasets/ship # 数据集根目录 train: images/train val: images/val nc: 6 # 类别数,按你的实际类别改 names: ['cargo', 'fishing', 'passenger', 'tug', 'sailboat', 'other']

这里有个高频坑:nc和names长度必须一致,且类别索引从 0 开始连续。如果标注时用了 1 起始的索引,训练时不会报错,但 mAP 会莫名其妙很低,这是血泪经验,转换脚本里一定要做一次校验。

3.3 用脚本做一次数据体检

正式训练前我习惯跑一个体检脚本,统计每类样本数、检查有没有越界坐标、有没有空标签:

import os, glob def check_dataset(label_dir, nc): cnt = [0] * nc bad = [] for f in glob.glob(os.path.join(label_dir, '*.txt')): with open(f) as fp: for i, line in enumerate(fp): parts = line.strip().split() if len(parts) != 5: bad.append((f, i, '字段数不对')); continue cid = int(parts[0]) vals = list(map(float, parts[1:])) if cid < 0 or cid >= nc: bad.append((f, i, f'类别越界 {cid}')); continue if any(v < 0 or v > 1 for v in vals): bad.append((f, i, '坐标未归一化')) cnt[cid] += 1 print('各类样本数:', cnt) print('问题条目:', bad[:10], '共', len(bad)) check_dataset('datasets/ship/labels/train', 6)

逻辑说明:逐行解析标签,检查字段数、类别范围、坐标范围三个最容易出错的点。参数nc要和 yaml 一致。如果某类样本数为 0 或者极少,训练时该类基本学不出来,要么补数据,要么用--weights做类别平衡采样。

4. 训练调参与指标验证:超参数怎么设才不玄学

4.1 超参数配置与命令行训练

「yolov5超参数」是另一个高频搜索点。YOLOv5 的超参在data/hyp.scratch.yaml里,船舶场景我一般改这几个:lr0初始学习率从 0.01 降到 0.005(数据量小容易震荡)、box回归权重从 0.05 提到 0.08(小目标定位要更准)、mosaic保持 1.0 但close_mosaic设 10(最后 10 个 epoch 关掉马赛克增强,让模型收敛到真实分布)。训练命令:

python train.py \ --weights yolov5s.pt \ --cfg models/yolov5s_se.yaml \ --data data/ship.yaml \ --hyp data/hyp.ship.yaml \ --epochs 200 \ --batch-size 16 \ --img-size 640 \ --device 0 \ --workers 8 \ --project runs/train --name ship_exp1

参数说明:--weights用官方预训练权重做迁移学习,比从头训快得多;--batch-size16 是 12G 显存下的稳妥值,显存不够就降到 8 并同步把lr0调小;--img-size640 是精度和速度的平衡点,小目标多可以试 960,但推理速度会掉一半;--workers是数据加载线程,设成 CPU 核数的 0.7 倍左右,设太大反而抢资源。

4.2 训练过程看什么指标

训练日志里重点盯三个:box_loss、obj_loss、mAP@0.5。box_loss不降说明回归有问题,检查标注框是否准确;obj_loss震荡说明正负样本分配不稳,可以调anchor_t;mAP@0.5是主指标,船舶场景一般能到 0.85 以上算可用。验证命令:

python val.py --weights runs/train/ship_exp1/weights/best.pt \ --data data/ship.yaml --img-size 640 --task val

如果验证集 mAP 比训练集低很多(超过 10 个点),是过拟合,加数据增强或加 dropout;如果两者都低,是欠拟合或标注问题,回到第 3 章体检。

4.3 消融实验怎么做才有说服力

改进类研究必须做消融,否则审稿人或评审会问「涨点是哪个模块带来的」。做法是固定其他条件,只改一个变量,跑四组:基线、加注意力、换损失、两者都加。每组至少跑两次取平均,因为深度学习训练本身有随机性。记录表格如下:

实验组骨干损失mAP@0.5FPS
baselineCSPDarknetCIOU0.84262
+SECSPDarknet+SECIOU0.86158
+EIOUCSPDarknetEIOU0.85362
全部CSPDarknet+SEEIOU0.87458

这张表能清楚看出每个改进的贡献和速度代价,比只报一个最终数字可信得多。

5. 部署与推理:从 PyTorch 到边缘设备

5.1 导出 ONNX 与 TensorRT

训练完的best.pt要部署,先导出:

# 导出 ONNX,opset 12 兼容性最好 python export.py --weights best.pt --include onnx --opset 12 --img-size 640 # 导出 TensorRT,需要装 tensorrt 并指定 fp16 加速 python export.py --weights best.pt --include engine --device 0 --half

参数说明:--opset 12是多数推理框架支持最广的版本,别盲目上 17;--half开启 FP16,速度能提 30% 以上,精度掉不到 1 个点,边缘设备首选。导出后务必用detect.py跑几张图对比 PyTorch 和 ONNX 的输出,确认没有精度损失。

5.2 后处理里的 NMS 调参

「yolov5后处理」在密集船只场景特别关键。默认 NMS 的iou_thres是 0.45,港口密集停靠时会把相邻船只框误删,可以提到 0.5~0.55;conf_thres默认 0.25,漏检多就降到 0.2,误检多就升到 0.3。这两个参数在detect.py里通过--conf-thres和--iou-thres传:

python detect.py --weights best.pt --source test_imgs/ \ --conf-thres 0.25 --iou-thres 0.5 --img-size 640

如果船只重叠严重,还可以考虑换成 Soft-NMS,但会牺牲速度,实时场景慎用。

5.3 边缘设备部署的注意点

在树莓派、Jetson 这类设备上部署,常见做法是先转 TensorRT engine 再用 C++ 或 Python 加载。注意三点:一是输入尺寸要和导出时一致,否则报维度错误;二是预处理(归一化、letterbox)必须和训练时完全一致,差一点精度就崩;三是显存/内存要留余量,Jetson Nano 跑 640 的 v5s 大概占 1.5G,超了就降 img-size 到 416。

6. 避坑与常见问题排查

6.1 训练 loss 变 NaN

现象:训练几个 epoch 后 loss 突然变成 nan,权重全废。原因:学习率太大或者某批数据里有异常值(坐标全 0 或全 1)。解决:先把lr0降到 0.001 重跑,同时用第 3 章的体检脚本过滤异常标注,确认数据干净后再逐步升学习率。

6.2 mAP 一直上不去

现象:训练 100 epoch,mAP@0.5 卡在 0.5 左右不动。原因:八成是类别索引不连续或标注框严重不准。解决:检查data.yaml的nc和names,用可视化脚本把标注框画到图上肉眼核对,船舶这种细长目标很容易标歪。

6.3 导出 ONNX 后推理结果和 PyTorch 不一致

现象:PyTorch 检测正常,ONNX 输出框全乱。原因:导出时 img-size 和推理时不一致,或者后处理里的 anchor 解码没对齐。解决:导出和推理统一用 640,并确认 ONNX 推理脚本用的是官方utils/general.py里的non_max_suppression,别自己手写解码。

6.4 显存溢出 OOM

现象:训练到一半报 CUDA out of memory。原因:batch-size 太大或 img-size 太大。解决:优先降 batch-size 到 8,还不行就降 img-size 到 512,同时开--cache ram会占更多内存,显存紧张时别开。

6.5 验证集指标虚高

现象:验证集 mAP 很高,实际部署效果差。原因:训练集和验证集来自同一段视频,帧间高度相似,等于变相泄漏。解决:按视频或按时间段划分数据集,别按帧随机分,这是最容易被忽略的坑。

7. 一个能落地的进阶技巧:用测试时增强换精度

如果项目对精度要求高、对速度没那么敏感(比如离线分析航道录像),可以开测试时增强(TTA)。YOLOv5 的val.py和detect.py都支持--augment参数,原理是对每张图做翻转、缩放等多种变换分别推理,再把结果融合。代价是推理时间涨 3~5 倍,但 mAP 通常能涨 1~3 个点,对小目标和遮挡目标尤其明显。

# 验证时开 TTA,对比不开的 mAP python val.py --weights best.pt --data data/ship.yaml --augment

我一般会先用 TTA 跑一遍验证集,如果涨点超过 2 个点,说明模型对几何变换还不够鲁棒,这时候与其上 TTA 硬扛,不如回头补数据增强(比如加随机旋转、透视变换)重训,把鲁棒性做进模型里,比推理时堆算力划算。TTA 更适合作为交付前的最后一道保险,而不是常规手段。

还有个细节:TTA 融合时不同变换的置信度尺度可能不一致,如果发现融合后框变多且乱,检查--augment是否和自定义后处理冲突,必要时只保留翻转这一种变换。

从那以后我每次交付船舶检测模型前,都会强制走一遍「数据体检 → 消融对照 → ONNX 精度对齐 → TTA 兜底」这四步,少一步都不敢上线。希望帮到你。

本文还有配套的精品资源,点击获取

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询