據(jù)集全解析:從格式核對到訓(xùn)練部署)
簡介這是一份面向YOLOv5目標(biāo)檢測任務(wù)的頭盔檢測數(shù)據(jù)集專為安全帽佩戴識(shí)別場景設(shè)計(jì)適合從事工地、工廠、園區(qū)等人員安全監(jiān)管的開發(fā)者以及剛接觸目標(biāo)檢測的學(xué)生和研究者。數(shù)據(jù)集包含80張真實(shí)場景JPG圖像并配有80個(gè)對應(yīng)的XML標(biāo)注文件標(biāo)注了安全帽的位置與狀態(tài)類別可直接用于YOLOv5模型的訓(xùn)練、驗(yàn)證與推理測試壓縮包共160個(gè)文件整體大小僅2.86MB輕量易用方便在本地快速跑通數(shù)據(jù)加載、標(biāo)簽解析、格式轉(zhuǎn)換和模型訓(xùn)練流程。目前已有482人學(xué)習(xí)使用。對于目標(biāo)檢測入門者可以用這份數(shù)據(jù)練習(xí)從VOC格式到Y(jié)OLO格式的轉(zhuǎn)換、劃分訓(xùn)練集與驗(yàn)證集、調(diào)整錨框參數(shù)等操作對于有經(jīng)驗(yàn)的開發(fā)者也可以將其作為小規(guī)?;鶞?zhǔn)集快速驗(yàn)證檢測算法或調(diào)參效果。整體目錄結(jié)構(gòu)干凈文件名對應(yīng)清晰是一份上手門檻低、實(shí)用性強(qiáng)的頭盔檢測練習(xí)數(shù)據(jù)。1. 頭盔檢測數(shù)據(jù)集不是越多越好先弄清楚YOLOv5要什么格式做工地安全帽檢測的人應(yīng)該都有同感圖片好找標(biāo)簽難弄。這份用于YOLOv5頭盔目標(biāo)檢測的數(shù)據(jù)集不是源碼也不是模型權(quán)重而是已經(jīng)按YOLO格式整理好的圖片加標(biāo)注文件ZIP解壓后可以直接丟進(jìn)YOLOv5訓(xùn)練。我拆包后的第一反應(yīng)是標(biāo)注格式是不是規(guī)范類別編號能不能對得上train/valid劃分是不是合理。如果你正準(zhǔn)備訓(xùn)練一個(gè)頭盔佩戴檢測模型而且不想在數(shù)據(jù)清洗上耗掉兩三天這份數(shù)據(jù)集值得先下載下來摸一遍底。適合剛接觸YOLOv5的初學(xué)者也適合想快速驗(yàn)證算法效果的從業(yè)者。接下來我會(huì)從標(biāo)簽格式、訓(xùn)練流程、踩坑記錄到現(xiàn)場部署把整條鏈路拆開講清楚。2. 數(shù)據(jù)集結(jié)構(gòu)與標(biāo)簽格式先從images和labels說起拿到任何一套YOLO數(shù)據(jù)集我建議先別急著開箱訓(xùn)練。先花十分鐘把它內(nèi)部結(jié)構(gòu)摸清楚能省掉后面一堆排查時(shí)間。頭盔檢測數(shù)據(jù)集最常見的組織方式就是images和labels兩個(gè)兄弟目錄這份ZIP解壓后基本也是這個(gè)套路。2.1 ZIP解壓后的目錄長什么樣在Linux或Windows下解壓后你會(huì)看到一個(gè)類似下面的目錄結(jié)構(gòu)helmet_dataset/ ├── images/ │ ├── train/ │ │ ├── img_00001.jpg │ │ ├── img_00002.jpg │ │ └── ... │ └── valid/ │ ├── img_00100.jpg │ └── ... └── labels/ ├── train/ │ ├── img_00001.txt │ ├── img_00002.txt │ └── ... └── valid/ ├── img_00100.txt └── ...images下面分別有train和valid兩個(gè)子目錄labels與images一一對應(yīng)。這個(gè)結(jié)構(gòu)是YOLOv5官方推薦的默認(rèn)布局train.py在讀取data.yaml時(shí)會(huì)按照你指定的路徑去找圖片和標(biāo)簽所以目錄名不需要強(qiáng)制叫images和labels但保持這種約定會(huì)讓后續(xù)操作更省心。如果你看到的是純圖片加一個(gè)annotations.xml或者json文件那就得先做一步轉(zhuǎn)換。好在這份數(shù)據(jù)集已經(jīng)幫你把這步做完了。關(guān)鍵是圖片和標(biāo)簽文件必須同名同后綴除了擴(kuò)展名。比如img_00001.jpg對img_00001.txt一旦名字對不上訓(xùn)練時(shí)YOLOv5會(huì)在加載圖片后找不到對應(yīng)標(biāo)簽然后直接跳過這張圖你根本不知道少了多少樣本。2.2 labels里的TXT到底存的什么用記事本或者VS Code打開任意一個(gè)TXT文件內(nèi)容通常是這樣的0 0.5130208 0.3888889 0.1265625 0.1555556 1 0.2567708 0.6458333 0.0781250 0.1833333 2 0.7604167 0.3027778 0.1031250 0.1416667每一行代表一個(gè)目標(biāo)框由五個(gè)數(shù)字組成類別編號、歸一化中心點(diǎn)x、歸一化中心點(diǎn)y、歸一化寬、歸一化高。以第一行為例0是類別編號0.5130208表示目標(biāo)框中心點(diǎn)位于圖片寬度方向的51.3%位置0.3888889是高度方向38.9%位置后面兩個(gè)數(shù)分別是框?qū)捳紙D片寬的比例和框高占圖片高的比例。注意這里用的是歸一化坐標(biāo)不是像素坐標(biāo)。YOLOv5在訓(xùn)練時(shí)會(huì)把這些數(shù)值直接當(dāng)作真值去算損失所以它們的取值范圍必須在0到1之間。如果你看到某個(gè)值大于1或者出現(xiàn)負(fù)數(shù)那說明標(biāo)注數(shù)據(jù)有問題輕則訓(xùn)練loss異常重則訓(xùn)練直接崩潰。我會(huì)在第四章專門講怎么批量檢查這類問題。這種純文本標(biāo)簽的好處是解析簡單不需要像XML那樣一層層剝節(jié)點(diǎn)。壞處是沒有任何語義信息你光看TXT不知道0代表什么必須配合yaml里的names才能讀懂。所以千萬保管好你的類別清單一旦丟失基本等于白干。對于頭盔檢測場景類別通常分三類0代表佩戴了安全帽的頭部1代表未佩戴安全帽的頭部2代表人體或者背景干擾物。具體類別順序要以你下載的這份數(shù)據(jù)為準(zhǔn)。我拿到數(shù)據(jù)后第一時(shí)間會(huì)用腳本統(tǒng)計(jì)每個(gè)類別的數(shù)量確認(rèn)標(biāo)簽和類別編號的對應(yīng)關(guān)系而不是盲目相信變量名。因?yàn)榫W(wǎng)上流傳的某些數(shù)據(jù)集看起來是頭盔實(shí)際標(biāo)簽類別順序可能跟你想的不一樣訓(xùn)練完才發(fā)現(xiàn)模型把安全帽和頭給搞反了。2.3 train/valid劃分與數(shù)據(jù)分布YOLOv5訓(xùn)練時(shí)要求提供訓(xùn)練集和驗(yàn)證集通常建議按9:1或8:2劃分。這份數(shù)據(jù)集的train和valid已經(jīng)分好但我不建議直接拿來就訓(xùn)。先跑一個(gè)簡單的統(tǒng)計(jì)腳本看看每個(gè)類別的樣本量是否均衡以及train和valid的類別分布是否接近。# count_classes.py import os from collections import Counter label_dirs [helmet_dataset/labels/train, helmet_dataset/labels/valid] for d in label_dirs: counter Counter() for filename in os.listdir(d): if not filename.endswith(.txt): continue with open(os.path.join(d, filename), r, encodingutf-8) as f: for line in f: if line.strip(): cls int(line.strip().split()[0]) counter[cls] 1 print(d, -, dict(counter))這段腳本會(huì)分別統(tǒng)計(jì)train和valid目錄下每個(gè)類別出現(xiàn)的總次數(shù)。默認(rèn)情況下如果某個(gè)類別在訓(xùn)練集里只有幾十個(gè)框而另一個(gè)類別有幾千個(gè)框模型就會(huì)嚴(yán)重偏向多數(shù)的類別少樣本類別幾乎學(xué)不到特征。頭盔檢測的場景里最常見的是未佩戴類樣本遠(yuǎn)少于佩戴類樣本因?yàn)榇蟛糠忠曨l截圖都是佩戴整齊的工人。這時(shí)候你需要做數(shù)據(jù)增強(qiáng)、過采樣或者調(diào)整損失權(quán)重我放到第五章展開。另一個(gè)要留心的點(diǎn)是圖片分辨率。頭盔檢測的原始圖片往往來自監(jiān)控?cái)z像頭分辨率從1280x720到1920x1080不等而YOLOv5默認(rèn)會(huì)把圖片resize到640x640再訓(xùn)練。如果原圖中人臉和頭盔區(qū)域非常小比如只有二三十個(gè)像素直接resize后小目標(biāo)特征幾乎被抹掉。遇到這種情況要么用更高的輸入分辨率比如1280要么先統(tǒng)計(jì)一下標(biāo)注框的像素尺寸分布再?zèng)Q定是否切割成小塊訓(xùn)練。另外訓(xùn)練前最好再用Python快速統(tǒng)計(jì)每張圖片里標(biāo)注框的數(shù)量如果單張圖片里有超過十個(gè)框可能是密集人群場景這對模型的NMS后處理要求更高。可以適當(dāng)調(diào)高--iou-thres減少重疊框被直接抑制的概率。統(tǒng)計(jì)完這些基礎(chǔ)信息你對這份數(shù)據(jù)集的脾氣就有數(shù)了。接下來就是把它真正跑起來。3. 把數(shù)據(jù)集跑進(jìn)YOLOv5從克隆倉庫到第一次訓(xùn)練數(shù)據(jù)集本身干凈還不夠還要確保訓(xùn)練流程能跑通。YOLOv5的官方倉庫一直在更新不同版本之間接口差異不大但細(xì)節(jié)上偶爾會(huì)有坑。我的習(xí)慣是鎖版本避免過幾個(gè)月后再跑發(fā)現(xiàn)參數(shù)對不上。3.1 環(huán)境準(zhǔn)備與依賴安裝先準(zhǔn)備一個(gè)Python 3.8或3.10的環(huán)境推薦用conda隔離別把系統(tǒng)Python搞亂。conda create -n yolo5 python3.8 -y conda activate yolo5 git clone https://github.com/ultralytics/yolov5 cd yolov5 pip install -r requirements.txt這里有幾個(gè)注意點(diǎn)。第一git clone默認(rèn)拉的是master分支如果你之前跑過老版本建議用git tag固定到某個(gè)穩(wěn)定版比如v6.0或v7.0。第二requirements.txt里會(huì)自動(dòng)安裝PyTorch但PyTorch的CPU版和GPU版差異很大。如果你機(jī)器上有NVIDIA顯卡最好先手動(dòng)安裝與CUDA版本匹配的PyTorch再裝其他依賴否則pip默認(rèn)裝的CPU版會(huì)慢到懷疑人生。第三如果你在公司內(nèi)網(wǎng)pip下載超時(shí)很常見可以用-i參數(shù)指定國內(nèi)鏡像源。3.2 寫data.yaml的四個(gè)關(guān)鍵字段訓(xùn)練前必須先準(zhǔn)備一個(gè)數(shù)據(jù)集配置文件YOLOv5的train.py靠它來定位圖片路徑和類別信息。在yolov5目錄下新建helmet.yaml# helmet.yaml path: ../helmet_dataset # 數(shù)據(jù)集根目錄相對當(dāng)前yaml文件的路徑 train: images/train # 訓(xùn)練集圖片目錄相對path val: images/valid # 驗(yàn)證集圖片目錄相對path # test: 留空即可 nc: 3 # 類別數(shù)量 names: [helmet, head, person] # 類別名稱順序必須與標(biāo)簽編號一致path、train、val、nc、names是必填的五個(gè)字段。path是數(shù)據(jù)集根目錄的絕對路徑或相對路徑。如果yaml放在yolov5根目錄下path寫成絕對路徑最穩(wěn)妥比如/home/user/helmet_dataset避免相對路徑解析出錯(cuò)。train和val用相對path的路徑字符串YOLOv5會(huì)自行拼接。nc的數(shù)量必須和標(biāo)簽中出現(xiàn)的最大類別編號1相等比如標(biāo)簽里最大編號是2nc就必須寫3。names的列表順序和標(biāo)簽編號一一對應(yīng)得確保names[0]對應(yīng)編號0names[1]對應(yīng)編號1以此類推。我見過不少人在names里寫了helmet、head但實(shí)際標(biāo)簽編號0是head1是helmet訓(xùn)練出來模型永遠(yuǎn)分不清哪是哪。先用統(tǒng)計(jì)腳本確認(rèn)一下再填。3.3 啟動(dòng)訓(xùn)練的命令與參數(shù)選擇配置文件就緒后跑訓(xùn)練的命令長這樣python train.py --img 640 --batch 16 --epochs 100 --data helmet.yaml --weights yolov5s.pt --workers 4常用參數(shù)說明如下--img 640輸入圖片統(tǒng)一resize到640x640分辨率。從小目標(biāo)檢測角度提升到960或1280能提高小頭盔的召回率但顯存占用和訓(xùn)練時(shí)間會(huì)顯著增加。--batch 16批大小。顯存不足時(shí)減半顯存富余可以加到32或64。批大小太小時(shí)BN層會(huì)不穩(wěn)定導(dǎo)致loss震蕩。--epochs 100訓(xùn)練輪數(shù)。數(shù)據(jù)集小的時(shí)候可以先跑50輪看趨勢收斂良好再繼續(xù)。--weights yolov5s.pt預(yù)訓(xùn)練權(quán)重。s是small版本速度快適合驗(yàn)證。如果追求精度可以換yolov5m.pt或yolov5l.pt。--workers 4數(shù)據(jù)加載線程數(shù)CPU核數(shù)多可以適當(dāng)提高。如果你是單卡訓(xùn)練直接跑沒問題。如果顯存只有4G建議把batch降到8同時(shí)把--img降到480先跑通流程。不要一上來就追求高指標(biāo)先確認(rèn)整個(gè)鏈路沒有報(bào)錯(cuò)。訓(xùn)練過程中終端會(huì)持續(xù)輸出epoch、box_loss、obj_loss、cls_loss、mAP等指標(biāo)。正常情況loss會(huì)逐步下降mAP0.5在幾十輪后能穩(wěn)定到0.9以上數(shù)據(jù)集簡單的話。如果看到loss曲線震蕩幅度很大或者mAP一直趴在地上八成是數(shù)據(jù)或配置出了問題別急著等100輪跑完直接CtrlC去查問題。3.4 驗(yàn)證訓(xùn)練結(jié)果跑一次detect.py訓(xùn)練結(jié)束后最好的權(quán)重存放在runs/train/exp/weights/best.pt。用驗(yàn)證集里的圖片測試一下python detect.py --weights runs/train/exp/weights/best.pt --source test.jpg --conf-thres 0.25--source可以指向單張圖片、一個(gè)目錄、視頻文件或者攝像頭id。--conf-thres是置信度閾值默認(rèn)0.25低于這個(gè)值的檢測結(jié)果會(huì)被過濾。如果你想看模型對每個(gè)框的完整預(yù)測把閾值調(diào)到0.1但隨之而來的是大量誤檢就看你的實(shí)際場景權(quán)衡。檢測結(jié)果會(huì)保存到runs/detect/exp目錄下圖片上畫有預(yù)測框和類別標(biāo)簽。先拿一兩張典型驗(yàn)證集圖片看看人眼確認(rèn)一下框的位置對不對、類別標(biāo)簽是否匹配。如果歪得離譜回到數(shù)據(jù)集去查標(biāo)簽而不是盲目加訓(xùn)練輪數(shù)。4. 數(shù)據(jù)集避坑指南標(biāo)簽錯(cuò)位、類別順序與訓(xùn)練不收斂這份數(shù)據(jù)集雖然整體能用但不代表沒坑。我把最常見的幾個(gè)問題按現(xiàn)象→原因→解決整理出來每一條都是我或身邊同事踩過的希望對你有用。4.1 現(xiàn)象訓(xùn)練時(shí)loss不下降mAP一直為0原因一標(biāo)簽文件中的類別編號與yaml中的names順序不對應(yīng)。比如標(biāo)簽里0代表未佩戴頭盔但yaml里names[0]寫的是helmet。模型學(xué)到的特征和語義標(biāo)簽完全錯(cuò)位雖然訓(xùn)練loss可能下降但算mAP時(shí)按錯(cuò)誤類別匹配結(jié)果始終為0。原因二標(biāo)簽坐標(biāo)格式不是歸一化的。有些轉(zhuǎn)換工具會(huì)直接輸出像素坐標(biāo)數(shù)值動(dòng)輒幾百上千YOLOv5的損失函數(shù)在計(jì)算IoU時(shí)會(huì)得到異常值梯度爆炸導(dǎo)致loss不收斂。解決第一步先寫腳本統(tǒng)計(jì)labels/train下所有TXT里的class編號集合與yaml的nc核對。第二步檢查每行后面的四個(gè)數(shù)字是否都在0到1之間。兩類問題都會(huì)在下面這個(gè)腳本里暴露# check_labels.py import os def check_label_file(path): with open(path, r, encodingutf-8) as f: for line in f: parts line.strip().split() if len(parts) ! 5: print(f格式錯(cuò)誤: {path} - {line.strip()}) return False cls int(parts[0]) x, y, w, h map(float, parts[1:]) if not (0 cls 2): print(f類別編號越界: {path} - cls{cls}) return False if not (0 x 1 and 0 y 1 and 0 w 1 and 0 h 1): print(f坐標(biāo)越界: {path} - {line.strip()}) return False return True label_dir helmet_dataset/labels/train for fname in os.listdir(label_dir): if fname.endswith(.txt): check_label_file(os.path.join(label_dir, fname)) print(檢查完成)這個(gè)腳本很短但能擋住九成數(shù)據(jù)集問題。跑完沒輸出任何報(bào)錯(cuò)再進(jìn)訓(xùn)練。4.2 現(xiàn)象訓(xùn)練正常但檢測結(jié)果把安全帽和頭搞反原因數(shù)據(jù)集的類別定義和你預(yù)期的語義相反。有些數(shù)據(jù)集把0定義為無帽頭1定義為有帽頭而你在yaml里寫的是names: [head, helmet]。模型輸出的邏輯是對的但你在應(yīng)用層解讀時(shí)語義錯(cuò)了。解決翻翻README或原始標(biāo)注說明確認(rèn)類別含義統(tǒng)一以數(shù)據(jù)集自帶標(biāo)簽為準(zhǔn)。我一般會(huì)在訓(xùn)練前把每個(gè)類別挑幾張圖出來人工核對一遍確認(rèn)框的位置和類別語義完全一致。這個(gè)動(dòng)作只需要十分鐘卻能避免訓(xùn)練完才發(fā)現(xiàn)標(biāo)簽語義反了的災(zāi)難。4.3 現(xiàn)象訓(xùn)練過程中有大量圖片被自動(dòng)跳過原因圖片和TXT文件名不一致或者TXT文件損壞。YOLOv5在數(shù)據(jù)加載時(shí)會(huì)嘗試為每張圖片尋找同名TXT標(biāo)簽找不到就跳過該樣本終端會(huì)輸出WARNING但很多人不會(huì)仔細(xì)看。解決寫腳本對比images和labels目錄下的文件名集合找出差集。常見原因是從Windows復(fù)制到Linux時(shí)大小寫變化或者某些文件后綴大小寫不一致。補(bǔ)全缺失的標(biāo)簽或刪除無標(biāo)簽圖片保證兩個(gè)目錄完全對齊。這里我習(xí)慣用一條簡單的Python命令找出差異文件# diff_names.py import os img_dir helmet_dataset/images/train lab_dir helmet_dataset/labels/train imgs {os.path.splitext(f)[0] for f in os.listdir(img_dir) if f.endswith(.jpg)} labs {os.path.splitext(f)[0] for f in os.listdir(lab_dir) if f.endswith(.txt)} print(缺標(biāo)簽的圖片, imgs - labs) print(缺圖片的標(biāo)簽, labs - imgs)輸出為空說明兩邊對齊否則按提示補(bǔ)文件。4.4 現(xiàn)象訓(xùn)練速度極慢GPU利用率忽高忽低原因圖片尺寸差異巨大或者數(shù)據(jù)加載線程數(shù)不足。監(jiān)控?cái)z像頭截圖常見1920x1080但混入部分手機(jī)拍攝的4000x3000大圖resize耗時(shí)嚴(yán)重--workers設(shè)為0會(huì)導(dǎo)致CPU預(yù)處理成為瓶頸。解決訓(xùn)練前將所有圖片統(tǒng)一尺寸或者至少壓縮到不超過1920x1920然后用--workers 8、--cache ram參數(shù)把數(shù)據(jù)緩存進(jìn)內(nèi)存。這里給一條通用預(yù)處理命令用Python批量處理# resize_images.py import cv2 import glob for img_path in glob.glob(helmet_dataset/images/train/*.jpg): img cv2.imread(img_path) h, w img.shape[:2] if max(h, w) 1920: scale 1920 / max(h, w) img cv2.resize(img, (int(w*scale), int(h*scale))) cv2.imwrite(img_path, img) print(resized, img_path)注意如果你調(diào)整了圖片尺寸標(biāo)簽是歸一化的所以不用動(dòng)這是YOLO格式的一大優(yōu)勢。但如果你用像素坐標(biāo)的標(biāo)簽這一步會(huì)直接導(dǎo)致標(biāo)簽全部失效。5. 數(shù)據(jù)增強(qiáng)與超參數(shù)調(diào)優(yōu)把這份數(shù)據(jù)集的價(jià)值榨干數(shù)據(jù)集的樣本量通常有限直接訓(xùn)練雖然能出結(jié)果但泛化能力可能不夠。我處理頭盔檢測時(shí)會(huì)從增強(qiáng)和超參數(shù)兩個(gè)方向去挖掘。5.1 用albumentations做離線增強(qiáng)YOLOv5自帶在線增強(qiáng)比如mosaic、隨機(jī)仿射、HSV擾動(dòng)這些在訓(xùn)練時(shí)開箱即用。但自帶的增強(qiáng)對某些場景不夠用比如對頭盔這種小目標(biāo)隨機(jī)裁剪擦除、模擬雨霧效果這些高級操作需要自己補(bǔ)充。我推薦用albumentations離線生成一批增強(qiáng)樣本擴(kuò)充訓(xùn)練集。# augment.py import albumentations as A import cv2 transform A.Compose([ A.RandomBrightnessContrast(p0.5), A.HueSaturationValue(hue_shift_limit5, sat_shift_limit10, val_shift_limit10, p0.5), A.RandomFog(fog_coef_lower0.1, fog_coef_upper0.3, p0.3), A.RandomRain(slant_lower10, slant_upper30, p0.2), A.HorizontalFlip(p0.5), ], bbox_paramsA.BboxParams(formatyolo, label_fields[class_labels])) for img_name, boxes, labels in your_data_loader(): image cv2.imread(img_name) augmented transform(imageimage, bboxesboxes, class_labelslabels) # augmented[image]、augmented[bboxes]、augmented[class_labels] # 寫回新的圖片和TXT這里的關(guān)鍵是bbox_params明確指定formatyoloalbumentations會(huì)幫你把邊界框同步變換。如果用了隨機(jī)裁剪或縮放必須保證增強(qiáng)后的框坐標(biāo)仍然落在0到1范圍內(nèi)。RandomFog和RandomRain對戶外監(jiān)控場景非常有用頭盔檢測經(jīng)常遇到陰雨天氣模型能學(xué)習(xí)到霧天和雨天的紋理特征。但這兩種增強(qiáng)會(huì)改變背景同時(shí)也可能讓目標(biāo)變模糊注意控制概率和系數(shù)不要讓增強(qiáng)后的圖片看起來完全是廢圖。離線增強(qiáng)的副作用是數(shù)據(jù)量成倍增加磁盤占用和訓(xùn)練時(shí)間都會(huì)上漲。我的習(xí)慣是先增強(qiáng)1倍看看val mAP提升是否明顯不明顯再考慮加大強(qiáng)度而不是無腦把數(shù)據(jù)集翻五倍。5.2 修改hyp.scratch-low.yaml的幾個(gè)關(guān)鍵參數(shù)YOLOv5把超參數(shù)放在data/hyps/hyp.scratch-low.yaml里。默認(rèn)參數(shù)適合通用目標(biāo)檢測但頭盔場景有它自己的特點(diǎn)目標(biāo)尺寸通常中等偏小類別少背景復(fù)雜。我會(huì)重點(diǎn)調(diào)整以下這幾個(gè)lr0: 0.01 # 初始學(xué)習(xí)率 lrf: 0.1 # 最終學(xué)習(xí)率 lr0 * lrf momentum: 0.937 weight_decay: 0.0005 warmup_epochs: 3.0 warmup_momentum: 0.8 box: 0.05 # box損失權(quán)重 cls: 0.5 # 類別損失權(quán)重 mosaic: 1.0 # mosaic增強(qiáng)概率 fliplr: 0.5 # 水平翻轉(zhuǎn)概率 hsv_h: 0.015 hsv_s: 0.7 hsv_v: 0.4這里說下我的調(diào)整邏輯。頭盔檢測屬于單類別差異明顯但背景干擾多的任務(wù)box損失的權(quán)重可以適當(dāng)提高讓模型更關(guān)注框的回歸精度。cls權(quán)重維持0.5即可因?yàn)轭悇e數(shù)少且類間差異大不需要過強(qiáng)。mosaic增強(qiáng)對提升小目標(biāo)魯棒性很有用默認(rèn)1.0時(shí)每張訓(xùn)練圖都由四張圖拼接但拼接后目標(biāo)尺度變化大如果你的數(shù)據(jù)集里已經(jīng)有很多小頭盔mosaic可能讓小目標(biāo)變得更小反而難學(xué)。遇到這種情況可以把mosaic降到0.5甚至0.3同時(shí)開啟mixup 0.5。改完超參數(shù)后訓(xùn)練時(shí)通過--hyp指定python train.py --data helmet.yaml --hyp data/hyps/hyp.scratch-low.yaml --weights yolov5s.pt --epochs 100另外補(bǔ)充一個(gè)batch size與學(xué)習(xí)率的配合。YOLOv5的train.py會(huì)自動(dòng)根據(jù)batch size進(jìn)行線性縮放學(xué)習(xí)率但如果你手動(dòng)改lr0要注意batch變化的影響。常規(guī)做法是batch翻倍lr0也翻倍保持收斂行為一致。5.3 處理類別不平衡圖片采樣與損失權(quán)重大多數(shù)頭盔數(shù)據(jù)集都有類別不平衡問題戴盔頭部多不戴盔頭部少。兩種處理思路第一種是過采樣少樣本圖片讓每個(gè)epoch里少樣本類別出現(xiàn)的次數(shù)更高。YOLOv5原生不直接支持按類別采樣但可以簡單粗暴地把少樣本圖片在數(shù)據(jù)目錄里復(fù)制幾分改個(gè)文件名即可。這種做法會(huì)增加磁盤占用換來的是每個(gè)epoch中少樣本出現(xiàn)頻率的提升。第二種是調(diào)整cls損失權(quán)重。在yaml的names后加一行權(quán)重列表不生效YOLOv5沒有直接的per-class loss weight接口但可以在自定義損失函數(shù)里改。不想動(dòng)源碼的話最常見做法還是數(shù)據(jù)層面過采樣。我的實(shí)際經(jīng)驗(yàn)是先統(tǒng)計(jì)類別數(shù)量如果最多與最少的比例超過10:1過采樣更有效如果只是2:1或3:1完全不用管模型能自然學(xué)到。別一上來就堆tricks先看數(shù)據(jù)分布。6. 部署到施工現(xiàn)場的驗(yàn)證清單從測試集到USB攝像頭訓(xùn)練完模型只是第一步真正要落地到施工現(xiàn)場還有很多驗(yàn)證工作要做。我最常犯的錯(cuò)誤是只盯著val mAP看跑到現(xiàn)場卻發(fā)現(xiàn)完全不能用。后來我給自己定了一套驗(yàn)證清單每條都在真實(shí)環(huán)境下過一遍。先用你手上的視頻片段測試而不僅僅是驗(yàn)證集圖片。頭盔檢測的難點(diǎn)往往在動(dòng)態(tài)場景人走進(jìn)監(jiān)控視野頭部角度變化遮陽帽和頭盔外觀接近夜間紅外畫面。把這些都錄下來用detect.py依次跑一遍觀察漏檢和誤檢。漏檢多就調(diào)低conf-thres從0.25降到0.15誤檢多就調(diào)高同時(shí)檢查NMS閾值。YOLOv5的detect.py中--conf-thres和--iou-thres就是這么用的現(xiàn)場調(diào)節(jié)比重新訓(xùn)練快得多。接著做極端樣例測試。準(zhǔn)備幾張佩戴深色頭盔、戴帽子、遠(yuǎn)處小目標(biāo)的圖片單獨(dú)跑一遍記錄模型的表現(xiàn)。深色頭盔容易和深色背景融合遠(yuǎn)處小目標(biāo)常被忽略這些高難度樣本才是評判模型好壞的標(biāo)準(zhǔn)。如果這一關(guān)過不了回到第五章繼續(xù)做針對性的增強(qiáng)。最后測試實(shí)時(shí)視頻流。用USB攝像頭或者RTSP流作為source跑推理看幀率能不能達(dá)到要求。python detect.py --weights best.pt --source 0 --conf-thres 0.2 --view-img--source 0表示本機(jī)第一個(gè)攝像頭。施工現(xiàn)場如果是IPC攝像頭改成rtsp://user:passip:554/stream1。這里要注意GPU推理時(shí)CPU同樣會(huì)被占用如果同時(shí)跑多個(gè)任務(wù)幀率會(huì)下降。現(xiàn)場部署通常建議用TensorRT加速但那又是另一個(gè)話題了。把這一套走完模型才算真正可用。如果你手上還沒有這份現(xiàn)成的數(shù)據(jù)集先去把它下載下來解壓后從第二章的目錄檢查開始走一遍。從那以后我每次拿到新的檢測數(shù)據(jù)集都會(huì)強(qiáng)制先跑一遍標(biāo)簽統(tǒng)計(jì)腳本再訓(xùn)練再錄一段現(xiàn)場視頻做實(shí)測。這三步缺一不可。希望這份頭盔數(shù)據(jù)集的拆解筆記能幫你少走點(diǎn)彎路訓(xùn)練出真正能上工地的模型。本文還有配套的精品資源點(diǎn)擊獲取