
簡介目標檢測是計算機視覺領域的核心任務之一其本質是在圖像中定位并識別感興趣的目標。在實際工程中針對小目標、復雜背景的檢測場景模型的選擇與訓練策略往往比網絡結構本身更關鍵。YOLOv5作為成熟穩定的檢測框架憑借其輕量級設計、靈活的配置和豐富的生態資源在諸多垂直領域中得到廣泛應用。本文以冬蟲夏草生長檢測為實踐案例系統介紹從數據集構建、標注規范、數據增強到模型訓練、超參調整、權重選擇再到推理優化與邊緣設備部署的完整鏈路。通過合理調整置信度閾值、輸入分辨率與錨框參數可有效提升小目標的召回率。該技術路線同樣適用于農作物監測、野生資源調查、工業缺陷檢測等場景為開發者提供了一套可復用的工程化解決方案。 這個項目其實挺有意思的。冬蟲夏草這玩意兒跟工業質檢里那些規規矩矩的螺絲釘完全不一樣它長在高原草甸上背景是枯草、泥土、碎石混在一起的復雜環境子座從土里冒出來個頭小、顏色跟周圍環境還特別接近人眼找起來都得瞇著眼睛仔細看。用YOLOv5來做單類別檢測聽起來不算復雜但真正跑通“數據準備→標注→訓練→權重部署”這條鏈路里頭的坑一點不少。這篇就把整個實戰過程掰開揉碎從數據集怎么來、標注要注意什么到訓練參數怎么調、權重文件怎么選再到推理和常見問題排查一次性講清楚。1. 項目核心思路與方案選型1.1 為什么選YOLOv5而不是YOLOv8或者更重的框架先說結論單類別目標檢測YOLOv5目前依然是性價比最高的選擇沒有之一。雖然YOLOv8、YOLOv9這些新版本在COCO這類通用數據集上刷榜刷得很歡但放到“冬蟲夏草生長檢測”這種垂直場景里YOLOv5的生態成熟度、踩坑資料數量、部署資料完整度都遠超新版本。具體原因有三點。第一YOLOv5對硬件的要求足夠友善。蟲草檢測這套任務目標是小尺寸、低對比度通常需要在實地設備上跑可能是Jetson Nano可能是RK3568也可能是工廠或者實驗室里一臺普通的老GPU。YOLOv5s和YOLOv5n這兩個輕量級版本在GTX 1660這種入門級顯卡上就能訓練推理時甚至CPU都能跑只不過速度慢一些。而YOLOv8雖然也有n/s版本但很多老設備上的推理庫和工具鏈對它的支持還沒有完全跟上。第二YOLOv5的代碼結構清晰配置文件簡單適合做二次改動。比如后面要講的anchor尺寸調整、數據增強策略開關都是幾行配置的事。而且國內外關于YOLOv5的教程、踩坑記錄、社區問答簡直是海量遇到問題搜一下基本都有答案。對這類偏應用型的項目來說框架的“可救性”比“先進性”重要得多。第三YOLOv5的輸出權重格式對后續部署非常友好。不管是轉成onnx、TorchScript還是TensorRT都有成熟穩定的轉換腳本這在后面做邊緣設備部署時會省掉大量時間。單類別任務尤其適合YOLOv5還有一個隱藏優勢它的Neck和Head設計本身是按通用物體檢測優化的在處理單類別、小目標、復雜背景這類場景時可控的調節空間很大不需要做網絡結構層面的改動只需要在數據增強、錨框、超參上做文章。1.2 單類別“生長檢測”的任務定位這里需要先把“檢測”和“分類”的概念理清楚。這個項目做的是“冬蟲夏草生長檢測”本質上是在圖像中回答兩個問題圖中有沒有冬蟲夏草如果有它在哪里這類需求在實際業務中對應很多場景。比如高原產區做蟲草資源的動態監測通過無人機或地面巡拍采集圖像用模型自動框出每個蟲草的位置統計分布密度再比如藥材企業做收購分級前的初篩把大量歷史照片里的蟲草快速標記出來替代人工一張張翻找還有科研單位做生長周期觀測通過連續圖像中的蟲草位置變化來分析出土時間、生長速度等指標。“1類別”意味著不需要區分蟲草的種類、等級、生長階段只要能找到“目標在哪”就行。這看起來比多類別任務簡單但實際做下來會發現單類別任務的難點不在“區分度”而在“查全率”也就是漏檢率。蟲草的顏色和周圍枯草接近早期出土的子座非常小幾十像素到一百像素都很常見如果不專門優化小目標檢測能力模型很容易漏掉大量真實目標。所以這個項目的數據集設計和訓練策略一切都是圍繞“少漏檢、少誤檢”來做的而不是追求把某個類別的AP刷到99%。2. 數據集構建與預處理2.1 數據來源與采集策略冬蟲夏草的數據集不像車牌、行人那么爛大街公開的現成數據集很少所以很大概率需要自己動手攢。根據我做類似農作物檢測項目的經驗數據來源可以分三條路按優先級排列。第一條路是實地采集也就是帶著相機或手機到種植基地、產區草甸去拍。這是最理想的方式因為拍到的圖像和實際部署場景完全一致沒有域偏移問題。拍攝時要注意幾個細節盡量覆蓋不同時間段因為早晨和傍晚的光線角度、色溫完全不一樣要拍不同天氣條件晴天、陰天、雨后蟲草出土后帶著水珠的樣子和干燥時差別很大還要覆蓋不同背景純草地、碎石地、枯草密集地都要有。拍攝高度和角度也要模擬實際使用場景如果最終打算用無人機俯拍那訓練數據就不要大量使用平視角度拍攝的圖。第二條路是整理歷史照片。很多產區的研究者、收購商手里都有大量歷史照片雖然可能沒有針對檢測任務做過標注但作為檢測任務的原始素材非常合適。我建議在動手標注之前先建一個簡單的素材池把同角度、同光線、同背景的相似照片去重避免模型過擬合到重復背景。第三條路是網絡公開圖片。這個只能作為補充因為公開圖片的版權、分辨率、拍攝角度差異太大而且能搜到的蟲草特寫圖大多是大目標、清晰背景跟實際野外場景差距很大。如果非要用只能作為增加背景多樣性的輔助不能作為主力數據。我以自己做的這套數據為例總共1080張圖其中實地采集約700張歷史資料整理300張網絡補充80張。數量不算多但單類別檢測本身數據需求就不像多類別那么高關鍵是質量。2.2 標注工具與YOLO格式要點標注工具我用的是LabelImg開源免費操作簡單安裝后直接就能用。用pip安裝就行pip install labelImg然后命令行啟動labelImg在工具里把圖片文件夾和預定義的類別文件路徑配置好類別文件就是一個txt每一行寫一個類別名。單類別項目就一行dongchongxiacao標注界面里用矩形框把蟲草的子座框出來。這里有個非常關鍵的實操經驗框的范圍寧小勿大。冬蟲夏草的檢測重點通常放在子座也就是露出地面的那一段真菌結構上不要把周圍的泥土、小草、雜物包進框里。因為框得太大會讓模型學到“蟲草一堆背景區域一個小目標”的錯誤映射推理時誤檢率會直線上升。標注完成后LabelImg默認會生成VOC格式的XML文件需要轉成YOLO格式的txt。YOLO格式的核心是每張圖對應一個txt文件每一行代表一個目標格式是class_id center_x center_y width height注意這里的四個坐標值全部是歸一化到0-1之間的用像素值除以圖像寬高得到。舉個例子一張1920x1080的圖中一個目標框左上角在(500, 300)右下角在(800, 700)那么img_w, img_h 1920, 1080 x1, y1, x2, y2 500, 300, 800, 700 cx ((x1 x2) / 2) / img_w cy ((y1 y2) / 2) / img_h w (x2 - x1) / img_w h (y2 - y1) / img_h如果自己寫轉換腳本這段邏輯是核心。還要注意YOLO格式的txt文件名必須和圖片文件名完全一致包括擴展名前面的部分且放在對應的labels目錄下否則訓練時數據加載會報錯。2.3 數據增強策略與樣本平衡數據增強對于蟲草這類小目標、復雜背景的任務極其重要。YOLOv5內置了Mosaic增強、隨機翻轉、HSV色域增強、隨機仿射變換等這些在訓練時默認會啟用。但對于蟲草場景我建議做幾個針對性調整。首先是Mosaic增強的拼圖策略。Mosaic會把4張圖縮放到小尺寸再拼接好處是增加了小目標的數量壞處是如果原圖本身分辨率不高縮放后目標會變得更加模糊。所以我建議在數據準備階段就不要把原圖壓得太小YOLOv5在訓練時會把圖resize到輸入尺寸比如640x640如果原圖本身分辨率不足目標信噪比會急劇下降。我自己的經驗是原圖分辨率至少保持1280以上訓練時imgsz可以設成640讓模型在縮放過程中學到更多細節。其次是翻轉增強。YOLOv5默認的翻轉參數是隨機水平翻轉0.5也就是一半概率左右翻轉。蟲草的生長方向雖然天然隨機的但如果你在實際部署時對方向有明確要求比如明確要檢測“從土里向上生長”的狀態翻轉過狠會讓模型對方向不敏感。我在這個項目里把水平翻轉概率降到0.25垂直翻轉直接關閉因為垂直翻轉會讓蟲草變成“倒掛”狀態實際場景不會出現學了反而干擾。第三是HSV色域增強。蟲草和背景的顏色差異很微妙過度調整飽和度、色相會讓模型學到錯誤的顏色特征。YOLOv5默認的hsv_h、hsv_s、hsv_v參數是0.015、0.7、0.4對通用任務合適但對蟲草這種低對比度目標我建議把hsv_s降到0.3左右把hsv_v保持0.4讓模型更關注形狀和紋理特征而不是死記顏色。數據集規模不夠時還可以用離線增強的方式擴充樣本比如旋轉90度、180度、270度對蟲草這種無方向性目標其實沒毛病以及加入高斯噪聲、輕微模糊模擬不同天氣條件下拍攝的效果。但要記住一個原則增強是為了模擬真實分布不是為了編造不存在的場景。2.4 數據集目錄結構標準的YOLOv5數據集目錄結構如下dataset/ ├── images/ │ ├── train/ │ ├── val/ │ └── test/ ├── labels/ │ ├── train/ │ ├── val/ │ └── test/ └── dongchongxiacao.yaml其中images和labels必須嚴格對應train、val的比例按8:1:1或9:1來分都可以。單類別任務數據量本身不大我建議驗證集比例稍微高一些比如15%這樣評估指標更可信。劃分的時候一定注意同一次拍攝的連續幀照片不要同時出現在訓練集和驗證集里不然驗證集結果會虛高。我習慣按文件名前綴或目錄來劃分而不是隨機抽這樣更貼近真實場景。yaml配置文件內容大概是這樣的train: dataset/images/train val: dataset/images/val test: dataset/images/test nc: 1 names: [dongchongxiacao]路徑建議用相對路徑這樣整個項目目錄拷到別的機器上不用改配置。yaml文件里的換行、空格縮進要嚴格按YAML語法一個空格錯位都會報錯。3. 環境配置與訓練關鍵步驟3.1 YOLOv5環境安裝環境安裝這塊網上教程五花八門我直接說一套最穩的流程。先創建Python虛擬環境推薦用condaconda create -n yolov5 python3.8 conda activate yolov5然后克隆YOLOv5倉庫并安裝依賴git clone https://github.com/ultralytics/yolov5.git cd yolov5 pip install -r requirements.txtrequirements.txt會裝torch、torchvision、opencv-python、numpy、matplotlib等一堆依賴。需要注意這里默認裝的是CPU版torch如果你有NVIDIA GPU需要先裝對應CUDA版本的torch再跑requirements。建議先單獨裝pip install torch torchvision --index-url https://download.pytorch.org/whl/cu118再執行pip install -r requirements.txt這樣能避免依賴順序問題。裝完之后先跑一個最簡單的測試python detect.py --weights yolov5s.pt --source data/images/bus.jpg如果順利輸出結果圖說明環境通了。如果卡在下載權重文件那一步就手動去下載yolov5s.pt放到項目根目錄。權重文件名必須嚴格匹配大小寫都不能錯。3.2 數據配置文件與訓練啟動環境就緒后把前面準備好的dataset目錄和yaml配置文件放到YOLOv5項目同級目錄下。訓練命令是python train.py --img 640 --batch 16 --epochs 200 --data dongchongxiacao.yaml --weights yolov5s.pt --name dongchong_test逐項解釋一下--img是輸入圖像尺寸640是默認值如果你的顯存夠比如12G以上可以調成960小目標檢測效果會明顯提升--batch是批大小16在8G顯存下是安全的如果爆顯存就降到8--epochs是訓練輪數單類別任務200輪完全夠再多了容易過擬合--weights是預訓練權重這里用yolov5s.pt如果你顯存很小可以用yolov5n.pt更輕量但精度會掉一點--name是訓練輸出的文件夾名YOLOv5會保存到runs/train/下。訓練過程中要盯幾個東西。第一個是loss曲線YOLOv5的輸出里box_loss、obj_loss、cls_loss三條曲線單類別任務主要關注box_loss和obj_loss。正常情況是前50輪快速下降之后緩慢收斂如果曲線一路走平或者反彈說明有問題下面排查章節詳細說。第二個是mAP曲線每10輪會自動在驗證集上評估一次mAP0.5一般到0.85以上就算能用蟲草這種難檢測的小目標0.8以上已經算不錯了。3.3 超參數調整與實戰心得YOLOv5自帶一個超參數文件data/hyps/hyp.scratch-low.yaml默認值對通用任務比較穩。但蟲草檢測有幾個參數值得動一動。一個是錨框anchor。YOLOv5默認的anchor是在COCO數據集聚類出來的對蟲草這種小目標來說偏大。如果你在訓練日志里看到某些anchor匹配率很低YOLOv5會自動重聚類所以一般不用手動改但為了保險可以在訓練前用YOLOv5自帶的聚類腳本對標注框做一次分析。方法不復雜本質是用K-means統計所有標注框的長寬分布。蟲草的目標框特點是細長、瘦高子座是長的跟COCO里那些方形目標差異很大。建議訓練時開啟--multi-scale參數讓模型適應不同尺度的目標。另一個是正負樣本匹配的iou閾值。YOLOv5低版本用的是single anchor匹配策略新版本改成動態分配。如果想調可以在模型配置文件里改anchor_t默認4.0這個值越大允許預測框偏離真實框的程度越大對召回率有幫助但會犧牲一些精度。單類別任務我建議適度調高比如設成4.5因為蟲草目標小、形狀細長太嚴格的正樣本匹配會讓模型學不到東西。還有一個非常容易被忽略的參數--workers。這個參數控制數據加載的線程數Windows下默認0Linux下可以設成4或8。數據加載速度跟不上GPU時訓練會一直等數據GPU利用率上不去看起來像模型壞了一樣實際是IO瓶頸。3.4 權重文件解讀與版本管理訓練結束后runs/train/dongchong_test/weights/目錄下會有兩個文件best.pt和last.pt。這兩個文件看似差不多實際用途完全不同。best.pt是整個訓練過程中在驗證集上表現最好的權重也是我們日常推理、部署要用的那個。last.pt是最后一個epoch的權重主要用于中斷后恢復訓練或者你想繼續在前一次訓練結果的基礎上接著跑。千萬別把它們搞混了很多人圖省事直接用last.pt部署結果精度明顯偏低。權重文件用起來有幾個細節要注意。第一best.pt是包含完整的模型結構、優化器狀態和訓練配置的文件比較大yolov5s大約15M如果只是做推理可以在detect.py里正常加載但如果是部署到生產環境建議用export.py先轉成onnx或TorchScript格式體積更小、加載更快。第二權重文件的版本和代碼版本必須匹配。用YOLOv6.0的代碼跑出來的權重拿到YOLOv5v5.0的代碼里直接推理大概率報錯或者結果異常。我在本地會用一個簡單的腳本管理多個項目的權重文件目錄結構按項目分weights/ ├── dongchong/ │ ├── best.pt │ ├── last.pt │ └── onnx/ │ └── best.onnx這樣每次訓練成果不會互相覆蓋也能快速回溯。4. 模型評估與推理部署實踐4.1 評估指標怎么看訓練完之后runs/train/dongchong_test/下會有results.png里面畫了所有指標曲線。單類別任務重點看四個Precision精確率、Recall召回率、mAP0.5、mAP0.5:0.95。在蟲草檢測場景里Recall比Precision重要。這個邏輯跟工業質檢剛好相反質檢里把良品誤判成次品會增加人工復檢成本但蟲草檢測如果漏檢Recall低意味著實際有蟲草的地方沒檢測出來統計密度或計數就會偏低這直接導致數據失真。所以訓練階段如果發現Precision和Recall有矛盾優先照顧Recall。YOLOv5在驗證時輸出的PR曲線圖會顯示置信度閾值與Precision/Recall的平衡關系。默認置信度閾值是0.25如果你發現推理時漏檢多可以把這個值降到0.15甚至0.1如果誤檢多就往上調到0.4。這個調參邏輯后面推理部分還會詳細說。一個容易踩的坑mAP0.5:0.95這個指標在蟲草這種小目標、細長形狀的任務上通常不會好看可能只有0.3-0.4這是正常的。因為這個IoU閾值范圍太嚴格蟲草的框稍微偏一點IoU就掉得厲害。不要單純因為mAP0.5:0.95不高就認為模型不行還是要看實際推理效果。4.2 推理參數優化推理用detect.py基本命令python detect.py --weights runs/train/dongchong_test/weights/best.pt --source test_images/ --conf 0.25 --iou 0.45 --img 640--conf是置信度閾值--iou是NMS的IoU閾值。實際調參經驗是蟲草檢測的置信度閾值不要設太高因為小目標、低對比度目標的置信度天然偏低。我實測下來0.15-0.2這個區間的置信度閾值能在漏檢和誤檢之間找到比較好的平衡點。NMS的iou閾值保持在0.45-0.5就行蟲草目標之間基本不會互相重疊。如果檢測的是視頻或實時攝像頭流還要注意--vid-stride參數默認是1也就是逐幀檢測。野外拍攝的視頻如果幀率很高比如30fps相鄰幀內容幾乎不變可以調成2或3省一半算力還不漏目標。代碼層面如果想在推理時順便輸出目標的數量可以在detect.py的輸出循環里加幾行判斷統計每個檢測結果里框的數量。這個功能在蟲草密度統計場景特別實用。4.3 邊緣設備部署的思路如果最終要部署在Jetson、RK3588這類邊緣設備上做實時檢測建議提前把權重轉成TensorRT或RKNN格式。YOLOv5自帶的export.py支持onnx導出python export.py --weights best.pt --include onnx --opset 11轉出來的onnx可以接著用TensorRT的trtexec工具優化或者轉成RKNN。這里有個重要提醒邊緣設備上的量化對細長小目標不友好。蟲草目標本身的像素面積小INT8量化后特征丟失嚴重很多目標就檢測不到了。如果邊緣設備推理精度掉得厲害優先考慮FP16而不是INT8或者干脆用FP32雖然慢一點但保精度。部署時還有一個很容易忽略的點輸入分辨率要和訓練時保持一致。如果訓練用640推理時為了提高速度改成320小目標會大量漏檢。如果確實需要提速建議改batch size或換輕量主干而不是降低輸入分辨率。5. 常見問題與排查技巧實錄5.1 訓練不收斂或loss震蕩這個現象在蟲草項目里很常見因為目標小、正負樣本極度不平衡。首先要確認一個關鍵點是不是數據標注出了問題。我遇到過好幾次訓練loss一直降不下去打開標注文件一看坐標歸一化做錯了有一半目標框的cx、cy超過1模型根本學不到正確位置。如果確認標注沒問題再檢查訓練集和驗證集是不是有重復。前面說過連續幀照片如果同時進訓練集和驗證集驗證集的loss會很低但推理時表現差這是典型的“假收斂”。另外數據太少也會導致loss震蕩單類別任務至少要有500張有效圖再多就穩很多。超參數方面如果前50輪loss完全沒有下降趨勢嘗試把--lr0初始學習率從默認的0.01降到0.001。蟲草這種難分類任務學習率太大容易在loss曲面震蕩小一點反而收斂更穩。5.2 CUDA顯存不足顯存不足是新手遇到最多的報錯英文提示通常是CUDA out of memory。最直接的解決辦法是降低--batch從16降到8再降到4直到能跑起來。但要注意batch太小導致梯度估計不準訓練會不穩定。我建議優先降低--img尺寸從640降到512或480這樣顯存占用下降非常明顯同時小目標性能損失不算太大。如果batch和img都不想動就開梯度累積可以通過在訓練腳本里設置--accumulate參數YOLOv5新版沒有直接暴露的CLI參數需要改代碼或在hyp里調相當于每多步積累一次梯度再更新效果近似于變相擴大batch。5.3 過擬合特征蟲草數據集如果采集場景單一模型很容易過擬合。表現形式是訓練集loss很低但驗證集loss反彈或者驗證集mAP遲遲上不去。解決辦法有兩個方向。一是嚴格劃分數據集保證訓練集和驗證集的拍攝場景不重疊二是加大數據增強強度把Mosaic的縮放范圍調大、開啟copy_paste增強YOLOv5新版支持讓模型見過更多樣的輸入。5.4 推理誤檢、漏檢調整思路把常見問題整理成一張速查表方便直接對著排查。現象可能原因解決方式漏檢多該框的沒框置信度閾值偏高把--conf從0.25降到0.15漏檢多且小目標完全看不見輸入分辨率太低把--img從640提高到960誤檢多把草、石頭框出來置信度閾值偏低把--conf從0.15升到0.35誤檢多且框偏大標注框畫得太大重新檢查并修改部分標注后重訓驗證集AP高但新圖效果差訓練集和部署場景差異大補充部署場景的數據或做遷移微調輸出結果閃爍視頻檢測幀間置信度波動結合跟蹤邏輯或提高幀推理穩定性5.5 幾個容易忽視的細節這些細節是做完整個項目之后回頭看最想讓當初的自己提前知道的。第一不要迷信訓練輪數多。單類別蟲草檢測150-200輪足夠再多就是浪費算力和顯存。如果發現100輪以后mAP已經開始走平可以直接提前停YOLOv5自帶早停機制默認patience是100也可以手動設小一點。第二權重文件損壞問題。從網上下載預訓練權重時如果文件下載不全訓練時可能不報錯但loss亂跳。遇到訓練異常先把權重文件刪掉重新下載排除這個最簡單的可能性。第三配置文件的YAML格式陷阱。YOLOv5的data yaml里冒號后面一定要有空格train: dataset/images/train這種寫法如果寫成train:dataset/images/train會直接報錯而且報錯信息還很不直觀新人容易在這里卡一個小時。第四標簽文件和圖片數量必須一一對應。有些圖是沒有目標的正確的做法是保留一個內容的txt文件0字節千萬不要把沒有目標的圖直接刪掉或者不生成空txt。YOLOv5在加載數據時會校驗數量對不上訓練就會中斷。第五多尺度訓練與推理分辨率的關系。如果訓練時用了--multi-scale模型在各尺度下都能工作但推理時最好還是用訓練時最常用的主尺度通常是640這樣效果最穩定。最后再分享一個小技巧當我對一個權重文件的效果不確定時會專門挑幾張最難的圖比如目標極小、背景極亂、光線很差的單獨做測試而不是只看驗證集mAP。因為驗證集是數據集劃分出來的跟訓練集同分布在這個數據集上效果好不代表真實現場效果好。用最難樣本做一個“壓力測試”這個權重能不能用心里馬上就有數了。這個項目做完最大的感受是目標檢測項目的重心往往不在模型本身而在數據和細節上。YOLOv5的代碼和權重都是現成的真正決定蟲草檢測效果好壞的是有沒有一張干凈的、標注合理的、分布貼近真實場景的數據集以及遇到了loss不降、顯存爆掉、識別不準這些問題時能不能快速定位到癥結。把這套流程完整跑一遍后續再換其他單類別檢測項目基本就是復制粘貼再微調的事。本文還有配套的精品資源點擊獲取