檢測(cè)實(shí)戰(zhàn)包:380MB含數(shù)據(jù)集、權(quán)重與訓(xùn)練日志)
簡(jiǎn)介本資源為基于YOLOV5的VOC目標(biāo)檢測(cè)實(shí)戰(zhàn)項(xiàng)目面向具備一定深度學(xué)習(xí)基礎(chǔ)、希望快速上手目標(biāo)檢測(cè)訓(xùn)練與推理的開發(fā)者與學(xué)習(xí)者。項(xiàng)目覆蓋火車、船、人、電視、飛機(jī)等20個(gè)類別的檢測(cè)任務(wù)提供可直接運(yùn)行的代碼、數(shù)據(jù)集與訓(xùn)練好的權(quán)重參數(shù)幫助讀者跳過環(huán)境搭建與數(shù)據(jù)整理的繁瑣環(huán)節(jié)專注于模型訓(xùn)練與效果驗(yàn)證。壓縮包共約2000個(gè)文件以txt標(biāo)簽與說明、py訓(xùn)練推理腳本、yaml配置文件、sh運(yùn)行腳本及md文檔為主整體約357MB。項(xiàng)目迭代100個(gè)epoch在runs目錄下保存了完整訓(xùn)練結(jié)果最佳精度達(dá)到map0.50.62、map0.5:0.950.42并在runs/detect中保留了網(wǎng)絡(luò)推理訓(xùn)練集的可視化結(jié)果便于直觀評(píng)估檢測(cè)效果。訓(xùn)練集含13700張圖片及對(duì)應(yīng)標(biāo)簽測(cè)試集含3425張圖片及標(biāo)簽數(shù)據(jù)規(guī)模適中適合作為課程設(shè)計(jì)、畢業(yè)設(shè)計(jì)或算法入門的實(shí)踐案例。目前已有161人學(xué)習(xí)配套腳本參數(shù)說明可進(jìn)一步輔助理解訓(xùn)練與推理流程。1. 20 分類 VOC 檢測(cè)項(xiàng)目380MB 里到底裝了什么如果你手頭正好有一個(gè) 20 類的目標(biāo)檢測(cè)需求比如識(shí)別火車、船、人、電視、飛機(jī)這些常見目標(biāo)又不想從零標(biāo)注數(shù)據(jù)、從零調(diào)參那這個(gè) YOLOV5 VOC 的實(shí)戰(zhàn)包值得先拆開看看。它不是一個(gè)空殼 demo而是把數(shù)據(jù)集、訓(xùn)練腳本、推理腳本、訓(xùn)練好的權(quán)重、100 個(gè) epoch 的訓(xùn)練日志和推理結(jié)果一起打包總大小 380MB。訓(xùn)練集 13700 張圖配 13700 個(gè) txt 標(biāo)簽驗(yàn)證集 3425 張圖配 3425 個(gè)標(biāo)簽覆蓋 20 個(gè)類別。訓(xùn)練到最好的精度是 map0.50.62、map0.5:0.950.42runs/detect 下還存了網(wǎng)絡(luò)對(duì)訓(xùn)練集的全部推理結(jié)果。換句話說你拿到手就能跑推理、能接著訓(xùn)練、能對(duì)照日志看它當(dāng)時(shí)是怎么收斂的。適合兩類人一類是想快速驗(yàn)證自己業(yè)務(wù)場(chǎng)景能不能套 VOC 格式跑通的工程師另一類是想拿一份完整訓(xùn)練記錄來對(duì)照自己調(diào)參過程的學(xué)習(xí)者。下面按「資源是什么 → 怎么用 → 坑在哪」的順序拆。2. 數(shù)據(jù)集結(jié)構(gòu)與 VOC 轉(zhuǎn) YOLO 格式13700 張圖怎么對(duì)上 13700 個(gè)標(biāo)簽2.1 目錄布局與類別映射這個(gè)項(xiàng)目的數(shù)據(jù)集不是原始 VOC 的 XML 結(jié)構(gòu)而是已經(jīng)轉(zhuǎn)成 YOLO 需要的 images labels 配對(duì)形式。訓(xùn)練集在 datasets-images-train 下13700 張圖片和 13700 個(gè) txt 標(biāo)簽文件一一對(duì)應(yīng)驗(yàn)證集在 datasets-images-val 下3425 張圖配 3425 個(gè)標(biāo)簽。20 個(gè)類別包括火車、船、人、電視、飛機(jī)等類別順序由數(shù)據(jù)配置文件里的 names 列表決定這個(gè)順序一旦定下就不能亂改否則標(biāo)簽索引和模型輸出會(huì)對(duì)不上。常見做法是先把類別名按固定順序?qū)戇M(jìn)一個(gè) data.yaml訓(xùn)練和推理都讀同一份。下面是一個(gè)可直接抄的配置骨架# data.yaml path: ./datasets-images # 數(shù)據(jù)集根目錄 train: train # 訓(xùn)練集相對(duì)路徑 val: val # 驗(yàn)證集相對(duì)路徑 nc: 20 # 類別數(shù)必須和 names 長(zhǎng)度一致 names: 0: train 1: boat 2: person 3: tv 4: airplane # ... 其余類別按你的實(shí)際順序補(bǔ)齊到 20 個(gè)邏輯說明path 是根目錄train/val 是相對(duì) path 的子目錄YOLOV5 會(huì)去 path/train/images 找圖、path/train/labels 找標(biāo)簽。nc 寫錯(cuò)是最常見的翻車點(diǎn)20 類寫成 19 類訓(xùn)練不報(bào)錯(cuò)但精度會(huì)莫名其妙掉。names 的索引必須和 txt 標(biāo)簽里每行第一個(gè)數(shù)字對(duì)應(yīng)標(biāo)簽行格式是class_id x_center y_center width height坐標(biāo)都是歸一化到 0~1 的值。2.2 從 VOC XML 轉(zhuǎn) YOLO txt 的腳本與邊界坑如果你手上是原始 VOC 的 Annotations XML需要自己轉(zhuǎn)。轉(zhuǎn)換核心是把 VOC 的絕對(duì)坐標(biāo) xmin/ymin/xmax/ymax 轉(zhuǎn)成歸一化的中心點(diǎn)加寬高。下面這段腳本我一般會(huì)直接拿來改import os import xml.etree.ElementTree as ET # 類別到索引的映射順序必須和 data.yaml 的 names 完全一致 class_map {train: 0, boat: 1, person: 2, tv: 3, airplane: 4} # 其余 15 類按實(shí)際補(bǔ)齊 def convert(xml_dir, out_dir, img_w, img_h): for xml_file in os.listdir(xml_dir): if not xml_file.endswith(.xml): continue tree ET.parse(os.path.join(xml_dir, xml_file)) root tree.getroot() lines [] for obj in root.iter(object): name obj.find(name).text if name not in class_map: continue # 未登記類別直接跳過避免索引錯(cuò)位 cls_id class_map[name] bbox obj.find(bndbox) xmin float(bbox.find(xmin).text) ymin float(bbox.find(ymin).text) xmax float(bbox.find(xmax).text) ymax float(bbox.find(ymax).text) # 歸一化并轉(zhuǎn)中心點(diǎn)格式 x_center (xmin xmax) / 2.0 / img_w y_center (ymin ymax) / 2.0 / img_h w (xmax - xmin) / img_w h (ymax - ymin) / img_h lines.append(f{cls_id} {x_center:.6f} {y_center:.6f} {w:.6f} {h:.6f}) out_name os.path.splitext(xml_file)[0] .txt with open(os.path.join(out_dir, out_name), w) as f: f.write(\n.join(lines)) convert(./Annotations, ./labels, 640, 640)參數(shù)說明img_w、img_h 必須用每張圖真實(shí)的寬高不能統(tǒng)一寫 640否則非正方形圖會(huì)坐標(biāo)偏移。class_map 里沒登記的類別我選擇跳過而不是報(bào)錯(cuò)因?yàn)?VOC 里?;熘恍┎恍枰念悇e直接跳過比中斷轉(zhuǎn)換更實(shí)用。轉(zhuǎn)換完一定要抽查幾張用可視化腳本把框畫回圖上確認(rèn)框位置沒偏。提示標(biāo)簽文件和圖片文件必須同名只差擴(kuò)展名。13700 對(duì)里只要有一對(duì)名字對(duì)不上訓(xùn)練時(shí)就會(huì)報(bào)「找不到標(biāo)簽」或者靜默跳過最后表現(xiàn)為某類精度異常低。3. 訓(xùn)練腳本參數(shù)怎么設(shè)100 epoch 跑出 map0.50.62 的配置拆解3.1 關(guān)鍵超參與命令行寫法這個(gè)項(xiàng)目迭代了 100 個(gè) epoch最終 map0.50.62、map0.5:0.950.42。這個(gè)精度不算頂尖但對(duì)于 20 類、1.7 萬張圖的規(guī)模屬于能直接用的水平。要復(fù)現(xiàn)或接著訓(xùn)核心是 train.py 的參數(shù)。常見做法是先用預(yù)訓(xùn)練權(quán)重起步再按自己的數(shù)據(jù)微調(diào)python train.py \ --data data.yaml \ --cfg models/yolov5s.yaml \ --weights yolov5s.pt \ --epochs 100 \ --batch-size 16 \ --img-size 640 \ --optimizer SGD \ --lr0 0.01 \ --lrf 0.01 \ --cache參數(shù)說明--weights 指定預(yù)訓(xùn)練權(quán)重從零訓(xùn) 20 類小數(shù)據(jù)集很容易不收斂用預(yù)訓(xùn)練是省時(shí)間的關(guān)鍵。--batch-size 16 是 8G 顯存左右的穩(wěn)妥值顯存不夠就降到 8但 batch 太小 BN 層統(tǒng)計(jì)會(huì)不穩(wěn)。--img-size 640 是 YOLOV5 的默認(rèn)輸入改大能提小目標(biāo)精度但顯存和耗時(shí)都漲。--cache 把圖片緩存到內(nèi)存1.7 萬張圖能明顯加快每個(gè) epoch但內(nèi)存小于 16G 就別開。--lr0 初始學(xué)習(xí)率和 --lrf 最終學(xué)習(xí)率比例決定余弦退火曲線0.01 配 0.01 是官方推薦起點(diǎn)。3.2 訓(xùn)練日志與 runs 目錄怎么讀訓(xùn)練結(jié)果全在 runs 目錄下每次訓(xùn)練會(huì)新建一個(gè) exp 文件夾里面 results.csv 記錄每個(gè) epoch 的 loss 和 mapweights 下存 best.pt 和 last.pt。判斷訓(xùn)練是否健康重點(diǎn)看三個(gè)信號(hào)box_loss 和 obj_loss 是否穩(wěn)定下降、map0.5 是否在后期還在漲、驗(yàn)證集 loss 有沒有先降后升。如果驗(yàn)證 loss 抬頭而訓(xùn)練 loss 還在降就是過擬合該早?;蚣訑?shù)據(jù)增強(qiáng)。常見做法是訓(xùn)練完用 results.csv 畫曲線或者直接看 runs/train/exp 下的 results.png。這個(gè)項(xiàng)目 100 epoch 的曲線如果后期趨平說明 100 輪基本夠用如果還在明顯上升可以接著加輪次。runs/detect 下存的是推理結(jié)果可以直接看模型在訓(xùn)練集上的實(shí)際表現(xiàn)注意這是訓(xùn)練集精度會(huì)偏高別拿它當(dāng)泛化指標(biāo)。注意best.pt 是按驗(yàn)證集 map 選的不是按訓(xùn)練 loss。如果你換了驗(yàn)證集劃分best.pt 的含義就變了別混用不同劃分下的權(quán)重做對(duì)比。4. 推理與部署從 detect.py 到邊緣設(shè)備量化4.1 推理腳本參數(shù)與結(jié)果核對(duì)推理入口是 detect.py最常用的幾條參數(shù)是權(quán)重、輸入源、置信度和 NMS 閾值python detect.py \ --weights runs/train/exp/weights/best.pt \ --source datasets-images-val \ --img-size 640 \ --conf-thres 0.25 \ --iou-thres 0.45 \ --save-txt參數(shù)說明--source 可以是單張圖、文件夾、視頻或攝像頭編號(hào)。--conf-thres 0.25 是置信度門檻調(diào)低召回高但誤檢多調(diào)高反之業(yè)務(wù)上先看你要的是查全還是查準(zhǔn)。--iou-thres 0.45 控制 NMS 合并重疊框的力度密集場(chǎng)景可以適當(dāng)調(diào)高到 0.5~0.6 減少漏合并。--save-txt 會(huì)把檢測(cè)框按 YOLO 格式存下來方便和標(biāo)簽對(duì)比算指標(biāo)。推理結(jié)果默認(rèn)存 runs/detect/exp核對(duì)時(shí)重點(diǎn)看漏檢和誤檢分別集中在哪些類20 類里通常有幾類樣本少精度會(huì)明顯拖后腿。4.2 后處理與邊緣部署的量化思路YOLOV5 的后處理主要是三件事把輸出解碼成框、按置信度過濾、NMS 去重。部署到邊緣設(shè)備時(shí)常見做法是先導(dǎo)出 ONNX 再量化。以 RK3568 這類平臺(tái)為例流程是 PyTorch → ONNX → 量化校準(zhǔn) → 板端推理。量化會(huì)帶來精度損失map0.5 可能掉 1~3 個(gè)點(diǎn)所以校準(zhǔn)集要覆蓋 20 個(gè)類的典型樣本不能只用一類圖。樹莓派 4B/5 上部署自己訓(xùn)練的模型一般走 ONNX Runtime 或 ncnn幀率取決于輸入尺寸和是否量化640 輸入在樹莓派 5 上通常是個(gè)位數(shù)到十幾幀想實(shí)時(shí)得降輸入或換更小的模型。提示導(dǎo)出 ONNX 時(shí)注意 opset 版本和動(dòng)態(tài)軸設(shè)置動(dòng)態(tài) batch 在部分推理框架上會(huì)拖慢速度固定 batch1 往往更快。5. 避坑與排查20 分類項(xiàng)目里最容易翻車的五件事現(xiàn)象一訓(xùn)練不報(bào)錯(cuò)但 map 一直是 0。原因多半是標(biāo)簽路徑或類別索引對(duì)不上YOLOV5 找不到有效標(biāo)簽就當(dāng)成全背景訓(xùn)。解決先跑一遍數(shù)據(jù)檢查確認(rèn)每張圖都有同名 txt且 txt 里 class_id 都在 0~19 范圍內(nèi)。現(xiàn)象二某一類精度特別低其他類正常。原因通常是該類樣本太少或標(biāo)注質(zhì)量差。解決統(tǒng)計(jì)每類框數(shù)量樣本少于幾百的類考慮補(bǔ)充數(shù)據(jù)或做重采樣同時(shí)抽查該類標(biāo)簽有沒有漏標(biāo)、錯(cuò)標(biāo)?,F(xiàn)象三顯存爆了batch 降到 1 還是 OOM。原因可能是 --img-size 太大或 --cache 把圖全塞進(jìn)內(nèi)存。解決先關(guān) --cache再把 img-size 降到 416 試跑確認(rèn)能跑通再逐步加回去?,F(xiàn)象四推理結(jié)果框位置整體偏移。原因多是訓(xùn)練和推理的 img-size 不一致或者 letterbox 填充參數(shù)沒對(duì)齊。解決保證 detect.py 的 --img-size 和訓(xùn)練時(shí)一致檢查預(yù)處理有沒有做等比例縮放加灰邊填充?,F(xiàn)象五換驗(yàn)證集劃分后 best.pt 精度暴跌。原因是你用的權(quán)重是按舊劃分選出來的和新劃分的分布不匹配。解決要么固定劃分不動(dòng)要么在新劃分上重新訓(xùn)一輪別拿舊 best.pt 直接對(duì)比新指標(biāo)。6. 進(jìn)階技巧用 100 epoch 日志反推超參該往哪調(diào)拿到一份已經(jīng)跑完 100 epoch 的日志最大的價(jià)值不是直接用權(quán)重而是反推這套超參在你的場(chǎng)景里該怎么改。我一般會(huì)先把 results.csv 拉出來按 epoch 看 map0.5 的斜率如果前 30 輪就沖到接近最終值然后走平說明學(xué)習(xí)率偏大或數(shù)據(jù)太簡(jiǎn)單可以降 lr0 讓收斂更細(xì)如果 100 輪結(jié)束還在緩慢上升說明輪次不夠或?qū)W習(xí)率衰減太慢可以加 epoch 或調(diào)小 lrf。再對(duì)照 20 個(gè)類的 per-class map把低于平均的類挑出來。這些類要么補(bǔ)數(shù)據(jù)要么在數(shù)據(jù)增強(qiáng)上針對(duì)性加強(qiáng)比如小目標(biāo)多的類可以開 mosaic 和 copy-paste。超參方面YOLOV5 的 hyp 文件里有幾個(gè)常調(diào)的box、cls、obj 三個(gè) loss 權(quán)重默認(rèn) 0.05/0.5/1.0類別不平衡時(shí)可以適當(dāng)提 clsanchor 如果和你的目標(biāo)尺寸差太多可以用 k-means 在自己的數(shù)據(jù)上重聚一遍。驗(yàn)證方法很簡(jiǎn)單固定驗(yàn)證集每次只改一個(gè)參數(shù)跑 20~30 epoch 看 map 變化別一次改一堆否則出了問題根本不知道是哪個(gè)參數(shù)導(dǎo)致的。這套流程我踩過坑——有次同時(shí)改了學(xué)習(xí)率和增強(qiáng)結(jié)果精度掉了卻定位不到原因白白多跑了兩天。從那以后我每次調(diào)參都強(qiáng)制走一遍「單變量 固定驗(yàn)證集」的流程寧可慢一點(diǎn)也要可復(fù)現(xiàn)。希望這份拆解幫到你拿到資源后先跑推理確認(rèn)環(huán)境通再動(dòng)訓(xùn)練參數(shù)。本文還有配套的精品資源點(diǎn)擊獲取