恒美微站 Logo 恒美微站
  • 首页
  • 关于我们
  • 建站服务
  • 主题模板
  • 案例展示
  • 资讯中心
  • 联系我们

船只检测数据集实战:3100张图如何训练出可用的YOLOv8模型

  • 首页
  • 资讯中心
  • /
  • 船只检测数据集实战:3100张图如何训练出可用的YOLOv8模型

相关资讯

打印审计必备:从SPOOL文件解析SHD与SPL还原打印记录 2026/10/11 22:28:31
基于SSM的电影院订票系统前后台开发实战与避坑指南 2026/10/11 22:28:31
vllm-metal TurboQuant 实战:KV 缓存压缩 2.5 倍扩展上下文的原理与配置 2026/10/11 22:28:31

最新资讯

基于随机森林的血小板库存优化:从需求预测到FIFO模拟的完整复现
CLRC663缺货替代实践:NFC读卡器Pin-to-Pin迁移全记录
集成测试实战:从接口对齐到异常注入的完整验证指南
【解决方案】cmd 能激活 conda 环境,但 VS Code 或 Cursor 不行:把 settings 改到 TaoToken 的排查路径
NPDP全真模拟题解析:七大知识领域与三轮刷题备考策略
碳化硅电源适配器EMC优化:从干扰定位到整改实战

今日推荐

Debian新手入门:从部署到日常操作的完整指南
MongoDB复制集扩缩容实战:从rs.add到选主事故复盘
条形码目标检测数据集实战:从YOLOv8训练到部署

本周热门

UE动画修改实战:从资产编辑到重定向与蒙太奇驱动
统计随机数生成器攻击下的KLJN安全密钥交换协议Matlab仿真
政务API安全治理:资产测绘、低代码编排与行标对标实践

本月精选

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证
2026 大模型集体涨价:用 Python 做企业 Token 成本测算与选型避坑(附配置)

船只检测数据集实战:3100张图如何训练出可用的YOLOv8模型

