檢測(cè):從數(shù)據(jù)采集到部署的完整實(shí)戰(zhàn))
簡(jiǎn)介基于YOLOv5的豬臉目標(biāo)檢測(cè)模型與代碼適合畜牧智能化管理、計(jì)算機(jī)視覺(jué)初學(xué)者及智慧農(nóng)業(yè)開(kāi)發(fā)者使用可用于豬只個(gè)體識(shí)別、健康監(jiān)測(cè)等場(chǎng)景。整個(gè)壓縮包共236個(gè)文件約70.75MB以Python腳本、YAML配置、Jupyter Notebook、預(yù)訓(xùn)練權(quán)重.pt和示例圖片為主同時(shí)也包含Dockerfile、Git配置等工程化文件便于直接訓(xùn)練、推理或二次開(kāi)發(fā)。目前已有1289人學(xué)習(xí)下載資源內(nèi)提供best_yolo_tiny.pt與best.pt兩套權(quán)重前者為輕量版速度更快適合算力受限環(huán)境后者為標(biāo)準(zhǔn)版精度更優(yōu)。main.ipynb引導(dǎo)完成從環(huán)境設(shè)置、模型加載到數(shù)據(jù)預(yù)處理、目標(biāo)檢測(cè)與結(jié)果可視化的完整流程并附帶測(cè)試圖片供快速驗(yàn)證項(xiàng)目中還引入Focal Loss解決類(lèi)別不平衡配合數(shù)據(jù)增強(qiáng)與多尺度訓(xùn)練提升檢測(cè)泛化能力是學(xué)習(xí)YOLOv5目標(biāo)檢測(cè)和落地豬臉識(shí)別的不錯(cuò)起點(diǎn)。代碼結(jié)構(gòu)清晰支持自定義數(shù)據(jù)集進(jìn)行模型微調(diào)可直接替換為自己的豬臉圖片進(jìn)行訓(xùn)練驗(yàn)證也可作為課程設(shè)計(jì)或科研項(xiàng)目的參照實(shí)現(xiàn)同時(shí)附帶的文本說(shuō)明可幫助快速定位所需內(nèi)容便于直接上手無(wú)論是入門(mén)學(xué)習(xí)還是工程落地都有參考價(jià)值。 養(yǎng)了上千頭豬怎么一眼認(rèn)出每一頭這個(gè)問(wèn)題的答案聽(tīng)起來(lái)有點(diǎn)魔幻但確實(shí)是現(xiàn)代規(guī)模化養(yǎng)殖里最頭疼的剛需。傳統(tǒng)做法是給豬打耳標(biāo)可耳標(biāo)容易脫落、戴久了還可能引發(fā)耳部感染豬打架時(shí)也經(jīng)常把耳標(biāo)扯掉補(bǔ)打一次又是一筆人力成本。我當(dāng)時(shí)接到這個(gè)需求第一反應(yīng)就是豬臉和人臉一樣特征夠獨(dú)特能不能直接用目標(biāo)檢測(cè)把豬臉從畫(huà)面里撈出來(lái)于是就有了這個(gè)項(xiàng)目——基于YOLOv5的豬臉目標(biāo)檢測(cè)模型與代碼。這個(gè)項(xiàng)目解決的并不是“認(rèn)出這頭豬是誰(shuí)”而是更前置的一步在復(fù)雜的欄舍場(chǎng)景里先把每一張豬臉的位置和邊界框找出來(lái)。說(shuō)白了目標(biāo)檢測(cè)負(fù)責(zé)“定位”后續(xù)的身份識(shí)別再基于檢測(cè)框去做特征比對(duì)。整個(gè)項(xiàng)目從數(shù)據(jù)采集、標(biāo)注、訓(xùn)練到部署全程走通適合正在做農(nóng)業(yè)視覺(jué)、智慧養(yǎng)殖方向的開(kāi)發(fā)者參考也適合想入門(mén)YOLOv5但不想只跑官方Coco Demo的初學(xué)者照著這份實(shí)操路徑能少踩不少坑。1. 項(xiàng)目整體設(shè)計(jì)與方案選型1.1 為什么選擇YOLOv5而不是其他檢測(cè)框架先說(shuō)結(jié)論在這個(gè)場(chǎng)景下YOLOv5是性價(jià)比最高的選擇沒(méi)有之一。養(yǎng)豬場(chǎng)的實(shí)際環(huán)境不是實(shí)驗(yàn)室拍攝設(shè)備可能只是一臺(tái)500塊錢(qián)的魚(yú)眼攝像頭計(jì)算設(shè)備可能是一塊Jetson Nano或者一臺(tái)普通工控機(jī)。這就要求檢測(cè)模型必須在算力有限的情況下保持足夠的幀率YOLOv5作為單階段檢測(cè)器的代表在速度和精度之間拿捏得相當(dāng)均衡。對(duì)比Faster R-CNN這類(lèi)雙階段檢測(cè)器雖然精度理論上更高但推理速度根本跑不滿實(shí)時(shí)視頻流。而YOLOv8、YOLOX這些新模型雖然更強(qiáng)但當(dāng)時(shí)生態(tài)和第三方輔助腳本遠(yuǎn)沒(méi)有YOLOv5成熟。還有個(gè)關(guān)鍵點(diǎn)YOLOv5的Ultralytics倉(cāng)庫(kù)把訓(xùn)練、驗(yàn)證、導(dǎo)出、部署的鏈路做得極其完整幾乎開(kāi)箱即用。項(xiàng)目里大量時(shí)間應(yīng)該留給數(shù)據(jù)整理和調(diào)參而不是折騰框架本身。1.2 任務(wù)邊界與模型結(jié)構(gòu)的適配這個(gè)項(xiàng)目我只做目標(biāo)檢測(cè)不做分類(lèi)學(xué)意義上的個(gè)體識(shí)別。為什么要把邊界卡在這里因?yàn)樨i臉檢測(cè)是整個(gè)視覺(jué)方案的地基檢測(cè)框位置準(zhǔn)不準(zhǔn)直接影響后續(xù)所有環(huán)節(jié)。比如后續(xù)要做個(gè)體識(shí)別如果檢測(cè)框把兩只豬的耳朵都框進(jìn)去了特征提取就會(huì)串味識(shí)別準(zhǔn)確率直接崩盤(pán)。YOLOv5的主干網(wǎng)絡(luò)CSPDarknet能夠提取全局和局部特征頸部PANet結(jié)構(gòu)擅長(zhǎng)融合不同尺度的特征圖這讓它在類(lèi)似豬臉這種“紋理細(xì)節(jié)多但目標(biāo)形狀偏圓形”的檢測(cè)任務(wù)里表現(xiàn)不錯(cuò)??紤]到豬欄場(chǎng)景經(jīng)常出現(xiàn)擁擠、遮擋、逆光我最終選用了YOLOv5s和YOLOv5m兩個(gè)版本對(duì)比s版跑起來(lái)輕快m版準(zhǔn)確率更高后面訓(xùn)練環(huán)節(jié)我會(huì)給出具體的評(píng)測(cè)數(shù)據(jù)。2. 數(shù)據(jù)集構(gòu)建與預(yù)處理方案2.1 數(shù)據(jù)來(lái)源與采集要點(diǎn)這可能是整個(gè)項(xiàng)目里最耗時(shí)間的環(huán)節(jié)。公開(kāi)數(shù)據(jù)集幾乎沒(méi)有現(xiàn)成的豬臉檢測(cè)數(shù)據(jù)所以只能自采。我前后協(xié)調(diào)了三個(gè)豬場(chǎng)在產(chǎn)房、保育欄、育肥欄分別架設(shè)攝像頭連續(xù)錄制了一周的視頻素材然后按幀抽圖最后篩出兩萬(wàn)多張有效圖片。采集中有幾個(gè)很實(shí)在的細(xì)節(jié)。第一不要只在白天光線好的時(shí)候拍凌晨和傍晚欄舍里的昏暗光線、燈光直射造成的過(guò)曝這些都要覆蓋否則模型到了真實(shí)環(huán)境馬上就露餡。第二盡量覆蓋多品種豬只大白、長(zhǎng)白、杜洛克的面部特征差異還挺明顯的。第三視頻抽幀時(shí)不要連續(xù)抽間隔個(gè)十幾幀再取一張否則相鄰幀太相似訓(xùn)練集和驗(yàn)證集之間會(huì)發(fā)生嚴(yán)重的數(shù)據(jù)泄漏。2.2 標(biāo)注工具與格式轉(zhuǎn)換標(biāo)注用的是LabelImg畫(huà)矩形框?qū)С龀蒝OC格式的XML文件。這里有一個(gè)YOLOv5特有的坑訓(xùn)練時(shí)需要的是TXT格式的標(biāo)注文件每行內(nèi)容是“類(lèi)別ID 中心點(diǎn)x坐標(biāo) 中心點(diǎn)y坐標(biāo) 框?qū)?框高”而且坐標(biāo)必須是除以圖片寬高后的歸一化數(shù)值。我自己寫(xiě)過(guò)一段Python腳本做格式轉(zhuǎn)換核心邏輯也不復(fù)雜讀XML拿到bndbox的四個(gè)值計(jì)算出中心坐標(biāo)和寬高再分別除以圖片尺寸。類(lèi)別ID這里特別注意如果只有“pig_face”一個(gè)類(lèi)別ID就是0。如果你后續(xù)要擴(kuò)展出耳朵、軀干等其他部位ID的順序一定要和data yaml里的names列表保持一致不然訓(xùn)練出來(lái)的模型預(yù)測(cè)結(jié)果會(huì)驢唇不對(duì)馬嘴。2.3 數(shù)據(jù)增強(qiáng)策略與樣本劃分豬臉檢測(cè)場(chǎng)景里數(shù)據(jù)增強(qiáng)不是錦上添花而是模型能不能泛化的關(guān)鍵。我用的增強(qiáng)組合包括隨機(jī)水平翻轉(zhuǎn)、±30度的隨機(jī)旋轉(zhuǎn)、亮度對(duì)比度擾動(dòng)模擬不同光線、隨機(jī)裁剪和縮放以及一點(diǎn)輕微的模糊處理。YOLOv5自帶的Mosaic增強(qiáng)很猛相當(dāng)于把四張圖拼成一張訓(xùn)練小目標(biāo)檢測(cè)能力提升明顯我推薦把Mosaic開(kāi)啟概率保持在1.0只在最后十幾個(gè)epoch可以關(guān)閉讓模型穩(wěn)定收斂。樣本劃分這塊我要重點(diǎn)提醒一定要按豬只個(gè)體來(lái)劃分而不是簡(jiǎn)單隨機(jī)打亂。我一開(kāi)始直接把所有圖片隨機(jī)分成訓(xùn)練集和驗(yàn)證集結(jié)果模型效果虛高落到現(xiàn)實(shí)場(chǎng)景就垮了。原因很簡(jiǎn)單同一頭豬的視頻幀高度相似模型等于提前見(jiàn)過(guò)驗(yàn)證集的豬了。后來(lái)改成按拍攝批次劃分確保訓(xùn)練集和驗(yàn)證集里不出現(xiàn)同一頭豬這個(gè)評(píng)估結(jié)果才真正可信。最終數(shù)據(jù)比例在811左右訓(xùn)練集一萬(wàn)六千多張驗(yàn)證集和測(cè)試集各兩千張上下。3. 模型訓(xùn)練流程與評(píng)價(jià)指標(biāo)解讀3.1 環(huán)境配置與硬件要求很多新手上來(lái)就問(wèn)目標(biāo)檢測(cè)訓(xùn)練需要用到GPU嗎我的回答是如果你手里只有CPU可以跑通流程但幾百個(gè)epoch可能要跑上好幾天而且是CPU滿載、風(fēng)扇轟鳴的那種折磨。訓(xùn)練YOLOv5確實(shí)需要GPU哪怕是一張二手GTX 1660 Super都能明顯提升體驗(yàn)有條件的話RTX 3060 12G顯存基本上能勝任絕大多數(shù)訓(xùn)練任務(wù)12G顯存意味著可以比較舒服地開(kāi)batch size 16配合YOLOv5s。我自己用的是RTX 3090訓(xùn)練YOLOv5s跑100個(gè)epoch大約三個(gè)半小時(shí)如果你是RTX 3060時(shí)間翻倍也還能接受。環(huán)境方面建議用PyTorch的官方Docker鏡像或者M(jìn)iniconda建虛擬環(huán)境CUDA版本和PyTorch版本一定要匹配最常見(jiàn)的坑就是裝了最新版PyTorch但顯卡驅(qū)動(dòng)太老導(dǎo)致CUDA initialization error。clone Ultralytics的YOLOv5倉(cāng)庫(kù)后執(zhí)行pip install -r requirements.txt就能裝齊依賴。3.2 數(shù)據(jù)配置YAML詳解YOLOv5的數(shù)據(jù)配置走的是YAML文件這個(gè)文件是訓(xùn)練入口的眼睛路徑錯(cuò)了訓(xùn)練直接報(bào)錯(cuò)或者靜默使用錯(cuò)誤數(shù)據(jù)。實(shí)際使用時(shí)train和val字段直接寫(xiě)絕對(duì)路徑最省心相對(duì)路徑經(jīng)常因?yàn)楫?dāng)前目錄不同而踩坑。nc是類(lèi)別總數(shù)這里是1names列表里的名稱(chēng)必須和標(biāo)注時(shí)的類(lèi)別一一對(duì)應(yīng)比如我這里就是names: [pig_face]。# pig_face.yaml train: /data/pigface/train/images val: /data/pigface/val/images test: /data/pigface/test/images nc: 1 names: [pig_face]這個(gè)文件放好后啟動(dòng)訓(xùn)練的命令大概是這樣的。weights參數(shù)建議從官方預(yù)訓(xùn)練權(quán)重開(kāi)始遷移學(xué)習(xí)不要從頭訓(xùn)練coco數(shù)據(jù)集上的通用特征對(duì)豬臉檢測(cè)有很大幫助。img size用640起步后面可以嘗試1280來(lái)提升小目標(biāo)檢測(cè)能力。python train.py --data pig_face.yaml --weights yolov5s.pt --img 640 --batch-size 16 --epochs 100 --name pigface_exp3.3 訓(xùn)練過(guò)程中的評(píng)價(jià)標(biāo)準(zhǔn)解讀訓(xùn)練日志里最需要盯的指標(biāo)不是loss而是mAP。這里把目標(biāo)檢測(cè)訓(xùn)練過(guò)程中評(píng)價(jià)標(biāo)準(zhǔn)一次說(shuō)清楚。先記住兩個(gè)基礎(chǔ)概念Precision是查準(zhǔn)率模型預(yù)測(cè)的框里真的含有豬臉的比例懲罰的是誤檢Recall是查全率所有真豬臉里被模型撈上來(lái)的比例懲罰的是漏檢。這兩個(gè)指標(biāo)天然存在矛盾提高閾值減少了誤檢但會(huì)漏掉一些模糊的目標(biāo)。mAP則是把不同置信度閾值下的Precision和Recall串起來(lái)算PR曲線下的面積是綜合衡量模型性能的金標(biāo)準(zhǔn)。YOLOv5訓(xùn)練時(shí)會(huì)輸出兩組最關(guān)鍵的指標(biāo)mAP0.5和mAP0.5:0.95。前者是IoU閾值為0.5時(shí)的平均精度IoU就是預(yù)測(cè)框和真實(shí)框的交并比大于0.5就算檢測(cè)正確這個(gè)指標(biāo)比較寬松適合粗粒度評(píng)估。后者是IoU從0.5到0.95每隔0.05取一個(gè)閾值共10個(gè)閾值下的mAP平均值極其嚴(yán)格要求預(yù)測(cè)框和真實(shí)框高度重合適合精確定位類(lèi)的任務(wù)。我的豬臉模型最終mAP0.5到0.967mAP0.5:0.95大約是0.812后者更說(shuō)明這個(gè)模型在實(shí)際部署時(shí)的定位精度夠用。另外關(guān)注一下PR曲線如果曲線右上角的面積大說(shuō)明模型在保持高召回的同時(shí)誤檢也控制得好。訓(xùn)練結(jié)束后跑一下驗(yàn)證集用下面的命令能直接輸出PR曲線、混淆矩陣這些可視化結(jié)果比只看數(shù)字直觀得多。python val.py --data pig_face.yaml --weights runs/train/pigface_exp/weights/best.pt --img 6404. 推理部署與常見(jiàn)問(wèn)題排查4.1 單張圖片與視頻流的目標(biāo)檢測(cè)推理訓(xùn)練完成后推理環(huán)節(jié)使用官方detect.py非常方便指定權(quán)重文件和圖片來(lái)源就能跑出帶檢測(cè)框的結(jié)果圖。python detect.py --source test.jpg --weights runs/train/pigface_exp/weights/best.pt --conf 0.5參數(shù)里最值得調(diào)的是--conf也就是置信度閾值。我在實(shí)際場(chǎng)景里發(fā)現(xiàn)閾值設(shè)成0.5對(duì)豬臉來(lái)說(shuō)略激進(jìn)很多被遮擋一半的豬臉會(huì)被濾掉但設(shè)成0.25又會(huì)混入不少誤檢。經(jīng)驗(yàn)值是白天光線好時(shí)用0.45夜間或者畫(huà)面模糊場(chǎng)景降到0.3。--iou參數(shù)控制NMS的抑制閾值默認(rèn)0.45通常夠用如果畫(huà)面中豬臉重疊特別密集可以調(diào)到0.3強(qiáng)制壓低冗余框。如果要想部署到邊緣設(shè)備或者接入攝像頭實(shí)時(shí)視頻流我建議導(dǎo)出成TensorRT或ONNX格式再推理。YOLOv5倉(cāng)庫(kù)自帶export.py一鍵導(dǎo)出很省事。TensorRT在Jetson平臺(tái)上能比PyTorch原生加快三倍左右是邊緣部署的首選方案。導(dǎo)出時(shí)注意--half參數(shù)開(kāi)啟FP16量化精度幾乎不掉但速度翻倍。4.2 輕量場(chǎng)景下的小目標(biāo)檢測(cè)優(yōu)化豬臉檢測(cè)有個(gè)很現(xiàn)實(shí)的難題是豬欄空間大攝像頭俯拍時(shí)遠(yuǎn)端的豬在畫(huà)面里只占很小的一塊區(qū)域這就是典型的小目標(biāo)檢測(cè)問(wèn)題。我的模型在初始版本上對(duì)小目標(biāo)召回率明顯偏低后來(lái)做了三個(gè)改進(jìn)效果立竿見(jiàn)影。第一把輸入分辨率從640提升到1280。模型能看到的細(xì)節(jié)增多了小目標(biāo)特征也保住了但對(duì)GPU顯存要求翻倍實(shí)測(cè)batch size會(huì)從16降到8訓(xùn)練時(shí)間明顯變長(zhǎng)。第二開(kāi)啟TTA測(cè)試時(shí)增強(qiáng)檢測(cè)時(shí)對(duì)圖片做多尺度推理再融合結(jié)果對(duì)低分辨率小目標(biāo)友好代價(jià)是推理速度變慢不適合實(shí)時(shí)場(chǎng)景。第三借鑒YOLOv8小目標(biāo)檢測(cè)頭的思路在頸部網(wǎng)絡(luò)增加一個(gè)針對(duì)小尺度目標(biāo)的預(yù)測(cè)頭這個(gè)改動(dòng)工作量大但效果最明顯。4.3 常見(jiàn)問(wèn)題速查表實(shí)戰(zhàn)中遇到的坑我整理成一個(gè)速查表這些都是踩過(guò)之后才長(zhǎng)記性的東西。問(wèn)題現(xiàn)象原因分析解決方案loss一直不降學(xué)習(xí)率過(guò)高、模型不收斂初始lr調(diào)到0.001配合cosine schedulermAP很低但訓(xùn)練loss正常數(shù)據(jù)集劃分泄漏或標(biāo)注框不準(zhǔn)按個(gè)體劃分?jǐn)?shù)據(jù)逐張檢查標(biāo)注質(zhì)量顯存溢出OOMbatch過(guò)大或輸入分辨率過(guò)大減小batch或開(kāi)啟--cache后降低pin_memory推理時(shí)把食槽/地面陰影誤檢成豬臉背景類(lèi)樣本太少收集困難負(fù)樣本加入訓(xùn)練集做硬負(fù)樣本挖掘夜間畫(huà)面漏檢嚴(yán)重圖像亮度太低、噪聲大訓(xùn)練時(shí)加入低光增強(qiáng)推理前做圖像增強(qiáng)預(yù)處理排查時(shí)先看訓(xùn)練集loss和驗(yàn)證集loss的差距差距大就是過(guò)擬合加大數(shù)據(jù)增強(qiáng)或者降低模型復(fù)雜度兩個(gè)loss都高就是模型容量不夠換上更大的YOLOv5m甚至YOLOv5l。4.4 模型效果與生產(chǎn)環(huán)境部署驗(yàn)證最終交付時(shí)我選了YOLOv5m作為生產(chǎn)模型原因很簡(jiǎn)單它在測(cè)試集上的mAP0.5比s版高了1.8個(gè)百分點(diǎn)而單幀推理時(shí)間只多了6毫秒在Jetson Nano上依然能跑到每秒18幀滿足實(shí)時(shí)監(jiān)控需求。實(shí)際部署到豬場(chǎng)兩個(gè)多月模型的穩(wěn)定性比我預(yù)想的好白天識(shí)別率能達(dá)到九成以上夜間配合補(bǔ)光燈之后也在八成左右。部署過(guò)程中有個(gè)意外收獲原本以為最難解決的個(gè)體重疊問(wèn)題其實(shí)通過(guò)置信度閾值動(dòng)態(tài)調(diào)整就能壓到很低。遠(yuǎn)距離的豬臉置信度天然偏低近距離的被遮擋時(shí)置信度也偏低但整體來(lái)說(shuō)誤檢數(shù)量遠(yuǎn)低于漏檢這個(gè)行為模式在養(yǎng)殖場(chǎng)景里比追求極致精度更重要誤檢可以靠后續(xù)跟蹤算法過(guò)濾漏檢就真的丟目標(biāo)了。5. 項(xiàng)目后續(xù)可以擴(kuò)展的方向整套流程跑通后豬臉檢測(cè)這個(gè)地基已經(jīng)相當(dāng)扎實(shí)后續(xù)的擴(kuò)展空間很大。最直接的方向是在檢測(cè)框基礎(chǔ)上接一個(gè)ReID模型做個(gè)體識(shí)別也就是具體到“這一頭豬是誰(shuí)”。也有人把二維檢測(cè)擴(kuò)展到三維目標(biāo)檢測(cè)通過(guò)豬臉在多個(gè)視角下的檢測(cè)框重建三維面部輪廓做體型評(píng)估。如果手頭有紅外熱成像攝像頭還可以試試多模態(tài)目標(biāo)檢測(cè)把可見(jiàn)光圖像和熱成像數(shù)據(jù)融合夜間識(shí)別效果會(huì)再上一個(gè)臺(tái)階。我個(gè)人在實(shí)際操作中最大的體會(huì)是目標(biāo)檢測(cè)項(xiàng)目難的不在模型訓(xùn)練而在數(shù)據(jù)和生產(chǎn)環(huán)境的磨合。YOLOv5的代碼足夠成熟但每一片數(shù)據(jù)都有它自己的脾氣豬臉數(shù)據(jù)不會(huì)比一般物體檢測(cè)簡(jiǎn)單——豬不配合光線不可控環(huán)境又臟又亂這才是這類(lèi)項(xiàng)目真正的考驗(yàn)。最后再分享一個(gè)小技巧訓(xùn)練過(guò)程中記得定期保存驗(yàn)證集里檢測(cè)效果差的樣本積累到一定量后手動(dòng)標(biāo)注并補(bǔ)進(jìn)訓(xùn)練集這種主動(dòng)學(xué)習(xí)式的迭代策略比一次性把數(shù)據(jù)做到兩萬(wàn)張要高效得多。本文還有配套的精品資源點(diǎn)擊獲取