ARTICLE DETAIL

资讯详情

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

YOLOv13俯视舰船检测实战:小目标训练与部署避坑指南

YOLOv13俯视舰船检测实战:小目标训练与部署避坑指南 简介面向遥感与无人机俯视视角的舰船目标检测任务资源包整合了YOLOv13与YOLOv10两套训练好的模型权重、配套舰船数据集及完整Python训练/推理代码。数据集中图片与txt标签一一对应采用YOLO标注格式配置好PyTorch环境即可直接加载pt模型进行检测或继续训练适合需要快速落地舰船识别方案的算法工程师、研究生及竞赛选手。包体共2000个文件其中包含1059个txt标签、655个jpg图像、162个py脚本、84个yaml配置以及pt权重、C推理文件和说明文档压缩包整体约683.48MB目录结构清晰兼顾数据集、模型与代码三大模块。目前已有84人学习下载资源还附带遥感舰船检测参考结果与博客指引可帮助使用者快速验证效果。综合来看从数据标注、模型权重到推理部署均有覆盖尤其适合刚接触无人机或遥感场景目标检测的开发者作为起点项目。1. 俯视视角下的舰船检测为什么这个场景让 YOLO 系模型既好使又难缠俯视视角下的舰船目标检测是遥感与水上监管里最常被低估的一类任务。你拿到一个 YOLOv13 的训练工程里面有模型权重、有数据集看起来“直接就能用”但真正跑起来会发现同样的 YOLO 架构在马路上的车和俯视视角下的船表现完全是两回事。船在图像里往往只有几十个像素宽方向任意背景是水面纹理、码头设施、桥梁阴影的混叠加上太阳反光和波浪造成的假阳性能把一个在 COCO 上 mAP 50 多的模型打到惨不忍睹。这个标题里的项目组合——YOLOv13 俯视舰船检测 已训练模型 数据集——本质上是在解决一件事让目标检测在“小目标 任意朝向 复杂背景”的无人机/卫星俯视场景下依然能落地。适合的读者是正在做海事监管、港口安防、渔政巡逻或遥感解译的工程师手里有标注数据或正愁没有现成模型可用的团队。本文不吹嘘 YOLOv13 有多强而是把这个项目拆开从模型结构、数据集构成、训练参数到实际推理踩坑全部过一遍。2. 从 YOLOv10 到 YOLOv13俯视舰船检测的模型选型与结构差异2.1 YOLOv10 与 YOLOv13 的核心差异不止是版本号变大YOLOv10 是 Ultralytics 官方在 2024 年推出的版本最大的改动是去掉了 NMS非极大值抑制的后处理依赖提出了“无 NMS 训练”的机制。模型在训练时通过一致的双重分配策略让每个目标只对应一个正样本位置推理时直接输出最终预测结果省掉了 NMS 这一层耗时操作。而 YOLOv13 并不是 Ultralytics 官方版本号——官方主线到 v11 之后更多精力在架构搜索和多任务统一上v13 这个命名更多来自社区聚合版本或第三方增强工程常见做法是在 v11 的 C3k2 模块基础上引入更细粒度的注意力模块或可变形卷积针对小目标做了特征层融合的改良。做舰船检测选它核心理由是这类社区版在“小目标召回率”上往往做了专项优化比如增加 P2 输出层浅层高分辨率特征图来覆盖小目标。从实际结构上看v13 变体通常会在 Backbone 末端保留 SPPF 模块但在 Neck 部分把 PANet 的顶层特征和底层特征做额外的 cross-scale 连接让 8 倍下采样和 32 倍下采样的特征能够更充分融合这对俯视舰船检测至关重要。俯视图里的船宽度经常在 20 像素以内如果只用 16 倍以下的深层特征细节已经被卷积池化抹掉了。v13 这类社区版往往会把 P2 层从检测头里暴露出来代价是推理速度下降 10%-20%但换来的是小目标召回率提升。从选型角度说如果你的部署环境是嵌入式设备Jetson 或树莓派YOLOv10 的 NMS-free 结构更合适如果你有 GPU 服务器且更看重小目标精度v13 变体更值得试。2.2 锚框、标签分配与 DFL俯视舰船检测里三个被忽视的设置YOLOv10 和 v13 都继承了 v8 以来的 anchor-free 思路但这不意味着锚框完全退出讨论。在 DFLDistribution Focal Loss里模型输出的不是单一坐标偏移值而是一个离散分布通过 softmax 加权求和得到最终预测坐标。这对舰船这种长宽比极不稳定的目标从渔船到集装箱船宽高比可以从 1:1 到 1:5 甚至更高来说是个重要特性离散分布能表达更复杂的坐标分布形态对不同朝向的舰船有更好的适应力。实际训练中我会把 DFL 的损失权重设为默认的 0.5但把分类损失的权重从默认的 0.5 调高到 0.7因为俯视舰船检测的难点之一就是“船和码头上的集装箱、白色浪花”在特征上极其相似分类误差远大于定位误差。标签分配策略上YOLOv10 的 dual assignment 在 v13 社区版里通常被保留或改造。核心是先通过几何匹配选一组候选正样本再通过分类得分和 IoU 的加权选出最终正样本。这里一个容易被忽略的参数是simOTA或TAL的候选框数量默认情况下候选正样本数量是 13 个左右。对舰船数据集这个值建议适当减小到 9-10因为俯视舰船经常是密集停靠的一个锚点位置可能有 2-3 艘船重叠候选太多会导致标签分配的歧义模型训练时梯度互相拉扯表现为 loss 降不下去或检测框在密集区域抖动。我一般先可视化两次训练结果的标签分配图如果发现一个目标框被分配给好几个不同位置候选正样本数量就得往下调。2.3 训练好的模型文件里到底有什么权重文件的构成与适用边界这个标题里提到的“训练好的舰船目标检测模型”解压后通常包含几个 .pt 文件PyTorch 权重格式、一个 .yaml 配置文件、可能还有 .onnx 格式的导出模型。.pt文件里存的不只是权重数值还包括模型结构定义、类别名称列表、训练超参数记录和 opt 优化器状态如果未剔除。用torch.load打开后你会发现它本质是一个字典对象包含model、ema、updates、train_args等键。加载时有个坑如果训练时的 Python 环境和你现在的不一致比如训练时是 Python 3.10 PyTorch 2.1你现在是 Python 3.11 PyTorch 2.3直接torch.load可能报pickle.UnpicklingError最常见的解决方法是weights_onlyFalse参数或者用ultralytics.YOLO类的taskdetect参数强行加载。另一个关键点是训练好的模型并不等同于“开箱即用”。训练时的图像分辨率配比、类别定义、数据增强策略都会写进模型文件里。如果你的业务场景是 640x640 输入而训练时用的是 1280x1280那么模型在小分辨率下的表现会明显劣化不是因为模型变笨了而是因为输入尺寸变化导致的感受野覆盖范围不同。建议直接用模型自带的imgsz参数推理或者重新用model.val()在不同分辨率下跑一遍验证集画一条“分辨率 vs. mAP”曲线再决定部署尺寸。这也是我认为“训练好的模型”最常见的翻车点不是模型有问题是使用姿势有问题。3. 舰船目标检测数据集构成、格式与预处理细节3.1 一个能用的舰船数据集长什么样图像来源、类别设计与标注质量这个项目里附带的数据集从命名看是专门为俯视舰船检测收集整理的。常见的舰船检测数据集合类别包括货船cargo、渔船fishing、集装箱船container、客船passenger、驳船barge、拖船tug等有的还会加入“码头船只”“其他船舶”作为背景类别。类别数量建议控制在 4-8 类之间。超过 10 类会带来一个现实问题俯视视角下部分类别之间差异极小——比如拖船和渔船在 50 米高度向下看几乎没区别强行细分只会让模型在同一目标上反复横跳训练出来的模型预测结果在两类之间频繁抖动。数据集的图像来源一般有三类无人机航拍、卫星遥感影像、港口摄像头截图。这三类来源在标注时的难度差异很大。无人机航拍图像通常有 4K 分辨率舰船目标在原始分辨率下比较清晰但缩放到 640x640 训练尺寸后很多小船只有 10 像素左右这时需要做滑窗裁剪策略——把原始大图切成 640x640 或 1024x1024 的 patch每个 patch 有 20%-30% 的重叠率确保目标不会正好被切在边界上。我处理这类数据时习惯用sahi库的切片推理配合训练数据制作可以在不损失原图分辨率的前提下把目标有效尺寸放大一倍以上。3.2 数据集目录结构与标签格式VOC、COCO 还是 YOLO 格式拿到手的数据集第一步是确定标签格式。YOLO 系列的格式是每个图像对应一个 .txt 文件每行内容为class_id x_center y_center width height所有坐标都归一化到 0-1 之间。这个项目如果是从遥感社区转发来的很可能是 COCO 格式一个大的 annotations.json或 VOC 格式XML 文件需要先做一次转换。转换的核心逻辑是读取原始标注坐标按图像宽高做归一化然后写到 txt 文件里。需要注意的是YOLO 格式里宽高是绝对值除以图像宽高而 COCO 格式里的 bbox 是[x_min, y_min, width, height]像素值。很多人在这一步把 COCO 的x_min, y_min当成中心点坐标直接除以图像尺寸结果所有标注框都跑到左上角去了。目录结构的常见做法如下dataset/ ├── images/ │ ├── train/ │ ├── val/ │ └── test/ ├── labels/ │ ├── train/ │ ├── val/ │ └── test/ ├── data.yaml └── classes.txtdata.yaml的写法中有一个常见坑path字段如果写相对路径换一台机器或者换个工作目录就会失效模型训练时直接报Dataset not found。我一般建议用绝对路径写path字段或者在代码里把path参数拼成完整路径再传给model.train()。classes.txt里的类别顺序必须和标签文件里的class_id一一对应如果项目数据集里已经标注过就不要随意打乱顺序否则模型会学会把一个类别预测成另一个类别——这种情况在验证集上跑出来 mAP 还很高因为验证集的标签也被你一起改了顺序属于典型的自欺欺人式评估。3.3 数据增强策略俯视舰船场景下的增强参数与自适应方法训练舰船检测模型增强策略和通用目标检测有显著差异。俯视视角下舰船没有“上下左右”的语义概念——船头朝哪个方向都不影响它是船所以 Mosaic、MixUp 这类增强对舰船场景有天然的适配性。建议开启degrees180全角度旋转因为舰船朝向是完全随机的不旋转等于人为制造数据偏差。flipud0.5和fliplr0.5可以同时开启水平翻转和垂直翻转对船来说都是合法的视角变化。但有一个增强参数需要特别小心shear和perspective。这两个增强会在图像中引入仿射形变对道路场景的目标影响不大但对舰船这种几何结构相对刚性的目标过大的 shear 会让船体扭曲变形模型学会的是“扭曲的船”而不是“任何角度的船”。我一般把shear控制在 0-5 度以内perspective控制在 0.0001 以下。另一个值得调的是scale它负责控制图像缩放范围对小目标场景建议从默认的 0.5 降到 0.3-0.4避免过度缩小导致目标几乎消失也避免放大后目标撑满整个画面导致上下文丢失。增强参数中还有一个容易被忽略的mosaic概率。YOLOv10 和 v13 社区版默认 mosaic 为 1.0即所有 epoch 都启用。但实战经验表明当训练到最后 20%-30% 的 epoch 时应该把 mosaic 关闭或降为 0.1-0.2。原因是 mosaic 拼接出来的图像在边缘处存在强烈的人工痕迹模型会在后期开始记忆这些痕迹而不是真实特征。Ultralytics 的代码里有一个自动关闭机制在最后 10 个 epoch 自动调低但如果你用的社区版没有这个设置就需要手动适配。我会在每个 epoch 结束后打印增强参数的实际值确认 mosaic 是否已经降低。3.4 训练集与验证集划分不要随机切分按场景和来源划分舰船检测数据集的划分比通用数据集更讲究。如果同一艘船在同一片水域出现在多个视频帧里随机划分会导致验证集里出现训练集中几乎相同的图像——光照、视角、船只位置都几乎一样验证集 mAP 虚高到 95% 以上。我做过一个反例用随机划分训练出来的模型在评估时 mAP 92%一出实验室换到另一个港口的视频里mAP 直接掉到 40% 左右。原因就是训练集和验证集“过度同源”。更合理的做法是按采集时段、地理区域或视频片段划分。比如你有 10 段无人机视频可以按 8:2 划分确保同一段视频的帧要么全部在训练集要么全部在验证集。这样验证集能真实反映模型的泛化能力。另一个方法是用聚类算法按图像特征色彩直方图、纹理谱先分组再从各个簇里抽少量图像进验证集能有效避免“同场景冗余”。这个做法在数据量不足 5000 张时尤其重要数据越少随机切分的风险越大因为验证集里可能只有几十张图一旦有几张和训练集高度相似指标就失真了。4. 用 YOLOv13 训练舰船检测模型全流程命令与参数调优4.1 环境准备与依赖安装一个能跑通训练的最小环境训练 YOLOv13 这类社区版本首先要确认依赖版本。Ultralytics 官方库的依赖要求是 PyTorch 1.8但我实际接触到 v13 社区版时通常要求 PyTorch 2.0、torchvision 0.15且需要ultralytics包版本不低于某个内部版本比如 8.1.x。安装时最稳妥的方式是新建一个独立的 conda 环境避免和系统的 PyTorch 环境冲突conda create -n yolov13 python3.10 -y conda activate yolov13 pip install torch2.1.2 torchvision0.16.2 --index-url https://download.pytorch.org/whl/cu118 pip install ultralytics8.1.34 pip install opencv-python tqdm matplotlib seaborn这里的版本组合是我在 NVIDIA RTX 3090 / 4090 上验证过的PyTorch 2.1.2 配合 CUDA 11.8训练速度比 PyTorch 2.3 CUDA 12.1 约快 5%-8%v13 社区版的前向传播里包含较多自定义 CUDA kernel不同 CUDA 版本的算子融合效率差异明显。如果你用的是 RTX 20 系显卡CUDA 版本建议降低到 11.7 或 11.8如果是 RTX 40 系以上12.1 也可以但实际体验差别不大。安装完成后用一个最小的推理测试确认环境可用python -c from ultralytics import YOLO; model YOLO(yolov10n.pt); results model.predict(https://ultralytics.com/images/bus.jpg, imgsz640); print(results[0].boxes.xyxy.cpu().numpy())如果这条命令能输出检测框坐标说明环境基本正常。如果报错提到DLL load failed或libcublas说明 CUDA 和 PyTorch 的匹配有问题重新按对应版本安装即可。这类问题 80% 都出在 torch 和 torchvision 版本不匹配上不要急着卸载重装整个环境先用pip check确认依赖关系。4.2 训练命令从预训练权重到自定义数据集的正确打开方式拿到项目里的模型权重后要知道它是在什么数据上训练的。如果它本身就是在舰船数据上训练的你可以直接用这个权重做继续训练fine-tune训练命令如下yolo detect train \ data/path/to/dataset/data.yaml \ model/path/to/pretrained/ship_best.pt \ epochs100 \ imgsz640 \ batch16 \ device0 \ patience15 \ optimizerAdamW \ lr00.001 \ lrf0.01 \ mosaic0.8 \ degrees180 \ flipud0.5 \ fliplr0.5 \ scale0.35 \ shear0.5 \ perspective0.0001 \ project./runs/ship_det \ nameexp1这段命令的每个参数都有实际意义。patience15是早停机制如果验证集 mAP 连续 15 个 epoch 没有提升就自动停止可以帮你节省大量时间optimizerAdamW是舰船检测中比 SGD 更稳的选择在数据集偏小几千张时AdamW 对学习率的敏感度比 SGD 低更适合直接跑lr00.001是初始学习率如果是从零开始训练没有预训练权重建议改为 0.01如果是在已有舰船模型上继续训练0.001 是安全值过大容易把已学好的低层特征破坏。lrf0.01是最终学习率系数表示最终学习率衰减到初始值的 1%。scale0.35前面说过是控制图像随机缩放范围的对舰船小目标场景有重要作用。很多人会用默认的 0.5但如果不配合 mosaic 增强0.5 的缩放范围会让大量目标缩到 5 像素以下模型根本学不到有效特征。degrees180全角度旋转在小目标场景下有一个副作用旋转会引入插值噪声对像素级细节损失较大。一个折中的做法是前 50 个 epoch 用degrees180后 50 个 epoch 降为degrees45让模型在后期集中精修学习到的特征。Ultralytics 不支持训练中途动态改增强参数但你可以用model.train(degrees45)在第二个阶段单独启动训练并加载前一阶段权重。4.3 训练过程中的日志解读loss 曲线、mAP 曲线和类别指标的读法训练开始后终端输出的日志包含许多关键指标。train/box_loss是定位损失train/cls_loss是分类损失train/dfl_loss是 DFL 损失metrics/precision(B)和metrics/recall(B)是验证集的精确率和召回率metrics/mAP50(B)是 IoU 阈值 0.5 时的 mAPmetrics/mAP50-95(B)是 0.5 到 0.95 范围内多个 IoU 阈值的平均 mAP。对舰船检测我主要盯三个指标metrics/recall(B)、mAP50和mAP50-95。俯视舰船检测的失败模式经常是召回率低而不是精确率低——也就是说模型预测出来的框基本都是对的但很多船根本没被检测出来。如果你的训练日志里recall(B)在 60% 以下说明小目标被漏检了。这时的调整手段按优先级排列一是增大imgsz从 640 到 960 或 1280小目标的特征在更高分辨率下会更清晰二是检查增强参数里的scale过大的缩放范围会让训练数据中的目标过小三是检查模型是否开启了 P2 层如果用的是 YOLOv10 官方权重它默认没有 P2 输出层需要在模型定义里修改detect模块的ch参数。训练日志里如果出现nan或inf的 loss 值不要犹豫直接停掉训练。这个问题的原因通常有三个学习率过高、数据集里有损坏的标签比如坐标值超出 0-1 范围、GPU 显存溢出导致的数值异常。先跑一段数据检查脚本import cv2, os, numpy as np img_dir dataset/images/train label_dir dataset/labels/train for f in os.listdir(label_dir): label_path os.path.join(label_dir, f) with open(label_path, r) as fp: lines fp.readlines() for line in lines: parts line.strip().split() if len(parts) ! 5: print(fInvalid line in {f}: {line}) continue cls, x, y, w, h parts x, y, w, h float(x), float(y), float(w), float(h) if x 0 or x 1 or y 0 or y 1 or w 0 or w 1 or h 0 or h 1: print(fCoordinate out of range in {f}: {line}) break这段脚本遍历所有标签文件检查每行是否只有 5 个值、坐标是否在 0-1 范围内。如果输出为空说明标签基本没有格式问题。如果输出有越界坐标找到对应图像用可视化脚本绘制边界框确认是标注错误还是转换脚本的问题。4.4 用训练好的模型做推理验证置信度阈值与 NMS 参数的校正训练完成后推理和验证是两回事。验证用的是model.val()里内置的置信度阈值和 IoU 阈值但推理时这些阈值是可以手动调整的。舰船检测场景下我一般会把置信度阈值调低到 0.15-0.25因为小目标在低分辨率下的置信度天然偏小过高的阈值会把模型辛苦学到的能力全部过滤掉。这个调整在代码里是from ultralytics import YOLO model YOLO(runs/ship_det/exp1/weights/best.pt) results model.predict( sourcetest_images/, conf0.2, iou0.45, imgsz640, saveTrue, save_txtTrue, save_confTrue )iou0.45是 NMS 的 IoU 阈值舰船密集停靠场景下建议调低到 0.3-0.35否则两个靠得很近的船会被合并成一个检测框。如果你发现两个目标检测框重复率很高频繁出现一个船被框两次的情况把iou提高如果发现一个区域多个船只出了一个框把iou降低。这个参数是舰船检测里最需要反复试的因为它直接受目标密集程度影响。渔港里十几条船靠在一起和开阔海面上一条船最优的 IoU 阈值相差很大。更精细的做法是在验证集上跑一次阈值扫描在 0.1 到 0.9 之间每次按 0.05 的步长调整置信度阈值计算每个阈值下的精确率和召回率选一个两者相交或根据业务权重决定的阈值。4.5 低显存环境下的训练模型并行、梯度累积与 AMP 混合精度很多做舰船检测的团队没有 24G 显存的显卡常见的 8G 或 12G 显存跑一套 YOLOv13 训练batch size 会非常受限。这时有两条路线梯度累积和 AMP 混合精度。batch16但显存只能放 4 张图时可以设置batch4配合accumulate4效果等价于 batch size 16每 4 个 batch 叠加一次梯度再更新权重。Ultralytics 的accumulate参数直接支持这个写法不需要改代码。AMP 混合精度是默认开启的但我遇到过个别社区版在 AMP 下前面若干 epoch 正常、第 20 个 epoch 开始 loss 变成 nan 的情况原因是某些自定义模块的 fp16 数值稳定性不好。解决办法是在训练命令中加ampFalse代价是训练速度降低 15%-25%但能避免训练中途翻车。如果你必须用 AMP可以尝试把linear_lam或gamma参数调大来增加数值稳定性。如果连 8G 显存都没有可以尝试用 YOLOv10n 或 YOLOv10s 代替 v13 训练。v13 社区版通常为了小目标精度牺牲了计算效率在 6G 显存下基本跑不动 640x640 以上的分辨率。YOLOv10n 的参数量只有 2.3M 左右在同样显存下能训练更大的 batch。等模型收敛后再拿这个结果作为预训练权重转训到 v13 上相当于用两阶段方式完成迁移。这种方法在小目标场景下实际效果不错因为第一阶段的低精度模型已经学到了舰船的基本形状特征第二阶段只需要在更高分辨率下做 refine。5. 舰船检测模型落地的避坑指南从训练到部署的 4 个高频踩坑点5.1 坑一模型对自己的训练数据效果好换一批相似图像立刻翻车现象用自己的验证集评估mAP50 达到 90% 以上但换上另一个港口或另一种天气的无人机图像检测框开始乱飘漏检率暴增。原因数据分布过窄。训练集里如果只有晴天、正午、单一水域的图像模型会把“水面纹理 光照条件”作为特征的一部分记忆下来。俯视场景下同一艘船在强光和水面反光条件下的特征变化远大于在自然光道路场景下的特征变化。解决第一在数据收集阶段刻意覆盖多时段清晨、正午、黄昏和多天气阴天、雨天、雾天的图像哪怕每种只有几百张也比同一时段几千张有效得多。第二训练时把hsv_h、hsv_s、hsv_v三个颜色增强参数调大默认值是 0.015、0.7、0.4建议调大到 0.05、0.9、0.7增强模型对色偏和光照变化的鲁棒性。第三用随机光照扰动模拟不同光照条件——在数据加载器里对图像做随机的 gamma 变换和亮度偏移这个在 Ultralytics 里可以通过augmentTrue对外开放的hsv_v参数实现。5.2 坑二重叠舰船在 NMS 阶段被错误合并导致漏检现象船只在港口密集停靠时两条船首尾相碰检测结果只剩一个框目标计数明显低于实际数量。原因NMS 的 IoU 阈值过高默认 0.45-0.5相邻舰船的检测框 IoU 超过了阈值被认为是一个目标的重复检测于是被合并掉。解决推理时将iou阈值降到 0.3 或更低。同时训练阶段做 Mosaic 增强时拼接边界容易产生不连续的船体形态——如果模型在训练时见过大量被拼接边界切开的船它学到的框可能会倾向于覆盖“部分船体”这会导致推理时相邻船的框大面积重叠。验证这一步的有效方法是画出来一张密集停靠的推理结果图逐个检查低 IoU 阈值下是否有同一目标被重复框选——如果有说明模型本身存在双框倾向而不是 NMS 的问题。5.3 坑三类别不均衡导致小类别训练不收敛模型只预测“货船”类现象训练 50 个 epoch 后验证时所有目标都被预测为某个大类其他类别精确率为 0。原因数据集里 5 个类别货船占 6000 个标注框渔船只有 300 个标注框。默认的采样方式会让模型在梯度更新时被大类主导小类的梯度过小权重更新方向基本由大类决定。解决最简单的调整是使用v10或v13里自带的class_weights参数按类别数量的倒数给每个类别设置损失权重。Ultralytics 的model.train()支持传入class_weights列表例如class_weights[1.0, 3.5, 2.0, ...]。但这种方式不能完全解决问题更根本的调整是数据层面的对小类别做过采样复制小类别样本参与训练。实际做法是对包含小类别的图像做 1-2 次重复并把增强参数调大旋转、翻转、色彩抖动让模型看到更多小类别的变化形式。如果这两招都用了还是不收敛检查类别定义是否合理——比如渔船和拖船在俯视下是否真的可分如果人工也很难区分把类别合并是一个坦诚的选择。5.4 坑四训练过程中显存溢出OOM程序直接崩溃现象训练日志在某个 epoch 开始时中断终端报CUDA out of memory。原因除了 batch size 过大外还有一个常见原因是 Mosaic 增强。Mosaic 会在每张合成图中加载 4 张原始图像显存瞬时占用是正常情况的 4 倍。如果你在训练中开启 mosaic 后 OOM而不开 mosaic 就正常说明是 Mosaic 加载的内存峰值导致溢出。解决方案一把batch减半同时对mosaic使用close_mosaic参数让最后 10 个 epoch 自动关闭 mosaic——这能避开后期的 OOM 风险方案二开启cacheTrue参数Ultralytics 会预先把训练图像缓存为内存中的张量可以减少数据加载时的显存反复分配方案三把rectTrue打开让训练时填充到相同尺寸的空白区域最小化减少显存浪费。这三种做法中rectTrue对舰船检测有额外好处不是所有输入都被拉伸成正方形船只的宽高比信息被更好地保留下来。5.5 属于这个场景的避坑清单从标签、增强到评估指标的 5 条清单上面四个坑是高频症状还有一些低频但同样要命的点值得列成一个清单方便你在训练前快速排查第一标注框的坐标必须是目标的最小外接矩形还是水平外接框YOLO 系输出的是水平框axis-aligned bounding box这决定了倾斜舰船的标注质量会直接受限。如果业务要求检测结果带朝向角比如 AIS 系统匹配需要航向YOLO 系模型不适合建议转向带旋转框检测的 YOLOv8-OBB 或 Oriented R-CNN。第二不要迷信 mAP50舰船检测的最终价值是“能否支持下游决策”如果检测结果要输入给计数模块或 AIS 匹配模块mAP50-95 的参考意义更大因为它对定位精度更敏感——坐标偏差一点点就会拉低分数。第三训练前检查所有标注框的最小面积如果大量标注框小于 5 像素这部分样本对模型的贡献几乎为零考虑把它们从训练数据中剔除或者用数据增强把它们放大后再加入数据集。第四夜间或红外图像不要直接扔进去和可见光图像混训模型会在可见光图像上学到“天空泛白、水面深灰”的纹理特征红外图像的低像素密度和不同纹理会扰乱训练过程建议单独训一个红外分支模型或者至少关闭 RGB 色彩相关的增强hsv_h0。第五训练好的模型在部署前必须做一次 ONNX 导出和数值对比测试确认导出前后输出一致否则 TensorRT 加速里出现的“检测精度下降”会被误以为是模型问题但其实只是量化精度损失——这里需要一个简单的容差基准导出前后同一批测试图的 mAP 差异不能超过 0.5%。6. 从训练到上线的最后一公里模型导出、TensorRT 加速与效果验证训练收敛只是工作的一半另一半是把模型送进目标环境并让它稳定工作。如果你的部署环境是 NVIDIA 嵌入式设备Jetson Orin、Jetson Xavier或服务器 GPUTensorRT 加速是必经之路。YOLOv13 这类社区版的 PT 权重不能直接扔进 TensorRT需要先导出 ONNX 再转引擎。导出时要注意一个细节opset版本不能太高也不能太低TensorRT 8.x 对 opset 12-14 的兼容性最好opset 17 之后的部分算子比如MulticlassNMS在 TensorRT 里支持不完整容易出现“能导出但不能运行”的尴尬情况。我的标准流程是yolo export modelruns/ship_det/exp1/weights/best.pt formatonnx opset13 simplifyTrue trtexec --onnxbest.onnx --saveEnginebest_fp16.engine --fp16 --workspace2048trtexec是 TensorRT 自带的命令行工具。--fp16开启半精度推理舰船检测场景下精度损失通常在 0.3%-0.5% 以内速度提升却可观在 Jetson Orin Nano 上YOLOv10s 的 FP16 推理速度约为 25ms/帧FP32 下约 40ms/帧。如果你在无人机平台上部署帧率从几个 FPS 提升到超过 20 FPS意味着检测系统从“不可用”变成“可用”。但这里有个关键步骤导出后必须做精度对比验证。我习惯写一个简单的 Python 脚本用同一个测试集分别跑 PT 模型和 ONNX/TensorRT 模型计算二者的 mAP 差异from ultralytics import YOLO import numpy as np pt_model YOLO(runs/ship_det/exp1/weights/best.pt) rt_model YOLO(runs/ship_det/exp1/weights/best.engine) # TensorRT engine test_images [test1.jpg, test2.jpg, test3.jpg] for img_path in test_images: r1 pt_model.predict(img_path, conf0.2, iou0.35, imgsz640)[0] r2 rt_model.predict(img_path, conf0.2, iou0.35, imgsz640)[0] boxes1 r1.boxes.xyxy.cpu().numpy() boxes2 r2.boxes.xyxy.cpu().numpy() print(f{img_path}: PT{len(boxes1)} boxes, TensorRT{len(boxes2)} boxes) if len(boxes1) and len(boxes2): iou compute_iou(boxes1, boxes2) if iou 0.9: print(f Warning: IoU{iou:.3f}, check quantization impact)compute_iou是自己实现的一个函数计算两组框的交互比。如果 TensorRT 模型和 PT 模型在同一张图上检测结果差异很大优先检查两个点一是 ONNX 导出时的simplifyTrue是否会改变计算图结构某些社区版在简化后会移除看似多余的节点但实际影响输出二是 TensorRT 引擎的 FP16 精度是否对某些层有数值扰动建议把--fp16换成--noTF16或--best试一次对比结果。验证的下一步是把检测结果接进业务系统。舰船检测的下游应用常见有三种一是目标计数渔业监管需要统计渔港内渔船数量二是目标跟踪检测结果 ByteTrack 或 DeepSORT 做轨迹分析三是视频结构化把检测结果连同时间戳、地理位置存库供事后检索。这三种应用的接口形式都是把检测框、置信度和类别序列化后传给下游模块。我建议在模型输出层和业务逻辑之间加一层适配器统一输出格式。不管模型内部是 YOLOv10 的 NMS-free 输出还是 YOLOv13 的 NMS 输出适配器都输出[x1, y1, x2, y2, score, class_id]的列表这样以后替换模型或升级架构业务代码完全不需要改动。最后分享一个我的习惯每次做完一个舰船检测项目我都会把测试集里“模型预测得特别离谱”的图像单独保存到一个文件夹里叫hard_cases/。每次训练的新版本模型我都会用这些 hard cases 做回归测试。这个方法比看 mAP 曲线更直接——因为 mAP 是一个平均值它掩盖了某些极端场景的系统性失败。如果新版本模型在 hard cases 上表现更差我宁愿不要那个更高的 mAP因为我知道真实部署场景里出现 hard cases 的概率远比验证集里更高。这也是我对所有“训练好的模型”最深的体会模型只是工具如何验证它、理解它的边界、并在边界处做兜底才是工程落地的关键。希望这些经验能帮你少走一些弯路。本文还有配套的精品资源点击获取
返回列表