:雙格式數(shù)據(jù)集與訓(xùn)練部署全解析)
簡介YOLOv7打電話行為檢測項目面向計算機(jī)視覺開發(fā)者與邊緣設(shè)備部署場景適合需要快速落地手持電話識別功能的工程人員及高校研究者。壓縮包提供訓(xùn)練好的權(quán)重、完整訓(xùn)練代碼以及配套數(shù)據(jù)集可直接加載權(quán)重進(jìn)行圖片/視頻推理也可基于PyTorch框架繼續(xù)訓(xùn)練優(yōu)化。數(shù)據(jù)集圖片涵蓋多種光線、角度與距離下的手持電話姿態(tài)jpg原圖與txt、xml兩種標(biāo)注格式相互對應(yīng)既滿足YOLO系列訓(xùn)練要求也兼容VOC格式遷移學(xué)習(xí)。資源共2000個文件包含1383張jpg圖片、1321個txt標(biāo)簽、1077個xml標(biāo)簽另有訓(xùn)練/評估所用的py腳本、yaml配置、pt權(quán)重文件及說明文檔文件類型覆蓋數(shù)據(jù)、標(biāo)注、模型與代碼結(jié)構(gòu)清晰便于按目錄快速定位數(shù)據(jù)、訓(xùn)練腳本或權(quán)重。整包約703MB已有725人學(xué)習(xí)下載適用于手機(jī)使用監(jiān)管、駕駛行為分析等場景的模型搭建與算法驗證。1. 打電話檢測的現(xiàn)實場景為什么這份 YOLOv7 權(quán)重和雙格式標(biāo)簽數(shù)據(jù)集值得復(fù)現(xiàn)做監(jiān)控行為識別的人都有同感YOLOv7 打電話檢測聽著不難真正自己跑一遍數(shù)據(jù)采集和標(biāo)注能占掉一半時間。這份資源把訓(xùn)練好的模型和打電話數(shù)據(jù)集一起打包標(biāo)簽同時給 txt 和 xml 兩種格式分別放在兩個文件夾里。核心價值就一句話——「有沒有人在打電話」這件事不需要從零打標(biāo)圖片、視頻和攝像頭流都能直接檢出。它適合三類人剛接觸目標(biāo)檢測、想用真實業(yè)務(wù)場景練手的學(xué)生做工地安全、司機(jī)行為規(guī)范這類監(jiān)控應(yīng)用的開發(fā)以及已經(jīng)有 YOLO 基礎(chǔ)、想換一個高質(zhì)量數(shù)據(jù)集驗證自己部署流程的人。接下來我按數(shù)據(jù)格式、訓(xùn)練參數(shù)、踩坑記錄和推理部署四個方向把這份資源完整拆一遍。2. 數(shù)據(jù)集與標(biāo)簽結(jié)構(gòu)txt/xml 雙格式怎么對齊訓(xùn)練前先想清楚2.1 先看懂資源里的數(shù)據(jù)組織打開壓縮包模型相關(guān)的文件是 common.py、loss.py、datasets.py、yolo.py、train.py、train_aux.py 這一套數(shù)據(jù)集的標(biāo)簽按說明分為 txt 和 xml 兩種格式分別放在兩個文件夾里。我拆過的目標(biāo)檢測資源里這種雙格式處理算比較貼心的YOLO 訓(xùn)練時只認(rèn) txt而標(biāo)注工具 LabelImg 默認(rèn)保存 xml很多人第一次接觸時就是死在「兩種格式哪個給訓(xùn)練用」上。常見目錄結(jié)構(gòu)是下面這樣你拿到資源后可以比照一下dataset/ ├── images/ │ ├── 0001.jpg │ └── 0002.jpg ├── labels_txt/ │ ├── 0001.txt │ └── 0002.txt └── labels_xml/ ├── 0001.xml └── 0002.xmlimages 放原始圖片labels_txt 放 YOLO 訓(xùn)練真正使用的標(biāo)注文件labels_xml 放 VOC 風(fēng)格的 XML 標(biāo)注。實際訓(xùn)練時一般把 labels_txt 重命名成 labels讓 YOLOv7 的 datasets.py 能在圖片同級的 labels 目錄下找到對應(yīng) txt。不要直接改 XML 后綴當(dāng) txt 用那樣一定翻車兩個格式字段結(jié)構(gòu)完全不同下面細(xì)說。2.2 兩種標(biāo)簽格式的字段差異和映射關(guān)系YOLO 的 txt 每行對應(yīng)一個目標(biāo)一行五列含義分別是類別索引、目標(biāo)中心點(diǎn)的 x 坐標(biāo)、中心點(diǎn)的 y 坐標(biāo)、目標(biāo)的寬度、目標(biāo)的高度。四個坐標(biāo)值都是相對于圖片寬高的歸一化數(shù)值范圍通常在 0 到 1 之間。打電話檢測里類別一般只有一個所以類索引絕大部分是 0。VOC 風(fēng)格的 xml 則完全不一樣。它用object節(jié)點(diǎn)描述一個目標(biāo)name存類別名比如 phone_call真正的坐標(biāo)在bndbox里四個值 xmin、ymin、xmax、ymax 是像素絕對坐標(biāo)。舉個例子一張 640×480 的監(jiān)控截圖里手機(jī)目標(biāo)框左上角是 (134, 90)右下角是 (216, 190)在 xml 里就寫死這四個整數(shù)。但同樣的目標(biāo)按 YOLO 格式表示就要先換算成中心點(diǎn)再做歸一化格式坐標(biāo)含義是否歸一化每行內(nèi)容YOLO txtx_center y_center width height是class_id x_center y_center width heightVOC xmlbndbox: xmin ymin xmax ymax否name bndbox 節(jié)點(diǎn)換算關(guān)系是x_center (xmin xmax) / 2 / 圖片寬y_center (ymin ymax) / 2 / 圖片高目標(biāo)寬 (xmax - xmin) / 圖片寬目標(biāo)高 (ymax - ymin) / 圖片高。注意分母是整張圖的寬高不是目標(biāo)的寬高新手在這一步最容易把寬高搞反。資源里同時提供兩種格式最大的價值是你可以相互校驗。我拿到 txt 后會隨機(jī)挑幾張圖把 txt 坐標(biāo)畫回原圖看框準(zhǔn)不準(zhǔn)如果出現(xiàn)錯位再用 xml 反查原始坐標(biāo)就能定位是標(biāo)注問題還是轉(zhuǎn)換問題。這種方法比直接看數(shù)字靠譜得多畢竟打電話場景里手和手機(jī)經(jīng)常半遮擋框稍微偏一點(diǎn)訓(xùn)練出來的模型就很容易把手機(jī)漏掉。這里還要強(qiáng)調(diào)一個「類名統(tǒng)一」的坑xml 里的name標(biāo)簽有可能是 phone、call、phone_call 好幾個叫法而 txt 里的 class_id 是純數(shù)字轉(zhuǎn)換時必須通過 class_map 這個字典把所有 xml 里的類別名映射到同一個數(shù)字。否則同一個 0 類別在不同圖片里指代的對象不一致訓(xùn)練時模型會徹底混亂表現(xiàn)就是 loss 一路下降但驗證 mAP 始終為零。2.3 寫腳本把 xml 批量轉(zhuǎn)成 YOLO 訓(xùn)練格式雖然資源已經(jīng)幫你轉(zhuǎn)好了 txt但你要擴(kuò)展自己的數(shù)據(jù)時這個轉(zhuǎn)換腳本是繞不開的。下面這個腳本是我常用的改法用 Python 解析 xml再寫到 txtimport xml.etree.ElementTree as ET import os import cv2 def xml_to_yolo(xml_folder, txt_folder, img_folder, class_map): os.makedirs(txt_folder, exist_okTrue) for xml_file in os.listdir(xml_folder): if not xml_file.endswith(.xml): continue tree ET.parse(os.path.join(xml_folder, xml_file)) root tree.getroot() # 用 xml 里的 filename 字段找原圖注意可能帶子路徑 img_name root.find(filename).text img cv2.imread(os.path.join(img_folder, img_name)) h, w img.shape[:2] txt_name xml_file.replace(.xml, .txt) with open(os.path.join(txt_folder, txt_name), w) as f: for obj in root.iter(object): name obj.find(name).text if name not in class_map: continue box obj.find(bndbox) xmin float(box.find(xmin).text) ymin float(box.find(ymin).text) xmax float(box.find(xmax).text) ymax float(box.find(ymax).text) # 中心點(diǎn)歸一化分母是原圖寬高 x_center (xmin xmax) / 2.0 / w y_center (ymin ymax) / 2.0 / h bw (xmax - xmin) / w bh (ymax - ymin) / h # 過濾反向框和零寬高訓(xùn)練時會讓 loss 變成 NaN if bw 0 or bh 0 or x_center 0 or y_center 0: continue f.write(f{class_map[name]} {x_center:.6f} {y_center:.6f} {bw:.6f} {bh:.6f}\n) if __name__ __main__: xml_to_yolo(labels_xml, labels_txt, images, {phone_call: 0})腳本邏輯分四步先遍歷 xml 文件按文件名找到對應(yīng)原圖讀取原圖寬高作為歸一化分母然后解析每個object節(jié)點(diǎn)里的類別名和 bndbox 坐標(biāo)再按公式把絕對坐標(biāo)轉(zhuǎn)成中心點(diǎn)加寬高的歸一化數(shù)值最后按 YOLO 格式寫入 txt。參數(shù)方面img_folder必須指向原圖目錄腳本要從圖里讀寬高路徑不對會直接報錯class_map是類別名到索引的映射打電話檢測只有 phone_call所以對上 0 就行。如果后面要加「玩手機(jī)」「低頭」這類行為類別名要按順序補(bǔ)齊訓(xùn)練時 data 文件里的 names 順序必須跟這個 class_map 完全一致這是目標(biāo)檢測里最典型的標(biāo)簽錯位問題。跑完腳本后我建議再做一個回讀校驗從生成的 txt 里讀框用 OpenCV 畫到原圖上肉眼過一遍。重點(diǎn)看三個位置手指遮擋電話的位置、遠(yuǎn)處小目標(biāo)、兩張圖拼接造成的大寬高比。這些區(qū)域最容易出現(xiàn)坐標(biāo)換算錯誤早發(fā)現(xiàn)比訓(xùn)練到一半再排查省事。3. 訓(xùn)練流程與參數(shù)train.py 和 train_aux.py 怎么選關(guān)鍵參數(shù)別用默認(rèn)值3.1 從文件清單先確認(rèn)代碼基礎(chǔ)資源包里有 common.py、loss.py、datasets.py、yolo.py、train.py、train_aux.py這套文件是 YOLOv7 訓(xùn)練的核心骨架。datasets.py 負(fù)責(zé)圖片和標(biāo)簽的加載與增強(qiáng)common.py 里是模型基礎(chǔ)算子像 RepConv、SPPCSPC 這些結(jié)構(gòu)都在這里yolo.py 負(fù)責(zé)組裝主干網(wǎng)絡(luò)和檢測頭loss.py 計算各類損失train.py 和 train_aux.py 是兩個不同的訓(xùn)練入口。yolov7.pdf 專門講模型網(wǎng)絡(luò)結(jié)構(gòu)訓(xùn)練前翻一遍能幫你在調(diào)參時少走很多彎路。這里要特別提醒很多人拿到資源包只看權(quán)重和數(shù)據(jù)集不看這幾個 py 文件結(jié)果在新機(jī)器上跑的時候報 No module named yolo。YOLOv7 的 Python 代碼是在倉庫根目錄運(yùn)行的train.py 和 detect.py 會直接 import 同目錄的 common、yolo 這些文件所以別把權(quán)重和數(shù)據(jù)集單獨(dú)拷走要帶著整個目錄結(jié)構(gòu)一起解壓。我見過不止一個人只把runs目錄拷出來想直接 detect結(jié)果 import 報錯又費(fèi)了半天時間重新下載整個倉庫。依賴方面這套代碼采用 PyTorch 框架Python 文件也都是基于 PyTorch 寫的。常見做法是先用 pip 安裝 torch、torchvision、opencv-python、numpy、pyyaml 這些基礎(chǔ)庫再安裝 requirements 里的依賴。版本上不需要追求最新PyTorch 1.7 以上的穩(wěn)定版都能跑關(guān)鍵要保證 torch 和 torchvision 版本配套。3.2 配置數(shù)據(jù)文件類別數(shù)量、圖片路徑、labels 目錄YOLOv7 訓(xùn)練前要準(zhǔn)備一個數(shù)據(jù)配置文件常見叫 call.yaml。打電話檢測只有一類最簡配置是這樣train: dataset/images val: dataset/images nc: 1 names: [phone_call]train 和 val 填圖片目錄路徑注意不是填 txt 路徑nc 是類別數(shù)量打電話檢測就是 1names 是類別名列表順序必須和 txt 里的 class_id 對應(yīng)。如果 txt 里類別是 0那 names[0] 就是 phone_call寫反了訓(xùn)練時 loss 不報錯但驗證 mAP 永遠(yuǎn)是 0。還要補(bǔ)充一點(diǎn)YOLOv7 的 datasets.py 默認(rèn)按圖片文件名找同名的 txt 文件并且要求 txt 路徑是圖片路徑把 images 替換成 labels 后的結(jié)果。所以如果你把原圖和標(biāo)簽放在同一個文件夾里會直接找不到標(biāo)簽。常見做法是把 labels_txt 這個文件夾重命名成 labels放到和 images 同級的目錄保持這樣的結(jié)構(gòu)dataset/ ├── images/ │ ├── 0001.jpg │ └── 0002.jpg └── labels/ ├── 0001.txt └── 0002.txt有人會問 xml 標(biāo)簽放哪里xml 在這里只作為編輯和查看的中間格式訓(xùn)練時不參與加載。我給客戶的交付規(guī)范通常是xml 保留在原始標(biāo)注文件夾里備份用txt 負(fù)責(zé)給訓(xùn)練吃。兩份并存正好互相留底萬一 txt 被程序清掉了還能從 xml 重新生成算是給自己留了一顆后悔藥。3.3 訓(xùn)練命令兩個入口的分工和關(guān)鍵參數(shù)train.py 是標(biāo)準(zhǔn)訓(xùn)練入口適合大多數(shù)常規(guī)場景train_aux.py 是帶輔助檢測頭的訓(xùn)練入口適合小目標(biāo)偏多的場景。打電話檢測里手機(jī)在監(jiān)控畫面中往往只有幾十像素甚至更小我用下來更推薦 train_aux.py。它在主干網(wǎng)絡(luò)里額外加輔助分支對小目標(biāo)更友好代價是訓(xùn)練時間變長、顯存占用更高。先看 train.py 的啟動命令python train.py --data data/call.yaml --cfg cfg/training/yolov7.yaml --weights yolov7.pt --batch-size 16 --img 640 640 --epochs 100 --name call --device 0拆一下參數(shù)--data指向剛才創(chuàng)建的 call.yaml--cfg是模型結(jié)構(gòu)文件打電話檢測用默認(rèn)的 yolov7.yaml 就行--weights是預(yù)訓(xùn)練權(quán)重如果不想從頭訓(xùn)練就填官方 yolov7.pt--batch-size是每輪迭代的圖片數(shù)量--img 640 640是訓(xùn)練分辨率兩個值分別為寬和高--epochs是訓(xùn)練輪數(shù)--name是輸出目錄名訓(xùn)練好的權(quán)重會存到 runs/train/call/weights/ 下。關(guān)鍵要區(qū)分 best.pt 和 last.ptbest.pt 按驗證集 mAP 最優(yōu)保存last.pt 是最后一輪權(quán)重。打電話檢測這種目標(biāo)很小的場景最后一輪不一定是最優(yōu)解經(jīng)常出現(xiàn)驗證集已經(jīng)收斂、后面又震蕩的情況所以后續(xù)部署優(yōu)先用 best.pt。如果顯存不夠比如 8G 顯存跑 batch-size 16 會直接崩我一般降到 8 或 4同時把--workers設(shè)為 4讓數(shù)據(jù)加載不要拖慢 GPU。還有一個容易被忽略的參數(shù)是--hyp它指定超參數(shù)文件默認(rèn)是 data/hyp.scratch.pth。需要調(diào)學(xué)習(xí)率時直接改這個文件里的 lr0、lrf比改訓(xùn)練代碼更快。電話檢測的訓(xùn)練集通常只有幾百到幾千張學(xué)習(xí)率改到 0.001 上下比較穩(wěn)用默認(rèn)的 0.01 也不是不行但收斂曲線會抖得厲害。train_aux.py 的命令基本一致python train_aux.py --data data/call.yaml --cfg cfg/training/yolov7.yaml --weights yolov7.pt --batch-size 16 --img 640 640 --epochs 100 --name call-aux注意 train_aux.py 訓(xùn)練出來的權(quán)重結(jié)構(gòu)里帶有 aux 分支但推理接口是兼容的detect.py 能直接加載不需要額外改代碼。中途想續(xù)訓(xùn)加--resume參數(shù)并指定 runs/train/call/weights/last.pt 就能接著跑學(xué)習(xí)率和當(dāng)前 epoch 都會從上次狀態(tài)恢復(fù)這是 YOLOv7 自帶的一個很實用的功能。4. 復(fù)現(xiàn)中的避坑與排查五個最容易翻車的地方每條都是血淚經(jīng)驗4.1 訓(xùn)練 Loss 變成 NaN 或者一直不降現(xiàn)象訓(xùn)練剛開始幾十個 iteration終端里 loss 就打印出 nan或者 loss 一直在 8、9 附近死活不降。val 階段出來的 mAP 全是 0。原因最常見的是標(biāo)簽坐標(biāo)越界。txt 里的歸一化坐標(biāo)大于 1或者出現(xiàn)了負(fù)數(shù)寬高訓(xùn)練時損失函數(shù)里出現(xiàn) log(0) 或無效框梯度直接爆掉。第二種原因是學(xué)習(xí)率設(shè)得太大尤其是用 batch-size 4 這種小 batch 時默認(rèn)學(xué)習(xí)率相對過大也會 NaN。解決先把所有 txt 掃描一遍過濾掉 x_center、y_center 不在 0 到 1 之間、w 或 h 小于等于 0 的行可以用上一章的轉(zhuǎn)換腳本順手做。然后看超參數(shù)文件里 lr0 是不是 0.01如果是打電話檢測這個小數(shù)據(jù)集可以降到 0.001。最后再確認(rèn)類別索引沒有越界nc1 時 txt 里不能出現(xiàn) 1、2 這類索引。這三步走完NaN 基本能消掉。4.2 驗證 mAP 一直是 0但訓(xùn)練 loss 看起來正?,F(xiàn)象訓(xùn)練正常跑完 100 個 epochloss 曲線平滑下降但每次驗證時 Precision、Recall、mAP 全部為 0檢測結(jié)果圖上一張框都沒有。原因十有八九是類別不匹配。訓(xùn)練數(shù)據(jù)的 txt 里類別索引是 0表示 phone_call但 call.yaml 里 names 寫成了[0]或者類別順序?qū)戝e導(dǎo)致模型學(xué)到的東西和驗證標(biāo)簽對不上。另一個常見原因是 xml 轉(zhuǎn) txt 時xml 里的類別名是 phone而 class_map 里寫的是 phone_call實際沒有轉(zhuǎn)換出任何 txt但腳本沒報錯。解決用代碼把數(shù)據(jù)集里的 txt 全部讀出來統(tǒng)計出現(xiàn)過的類別索引集合確認(rèn)它們從 0 開始連續(xù)分布。同時檢查 call.yaml 的 names確保 names[0] 和 txt 里索引 0 對應(yīng)的語義一致。再用 detect.py 拿訓(xùn)練集里的一張圖測一下如果連訓(xùn)練集視頻數(shù)據(jù)都檢測不到說明模型學(xué)到的是背景需要回爐檢查數(shù)據(jù)加載過程。4.3 train_aux.py 直接加載普通權(quán)重報錯現(xiàn)象用 train_aux.py 訓(xùn)練--weights填的是 train.py 訓(xùn)練出來的 best.pt結(jié)果啟動時報 model 權(quán)重鍵名不匹配或者缺少 aux head 對應(yīng)的參數(shù)。原因train_aux.py 對應(yīng)的模型結(jié)構(gòu)帶了輔助分支而 train.py 訓(xùn)練出的模型沒有這些 aux 結(jié)構(gòu)權(quán)重文件里的 key 對不上屬于結(jié)構(gòu)不一致不是文件損壞。解決兩種方式一是讓 train_aux.py 從頭訓(xùn)練--weights 并配合官方 COCO 預(yù)訓(xùn)練權(quán)重讓模型先學(xué)會通用特征二是直接用資源里已經(jīng)訓(xùn)練好的權(quán)重確認(rèn)它本身是普通版還是 aux 版再選擇對應(yīng)的訓(xùn)練入口。判斷方法很簡單加載權(quán)重后打印 model.state_dict 的 keys看里面有沒有aux字樣。以后要混用記得先看 README 說明別默認(rèn)兩個入口權(quán)重互通。4.4 顯存不足batch-size 調(diào)到 4 還是崩現(xiàn)象啟動訓(xùn)練后沒幾秒報 CUDA out of memory把 batch-size 從 16 降到 8再降到 4還是崩。原因打電話檢測的數(shù)據(jù)圖片如果原圖分辨率很高比如 1920×1080 的監(jiān)控截圖datasets.py 在做增強(qiáng)時會先加載原圖再隨機(jī)縮放顯存開銷比 640×640 的訓(xùn)練分辨率大得多。另外如果開了多卡--device 0,1會把模型均勻分布到各卡只要其中一張卡顯存小也會崩。解決先固定--device 0只占一塊卡。再把--img從 640 640 降到 416 416對電話這種中等大小目標(biāo)影響不大。batch-size 保持 8配合梯度累積把實際大 batch 的效果保住。YOLOv7 官方訓(xùn)練腳本里沒有直接的梯度累積參數(shù)手工改的話每 4 個 step 做一次 optimizer.step 就行。還有一個很實用的小技巧是給數(shù)據(jù)中心增加獨(dú)立的緩存目錄避免 dataloader 反復(fù)讀大圖導(dǎo)致內(nèi)存居高不下。4.5 推理時什么都檢測不到置信度全黑現(xiàn)象模型訓(xùn)練完了用 best.pt 跑 detect.py出來的結(jié)果圖一個框都沒有或者只在角落畫一個置信度 0.05 的框基本等于沒用。原因一是訓(xùn)練集全部是「人拿著手機(jī)在打電話」的正樣本一張不含目標(biāo)的負(fù)樣本都沒有模型學(xué)成了只要手里沒手機(jī)就全圖無目標(biāo)這其實是過擬合在打電話這個單一姿態(tài)上。二是推理時的置信度閾值太高默認(rèn) 0.25打電話動作里手機(jī)被手擋住大部分目標(biāo)模糊真實置信度本來就只有 0.1 到 0.2。解決在訓(xùn)練集里加入一些「正常走路、沒有打電話」的圖片作為負(fù)樣本不需要打標(biāo)空 txt 即可讓模型學(xué)到背景多樣性。推理時把--conf 0.1試一遍看能不能撈回一批目標(biāo)。如果 0.1 下框出來了但雜亂再用 NMS 閾值把重復(fù)框壓下去。數(shù)據(jù)增強(qiáng)上也可以把 mosaic 和 mixup 打開打電話檢測的圖片里手部遮擋嚴(yán)重增強(qiáng)能幫模型學(xué)會看局部特征。5. 部署與推理把訓(xùn)練好的打電話檢測模型接到圖片、視頻和攝像頭流5.1 用 detect.py 驗證 best.pt 和 last.pt 的差別訓(xùn)練完成后推理驗證我習(xí)慣用最優(yōu)權(quán)重而不是最后一輪權(quán)重。命令很直接python detect.py --weights runs/train/call/weights/best.pt --source test.jpg --conf 0.4 --img-size 640--weights指定權(quán)重文件--source是輸入來源--conf是置信度閾值--img-size是推理分辨率。輸出結(jié)果默認(rèn)寫到 runs/detect/exp 下帶框的圖片會被保存下來。實際部署時建議分別拿 best.pt 和 last.pt 在同一個測試集上過一遍。我遇到過 best.pt 在驗證集上 mAP 略高但對模糊監(jiān)控幀的反感度更高last.pt 反而更穩(wěn)。原因在于 best.pt 是按 mAP 挑的可能對個別難例不夠魯棒。所以部署前至少準(zhǔn)備 100 張沒見過的場景圖兩個權(quán)重都跑一遍肉眼對比結(jié)果再決定留哪個。detect.py 里也可以直接開--save-txt把檢測框坐標(biāo)落盤配合后來接業(yè)務(wù)系統(tǒng)時使用。它的輸出格式和標(biāo)簽 txt 類似也是 class_id、中心點(diǎn)、寬高的歸一化坐標(biāo)只是最后多了置信度一列。5.2 source 參數(shù)的四種寫法本地攝像頭和 RTSP 流detect.py 的--source很靈活同一個參數(shù)按不同寫法決定輸入類型。這是最常用的四種寫法含義示例test.jpg單張圖片--source test.jpgvideos/文件夾下所有圖片/視頻--source videos/0本地攝像頭索引--source 0rtsp://ip:554/stream1RTSP 網(wǎng)絡(luò)流--source rtsp://192.168.1.64/stream1接本地攝像頭最常見的問題是索引漂移明明插的是 0 號 USB 攝像頭但系統(tǒng)把集成攝像頭當(dāng)成了 0插拔后索引會變。先跑ls /dev/video*認(rèn)清楚再填對索引。接 RTSP 流時YOLOv7 的 detect.py 會逐幀解碼網(wǎng)絡(luò)延遲大或帶寬不足時經(jīng)常出現(xiàn)畫面卡頓、檢測結(jié)果一幀慢一幀。這個場景里不要把 source 直接填 RTSP 地址跑 detect.py更穩(wěn)的做法是在本地開一個緩存管道先把 RTSP 拉到本地編碼再用--source local.mp4去做檢測。打電話檢測這類監(jiān)控業(yè)務(wù)用后一種方案部署起來不容易被網(wǎng)絡(luò)抖動拖垮。5.3 推理加速開啟 half 精度與分辨率取舍PyTorch 模型部署到實際視頻流上遇到的第一件事就是幀率不夠。YOLOv7 的 detect.py 里可以直接加--half 1模型和輸入都會轉(zhuǎn)成 FP16 精度推理顯存帶寬占用減半大多數(shù) NVIDIA 顯卡上能獲得接近翻倍的幀率提升。python detect.py --weights runs/train/call/weights/best.pt --source 0 --conf 0.4 --half注意并不是所有卡都支持 FP16。老一點(diǎn)的 Tesla P100、GTX 10 系可以部分舊架構(gòu)或 CPU 推理就不要開開了反而更慢。如果是 CPU 部署--img-size 320比--half實在代價是遠(yuǎn)處小目標(biāo)可能漏檢。分辨率的取舍上監(jiān)控畫面里打電話場景有兩種典型情況一種是攝像頭正對工位人基本在畫面中央640 足夠另一種是走廊、閘機(jī)這類廣角畫面手機(jī)只有十幾個像素這時把--img-size 960提上去召回率立刻有變化。幀率會下降但推流端可以用 mingguojian 這類硬編組件配合不贅述。從這份資源的訓(xùn)練權(quán)重看它本身在 640 分辨率下已經(jīng)收斂得不錯先跑通再優(yōu)化尺寸不要一開始就盲目開 1280。6. NMS 與分辨率的搭配一個讓打電話小目標(biāo)不再漏檢的經(jīng)驗值打電話檢測和普通物體檢測最大的不同在于手機(jī)經(jīng)常只有幾十像素大而且貼在臉上、手上天然容易被 NMS 誤殺。絕大多數(shù)人第一次部署用的都是默認(rèn)配置 conf 0.25、iou 0.45、img 640。這三個默認(rèn)值在通用檢測上問題不大但放到打電話場景里漏檢率會明顯偏高。我的做法是按目標(biāo)尺寸分兩檔調(diào)。攝像頭距離人三米以上或者畫面寬度超過 1280 像素時先別急著拉高分辨率而是把 NMS 的 IoU 閾值從默認(rèn) 0.45 降到 0.3同時把 conf 閾值從 0.25 降到 0.15。為什么要降 IoU因為打電話動作里手和手機(jī)高度重合兩個候選框的 IoU 經(jīng)常輕松超過 0.4默認(rèn)閾值下后產(chǎn)生的框會被直接抑制掉其中可能就有一個真正框住手機(jī)的高質(zhì)量框。IoU 降到 0.3 后重疊區(qū)域更大才會被殺小目標(biāo)保住的機(jī)會大很多。如果畫面是近距離特寫目標(biāo)占畫面比例大反而可以調(diào)回 0.45避免輸出一堆重復(fù)框。分辨率的取舍也類似攝像頭是 1080P 以上的監(jiān)控槍機(jī)我一般用--img 960保持長邊清晰如果是清晰度只有 720P 的老設(shè)備把分辨率拉到 1280 也換不來有用信息質(zhì)感本來就丟不如靠數(shù)據(jù)增強(qiáng)彌補(bǔ)。這套參數(shù)我是在一次工地行為識別項目中調(diào)出來的。當(dāng)時默認(rèn)參數(shù)下遠(yuǎn)處三個人同時打電話只檢出一個人把 conf 降到 0.15、IoU 設(shè)成 0.3 后兩個漏檢都回來了。從那以后我每次部署新場景都會先用 30 張困難樣本快速過一遍檢測結(jié)果看漏檢和重復(fù)框的比例再決定要不要動這兩個閾值而不是直接拿默認(rèn)配置上線。希望這個習(xí)慣能幫到你。本文還有配套的精品資源點(diǎn)擊獲取