據(jù)集構建與YOLOv8訓練部署實戰(zhàn)——4300張圖片全流程解析)
做了幾年目標檢測項目我越來越覺得數(shù)據(jù)集的構建過程比模型訓練本身更考驗耐心。這次這套貓狗檢測數(shù)據(jù)集總共4300張YOLO格式標注圖片就是我在做寵物識別項目時從零開始攢起來的。整個過程踩過不少坑也走了很多彎路今天把從數(shù)據(jù)采集、標注規(guī)范到YOLO訓練部署的完整鏈路整理出來希望能幫到正在做類似寵物識別、貓狗檢測項目的朋友。1. 為什么我不直接用開源貓狗數(shù)據(jù)集而要自己攢這4300張1.1 公開數(shù)據(jù)集的最大問題不是數(shù)據(jù)量而是長相差太多很多人做寵物識別第一反應就是去Kaggle找個貓狗數(shù)據(jù)集下載這沒錯但實際跑起來你很快會發(fā)現(xiàn)一個問題公開數(shù)據(jù)集里的圖和真實應用場景里的圖完全是兩個世界。Kaggle那個經(jīng)典的貓狗大戰(zhàn)數(shù)據(jù)集Dogs vs. Cats有25000張圖數(shù)據(jù)量絕對夠但里面的圖片大部分是十幾年前網(wǎng)友上傳的,分辨率低、主體占比大、背景干凈貓咪和狗基本都在畫面正中間。你用這種數(shù)據(jù)訓練出來的模型拿到真實的寵物自動喂食器、小區(qū)流浪貓監(jiān)控或者寵物社交App的拍圖識別場景里效果會明顯下滑。真實場景是復雜的貓咪躲在沙發(fā)角落、狗在草地上狂奔、強逆光、晚上只有微弱燈光、多只寵物同框、部分身體被遮擋、甚至只露個屁股。所以我決定自建數(shù)據(jù)集時目標就定得很明確不求量大但求場景全、貼近真實。4300張圖聽起來不算多但只要能覆蓋真實場景的變化訓練效果會比盲目堆量好得多。1.2 這個數(shù)據(jù)集要解決什么問題這套數(shù)據(jù)集只做兩個類別的檢測dog和cat。檢測任務和分類任務有個本質區(qū)別分類是給整張圖判斷這是什么檢測要回答的是圖里有幾只寵物每只在哪是多大的框。所以我標注的時候不是給整張圖打一個標簽而是要框出每一只貓和狗。實際使用中這套數(shù)據(jù)可以支撐以下場景寵物自動喂食器里識別寵物靠近區(qū)分貓狗啟動不同出糧策略小區(qū)或門店的寵物統(tǒng)計統(tǒng)計某段時間內出現(xiàn)的貓狗數(shù)量寵物社交產品用戶上傳照片后自動識別寵物并打上標簽智能攝像頭寵物異常行為警報比如貓上桌、狗扒門這類確定好這些問題之后整個數(shù)據(jù)集項目的脈絡就清晰了采集什么場景的圖、標注到什么粒度、訓練時用什么策略、驗證時重點看哪些指標全部圍繞這幾個應用場景來定。2. 4300張圖的誕生采集篩選、標注規(guī)范與格式轉換2.1 數(shù)據(jù)來源與合規(guī)意識數(shù)據(jù)來源我主要用了三類按占比排列自采圖片自己用手機、相機在不同時間早中晚、夜間開燈/關燈、不同地點室內客廳、陽臺、戶外草地、樓道、車內拍攝的寵物照片大約占四成可商用授權的圖庫素材專門篩選了允許商用和修改的圖片平臺避免版權風險開源數(shù)據(jù)集中的精選子集從部分開放許可證的數(shù)據(jù)集中挑選圖片但不盲目全收只挑場景或者畫質合格的那部分注意數(shù)據(jù)合規(guī)這件事我是認真做了功課的。訓練數(shù)據(jù)一旦用于商業(yè)項目圖片的授權問題會直接影響產品能否上線。建議大家都按照要么自己拍、要么明確可商用授權的標準來卡數(shù)據(jù)來源。2.2 篩選標準的細化采集到原始圖片后我做了三輪篩選每一輪淘汰率都不低第一輪是清晰度篩查。模糊圖、嚴重過曝圖、運動拖影圖直接刪。檢測模型對模糊極其敏感訓練數(shù)據(jù)里模糊圖太多模型學到的特征是模糊的紋理推理時反而會對清晰目標不敏感。這一輪大概刪了10%。第二輪是重復圖去重。我用的是感知哈希pHash算法做相似度計算相似度超過0.9的只保留一張。如果不做去重訓練集里會有大量近乎重復的樣本模型相當于反復看同一張圖數(shù)據(jù)多樣性下降還容易過擬合。第三輪是語義檢查。這一步很關鍵。公開數(shù)據(jù)集里的貓狗圖片偶爾會有標簽錯亂比如把狐貍標成dog、把猞猁之類的標成cat。這些錯誤標簽混進訓練集會直接拉低模型精度。我手動抽查了每批圖片的標簽準確性對存疑的圖片單獨篩出來人工復核。最終4300張圖的類別分布如下類別圖片數(shù)張實例總數(shù)只dog23503120cat19502680單張圖里多目標的樣本大約占30%這個比例我個人建議要刻意保持。如果全是單寵圖片模型面對多只寵物同框時很容易漏檢。2.3 標注工具的選型與標注規(guī)范標注工具我對比過幾個最后按項目情況選擇了x-anylabeling選它的原因是操作效率高、支持自動保存、也支持YOLO/voc/pascal coco格式直接導出。LabelImg雖然經(jīng)典但多年沒維護了在高分屏下的體驗比較一般。標注規(guī)范是保證數(shù)據(jù)質量的核心不能邊標邊改。我在動手前定了一套規(guī)則團隊協(xié)作時嚴格按照這套執(zhí)行目標完整可見就框全身不追求貼到極致但要保證目標主體軀干頭部在框內遮擋超過70%的實例不標注屬于無法判斷的樣本只露出頭部或只露出背部的模糊半遮擋實例不標注避免給模型引入噪聲兩只寵物緊挨著但邊界清晰時分別單獨標注完全不清晰的遠處目標不標注這里有個經(jīng)驗之談標注框不需要往死里貼合目標邊緣。YOLO的損失計算是基于預測框和真實框的IoU標注框差幾個像素對最終精度影響很小但為了摳幾個像素浪費大量時間就完全沒有必要了。重要的是把該框的都框了、不該框的別亂框這件事做對。2.4 從標注格式到YOLO訓練格式的轉換標注工具導出的格式通常是VOC XML或COCO JSON而YOLO訓練需要的是txt文件每行對應一個目標格式是類別ID x_center y_center width height這四個坐標值全部是歸一化到0~1之間的比例值不是像素值。舉個例子一張寬960、高640的圖中某個目標的框左上角在(192, 128)右下角在(672, 512)那么x_center (192 672) / 2 / 960 0.45 y_center (128 512) / 2 / 640 0.5 width (672 - 192) / 960 0.5 height (512 - 128) / 640 0.6對應的txt行就是0 0.45 0.5 0.5 0.6這個轉換邏輯不復雜但如果圖片集比較大建議直接寫腳本批量處理而不是用標注工具自帶的導出功能。原因有兩個一是可以順手做數(shù)據(jù)集的隨機劃分二是可以在轉換時統(tǒng)一檢查坐標越界、空標注文件等問題。數(shù)據(jù)劃分我用的是train/val的比例隨機打亂后按9:1分配。這個比例對4300張圖來說比較合理測試集拆出來太多會導致訓練數(shù)據(jù)吃緊太少又很難評估真實效果。劃分完確認一下每個集合里dog和cat的比例均衡避免出現(xiàn)驗證集里全是狗的情況。3. YOLOv8訓練前的目錄與配置文件90%的人會在這里栽跟頭3.1 版本選型為什么是YOLOv8現(xiàn)在說到YOLO其實社區(qū)里已經(jīng)有很多分支從YOLOv5到YOLOv8、YOLOv9甚至YOLO11都在發(fā)展。我選擇YOLOv8而不是其他版本主要是這三個原因生態(tài)成熟Ultralytics官方維護文檔豐富安裝部署簡單pip裝一下就能跑預訓練權重豐富官方提供了n/s/m/l/x五個規(guī)格的預訓練模型可以直接在COCO預訓練權重基礎上做遷移學習收斂速度遠超從頭訓練驗證推理靈活訓練完可以方便地導出ONNX、TensorRT等格式部署到邊緣設備時選擇多資料下載方面YOLOv8的預訓練模型權重可以直接從Ultralytics官方GitHub倉庫鏈接下載也可以直接讓代碼自動下載。對國內網(wǎng)絡環(huán)境不太穩(wěn)定的情況可以手動下載后放到指定目錄然后訓練時指定本地權重路徑。3.2 標準的目錄結構與數(shù)據(jù)集配置文件YOLOv8訓練要求數(shù)據(jù)集目錄有非常明確的結構建議一次性搭好避免訓練時報路徑錯誤pet-dataset/ ├── images/ │ ├── train/ │ └── val/ ├── labels/ │ ├── train/ │ └── val/ └── pet.yaml特別注意images目錄和labels目錄下的文件名要一一對應比如images/train/0001.jpg必須對應labels/train/0001.txt。如果出現(xiàn)txt缺失或者圖片缺失訓練時要么報錯要么數(shù)據(jù)加載量會莫名變少很難排查。pet.yaml的內容如下path: ./pet-dataset train: images/train val: images/val nc: 2 names: 0: dog 1: cat這里最容易被忽略的是path字段建議用絕對路徑。如果寫相對路徑很多新手會默認從項目根目錄開始解析結果花了半小時找行程錯誤最后發(fā)現(xiàn)是路徑相對位置理解錯了。3.3 核心訓練參數(shù)怎么定我這次訓練的基準配置放在了下面大家可以作為起步參考model: yolov8s.pt data: pet.yaml epochs: 100 batch: 16 imgsz: 640 optimizer: AdamW lr0: 0.0005模型規(guī)格選了yolov8s而不是yolov8n。n雖然速度最快但小模型對小型寵物目標的特征提取能力有限s在城市級推理場景和精度之間更均衡輸入分辨率640是默認選擇。寵物目標絕大多數(shù)情況下不算特別小的目標640分辨率足夠batch值要看顯卡顯存來定。個人實測在6GB顯存下yolov8s640分辨率batch設為16剛好能跑如果顯存緊張batch降到8再配合梯度累積效果也不錯優(yōu)化器選了AdamW。YOLOv8默認是SGD但AdamW在中小型數(shù)據(jù)集上收斂更穩(wěn)不用太焦慮學習率設置的問題。缺點是顯存占用會略高不過這個數(shù)據(jù)集規(guī)模下影響不大4. 訓練曲線、混淆矩陣與三個容易翻車的細節(jié)訓練真正跑起來之后比起哇AI好神奇你更需要盯著的是訓練曲線和一系列評估指標。我這邊訓練的最終結果如下指標數(shù)值mAP0.50.961mAP0.5:0.950.872Precision0.943Recall0.927這個結果對我來說是達到預期的。但過程中其實不是一帆風順我踩了幾個坑每一個都能讓訓練成果打折扣下面展開說。4.1 第一個坑訓練中BN層崩潰訓練到大概第40輪左右我突然發(fā)現(xiàn)loss變成nan了。當時第一反應是學習率太大但調低之后重啟訓練跑到一半又會出現(xiàn)。排查之后發(fā)現(xiàn)根因是batch size偏小加上部分圖片退化異常。BNBatch Normalization層在batch過小的時候統(tǒng)計的均值和方差波動極大一旦某次迭代的方差算出來是0BN層就會輸出nan接下來所有梯度都被污染。這類問題的主要對策按優(yōu)先級排列把batch size從8提升到16檢查是否有個別圖片文件損壞我在數(shù)據(jù)清洗時篩過一輪但偶爾還是有一兩張大圖解碼異常如果確實只能用小batch可以把BN層的momentum調大一點減少對當前batch統(tǒng)計值的依賴4.2 第二個坑混淆矩陣的總和不是100%訓練結束看confusion matrix的時候有人會發(fā)現(xiàn)每一行的比例加起來不是100%就開始懷疑是不是模型出了問題。其實這個現(xiàn)象在YOLO的混淆矩陣里是正常的。具體解釋是YOLO的混淆矩陣在計算時每個預測框會對應一個最高置信度的類別但置信度低于閾值的目標會被歸到background那一行或列。也就是說矩陣中顯示的是歸一化后的分布比例出現(xiàn)行和不為1是因為有一部分預測框被判定為了background并沒有在dog或cat類別里顯示出來。所以看到confusion matrix總和不為1不要慌。應該先看background那一行占了多大比例如果background占比明顯偏高說明你的置信度閾值設得太高或模型存在較多漏檢如果dog、cat之間的交叉誤判很少模型就是正常的。4.3 第三個坑類別分布不均帶來的收斂慢我最初的數(shù)據(jù)里dog和cat圖片數(shù)的比例差不多是6:4雖然不算極端但訓練時發(fā)現(xiàn)dog類收斂明顯比cat慢。原因是dog類別實例多模型在每輪迭代中見到dog的樣本頻率更高權重更新也更頻繁。這里我沒有急著給cat類強行復制圖片而是給損失函數(shù)里的類別權重做了調整在用Ultralytics框架訓練時可以通過給數(shù)據(jù)集配置文件或者訓練代碼傳入類別權重參數(shù)讓模型在計算分類損失時對cat類的錯誤更加敏感。調整之后cat類別的精度在后續(xù)幾個epoch里明顯追了上來。5. 從驗證集到真實攝像頭實測效果與部署時的幾個建議訓練階段指標漂亮只是一半最終能不能用要看真實場景。我訓練完之后做了兩輪實測。第一輪是用手機拍視頻模擬真實用戶使用場景。測試內容包括家里兩只貓在不同房間走動樓下小區(qū)里遛狗的路人夜間走廊有微弱燈光時貓穿過貓從攝像頭側前方快速跑過第二輪是拿了一套完全沒參與訓練的圖片大概120張由朋友幫忙拍攝做盲測。這輪測試非常有價值暴露了單純看mAP看不到的問題。盲測中我發(fā)現(xiàn)的一個明顯短板是當寵物在畫面中占比非常小的時候比如畫面寬度640像素中寵物只占80像素漏檢率明顯上升。這個不是標注問題而是模型天然對小目標不敏感。如果你也要做類似場景給幾個實際建議部署時盡量讓寵物在畫面中的比例大一些鏡頭安裝角度不要太高推理分辨率不要低于訓練分辨率我用640訓練推理也盡量保持640不要為了速度隨便降到416如果是低算力設備部署我建議導出ONNX后用TensorRT做INT8量化精度損失可以控制在2%以內但速度提升往往非常明顯推理側還有一個讓我印象很深的問題NMS閾值不要輕易動。我把NMS的IoU閾值從默認的0.7改到0.5之后原本兩條狗緊挨著的場景檢測框會突然消失一個。原因很簡單兩個框重疊面積大NMS直接把低置信度那個框抑制掉了。所以非必要不動NMS閾值動之前先在真實數(shù)據(jù)上測過再說。6. 數(shù)據(jù)集不會一次做完版本迭代與錯誤樣例復盤6.1 收集失敗case才是數(shù)據(jù)迭代的起點模型部署到真實環(huán)境后你會發(fā)現(xiàn)誤檢和漏檢的出現(xiàn)模式很有規(guī)律。比如我碰到的幾個典型錯誤案例毛絨玩具狗被識別成dog置信度還不低貓背包、貓窩上的印花貓被判成cat逆光情況下把垃圾桶旁邊的一團塑料袋誤判成cat這些錯誤案例如果只是看一眼就完事那數(shù)據(jù)集永遠止步于4300張。正確做法是把每一個錯誤case都收集到一個專門的目錄里隔一段時間人工復核并補充標注然后以增量訓練的方式更新模型。我自己的迭代節(jié)奏是每兩周收集一次錯誤case每次補充100-200張圖。經(jīng)過三輪迭代之后模型對毛絨玩具、印花圖案這類偽目標的抗干擾能力提升明顯誤檢率幾乎降了一半。這一步投入的時間不多但收效非??捎^。6.2 給數(shù)據(jù)版本留好記錄后續(xù)會瘋狂感謝自己數(shù)據(jù)集做了3個月之后你就明白版本管理不是可選項而是必需品。我見過有人數(shù)據(jù)集文件重命名后又找不到舊版最后只能重新標注白白浪費了幾十個小時。按我現(xiàn)在的習慣每次數(shù)據(jù)調整都會記錄三件事改動的時間、改動的文件范圍、改動的原因。比如v2.1 2025-03-12新增120張夜間場景圖修復17張標簽坐標偏移刪除8張重復圖這樣等模型出了問題需要回滾數(shù)據(jù)版本時你手里永遠有一本清清楚楚的賬。6.3 數(shù)據(jù)增強要不要加加多狠才合適訓練YOLO時官方默認會開啟mosaic、翻轉、色彩變換等數(shù)據(jù)增強。一開始我為了防止過擬合把mosaic概率調得比較高但后來發(fā)現(xiàn)寵物目標如果被mosaic切得太碎模型在小目標上的表現(xiàn)反而變差。特別是貓這種喜歡縮成一團的動物身體本來就不大被Mosaic一裁切標注框可能就剩原來的一半了。最終我把mosaic概率從默認的1.0降到了0.5同時把copy_paste增強概率適度調高一點。調整之后模型對完整目標的檢測效果更穩(wěn)定因為模型終于能看到完整的貓了。這個參數(shù)的調整原理其實很簡單數(shù)據(jù)增強的目的是增加多樣性但如果增強手段破壞了目標本身的完整性模型學到的就只是殘缺特征。這一步調參花了大概三天時間做對比實驗但效果是實實在在的。我建議你做類似項目時一定要自己跑幾組增強參數(shù)對比別嫌麻煩默認參數(shù)在寵物這種非剛性目標上并不一定是最佳選擇。