:數(shù)據(jù)集解析與訓練避坑指南)
簡介這份YOLO船舶目標檢測數(shù)據(jù)集面向計算機視覺學習者與算法工程師用于訓練和驗證水面船只識別模型適合從入門練手到模型對比實驗的多種場景。壓縮包共2000個文件約114.65MB其中1817個txt為YOLO格式標注文件178個jpg為船舶、皮劃艇、獨木舟等水上目標圖像另有5個yaml配置文件目錄已按train、valid、test劃分完畢并附帶data.yaml類別僅boat一類yolov5、yolov7、yolov8等主流框架可直接讀取訓練無需再自行整理標注。目前已有1523人學習下載說明該數(shù)據(jù)集在實際項目中被較多驗證。讀者拿到后可直接復現(xiàn)訓練流程觀察單類別小目標在復雜水面背景下的檢測表現(xiàn)也可用于數(shù)據(jù)增強、模型遷移與精度對比實驗配套博文還提供了檢測結果參考便于快速判斷數(shù)據(jù)質(zhì)量與訓練效果。1. 從 yolo-boat-detect-dataset-1.zip 說起船舶目標檢測數(shù)據(jù)集到底解決什么問題內(nèi)河航道監(jiān)控、港口靠泊管理、海上執(zhí)法巡查這些場景里最耗人力的環(huán)節(jié)不是看而是盯——盯著幾十路攝像頭畫面判斷哪一幀里出現(xiàn)了船、船在哪、是什么船型。用 YOLO 做船舶目標檢測第一道門檻從來不是模型結構而是數(shù)據(jù)。yolo-boat-detect-dataset-1.zip 這類命名方式本質(zhì)上是把船舶這個垂直場景的標注圖像打包成一個可直接喂給 YOLO 訓練流程的數(shù)據(jù)集壓縮包省掉從零采集、標注、清洗的幾周時間。它適合三類人一是剛入門 YOLO、想找一個非 COCO 非 VOC 的真實場景練手的人二是做水域安防、漁政、航運監(jiān)管方向需要快速驗證檢測可行性的人三是已有模型但想補充船舶類別樣本、做增量訓練的人。這個數(shù)據(jù)集能解決的核心問題是讓模型認識船但解決不了讓模型認識你的船——后者要靠你自己的場景數(shù)據(jù)做微調(diào)。理解這個邊界比急著解壓跑訓練更重要。2. 拆開壓縮包之前船舶檢測數(shù)據(jù)集的結構與 YOLO 格式對齊2.1 一個目標檢測數(shù)據(jù)集到底由什么組成不管壓縮包叫什么名字一個能直接用于 YOLO 訓練的檢測數(shù)據(jù)集內(nèi)部結構基本逃不出這幾樣東西圖像文件、標注文件、類別定義文件、以及劃分訓練/驗證/測試的索引。圖像是原始輸入標注是監(jiān)督信號類別定義決定輸出頭的維度索引決定每輪 epoch 喂哪些數(shù)據(jù)。船舶檢測的特殊性在于目標形態(tài)差異極大。遠洋貨輪在畫面里可能只占幾十個像素近岸漁船可能橫跨半個畫面船頭船尾的朝向、水面反光、霧天低對比度都會讓標注邊界框的松緊程度不一致。所以拿到一個船舶數(shù)據(jù)集第一件事不是看圖片好不好看而是看標注框是否貼合、類別是否統(tǒng)一、有沒有把船和船的倒影標成兩個目標。常見做法是先統(tǒng)計一遍標注分布每張圖平均幾個目標、目標框的寬高比分布、小目標面積小于 32×32 像素占比。這三個數(shù)字直接決定你后面選哪個 YOLO 版本、用多大的輸入分辨率、要不要開多尺度訓練。2.2 YOLO 標注格式與常見數(shù)據(jù)集格式的差異YOLO 用的是歸一化中心點格式每行一個目標類別索引 中心x 中心y 寬 高四個坐標都除以圖像寬高落在 0~1 之間。而很多公開數(shù)據(jù)集給的是 VOC 的 XML左上角右下角絕對坐標或 COCO 的 JSON絕對坐標類別 id。直接混用會導致框全錯位這是新手最常翻的車。下面這段腳本用來檢查一個 YOLO 格式數(shù)據(jù)集的基本健康度包括類別分布、框尺寸分布和越界框import os import glob from collections import Counter # 數(shù)據(jù)集根目錄按你解壓后的實際路徑改 DATA_ROOT ./yolo-boat-detect-dataset-1 LABEL_DIR os.path.join(DATA_ROOT, labels) IMG_DIR os.path.join(DATA_ROOT, images) cls_counter Counter() box_areas [] bad_lines 0 for txt in glob.glob(os.path.join(LABEL_DIR, **, *.txt), recursiveTrue): with open(txt, r) as f: for line in f: parts line.strip().split() if len(parts) ! 5: bad_lines 1 continue c, x, y, w, h parts x, y, w, h map(float, (x, y, w, h)) # 越界檢查歸一化坐標必須在 0~1 if not (0 x 1 and 0 y 1 and 0 w 1 and 0 h 1): bad_lines 1 continue cls_counter[int(c)] 1 box_areas.append(w * h) print(類別分布:, dict(cls_counter)) print(異常標注行數(shù):, bad_lines) if box_areas: small sum(1 for a in box_areas if a 0.01) # 相對面積小于1%視為小目標 print(f目標總數(shù): {len(box_areas)}, 小目標占比: {small/len(box_areas):.2%})邏輯說明腳本遍歷 labels 目錄下所有 txt逐行解析五元組。越界檢查是重點因為標注工具導出時偶爾會產(chǎn)生超出圖像邊界的框YOLO 訓練時這類框會被靜默裁剪或直接報錯。參數(shù)上0.01這個閾值是相對面積對應約 640 分辨率下 64×64 像素的框你可以按自己場景調(diào)整。類別分布如果出現(xiàn)某個類別數(shù)量為 0 或極端不均衡就要考慮是不是標注時漏標了。2.3 訓練/驗證集劃分與 data.yaml 的寫法YOLO 系列v5/v8/v11 都類似靠一個 yaml 文件告訴訓練器去哪找數(shù)據(jù)、有幾個類別、類別叫什么。這個文件寫錯訓練要么直接崩要么類別名對不上導致推理結果全是錯的。# data.yaml path: ./yolo-boat-detect-dataset-1 # 數(shù)據(jù)集根目錄 train: images/train # 訓練集圖像相對路徑 val: images/val # 驗證集圖像相對路徑 test: images/test # 可選 nc: 1 # 類別數(shù)船舶檢測通常先做單類 names: [boat] # 類別名順序必須和標注里的類別索引一致參數(shù)說明path是根目錄train/val是相對 path 的子路徑YOLO 會自動把路徑里的images替換成labels去找標注。nc和names長度必須一致且names的順序要和標注文件里類別索引 0、1、2 對應。如果數(shù)據(jù)集里船分了貨船/漁船/客船多類這里就要相應改成多類但建議第一次訓練先用單類跑通確認流程無誤再細分。提示劃分訓練驗證集時不要隨機打散同一段視頻的連續(xù)幀。同一艘船相鄰幾幀幾乎一樣隨機劃分會導致驗證集里出現(xiàn)訓練集見過的船指標虛高。按視頻源或時間段劃分更靠譜。3. 用 YOLO 在本地跑通船舶檢測的最小訓練流程3.1 環(huán)境準備與依賴安裝訓練船舶檢測模型硬件上有一塊 8GB 顯存的顯卡就能起步batch 設小一點即可。軟件上Python 3.8~3.11 都行CUDA 版本要和 PyTorch 對應。我一般用 conda 建獨立環(huán)境避免和系統(tǒng)里的包打架。conda create -n boat_yolo python3.10 -y conda activate boat_yolo # 按你的 CUDA 版本選對應命令這里以 CUDA 11.8 為例 pip install torch torchvision --index-url https://download.pytorch.org/whl/cu118 pip install ultralytics opencv-python pyyaml邏輯說明ultralytics 這個包把 YOLOv8/v11 的訓練、驗證、導出都封裝好了一條命令能跑完整個流程。CUDA 版本一定要和驅(qū)動匹配裝錯了會在torch.cuda.is_available()返回 False訓練自動掉到 CPU 上速度差幾十倍。裝完先跑一句驗證import torch print(torch.cuda.is_available(), torch.cuda.get_device_name(0))如果輸出 False先別急著往下走回去查驅(qū)動和 CUDA 版本對應關系這是最常見的翻車點。3.2 從預訓練權重開始微調(diào)船舶檢測數(shù)據(jù)量通常不大從零訓練容易過擬合標準做法是從 COCO 預訓練權重開始微調(diào)。COCO 里本來就有 boat 類所以遷移效果一般不錯。yolo detect train \ data./data.yaml \ modelyolov8n.pt \ epochs100 \ imgsz640 \ batch16 \ lr00.01 \ patience20 \ project./runs/boat \ nameexp1參數(shù)說明modelyolov8n.pt是最小的 nano 版本速度快、適合先驗證流程確認有效再換 s/m/l。imgsz640是輸入分辨率船舶小目標多的話可以提到 960 或 1280但顯存占用和訓練時間會明顯上升。lr00.01是初始學習率微調(diào)場景下如果發(fā)現(xiàn) loss 震蕩厲害可以降到 0.001。patience20表示驗證指標 20 輪不提升就早停省時間。batch16在 8GB 顯存上跑 640 分辨率一般夠用爆顯存就減到 8。訓練過程中重點看三個東西box_loss 是否穩(wěn)定下降、mAP50 是否在漲、驗證集的預測圖里有沒有大量漏檢。如果 box_loss 降但 mAP 不漲多半是過擬合或標注有問題如果一開始 loss 就是 nan檢查學習率是不是太大或標注里有非法值。3.3 推理與結果驗證訓練完在 runs/boat/exp1/weights/ 下會有 best.pt 和 last.pt。best.pt 是驗證指標最好的那輪推理一般用它。yolo detect predict \ model./runs/boat/exp1/weights/best.pt \ source./yolo-boat-detect-dataset-1/images/test \ conf0.25 \ iou0.45 \ saveTrue參數(shù)說明conf0.25是置信度閾值低于它的框不輸出船舶場景如果漏檢嚴重可以降到 0.1 看看但誤檢會變多。iou0.45是 NMS 的 IoU 閾值兩艘船靠得近時這個值調(diào)太大會把其中一艘壓掉調(diào)太小會重復框同一艘船。這兩個參數(shù)沒有萬能值要拿幾十張典型圖反復試。驗證階段別只看 mAP 數(shù)字。把預測結果按正確檢測/漏檢/誤檢/重復框分類各挑幾張看比盯著一個小數(shù)點有用得多。船舶檢測里最常見的誤檢是把水面反光、橋墩、浮標當成船這類問題靠調(diào)閾值解決不了得補負樣本。4. 船舶檢測訓練避坑5 個真實踩過的坑4.1 坑一驗證集 mAP 很高實際部署全是漏檢現(xiàn)象訓練日志里 mAP50 到 0.9 以上但拿現(xiàn)場視頻一跑遠處的船基本檢測不到。原因驗證集和訓練集來自同一批圖像分布一致且驗證集里可能沒有足夠的小目標樣本。mAP 是在驗證集上算的驗證集不代表真實場景。解決單獨準備一批來自實際部署場景的圖像做測試集不參與訓練和驗證。如果這批圖上指標掉得厲害說明模型沒泛化到你的場景需要補充該場景的標注數(shù)據(jù)做微調(diào)而不是繼續(xù)在原有數(shù)據(jù)上加 epoch。4.2 坑二標注框把船的倒影一起框進去現(xiàn)象模型在水面平靜、倒影清晰的圖上會把倒影也檢測成船或者框比實際船大一倍。原因標注階段標注員圖省事把船和倒影框在一起。模型學到的是船倒影的組合特征遇到倒影就觸發(fā)。解決重新檢查標注倒影不屬于目標本體框應只貼船體。如果倒影樣本很多可以把倒影單獨標一個類或作為負樣本讓模型學會區(qū)分。這個坑在船舶數(shù)據(jù)集里極其常見拿到任何船舶數(shù)據(jù)都要先抽查這一點。4.3 坑三類別索引和 names 順序?qū)Σ簧犀F(xiàn)象訓練不報錯但推理時所有船都被標成錯誤的類別名或者置信度異常低。原因data.yaml 里 names 的順序和標注文件里的類別索引不一致。比如標注里 0 是貨船、1 是漁船但 yaml 里寫反了。解決寫 yaml 前先統(tǒng)計標注里出現(xiàn)過的所有類別索引按索引順序填 names。改完 yaml 后重新訓練不要指望在舊權重上改名字就能對。4.4 坑四圖像和標注文件名不匹配現(xiàn)象訓練時警告 image not found 或 label missing大量樣本被跳過實際參與訓練的數(shù)據(jù)遠少于預期。原因YOLO 靠文件名不含擴展名匹配圖像和標注。如果圖像是boat_001.jpg標注是boat_001.txt沒問題但如果標注是boat_1.txt或帶了額外后綴就匹配不上。解決寫個腳本批量檢查圖像和標注的文件名集合是否一致差集就是問題文件。統(tǒng)一重命名后再訓練。這個檢查應該在訓練前做而不是等訓練日志里出現(xiàn)警告才回頭查。4.5 坑五小目標檢測效果差就盲目加大模型現(xiàn)象遠處小船檢測不到第一反應是換更大的模型n 換到 x結果速度慢了好幾倍小目標召回只提升一點點。原因小目標檢測的瓶頸往往在輸入分辨率不在模型容量。640 分辨率下一個 20 像素的船縮到網(wǎng)絡深層只剩幾個像素再大的模型也提取不出有效特征。解決優(yōu)先提高輸入分辨率640→1280或者用帶 P2 小目標檢測層的 YOLO 變體。分辨率提升對小目標的收益通常比換大模型明顯代價是顯存和推理時間。先試分辨率再考慮模型規(guī)模。5. 把船舶檢測做扎實從跑通到可用的幾個進階技巧跑通一次訓練只是起點。要讓船舶檢測真正可用有幾個我反復驗證過的做法。第一是分場景評估不要只看總體 mAP。把測試集按近景/遠景白天/夜間平靜水面/有浪分組分別算指標。你會經(jīng)常發(fā)現(xiàn)總體 0.85但夜間只有 0.4。這種細分指標才告訴你下一步該補哪類數(shù)據(jù)。第二是善用負樣本。船舶檢測最大的誤檢來源是水面反光、浮標、橋墩、岸上建筑。專門收集一批不含船但包含這些干擾物的圖像標注為空沒有標注行加入訓練集。這比調(diào)置信度閾值有效得多??諛俗⑽募?YOLO 里是合法的表示這張圖沒有目標。第三是推理時的切片策略。對于高分辨率監(jiān)控畫面整圖縮到 640 會丟失小目標。常見做法是把大圖切成有重疊的小塊分別推理再合并結果。下面是一個簡化的切片推理思路import cv2 import numpy as np def sliced_infer(model, img, slice_size640, overlap128): h, w img.shape[:2] step slice_size - overlap all_boxes [] for y in range(0, h, step): for x in range(0, w, step): patch img[y:yslice_size, x:xslice_size] if patch.shape[0] slice_size or patch.shape[1] slice_size: patch cv2.copyMakeBorder( patch, 0, slice_size-patch.shape[0], 0, slice_size-patch.shape[1], cv2.BORDER_CONSTANT, value(114,114,114)) results model(patch, conf0.25, verboseFalse) for box in results[0].boxes: xyxy box.xyxy[0].cpu().numpy() xyxy[[0,2]] x # 還原到原圖坐標 xyxy[[1,3]] y all_boxes.append((xyxy, float(box.conf[0]))) # 跨切片去重這里用簡單 IoU 過濾實際可用 NMS return all_boxes邏輯說明把大圖按固定步長切成小塊每塊單獨推理再把框坐標加回偏移量還原到原圖。overlap 是為了避免目標正好落在切片邊界被切斷。最后需要做一次全局 NMS 去掉重疊切片產(chǎn)生的重復框。參數(shù)上slice_size 和模型訓練分辨率一致overlap 一般取 slice_size 的 15%~25%。這個策略對高分辨率監(jiān)控畫面提升明顯代價是推理時間隨切片數(shù)線性增長。第四是模型導出。訓練用的 PyTorch 權重不適合直接部署通常導出成 ONNX 或 TensorRT。導出時注意輸入尺寸要和訓練時一致動態(tài) batch 按部署需求設。導出后一定要拿同一批圖對比 PyTorch 和導出模型的輸出確認沒有精度損失再上線。最后說個習慣每次訓練前把 data.yaml、標注統(tǒng)計結果、訓練命令記在一個文本文件里和權重放一起。過兩周回頭看你會慶幸自己留了這些記錄。船舶檢測這行數(shù)據(jù)版本和參數(shù)組合一多沒有記錄就是黑匣子出了問題連后悔藥都沒得吃。希望幫到你。本文還有配套的精品資源點擊獲取