发布时间:2026/10/11 22:33:31
船只检测数据集实战:3100张图如何训练出可用的YOLOv8模型 简介为便于目标检测算法训练而构建的船只检测数据集从COCO2017原始标注中提取共含3146张真实场景船只图片及对应标签。图片均配套txt与xml两类标注文件前者适配YOLO系列直接训练后者可在LabelImg等工具中校验复核目标类别统一为boat适合舰船识别、港口监控、水上交通管理等方向的开发者和研究者直接复用。压缩包体积约505.62MB解压后包括3146个jpg图像、3146个txt标签和3147个xml标签文件数量近万编号一一对应无需额外格式转换即可接入常见目标检测框架。目前已有560人学习/下载这批数据可快速支撑YOLO训练与评估流程也适合用于课程设计、毕业设计或早期算法验证图片源自COCO2017船舶大小、角度与背景存在差异可帮助检验模型在不同场景下的检测效果。整体来看双格式标签降低了不同工具间的迁移成本也适合作为船类目标检测入门与算法对比实验的基准数据。1. 船只检测数据集3100张从数据到手离真实水面还有多远做船只检测最怕的不是模型不够深而是数据不像船。水面反光、船体晃动、目标忽远忽近3100张的数据量刚好卡在“够起步、不够躺赢”的位置能微调出能看的模型但离直接部署还差一条完整链路。这类数据集按检测规范标注场景覆盖港口近景、航道中景和远海小目标类别多为货船、渔船、小艇、客船。适合水面监控开发者、船舶识别方向学生以及想搞清水上检测与道路检测差异的从业者。拿到一个船只检测数据集很多人第一件事就是开训结果在验证集上mAP不错一到视频里就露馅。下面这套路线从数据统计开始到训练参数再到一组边界验证方法基本能把“3100张数据”真正吃透。2. 3100张里的大海数据构成、标注格式与选型逻辑2.1 数据构成类别占比、场景拆解与目标大小分布先把数据当成黑匣子打开。3100张图听起来不多但如果一半是空无一物的水面另一半是密集停靠的港口训练出来的模型会非常偏。常见做法是写一个统计脚本先看三个数每张图的目标数量、类别分布、目标框相对原图的面积档位。这三项决定了后续增强策略和训练超参怎么给。一个简单的统计脚本可以这么写假设标注已经是YOLO格式的txtimport glob import os from collections import Counter label_dir dataset/labels/train img_dir dataset/images/train stats { images: 0, objects: 0, empty_images: 0, cls_counter: Counter(), size_bins: {small: 0, medium: 0, large: 0}, } for label_path in glob.glob(os.path.join(label_dir, *.txt)): with open(label_path) as f: boxes [line.strip() for line in f if line.strip()] stats[images] 1 if not boxes: stats[empty_images] 1 else: for line in boxes: parts line.split() cls_id parts[0] x, y, w, h map(float, parts[1:]) stats[objects] 1 stats[cls_counter][cls_id] 1 if w 0.2 and h 0.2: stats[size_bins][small] 1 elif w 0.5 and h 0.5: stats[size_bins][medium] 1 else: stats[size_bins][large] 1 print(stats)这段脚本的逻辑是先把每个txt里的目标行读出来再按类别和尺寸各归入一个桶。注意这里没有校验图片是否存在实际用的时候要加一个os.path.exists不然漏删了一个txt统计结果会带着幻觉跑。尺寸档位的划分没有统一标准我这里用的是相对归一化坐标下的比例w 0.2 and h 0.2基本对应远海小目标货船这类大目标会进large档。统计结果能直接告诉你两件事如果小目标占比不到10%那训练时必须开mosaic增强和更大输入分辨率如果空图特别多验证集里要保留一部分空图否则模型会变成“见水就报船”。还有一个隐藏信息是图片总数和框总数的比例3100张图如果只有3500个框平均每张1.1个目标训练时会频繁遇到重复背景这时候copy-paste增强会比单纯翻转更有效。2.2 标注格式换算VOC、YOLO与COCO的取舍多数船只检测数据的原始标注来自标注平台平台导出格式五花八门最常见的是VOC XML和YOLO txt部分项目给的是COCO JSON。选型原则很简单用yolo命令行训练就统一到YOLO格式用MMDetection或Detectron2则转成COCO。不要脑子里同时维护两套格式转换脚本地一定要保留数据更新后重新跑一遍就行。VOC转YOLO是我最常写的脚本。核心点是坐标归一化、越界裁剪、空目标跳过。还有一个隐蔽坑有些标注里xmax小于xmin这种框必须丢掉不然训练时损失会变成NaN。脚本可以这样写import xml.etree.ElementTree as ET def voc_to_yolo(xml_path, out_txt, class_map): tree ET.parse(xml_path) root tree.getroot() size root.find(size) img_w int(size.find(width).text) img_h int(size.find(height).text) lines [] for obj in root.iter(object): name obj.find(name).text if name not in class_map: raise KeyError(f未知类别: {name}) bndbox obj.find(bndbox) x1 float(bndbox.find(xmin).text) y1 float(bndbox.find(ymin).text) x2 float(bndbox.find(xmax).text) y2 float(bndbox.find(ymax).text) x1 max(0, min(x1, img_w - 1)) y1 max(0, min(y1, img_h - 1)) x2 max(1, min(x2, img_w)) y2 max(1, min(y2, img_h)) if x2 x1 or y2 y1: continue cx (x1 x2) / 2 / img_w cy (y1 y2) / 2 / img_h w (x2 - x1) / img_w h (y2 - y1) / img_h lines.append(f{class_map[name]} {cx:.6f} {cy:.6f} {w:.6f} {h:.6f}) with open(out_txt, w) as f: f.write(\n.join(lines))转换脚本里最值得记住的是那行越界裁剪。船只在航道监控里经常被画面边缘切掉一半如果标注框的坐标超出了图像尺寸YOLO在训练计算损失时会把框中心算出图像外轻则loss异常重则收敛失败。另外class_map必须单独维护一个字典比如把中文类别名或英文别名映射成从0开始的id一旦训练中途改了映射关系前面跑的所有实验都白费了。这类数据的类别一般不多3到5类顶天手动维护成本很低。COCO转YOLO时要注意COCO的坐标是左上角加宽高YOLO需要的是中心点加宽高转换公式正好反过来。这个步骤没有难度纯体力活但建议转换后做一次目视抽查把标注框画回图上确认没有整体偏移。我一般每转换一桶数据就抽50张看图肉眼扫一遍能发现脚本里不易察觉的坐标错位。2.3 数据增强策略海上场景为什么不能无脑翻转数据增强是3100张数据能不能打的关键但海上场景的增强不能照搬道路检测那套。原因很实在侧视拍摄的船有明确的“水面上下”语义船不可能出现在天上上下翻转产生的样本会让模型学出“倒着的船也能检测”的错误认知。俯视航拍数据则相反旋转90度是真实存在的物理状态翻转带来的副作用就小很多。所以拿到数据第一步要确认拍摄视角。以港口监控为代表的侧视数据我一般只开水平翻转上下翻转直接设成0。亮度对比度扰动可以加大水面反光时常让船身和背景亮度接近需要模型对亮度变化不敏感。hsv_h、hsv_s、hsv_v三个参数对应色调、饱和度、亮度扰动船只检测里饱和度扰动可以给到0.5以上因为真实监控里不同颜色船身很常见。一份适合侧视船检的增强配置可以参考hsv_h: 0.015 hsv_s: 0.6 hsv_v: 0.4 degrees: 0.0 translate: 0.1 scale: 0.4 shear: 0.0 perspective: 0.0001 flipud: 0.0 fliplr: 0.5 mosaic: 0.8 mixup: 0.1这里最关键的是flipud: 0.0和mosaic: 0.8。mosaic把四张图拼成一张相当于变相增大batch size对小目标检测的提升非常明显代价是训练时显存占用更高。3100张数据量不算大mixup开到0.1到0.2就够开太大会让模型学到船身和背景的“残影”反向拉低精度。另外多的语义我建议脱离开默认参数看实际效果不要照抄。3. 用YOLOv8在本地跑通船只检测最小训练方案3.1 训练前的目录结构与数据划分防泄漏是关键yolo命令行工具对数据目录有固定要求最好按这个结构组织dataset_split/ ├── images/ │ ├── train/ │ ├── val/ │ └── test/ └── labels/ ├── train/ └── val/很多人图省事直接把所有图片放一个目录训练时用train: dataset/images指定这样yolo会按比例自动切分但有一个风险如果你的数据来自连续视频帧自动切分会把同一段视频里的相邻帧同时分进train和val造成数据泄漏。验证集mAP会虚高真实场景一测就崩。我一般会先按“视频片段号”或“拍摄批次”分组再划分。伪代码逻辑是这样的import os, random, shutil random.seed(42) src_imgs dataset/images src_labels dataset/labels out_root dataset_split # 按文件名前缀分组 groups {} for f in os.listdir(src_imgs): prefix f.split(_)[0] # 例如 video1_0001.jpg - video1 groups.setdefault(prefix, []).append(f) group_names list(groups.keys()) random.shuffle(group_names) train_count int(len(group_names) * 0.8) val_count int(len(group_names) * 0.9) for idx, group in enumerate(group_names): split train if idx train_count else (val if idx val_count else test) for f in groups[group]: img_src os.path.join(src_imgs, f) label_src os.path.join(src_labels, f.rsplit(., 1)[0] .txt) shutil.copy(img_src, f{out_root}/images/{split}/{f}) shutil.copy(label_src, f{out_root}/labels/{split}/{f})这段脚本的核心是以组为单位划分保证同一个视频片段不会被切开。3100张数据如果来源是多个摄像头按摄像头编号分组也行原则是同一个场景的样本只能出现在一个集合里。分类别也要留意如果某个类别的图全集中在某一组分组后train里可能完全没有这个类别训练直接废掉。稳妥做法是先看类别分布再决定按组还是按文件随机。3.2 启动训练超参数初值对照表与最小命令目录准备好后写一个数据配置文件yolo命令行全靠它找图path: /home/user/dataset_split train: images/train val: images/val names: 0: cargo 1: fishing 2: speedboat 3: passengerpath是数据集的绝对路径train和val相对path写。类别顺序只要训练和推理保持一致就行但建议从0开始连续编号不要跳号否则yolo会报索引越界。让模型从预训练权重开始比从头训练收敛快很多3100张数据从头训非常容易过拟合。最小可复现的训练命令是yolo detect train \ datadataset_split/dataset.yaml \ modelyolov8s.pt \ epochs100 imgsz640 batch16 \ lr00.01 lrf0.01 patience30 \ projectruns/detect namevessel_v8s plotsTrue对应参数的选择理由和边界如下参数初值说明modelyolov8s.pt3100张数据用n太小、用m容易过拟合s是起步档imgsz640平衡速度与显存后续小目标优化可上1280batch1612GB显存左右可跑显存小先降到8epochs100配合early stopping不用手动看epochpatience30验证指标连续30轮不涨就自动停lr00.01标准初始学习率预训练权重推荐范围0.005~0.01plotsTrue保存loss曲线和预测样例方便复盘这里要专门说一下lr0。很多人上来就把学习率调到0.001觉得小学习率更稳结果3100张数据训到后面mAP卡在0.6上不去。预训练权重已经有不错的特征提取能力学习率太小反而让新数据学不进去。从0.01开始如果训练前几轮loss就爆炸再降到0.005也不迟。显存只够batch8时不要硬开imgsz1280。可以先保持640把模型跑通再考虑后续小目标优化。我见过一个案例某课程设计里显存只有6GB硬上imgsz1280导致batch被迫降到2结果BN统计不准mAP反而比640低5个点。这种硬撑没有意义。3.3 训练中要盯的数值损失曲线与mAP的联动训练跑起来之后不要只看终端刷出来的mAP。真正要盯的是三个损失曲线box_loss、cls_loss、dfl_loss以及验证集上的mAP50和mAP50-95。plotsTrue会把它们画在runs/detect/vessel_v8s目录下训练结束后直接看图片。一组典型的健康曲线是这样的前10轮三个loss快速下降mAP50从0.1左右冲到0.6中期进入平台期loss下降变缓如果后面验证集loss开始回升而训练集loss还在降说明过拟合已经开始。3100张图片通常在第40到60轮之间出现过拟合所以patience30是合理值不需要硬跑满100轮。还有一个很关键的判读经验mAP50涨但mAP50-95不涨说明模型能框出船的大概位置但边框精度不行。这种情况大概率是目标太小640分辨率下小艇只有十几个像素交并比怎么算都低。解决办法不是调损失权重而是下一步提高输入分辨率或改用切片推理。反过来如果mAP50和mAP50-95都低那通常是特征学习出了问题要回头检查数据标注和类别分布。4. 从3100张到稳定上船小目标、雾天与抗晃动的关键调整4.1 小目标漏检从输入分辨率到推理切片的联动远海小艇是船只检测的最大痛点。一个几十米的小船在1公里外监控画面里可能只有10×10像素yolov8s在640分辨率下很难抓住这种目标。第一个有效手段是把输入分辨率从640提到1280推理时也保持一致。命令里只改一个数yolo detect train \ datadataset_split/dataset.yaml \ modelruns/detect/vessel_v8s/weights/last.pt \ epochs50 imgsz1280 batch8 \ patience20 plotsTrue注意这里是在上一轮结果上继续训练学习率建议调低到0.005因为模型已经收敛过一次再打回高学习率会破坏已有权重。显存不够时不要硬上1280可以用960折中小目标提升幅度也能看到。另一个更极致的手段是推理时的切片策略把大图切成小块分别检测再合并结果。常见做法是用SAHI这类工具但核心思路很简单一张1920×1080的画面切成4个960×540的块模型看到的“小艇”变成了“中等目标”检测难度直线下降。代价是推理时间变成原来的3到4倍而且切块边缘的目标可能被切断。我一般只在远距离固定机位场景用切片近景监控没必要。4.2 雾天与黄昏数据层面的补强与预警如果你的3100张数据里全是晴天中午的船那模型一到雾天必然崩。常见做法是做离线数据增强直接生成一批带雾图片塞进训练集。用OpenCV模拟雾的脚本很简单import cv2 import numpy as np def add_fog(image, intensity0.5): h, w image.shape[:2] fog_layer np.full((h, w, 3), 255, dtypenp.uint8) noise np.random.randint(0, 25, (h, w, 3), dtypenp.uint8) fog_layer cv2.add(fog_layer, noise) fogged cv2.addWeighted(image, 1 - intensity, fog_layer, intensity, 0) return fogged这里的intensity控制雾的浓度0.3是薄雾0.6已经接近白茫茫一片。给训练集生成50到100张雾图就够不要贪多否则模型会把“雾”本身当成类别特征晴天数据反而掉点。黄昏和逆光可以用亮度扰动替代hsv_v调低一点就行。雾天增强有一个常见误区只加雾不改标注。加雾后船的轮廓还在标注框位置不变但模型学到的特征会从“清晰的船身轮廓”变成“模糊的船身明暗对比”。验证时最好单独留一批真雾天图片做测试如果mAP比晴天低了15%以上说明雾增强强度不够或者训练时雾图占比太低。4.3 抖动与水纹干扰NMS参数与置信度阈值的取舍水面反光和水纹纹理会制造大量误检这是船只检测区别于道路检测的典型场景。模型可能把一道高光波纹当成白色船身而且置信度还不低。调推理参数是最快见效的手段yolo detect predict \ modelruns/detect/vessel_v8s/weights/best.pt \ sourcetest_video.mp4 \ conf0.35 iou0.7 imgsz1280 \ agnostic_nmsTrueconf0.35意思是置信度低于0.35的框直接丢弃水纹误检通常置信度在0.3上下波动这个阈值能滤掉大半。设太高也会误伤真正的小艇远海小目标本来就模糊模型给它的置信度往往只有0.2到0.4。iou0.7控制NMS合并时框的重叠程度设太低会把同一艘船的多个检测框都保留设太高又会合并掉紧挨着的两条船。agnostic_nmsTrue在多类别检测时值得开。货船和客船如果类别判定错但两个框重叠度很高默认NMS不会互相抑制输出会同时出现“货船”和“客船”两个框叠在同一艘船上。开启agnostic后系统不再区分类别只看框的重叠这个现象会明显减少。水纹误检严重的场景如果提高conf后仍压不住可以考虑加几帧的时序过滤连续两帧都检测到同一个位置的框才输出。5. 船只检测数据集的避坑清单从标注到训练的5个翻车现场5.1 现象验证集mAP有0.86但视频里就是框不中小艇这是最迷惑人的一个坑。一个项目里验证集mAP50看着很高部署到港口视频里远处小艇漏掉八成。原因不在模型而在验证集的构成大部分验证图片是中近景的大船面积占画面三分之一模型只需要大概框个位置mAP就很高。小艇占总目标数量少对mAP的贡献被大船稀释了。解决方法是按目标面积分桶统计。训练结束后单独跑一个脚本把小目标归一化宽高都小于0.2的样本汇总成一个小目标测试集每次训练完都看这个子集的mAP。如果小目标mAP比整体低20%以上就说明模型没学会看远处的船。后续优先提高输入分辨率、加mosaic增强而不是继续堆叠训练轮数。5.2 现象训练曲线正常一到水纹密集区域就刷屏误检模型把水面反光当船这个现象在阳光强烈的午后特别严重。直接原因是训练数据里缺少这类“高光负样本”。3100张数据如果是从监控视频抽帧来的抽帧往往是均匀采样容易被较少出现的反光时段占便宜。解决分两步第一步从原始视频里手动截取一段没有船但水纹反光明显的片段抽100张左右作为负样本放进训练集让模型见过“没有船的水面长什么样”。第二步提高推理时的conf阈值到0.4误检框通常会比真目标置信度低。注意负样本加了之后验证时也要保留一部分空图否则模型可能从“见水就报”变成“见什么都报”。5.3 现象训练时cls_loss来回跳画图出来像锯齿某个项目训练loss曲线一直在0.5到0.8之间震荡不收敛也不发散。最后翻标注发现很多小船标注框没有贴紧船身框里包了一半水纹。模型同时看到“船身”和“周围水面”两种纹理分类特征互相干扰导致分类损失震荡。解决方法是统一标注规范船体边界只要能看到就必须贴边被遮挡的船可以放宽但不要为了凑完整框把背景大面积包进来。3100张数据量不大重新标注一遍的时间成本可以接受。如果数据太多可以用当前模型先做一轮预标注再把船身的框往里收紧人工只修明显超出船体的框。这个流程能省一半标注时间。5.4 现象类别比例失衡货船占了七成小艇占不到一成训练出来的模型对货船的mAP很高小艇几乎不可用。这是类别不均衡带来的经典问题。3100张数据本身就不大如果还严重偏科模型会把小艇当成“背景里的噪声”忽略掉。最有效的解法不是简单降低货船的样本量而是对小艇做定向增强把标注出的小艇目标裁剪下来通过copy-paste粘贴到没有船的水面背景图上生成一批新训练样本。粘贴的时候注意调整目标大小和光照不要让小艇看起来明显是“P上去的”。另一个思路是过采样小艇图片在每轮训练里被重复读取多遍配合mosaic增强效果也还不错。5.5 现象显存不够降batch结果mAP不升反降有人把imgsz从640提到1280后显存爆了于是把batch从16降到4训练几十轮后发现mAP比原来还低。原因在于batch太小导致BN统计不稳定模型每轮看到的样本差异太大梯度方向来回摆动。这对数据集的负面影响比分辨率提升带来的收益更大。解决方法是保batch降分辨率不要保分辨率降batch。1280跑不动就退回960batch保持8到16。如果一定想用1280可以用单卡训练时开启梯度累积或者直接换FP16半精度推理。但半精度对某些显卡兼容性有问题训练时如果爆NaN先关掉再排查。6. 用3100张数据集的边界值排查法验证模型有没有偷懒模型训练完不要急着部署先做一组“边界值排查”。这组测试和常规验证集完全不同它专挑最难、最偏、最容易让模型钻空子的样本用来回答一个问题模型到底是学会了识别船还是学会了识别“训练集里的船”。我一般建四个小集合每个20到50张。第一个是极端小目标集全是远海小艇检验分辨率提升有没有真正生效。第二个是负样本集只包含水面反光、码头建筑、天空云层检验误检率。第三个是灰度集把正常图片转成灰度再转回三通道检验模型是不是靠船体颜色在认船。第四个是翻转集把测试图水平翻转检验模型对方向变化的敏感度。灰度集的用法特别说明一下。把图片转灰度相当于强行剥掉颜色信息只保留纹理和形状。如果模型在灰度集上的mAP比原图下降了15%以上说明它很大程度在依赖颜色特征一旦遇到同色系的水面背景就会翻车。正常船只检测应该主要靠形状、龙骨线、轮廓这些结构特征颜色只是一个辅助信号。这个测试跑一遍比盯十轮训练曲线都能说明问题。边界值测试还可以配合输出可视化一起看。把模型预测的置信度画在图上负样本集里如果出现置信度大于0.5的误检框就要回头调conf阈值或补负样本。极端小目标集里如果置信度普遍低于0.2则说明训练时模型压根没把这种样本当回事下次迭代优先处理输入分辨率。这套方法本身不复杂但我后来每次接手类似项目都会先跑一遍。之前接手过一个水面监控模拟项目刚开始总mAP看着不错一跑边界集发现灰度集上掉了二十多个点才意识到模型靠船身颜色认船换个水质颜色的湖可能直接失效。自那以后就养成习惯边界集跑完再谈调参不然调了几天参数也不知道在给谁调。希望帮到你。本文还有配套的精品资源点击获取

关于恒美微站

恒美微站专注于为个体商户、工作室提供极简自助建站服务,让每个人都能轻松拥有专业网站。

快速链接

  • 关于我们
  • 建站服务
  • 主题模板
  • 案例展示
  • 资讯中心

服务项目

  • 可视化建站
  • 拖拽编辑
  • 主题定制
  • SEO 优化
  • 网站托管

联系方式

  • 📍 地址:北京市朝阳区建国路 88 号
  • 📞 电话:400-888-8888
  • ✉️ 邮箱:info@hmyw.cn
  • 🕐 时间:周一至周日 9:00-18:00

© 2024 恒美微站 hmyw.cn 版权所有 | 京 ICP 备 12345678 号