:從數(shù)據(jù)標(biāo)注到桌面應(yīng)用部署)
簡(jiǎn)介本資源是一套完整的YOLOv5打電話行為檢測(cè)實(shí)戰(zhàn)項(xiàng)目面向計(jì)算機(jī)視覺(jué)初學(xué)者與安防、交通監(jiān)管等場(chǎng)景開(kāi)發(fā)者解決日常監(jiān)控中對(duì)手機(jī)使用行為的自動(dòng)化識(shí)別需求。壓縮包共165個(gè)文件含34個(gè)核心Python腳本含訓(xùn)練/推理/界面邏輯、27個(gè)配置yaml文件模型結(jié)構(gòu)與超參、26張標(biāo)注圖像及8張界面截圖另有4個(gè)預(yù)訓(xùn)練.pt權(quán)重、4個(gè)PyQt設(shè)計(jì).ui文件、2個(gè)實(shí)測(cè)視頻mp4及CSV結(jié)果統(tǒng)計(jì)文件整體大小為433.91MB。已有600人學(xué)習(xí)下載項(xiàng)目已通過(guò)CSDN博文公開(kāi)驗(yàn)證效果。用戶可直接運(yùn)行PyQt圖形界面一鍵完成圖片、視頻及攝像頭實(shí)時(shí)檢測(cè)配套提供txt與xml雙格式標(biāo)注數(shù)據(jù)集支持快速遷移訓(xùn)練內(nèi)容預(yù)覽顯示包含TensorBoard日志、Docker部署文件及完整實(shí)驗(yàn)記錄results.csv兼顧算法復(fù)現(xiàn)、工程部署與結(jié)果分析全流程。1. 項(xiàng)目概述與核心價(jià)值最近在做一個(gè)挺有意思的監(jiān)控場(chǎng)景項(xiàng)目核心需求是自動(dòng)檢測(cè)畫(huà)面中是否有人正在打電話。這聽(tīng)起來(lái)簡(jiǎn)單但在實(shí)際安防、考場(chǎng)管理或者特定工作區(qū)域合規(guī)檢查里是個(gè)挺剛需的功能。傳統(tǒng)靠人眼盯監(jiān)控效率低還容易漏用AI來(lái)做自動(dòng)化識(shí)別就成了必然選擇。我這次選用的技術(shù)棧是YOLOv5來(lái)完成目標(biāo)檢測(cè)然后自己整理數(shù)據(jù)集、訓(xùn)練模型最后用PyQt做了個(gè)帶界面的演示程序把整個(gè)流程給跑通了。這個(gè)項(xiàng)目“YOLOv5打電話行為檢測(cè)”完整地覆蓋了從數(shù)據(jù)準(zhǔn)備、模型訓(xùn)練到應(yīng)用部署的閉環(huán)。對(duì)于想入門計(jì)算機(jī)視覺(jué)特別是目標(biāo)檢測(cè)應(yīng)用的朋友來(lái)說(shuō)是個(gè)非常不錯(cuò)的練手項(xiàng)目。它不像單純跑通一個(gè)demo那么簡(jiǎn)單你需要處理實(shí)際場(chǎng)景中光照、角度、遮擋等各種問(wèn)題還得考慮怎么把算法“包裝”成一個(gè)普通人能用的工具。整個(gè)過(guò)程下來(lái)你對(duì)數(shù)據(jù)標(biāo)注、模型調(diào)參、以及圖形界面開(kāi)發(fā)都會(huì)有更深的體會(huì)。接下來(lái)我就把這套方案的思路、踩過(guò)的坑和具體實(shí)現(xiàn)細(xì)節(jié)毫無(wú)保留地分享出來(lái)。2. 項(xiàng)目整體設(shè)計(jì)與技術(shù)選型考量2.1 為什么選擇YOLOv5目標(biāo)檢測(cè)框架很多比如Faster R-CNN、SSD、YOLO系列等。我最終選擇YOLOv5主要是基于以下幾點(diǎn)實(shí)際考量在精度和速度間取得了很好的平衡YOLOv5雖然不是最新的已有v8、v9等但其代碼成熟、社區(qū)資源豐富對(duì)于“打電話”這種常見(jiàn)行為其精度完全足夠。更重要的是它的推理速度非常快在普通的消費(fèi)級(jí)GPU如GTX 1660 Ti上處理一張圖片只需幾十毫秒這對(duì)于后續(xù)可能的實(shí)時(shí)視頻流處理至關(guān)重要。工程化友好易于上手YOLOv5的PyTorch實(shí)現(xiàn)代碼結(jié)構(gòu)清晰提供了從訓(xùn)練到部署的完整腳本。它的數(shù)據(jù)加載、模型定義、訓(xùn)練循環(huán)都封裝得很好修改起來(lái)很方便。特別是對(duì)于自定義數(shù)據(jù)集只需要按照其要求的格式Y(jié)OLO格式的txt標(biāo)注文件準(zhǔn)備幾乎不用改動(dòng)核心代碼。豐富的預(yù)訓(xùn)練模型和調(diào)參指南YOLOv5提供了從輕量級(jí)YOLOv5s到高精度YOLOv5x多個(gè)版本的預(yù)訓(xùn)練模型。我們可以用在大數(shù)據(jù)集如COCO上預(yù)訓(xùn)練好的權(quán)重進(jìn)行遷移學(xué)習(xí)這能極大加快我們?cè)谛?shù)據(jù)集打電話行為上的收斂速度并提升最終效果。官方和社區(qū)也有大量的超參數(shù)調(diào)優(yōu)經(jīng)驗(yàn)可供參考。注意雖然YOLOv8等更新版本在指標(biāo)上可能更優(yōu)但YOLOv5的穩(wěn)定性、文檔和社區(qū)支持對(duì)于項(xiàng)目快速落地更為關(guān)鍵。新版本有時(shí)會(huì)引入較大的變動(dòng)可能增加學(xué)習(xí)成本和調(diào)試時(shí)間。2.2 行為檢測(cè)的定義與難點(diǎn)“打電話行為檢測(cè)”嚴(yán)格來(lái)說(shuō)是一個(gè)細(xì)粒度的目標(biāo)檢測(cè)任務(wù)但它比單純的“檢測(cè)手機(jī)”或“檢測(cè)人”要復(fù)雜。核心定義我們需要檢測(cè)的是“人”與“手機(jī)”在特定空間位置上發(fā)生的交互行為。最典型的正樣本是手機(jī)貼近人的耳部區(qū)域。主要難點(diǎn)姿態(tài)多樣性人可能用左手或右手打電話可能站著、坐著、走著手機(jī)可能橫屏或豎屏。遮擋問(wèn)題長(zhǎng)發(fā)可能遮擋耳朵和手機(jī)手部也可能部分遮擋手機(jī)。類間差異類似的舉手動(dòng)作如撓頭、扶眼鏡可能被誤檢。尺度變化監(jiān)控?cái)z像頭距離遠(yuǎn)近會(huì)導(dǎo)致人和手機(jī)在圖像中的尺寸變化很大。光照與環(huán)境室內(nèi)外光照不均、逆光、夜間低光照等都會(huì)影響檢測(cè)效果。因此我們的方案不能只檢測(cè)“手機(jī)”而是需要同時(shí)檢測(cè)“人”和“手機(jī)”并通過(guò)它們之間的位置關(guān)系如交并比IoU、中心點(diǎn)距離來(lái)判定是否為“打電話”行為。一種更魯棒的做法是直接標(biāo)注“打電話的人”作為一個(gè)整體類別讓模型去學(xué)習(xí)這個(gè)復(fù)合特征。2.3 PyQt作為圖形界面的優(yōu)勢(shì)模型訓(xùn)練好后我們需要一個(gè)方式來(lái)展示效果、進(jìn)行測(cè)試或者給非技術(shù)人員使用。PyQt是一個(gè)理想的選擇跨平臺(tái)基于Qt可以輕松打包成Windows、macOS、Linux下的可執(zhí)行文件。功能強(qiáng)大提供豐富的UI組件可以方便地集成圖片/視頻加載、模型推理、結(jié)果展示畫(huà)框、標(biāo)簽、參數(shù)調(diào)整等功能。與Python生態(tài)無(wú)縫集成我們的模型是PyTorch的用PyQt可以都在Python環(huán)境下開(kāi)發(fā)避免跨語(yǔ)言調(diào)用的麻煩。打包方便可以使用PyInstaller或cx_Freeze等工具將整個(gè)Python項(xiàng)目包括模型、界面、依賴封裝成一個(gè)獨(dú)立的.exe文件方便分發(fā)。3. 數(shù)據(jù)集構(gòu)建與處理核心細(xì)節(jié)3.1 數(shù)據(jù)收集與標(biāo)注策略高質(zhì)量的數(shù)據(jù)集是模型成功的基石。對(duì)于“打電話行為”數(shù)據(jù)來(lái)源可以是公開(kāi)數(shù)據(jù)集搜索是否有現(xiàn)成的“cellphone”或“hand calling”相關(guān)數(shù)據(jù)集但通常需要自己整理。網(wǎng)絡(luò)爬取從合規(guī)的圖片視頻網(wǎng)站爬取相關(guān)場(chǎng)景圖片需注意版權(quán)和隱私。自行拍攝針對(duì)特定場(chǎng)景如辦公室、考場(chǎng)自行拍攝模擬打電話行為的圖片和視頻這樣數(shù)據(jù)最貼合實(shí)際應(yīng)用但工作量最大。我采用的是混合策略以部分公開(kāi)數(shù)據(jù)為基礎(chǔ)補(bǔ)充了大量自行拍攝和從電影、電視劇中截取的片段已脫敏僅用于技術(shù)研究。標(biāo)注工具推薦使用LabelImg或CVAT。這里使用LabelImg因?yàn)樗?jiǎn)單直接輸出就是YOLO格式。標(biāo)注類別定義 經(jīng)過(guò)權(quán)衡我定義了兩個(gè)類別person標(biāo)注整個(gè)人體。cellphone標(biāo)注手機(jī)。當(dāng)手機(jī)被手持且貼近耳部時(shí)才進(jìn)行標(biāo)注。更優(yōu)的方案直接定義一個(gè)類別calling標(biāo)注框覆蓋正在打電話的人通常是從頭到胸的區(qū)域包含手和手機(jī)。這樣模型直接學(xué)習(xí)“打電話”這個(gè)整體模式避免了后處理邏輯往往效果更好。我最初嘗試了雙類別方案后期部分?jǐn)?shù)據(jù)轉(zhuǎn)向了單類別calling方案進(jìn)行對(duì)比實(shí)驗(yàn)。3.2 數(shù)據(jù)格式與目錄結(jié)構(gòu)YOLOv5要求特定的數(shù)據(jù)格式。假設(shè)我們的項(xiàng)目根目錄為PhoneCall_Detection。PhoneCall_Detection/ ├── data/ │ ├── images/ # 存放所有圖片 │ │ ├── train/ # 訓(xùn)練集圖片 │ │ └── val/ # 驗(yàn)證集圖片 │ └── labels/ # 存放所有標(biāo)注文件與圖片同名.txt后綴 │ ├── train/ # 訓(xùn)練集標(biāo)簽 │ └── val/ # 驗(yàn)證集標(biāo)簽標(biāo)簽文件.txt格式 每一行代表一個(gè)標(biāo)注框格式為class_id x_center y_center width heightclass_id: 類別索引從0開(kāi)始。例如0代表person1代表cellphone。x_center, y_center: 邊界框中心點(diǎn)的歸一化坐標(biāo)除以圖片寬度和高度。width, height: 邊界框的歸一化寬度和高度。例如一張500x400的圖片上有一個(gè)person框其左上角為(100,50)右下角為(300,350)則計(jì)算如下x_center (100 300)/2 / 500 0.4y_center (50 350)/2 / 400 0.5width (300 - 100) / 500 0.4height (350 - 50) / 400 0.75 標(biāo)簽行即為0 0.4 0.5 0.4 0.753.3 數(shù)據(jù)增強(qiáng)與預(yù)處理為了提升模型泛化能力防止過(guò)擬合必須進(jìn)行數(shù)據(jù)增強(qiáng)。YOLOv5內(nèi)置了強(qiáng)大的增強(qiáng)功能在data/hyps/hyp.scratch-low.yaml等配置文件中定義。我們主要關(guān)注并可以調(diào)整的幾項(xiàng)Mosaic將四張圖片拼成一張進(jìn)行訓(xùn)練極大地豐富了背景和小目標(biāo)上下文。MixUp將兩張圖片線性混合增加類別和背景的復(fù)雜度。色彩空間變換包括色調(diào)(H)、飽和度(S)、明度(V)的隨機(jī)調(diào)整模擬不同光照。隨機(jī)旋轉(zhuǎn)、平移、縮放、剪切模擬視角變化。實(shí)操心得對(duì)于“打電話”行為要謹(jǐn)慎使用過(guò)度的旋轉(zhuǎn)和剪切因?yàn)檫@會(huì)破壞“手機(jī)貼近耳部”的關(guān)鍵空間關(guān)系。我通常會(huì)把旋轉(zhuǎn)和剪切的比例調(diào)低。相反色彩抖動(dòng)和模糊增強(qiáng)對(duì)提升魯棒性非常有效。我們需要?jiǎng)?chuàng)建一個(gè)自己的數(shù)據(jù)集配置文件例如data/phonecall.yaml# 數(shù)據(jù)集路徑 path: ../PhoneCall_Detection/data train: images/train val: images/val # 類別數(shù) nc: 2 # 如果使用‘person’和‘cellphone’兩類就是2。如果只用‘calling’一類就是1。 # 類別名稱列表 names: [person, cellphone] # 或 [calling]4. YOLOv5模型訓(xùn)練全流程解析4.1 環(huán)境搭建與代碼準(zhǔn)備首先從官方倉(cāng)庫(kù)克隆代碼并安裝依賴。# 克隆YOLOv5倉(cāng)庫(kù)建議使用較穩(wěn)定的版本如v6.0 git clone -b v6.0 https://github.com/ultralytics/yolov5.git cd yolov5 pip install -r requirements.txt # 安裝所有依賴踩坑記錄PyTorch版本需與CUDA版本匹配。如果使用GPU務(wù)必去PyTorch官網(wǎng)核對(duì)安裝命令。我曾因版本不匹配導(dǎo)致訓(xùn)練時(shí)卡死。4.2 模型選擇與遷移學(xué)習(xí)YOLOv5提供了多種規(guī)模的模型。對(duì)于“打電話檢測(cè)”這是一個(gè)相對(duì)簡(jiǎn)單的任務(wù)但為了保證在復(fù)雜場(chǎng)景下的精度我選擇了中等規(guī)模的YOLOv5m。它比YOLOv5s精度更高比YOLOv5l速度更快。啟動(dòng)訓(xùn)練的命令python train.py \ --img 640 \ # 訓(xùn)練圖片尺寸 --batch 16 \ # 批次大小根據(jù)GPU內(nèi)存調(diào)整 --epochs 100 \ # 訓(xùn)練輪數(shù) --data ../PhoneCall_Detection/data/phonecall.yaml \ # 數(shù)據(jù)集配置文件 --cfg models/yolov5m.yaml \ # 模型結(jié)構(gòu)配置文件 --weights yolov5m.pt \ # 加載預(yù)訓(xùn)練權(quán)重這是關(guān)鍵 --name phonecall_exp \ # 本次實(shí)驗(yàn)名稱 --cache \ # 緩存圖片到內(nèi)存加速訓(xùn)練 --device 0 # 使用GPU 0關(guān)鍵參數(shù)解析--weights yolov5m.pt這是遷移學(xué)習(xí)的精髓。yolov5m.pt是在COCO數(shù)據(jù)集上預(yù)訓(xùn)練好的權(quán)重。加載它意味著我們的模型已經(jīng)從海量數(shù)據(jù)中學(xué)到了如何提取通用特征邊緣、紋理、形狀等。我們只需要在其基礎(chǔ)上針對(duì)“打電話”這個(gè)特定任務(wù)進(jìn)行微調(diào)Fine-tuning這比從零訓(xùn)練快得多效果好得多。--img 640YOLOv5的默認(rèn)輸入尺寸。更大的尺寸如1280可能提升對(duì)小目標(biāo)的檢測(cè)精度但會(huì)顯著增加計(jì)算量和內(nèi)存消耗需要同步調(diào)整batch-size。--batch 16一次輸入16張圖片。在GPU內(nèi)存允許的情況下較大的batch size有助于訓(xùn)練穩(wěn)定。如果出現(xiàn)CUDA out of memory錯(cuò)誤需要降低batch或img大小。--epochs 100通常足夠收斂。可以通過(guò)觀察驗(yàn)證集損失曲線提前停止。4.3 訓(xùn)練過(guò)程監(jiān)控與超參數(shù)調(diào)優(yōu)訓(xùn)練開(kāi)始后YOLOv5會(huì)在runs/train/phonecall_exp目錄下生成大量有用的文件和可視化結(jié)果。results.png最重要的圖表包含了訓(xùn)練集和驗(yàn)證集的邊界框損失、分類損失、目標(biāo)性損失以及精度Precision、召回率Recall、mAP0.5等指標(biāo)。我們的目標(biāo)是讓驗(yàn)證集損失平穩(wěn)下降且mAP穩(wěn)步上升。confusion_matrix.png混淆矩陣查看類別間誤檢情況。例如cellphone是否容易被誤檢為person或其他背景。val_batch0_pred.jpg驗(yàn)證集樣本的預(yù)測(cè)結(jié)果可以直觀看到模型當(dāng)前的表現(xiàn)。超參數(shù)調(diào)優(yōu)經(jīng)驗(yàn) YOLOv5的超參數(shù)定義在data/hyps/目錄下。對(duì)于自定義數(shù)據(jù)集微調(diào)超參數(shù)能帶來(lái)提升。我主要調(diào)整了以下幾個(gè)學(xué)習(xí)率lr0這是最重要的參數(shù)。預(yù)訓(xùn)練權(quán)重微調(diào)時(shí)學(xué)習(xí)率不宜太大否則會(huì)破壞已有的好特征。我通常從默認(rèn)值如0.01開(kāi)始如果訓(xùn)練初期損失震蕩劇烈就調(diào)小如0.001。數(shù)據(jù)增強(qiáng)參數(shù)如前所述降低degrees旋轉(zhuǎn)角度和shear剪切強(qiáng)度以保持打電話姿態(tài)的完整性。適當(dāng)提高h(yuǎn)sv_h色調(diào)抖動(dòng)來(lái)增強(qiáng)色彩魯棒性。損失函數(shù)權(quán)重box_loss,obj_loss,cls_loss的權(quán)重。除非有特殊需求一般不建議新手改動(dòng)。一個(gè)實(shí)用的方法是使用網(wǎng)格搜索或貝葉斯優(yōu)化工具如wandb進(jìn)行自動(dòng)化調(diào)參但手動(dòng)根據(jù)結(jié)果分析調(diào)整2-3輪也能取得不錯(cuò)效果。4.4 模型評(píng)估與導(dǎo)出訓(xùn)練完成后在runs/train/phonecall_exp/weights目錄下會(huì)得到兩個(gè)最重要的模型文件best.pt在驗(yàn)證集上表現(xiàn)最好的權(quán)重。last.pt最后一輪的權(quán)重。我們使用best.pt進(jìn)行后續(xù)的評(píng)估和推理。評(píng)估模型python val.py \ --data ../PhoneCall_Detection/data/phonecall.yaml \ --weights runs/train/phonecall_exp/weights/best.pt \ --img 640 \ --batch 16 \ --task val \ --name phonecall_eval評(píng)估報(bào)告會(huì)詳細(xì)列出各個(gè)類別的精確率、召回率、mAP等這是我們判斷模型好壞的客觀標(biāo)準(zhǔn)。一個(gè)不錯(cuò)的“打電話”檢測(cè)模型mAP0.5應(yīng)該能達(dá)到0.85以上。模型導(dǎo)出 為了在PyQt界面中使用我們需要將PyTorch模型.pt導(dǎo)出為更通用的格式。最常用的是TorchScript或ONNX。# 導(dǎo)出為ONNX格式推薦兼容性更廣 python export.py \ --weights runs/train/phonecall_exp/weights/best.pt \ --img 640 640 \ # 輸入尺寸 (高寬) --batch 1 \ # 批處理大小 --device cpu \ # 導(dǎo)出時(shí)指定設(shè)備如果部署環(huán)境是CPU就選cpu --include onnx \ # 導(dǎo)出為ONNX --simplify # 簡(jiǎn)化模型導(dǎo)出的best.onnx文件就可以被OpenCV DNN、TensorRT等多種推理引擎加載為后續(xù)部署到不同平臺(tái)包括嵌入式設(shè)備提供了便利。5. PyQt圖形界面開(kāi)發(fā)與集成5.1 界面設(shè)計(jì)與功能規(guī)劃我們的PyQt界面需要實(shí)現(xiàn)以下核心功能媒體加載支持選擇單張圖片、圖片文件夾或視頻文件。模型加載選擇我們訓(xùn)練好的.pt或.onnx模型文件。推理執(zhí)行點(diǎn)擊按鈕對(duì)當(dāng)前媒體進(jìn)行檢測(cè)。結(jié)果可視化在圖片/視頻幀上繪制檢測(cè)框、類別標(biāo)簽和置信度。結(jié)果輸出顯示統(tǒng)計(jì)信息如檢測(cè)到的目標(biāo)數(shù)量并可將帶標(biāo)注的結(jié)果保存到本地。界面布局可以設(shè)計(jì)如下左側(cè)為媒體顯示區(qū)域QLabel右側(cè)為控制面板QGroupBox包含文件選擇按鈕、模型加載按鈕、推理按鈕、參數(shù)調(diào)節(jié)滑塊如置信度閾值、NMS閾值和結(jié)果信息顯示區(qū)QTextEdit。5.2 推理引擎的集成在PyQt中我們需要一個(gè)后臺(tái)線程來(lái)執(zhí)行模型推理避免阻塞UI主線程導(dǎo)致界面卡死。這里以使用原始PyTorch模型.pt為例展示核心推理代碼的集成。首先創(chuàng)建一個(gè)專門的工作線程類from PyQt5.QtCore import QThread, pyqtSignal import torch import cv2 import numpy as np class DetectionThread(QThread): # 定義信號(hào)用于與主線程通信 finished pyqtSignal(np.ndarray) # 發(fā)送處理后的圖像 info_updated pyqtSignal(str) # 發(fā)送檢測(cè)信息 def __init__(self, model_path, image, conf_thres0.5, iou_thres0.45): super().__init__() self.model_path model_path self.image image self.conf_thres conf_thres self.iou_thres iou_thres self.model None def run(self): 線程運(yùn)行的核心函數(shù) # 1. 加載模型懶加載第一次運(yùn)行時(shí)加載 if self.model is None: self.model torch.load(self.model_path, map_locationcpu)[model].float().eval() # 如果使用GPU可以改為 .to(cuda) # 2. 預(yù)處理圖像 img_rgb cv2.cvtColor(self.image, cv2.COLOR_BGR2RGB) img_resized self.preprocess(img_rgb) # 3. 推理 with torch.no_grad(): pred self.model(img_resized)[0] # 4. 后處理非極大值抑制(NMS) detections self.non_max_suppression(pred, self.conf_thres, self.iou_thres) # 5. 在原圖上繪制結(jié)果 result_img self.draw_boxes(self.image, detections) # 6. 發(fā)送信號(hào) self.finished.emit(result_img) self.info_updated.emit(f檢測(cè)到 {len(detections)} 個(gè)目標(biāo)) def preprocess(self, img): 將圖像預(yù)處理為模型輸入格式 # 這里需要實(shí)現(xiàn)resize, padding, 歸一化維度轉(zhuǎn)換等 # 具體代碼需參考YOLOv5的utils.datasets.py中的letterbox函數(shù) pass def non_max_suppression(self, prediction, conf_thres, iou_thres): 非極大值抑制過(guò)濾重疊框 # 具體實(shí)現(xiàn)參考YOLOv5的utils.general.py中的non_max_suppression函數(shù) pass def draw_boxes(self, img, detections): 在圖像上繪制檢測(cè)框 for *xyxy, conf, cls in detections: label f{self.model.names[int(cls)]} {conf:.2f} # 使用cv2.rectangle和cv2.putText畫(huà)框和文字 pass return img在主界面中我們連接按鈕信號(hào)啟動(dòng)這個(gè)工作線程class MainWindow(QMainWindow): def __init__(self): super().__init__() # ... 界面初始化代碼 ... self.detection_thread None self.btn_detect.clicked.connect(self.start_detection) def start_detection(self): if self.current_image is None: return # 禁用檢測(cè)按鈕防止重復(fù)點(diǎn)擊 self.btn_detect.setEnabled(False) # 創(chuàng)建并啟動(dòng)線程 self.detection_thread DetectionThread( model_pathruns/train/phonecall_exp/weights/best.pt, imageself.current_image, conf_thresself.slider_confidence.value()/100.0 ) self.detection_thread.finished.connect(self.on_detection_finished) self.detection_thread.info_updated.connect(self.text_info.append) self.detection_thread.start() def on_detection_finished(self, result_img): # 在主線程中更新UI self.display_image(result_img) self.btn_detect.setEnabled(True)5.3 性能優(yōu)化與體驗(yàn)提升視頻流處理對(duì)于視頻檢測(cè)需要在一個(gè)循環(huán)中讀取幀并送入檢測(cè)線程。可以使用QTimer定時(shí)觸發(fā)檢測(cè)或者使用另一個(gè)專門的視頻處理線程。注意控制檢測(cè)頻率如果每幀都檢測(cè)且模型較慢會(huì)導(dǎo)致嚴(yán)重延遲。可以采用跳幀檢測(cè)或降低視頻顯示分辨率。實(shí)時(shí)性優(yōu)化模型簡(jiǎn)化使用更小的模型YOLOv5s或?qū)δP瓦M(jìn)行剪枝、量化。推理引擎使用TensorRT或OpenVINO對(duì)ONNX模型進(jìn)行加速在相同硬件上可獲得數(shù)倍的性能提升。硬件加速確保PyTorch使用了GPUCUDA進(jìn)行推理。參數(shù)實(shí)時(shí)調(diào)節(jié)將置信度閾值和NMS閾值的滑塊信號(hào)連接到檢測(cè)函數(shù)實(shí)現(xiàn)參數(shù)實(shí)時(shí)調(diào)整并立即看到效果變化這對(duì)于模型調(diào)試非常有用。6. 項(xiàng)目封裝、部署與常見(jiàn)問(wèn)題排查6.1 使用PyInstaller打包為EXE為了讓沒(méi)有Python環(huán)境的人也能使用我們將整個(gè)應(yīng)用打包成Windows可執(zhí)行文件。首先創(chuàng)建一個(gè)主程序入口腳本main.py它只負(fù)責(zé)啟動(dòng)你的PyQt主窗口。然后使用PyInstaller打包。pip install pyinstaller # 基本打包命令 pyinstaller -F -w -i icon.ico main.py-F: 打包成單個(gè)exe文件。-w: 運(yùn)行時(shí)不顯示控制臺(tái)窗口對(duì)于GUI程序。-i: 設(shè)置exe的圖標(biāo)。打包巨坑與解決方案問(wèn)題1打包后運(yùn)行提示“No module named ‘torch’, ‘cv2’”等。原因PyInstaller有時(shí)無(wú)法自動(dòng)打包所有的二進(jìn)制依賴。解決在打包命令中通過(guò)--hidden-import手動(dòng)指定或創(chuàng)建一個(gè)hook文件。更簡(jiǎn)單的方法是在虛擬環(huán)境中確保所有依賴都已安裝然后使用--collect-all參數(shù)謹(jǐn)慎使用可能會(huì)使包很大。推薦方案使用spec文件進(jìn)行高級(jí)配置。先生成一個(gè)基礎(chǔ)的spec文件pyi-makespec main.py。然后編輯main.spec在Analysis部分添加隱藏導(dǎo)入a Analysis([main.py], pathex[], binaries[], datas[], # 這里很重要需要把模型文件、配置文件等資源加進(jìn)來(lái) hiddenimports[torch, torchvision, cv2, PIL, numpy, pyqt5], # 添加所有可能缺失的庫(kù) hookspath[], ...)還需要把模型文件等資源復(fù)制到exe所在目錄需要在datas里指定datas[(runs/train/phonecall_exp/weights/best.pt, .), (data/phonecall.yaml, data)],最后用pyinstaller main.spec命令打包。問(wèn)題2打包文件體積巨大1GB。原因PyInstaller打包了整個(gè)PyTorch和CUDA庫(kù)。解決使用CPU版本的PyTorch進(jìn)行打包pip install torch torchvision --index-url https://download.pytorch.org/whl/cpu。在推理代碼中確保模型加載到CPUtorch.load(..., map_locationcpu)。使用--exclude-module嘗試排除不必要的模塊效果有限。終極方案考慮使用ONNX RuntimeCPU版作為推理后端它比完整的PyTorchCUDA小得多。將模型導(dǎo)出為ONNX然后在PyQt中改用onnxruntime庫(kù)加載和推理。6.2 部署到其他平臺(tái)Linux/MacPyInstaller同樣支持在對(duì)應(yīng)系統(tǒng)下執(zhí)行打包命令即可。Web服務(wù)可以使用FastAPI或Flask將模型封裝成RESTful API前端通過(guò)網(wǎng)頁(yè)上傳圖片并獲取檢測(cè)結(jié)果。嵌入式設(shè)備如RK3568, RV1106這是另一個(gè)深水區(qū)。通常步驟是將模型轉(zhuǎn)換為該芯片廠商支持的格式如RKNN for Rockchip, NNIE for HiSilicon。使用C/C編寫(xiě)針對(duì)該平臺(tái)的推理代碼并優(yōu)化內(nèi)存和速度。編寫(xiě)簡(jiǎn)單的本地UI如基于Qt for Embedded或直接將結(jié)果通過(guò)網(wǎng)絡(luò)發(fā)送。 這個(gè)過(guò)程需要參考芯片廠商的官方SDK和文檔挑戰(zhàn)較大。6.3 常見(jiàn)問(wèn)題排查速查表問(wèn)題現(xiàn)象可能原因排查步驟與解決方案訓(xùn)練時(shí)loss為NaN學(xué)習(xí)率過(guò)高數(shù)據(jù)標(biāo)注有誤如坐標(biāo)超出0-1數(shù)據(jù)中存在損壞圖片。1. 大幅降低學(xué)習(xí)率lr0。2. 檢查標(biāo)注文件格式是否正確特別是歸一化坐標(biāo)。3. 使用--cache參數(shù)時(shí)嘗試不使用它或檢查圖片文件。模型推理速度慢模型過(guò)大如用了YOLOv5x未使用GPU推理輸入圖片尺寸過(guò)大。1. 換用更小的模型YOLOv5s/n。2. 確認(rèn)torch.cuda.is_available()為True模型和數(shù)據(jù)已.to(‘cuda’)。3. 減小推理時(shí)的imgsz參數(shù)如從640降到320。檢測(cè)框閃爍或不穩(wěn)定視頻中視頻幀間抖動(dòng)置信度閾值過(guò)低。1. 對(duì)檢測(cè)結(jié)果進(jìn)行軌跡平滑如使用卡爾曼濾波或簡(jiǎn)單的移動(dòng)平均。2. 適當(dāng)提高置信度閾值conf-thres。誤檢率高將水杯、手等檢為手機(jī)訓(xùn)練數(shù)據(jù)中負(fù)樣本類似物體但不是手機(jī)不足手機(jī)特征學(xué)習(xí)不充分。1. 在數(shù)據(jù)集中增加“困難負(fù)樣本”如手拿水杯、對(duì)講機(jī)等的圖片并進(jìn)行正確標(biāo)注或作為背景。2. 增加數(shù)據(jù)增強(qiáng)特別是色彩和模糊讓模型更關(guān)注形狀而非顏色。3. 檢查混淆矩陣針對(duì)性補(bǔ)充數(shù)據(jù)。漏檢率高尤其是小目標(biāo)或遮擋目標(biāo)數(shù)據(jù)集中小目標(biāo)和遮擋樣本少模型輸入分辨率過(guò)低。1. 專門收集并標(biāo)注小尺寸、遮擋嚴(yán)重的打電話圖片。2. 提高訓(xùn)練和推理時(shí)的imgsz如從640升到1280但要注意計(jì)算成本。3. 在數(shù)據(jù)增強(qiáng)中增加Mosaic和MixUp的比例。PyQt界面點(diǎn)擊檢測(cè)按鈕無(wú)反應(yīng)UI被推理線程阻塞信號(hào)/槽連接錯(cuò)誤。1. 確保推理任務(wù)在獨(dú)立的QThread中運(yùn)行并通過(guò)信號(hào)更新UI。2. 使用print或日志檢查線程的run函數(shù)是否被正確調(diào)用。3. 檢查按鈕的clicked信號(hào)是否正確連接到啟動(dòng)線程的槽函數(shù)。這個(gè)項(xiàng)目從數(shù)據(jù)準(zhǔn)備到最終可用的桌面軟件涉及了AI項(xiàng)目落地的多個(gè)關(guān)鍵環(huán)節(jié)。每個(gè)環(huán)節(jié)都有不少細(xì)節(jié)需要打磨尤其是數(shù)據(jù)質(zhì)量和推理性能的優(yōu)化往往需要反復(fù)迭代。希望這份詳細(xì)的梳理能幫你避開(kāi)我踩過(guò)的那些坑更順暢地完成自己的目標(biāo)檢測(cè)應(yīng)用。本文還有配套的精品資源點(diǎn)擊獲取