:從模型訓(xùn)練到部署實(shí)戰(zhàn))
做深度學(xué)習(xí)目標(biāo)檢測項(xiàng)目的人應(yīng)該都清楚密集行人檢測一直是個(gè)讓人頭疼的方向。人群場景里人挨著人、互相遮擋、尺度變化大用傳統(tǒng)檢測思路很難兼顧速度和精度。我最近把一個(gè)基于YOLOv12的密集行人識(shí)別檢測系統(tǒng)完整落地了包含訓(xùn)練好的模型、Python源碼、登錄注冊界面和可視化UI整套流程走下來踩了不少坑。這篇文章就把項(xiàng)目從數(shù)據(jù)準(zhǔn)備、模型訓(xùn)練到系統(tǒng)集成的完整過程拆開講分享一些真正能落地的經(jīng)驗(yàn)和細(xì)節(jié)適合正在做畢業(yè)設(shè)計(jì)、課程項(xiàng)目或者想快速上手YOLOv12做實(shí)際檢測系統(tǒng)的同學(xué)參考。1. 項(xiàng)目概述與核心需求拆解1.1 項(xiàng)目背景與實(shí)際需求密集行人檢測和普通的目標(biāo)檢測有幾個(gè)明顯的差異點(diǎn)。在商場、地鐵站、景區(qū)出入口這些場景里行人密度極高單個(gè)畫面里可能有幾十甚至上百個(gè)人而且行人之間互相遮擋嚴(yán)重遠(yuǎn)處的人只占幾十個(gè)像素近處的人可能占據(jù)大半個(gè)畫面。這種尺度差異和遮擋問題對模型的特征提取能力和檢測頭的回歸精度要求非常高。傳統(tǒng)的檢測算法要么漏檢率居高不下要么在GPU上跑起來幀率感人很難滿足實(shí)際場景對實(shí)時(shí)性和準(zhǔn)確率的雙重需求。我做的這個(gè)項(xiàng)目目標(biāo)很明確搭建一套完整可運(yùn)行的密集行人檢測系統(tǒng)而不是只訓(xùn)練一個(gè)模型就完事。系統(tǒng)需要包含用戶登錄注冊功能方便不同使用者管理自己的檢測任務(wù)需要提供一個(gè)圖形化界面讓用戶能上傳圖片或者視頻直觀看到檢測結(jié)果包括檢測框、置信度、當(dāng)前畫面人數(shù)統(tǒng)計(jì)等信息。模型層面要選一個(gè)在精度和速度之間平衡較好、且工程部署成熟度高的算法我最終選了YOLOv12。它的整體架構(gòu)在特征提取和多尺度融合上有不少改進(jìn)處理密集小目標(biāo)的場景比我之前用的一些方案要從容得多。需要說明的是模型本身我用的是公開可獲取的行人檢測數(shù)據(jù)和預(yù)訓(xùn)練權(quán)重進(jìn)行訓(xùn)練調(diào)優(yōu)同時(shí)在數(shù)據(jù)集層面針對密集場景做了專門的篩選和增強(qiáng)處理這部分會(huì)在后面詳細(xì)展開。整個(gè)項(xiàng)目的代碼結(jié)構(gòu)分為模型訓(xùn)練模塊、后端推理模塊、Web界面模塊三個(gè)部分各模塊之間通過約定好的接口串聯(lián)這也是為了后續(xù)擴(kuò)展和維護(hù)方便。1.2 技術(shù)選型與方案對比在做方案選型的時(shí)候我其實(shí)對比了好幾條技術(shù)路線。第一梯隊(duì)是直接用現(xiàn)成的檢測API比如各種云平臺(tái)提供的行人檢測服務(wù)優(yōu)點(diǎn)是省事但缺點(diǎn)也很明顯數(shù)據(jù)要傳出去隱私和延遲都是問題而且沒法針對自己的場景做模型定制。第二梯隊(duì)是自己從零寫檢測算法這個(gè)工作量太大了科研階段可以這么做工程項(xiàng)目沒必要。第三梯隊(duì)就是基于開源檢測框架做二次開發(fā)在自己準(zhǔn)備的數(shù)據(jù)集上訓(xùn)練和調(diào)優(yōu)這也是絕大多數(shù)實(shí)際項(xiàng)目的做法。在具體框架選擇上我對比了YOLOv5、YOLOv8和YOLOv12。YOLOv5出現(xiàn)時(shí)間長社區(qū)資料最多遇到問題容易找到答案但它的結(jié)構(gòu)相對老一些處理密集小目標(biāo)的效果有限。YOLOv8在C2f結(jié)構(gòu)、Anchor-Free檢測頭、數(shù)據(jù)增強(qiáng)策略方面做了不少改進(jìn)整體表現(xiàn)已經(jīng)不錯(cuò)。YOLOv12則是在前代基礎(chǔ)上引入了更先進(jìn)的注意力機(jī)制和多尺度融合策略在COCO這類復(fù)雜數(shù)據(jù)集上的檢測精度有進(jìn)一步提升尤其在小目標(biāo)和遮擋場景下的表現(xiàn)更穩(wěn)。最終選擇YOLOv12不只是看精度數(shù)字還考慮了工程落地的完整度。它的模型導(dǎo)出、量化部署、推理優(yōu)化的工具鏈比較成熟從PyTorch訓(xùn)練到導(dǎo)出ONNX再到后續(xù)部署鏈路很順暢。另外它對GPU顯存的要求不算離譜我這邊用一塊中等偏上的顯卡就能完成訓(xùn)練網(wǎng)上的開源資源和現(xiàn)成代碼也比較多遇到問題能查到解決方案。綜合來看YOLOv12是這個(gè)項(xiàng)目性價(jià)比最高的選擇。在界面層面我用Python的Web框架作為后端服務(wù)前端用輕量級(jí)的HTMLCSSJavaScript實(shí)現(xiàn)。選這個(gè)組合有幾個(gè)原因一是前后端部署簡單單機(jī)就能跑適合演示和畢設(shè)展示二是Python生態(tài)里調(diào)用PyTorch模型推理非常方便不用跨語言三是界面代碼容易改后續(xù)想換主題或者加頁面都很靈活。2. 數(shù)據(jù)集準(zhǔn)備與標(biāo)注實(shí)務(wù)2.1 數(shù)據(jù)集的獲取與篩選模型效果好不好數(shù)據(jù)集質(zhì)量是第一位的。YOLOv12雖然自帶預(yù)訓(xùn)練權(quán)重但預(yù)訓(xùn)練模型的類別覆蓋所有COCO類別直接在行人檢測場景上使用效果只能說勉強(qiáng)能用。要對密集行人場景有更好的檢測能力必須在專門的數(shù)據(jù)集上做微調(diào)。我在這個(gè)項(xiàng)目里用了一個(gè)公開的行人檢測數(shù)據(jù)集作為基礎(chǔ)同時(shí)從多個(gè)公開數(shù)據(jù)源里補(bǔ)充了一些密集人群場景的圖片。篩選的時(shí)候有幾個(gè)硬性標(biāo)準(zhǔn)畫面里必須有大量行人且存在明顯的重疊遮擋人臉的像素尺寸分布要廣既有大目標(biāo)也有小目標(biāo)場景要多樣白天、夜晚、室內(nèi)、室外都要有不然模型很容易過擬合到單一環(huán)境。前后整理下來有效圖片大概有一萬多張標(biāo)注的總行人數(shù)在幾萬量級(jí)。這個(gè)數(shù)據(jù)規(guī)模不算大但對單類別檢測來說已經(jīng)足夠支撐訓(xùn)練出一個(gè)可用的模型而且我后續(xù)做了不少數(shù)據(jù)增強(qiáng)來彌補(bǔ)樣本量不足的問題。標(biāo)注格式統(tǒng)一采用YOLO格式。每個(gè)圖片對應(yīng)一個(gè)同名的txt文件文件里每一行代表一個(gè)目標(biāo)格式是類別ID、歸一化后的中心點(diǎn)x坐標(biāo)、中心點(diǎn)y坐標(biāo)、歸一化后的框?qū)挾?、歸一化后的框高度。比如一張1920x1080的圖片里有一個(gè)行人框的左上角是(120, 80)右下角是(260, 400)那么對應(yīng)的歸一化計(jì)算就是中心點(diǎn)x(120260)/2/19200.0989中心點(diǎn)y(80400)/2/10800.2222寬度(260-120)/19200.0729高度(400-80)/10800.2963。這個(gè)格式在標(biāo)注工具導(dǎo)出時(shí)一般會(huì)自動(dòng)生成但自己檢查數(shù)據(jù)的時(shí)候手算一遍能加深理解。2.2 標(biāo)注質(zhì)量控制的幾個(gè)關(guān)鍵點(diǎn)標(biāo)注環(huán)節(jié)是純體力活也是最容易影響模型最終效果的環(huán)節(jié)。我在標(biāo)注和復(fù)核過程中發(fā)現(xiàn)以下幾個(gè)問題最容易出紕漏。第一個(gè)是遮擋目標(biāo)的標(biāo)注邊界。密集人群里很多行人只露出半個(gè)身子或者一個(gè)頭標(biāo)注的時(shí)候到底框到什么位置我的規(guī)則是只要能夠判斷這是一個(gè)獨(dú)立的人哪怕只有頭部可見也標(biāo)注出來框就貼著可見區(qū)域的邊緣。這樣模型才能在遮擋場景中學(xué)到“人只露出一部分也是人”的特征。如果漏標(biāo)了遮擋嚴(yán)重的行人模型訓(xùn)練時(shí)會(huì)把這些區(qū)域當(dāng)背景容易在推理時(shí)漏檢。第二個(gè)是小目標(biāo)的標(biāo)注精度。遠(yuǎn)處的小人可能只有十幾個(gè)像素標(biāo)注時(shí)候手一抖框就偏了。而YOLO格式對框的坐標(biāo)歸一化后小目標(biāo)的誤差會(huì)被放大。我后來是在標(biāo)注工具里把圖片放大到200%到300%再標(biāo)注確保小目標(biāo)的框貼合目標(biāo)邊緣。第三個(gè)是數(shù)據(jù)劃分。訓(xùn)練集、驗(yàn)證集、測試集要按大約8:1:1劃分而且要注意同一個(gè)場景的圖片不能同時(shí)出現(xiàn)在訓(xùn)練集和驗(yàn)證集里否則模型相當(dāng)于見過答案驗(yàn)證集指標(biāo)會(huì)虛高。我按照場景來源來劃分而不是隨機(jī)劃分這樣更接近真實(shí)應(yīng)用場景的泛化要求。提示標(biāo)注完成后一定要做一次數(shù)據(jù)可視化檢查。把標(biāo)注框畫回原圖上隨機(jī)抽幾百張圖人工看能發(fā)現(xiàn)大量標(biāo)注錯(cuò)位、漏標(biāo)、類別錯(cuò)誤的問題。這一步雖然費(fèi)時(shí)間但能避免模型帶著錯(cuò)誤數(shù)據(jù)訓(xùn)練幾小時(shí)甚至幾天。2.3 數(shù)據(jù)增強(qiáng)與樣本均衡策略數(shù)據(jù)集準(zhǔn)備完我在訓(xùn)練前還做了數(shù)據(jù)增強(qiáng)主要目的是提升模型對場景變化的魯棒性。YOLOv12的訓(xùn)練流程本身就內(nèi)置了Mosaic增強(qiáng)會(huì)把四張圖拼成一張圖訓(xùn)練這對提升模型應(yīng)對遮擋和小目標(biāo)的能力幫助很大。我在訓(xùn)練腳本里還額外開啟了水平翻轉(zhuǎn)、隨機(jī)亮度對比度調(diào)整、隨機(jī)縮放和色彩抖動(dòng)。實(shí)際操作中有一個(gè)很值得注意的細(xì)節(jié)密集行人場景里大目標(biāo)和小目標(biāo)的數(shù)量分布往往很極端。近處的大目標(biāo)少但面積大遠(yuǎn)處的小目標(biāo)多但很容易漏檢。YOLOv12的多尺度訓(xùn)練對這個(gè)問題有天然優(yōu)勢因?yàn)槟P蜁?huì)在不同分辨率下看到同一個(gè)目標(biāo)。我還用了自適應(yīng)錨框計(jì)算在訓(xùn)練前重新聚類了數(shù)據(jù)集中真實(shí)標(biāo)注框的尺寸分布讓錨框更貼合行人這種寬高比比較固定的目標(biāo)類型。數(shù)據(jù)增強(qiáng)不是越多越好我踩過一個(gè)坑把Mosaic開啟的強(qiáng)度調(diào)太高導(dǎo)致訓(xùn)練出來的模型出現(xiàn)了一些奇怪的預(yù)測比如隔著圍欄也檢測到一堆人。后來把增強(qiáng)參數(shù)調(diào)回合理范圍問題就恢復(fù)正常。增強(qiáng)的本質(zhì)是增加數(shù)據(jù)多樣性但要在模擬真實(shí)場景的范圍內(nèi)不能過度扭曲目標(biāo)的外觀特征。3. 模型訓(xùn)練與調(diào)優(yōu)過程3.1 訓(xùn)練環(huán)境準(zhǔn)備與依賴安裝訓(xùn)練環(huán)境我建議直接用Linux環(huán)境原因不多說深度學(xué)習(xí)生態(tài)對Linux的支持就是比Windows順暢。沒有現(xiàn)成Linux環(huán)境的話Windows上通過WSL也能跑但配置過程會(huì)多一些坑。顯卡方面我這次用的是某型號(hào)的消費(fèi)級(jí)顯卡顯存在8GB左右YOLOv12的小模型在這個(gè)顯存下可以用默認(rèn)參數(shù)訓(xùn)練如果顯存緊張就把batch size調(diào)小配合梯度累積來等效增大批大小。軟件依賴方面核心就是PyTorch和配套的CUDA版本。裝PyTorch的時(shí)候最容易踩的坑是CUDA版本和顯卡驅(qū)動(dòng)版本不匹配裝完發(fā)現(xiàn)torch.cuda.is_available()返回False。我的建議是先用nvidia-smi查看當(dāng)前驅(qū)動(dòng)支持的最高CUDA版本再去PyTorch官網(wǎng)選擇對應(yīng)的安裝命令。虛擬環(huán)境一定要用我見過太多人圖省事直接裝在全局環(huán)境里最后依賴沖突把系統(tǒng)搞崩了。推薦用conda創(chuàng)建獨(dú)立環(huán)境Python版本選3.9或3.10都行。項(xiàng)目的目錄結(jié)構(gòu)我會(huì)分成數(shù)據(jù)目錄、模型配置目錄、訓(xùn)練腳本目錄、推理腳本目錄和應(yīng)用界面目錄。數(shù)據(jù)目錄里放images和labels兩個(gè)子目錄再按train、val、test分別組織。模型配置目錄里存放YOLOv12的網(wǎng)絡(luò)結(jié)構(gòu)配置文件和超參數(shù)配置文件。訓(xùn)練腳本是整個(gè)模型訓(xùn)練的核心入口需要讀入數(shù)據(jù)配置和模型配置啟動(dòng)訓(xùn)練流程。3.2 訓(xùn)練參數(shù)的設(shè)置思路與調(diào)優(yōu)過程訓(xùn)練參數(shù)是新手最容易一頭霧水的地方。我把自己用的關(guān)鍵參數(shù)列一個(gè)表并結(jié)合這個(gè)項(xiàng)目的實(shí)際情況說明為什么這么設(shè)參數(shù)我的設(shè)置設(shè)置理由輸入分辨率640x640平衡檢測精度與推理速度密集行人場景夠用Batch Size168GB顯存的上限附近配合梯度累積保證穩(wěn)定性Epochs150數(shù)據(jù)集不大150輪足以讓模型收斂防止過擬合學(xué)習(xí)率0.01配合Warmup策略初始階段用小學(xué)習(xí)率讓模型穩(wěn)定起步優(yōu)化器SGD訓(xùn)練數(shù)據(jù)量不大SGD配合動(dòng)量項(xiàng)收斂穩(wěn)定權(quán)重衰減0.0005抑制過擬合行人檢測數(shù)據(jù)集規(guī)模有限這個(gè)值合理IoU閾值0.2密集場景存在大量重疊框降低閾值避免抑制過多候選框訓(xùn)練過程中要持續(xù)關(guān)注兩個(gè)指標(biāo)的變化趨勢一個(gè)是訓(xùn)練集上的loss下降曲線一個(gè)是驗(yàn)證集上的mAP。loss下降曲線如果出現(xiàn)震蕩或者不降反升大概率是學(xué)習(xí)率太大或者數(shù)據(jù)有問題。mAP主要看兩個(gè)值一個(gè)是mAP0.5一個(gè)是mAP0.5:0.95。前者代表通用閾值下的平均精度后者代表嚴(yán)格閾值下的表現(xiàn)后者對密集遮擋場景更敏感。我最后訓(xùn)練完的模型在驗(yàn)證集上的mAP0.5接近九成mAP0.5:0.95也到了一個(gè)可用的水平對單個(gè)類別的檢測來說效果已經(jīng)很能打了。訓(xùn)練過程中我發(fā)現(xiàn)一個(gè)細(xì)節(jié)訓(xùn)練后期的loss曲線會(huì)出現(xiàn)周期性小波動(dòng)這通常是Mosaic增強(qiáng)帶來的隨機(jī)性不必太擔(dān)心。更值得關(guān)注的是驗(yàn)證集loss和訓(xùn)練集loss的差值如果這個(gè)差值越來越大說明模型開始過擬合了這時(shí)候可以加大權(quán)重衰減或者增加數(shù)據(jù)增強(qiáng)強(qiáng)度也可以提前停止訓(xùn)練。注意訓(xùn)練過程中的模型權(quán)重文件不要只保留最后一個(gè)建議每個(gè)epoch結(jié)束后保存最近的3到5個(gè)版本。因?yàn)橛袝r(shí)候倒數(shù)第幾個(gè)epoch的驗(yàn)證集指標(biāo)反而比最后一個(gè)更好我用的是效果最好的那個(gè)epoch來作為最終模型而不是最后一個(gè)epoch。3.3 密集場景下的訓(xùn)練結(jié)果分析與模型評(píng)估訓(xùn)練完成后模型評(píng)估不能只看數(shù)字還要做直觀的預(yù)測可視化。我自己從測試集里專門挑了幾類高難度樣本做分析第一類是幾十個(gè)人擠在一起的超密集畫面第二類是逆光環(huán)境下人員輪廓模糊的畫面第三類是畫面中有大面積遮擋欄桿或柱子干擾的畫面。在超密集畫面上模型能檢測出絕大多數(shù)行人但邊緣區(qū)域的人漏檢率明顯升高這和模型感受野有關(guān)。檢測框的置信度分布呈現(xiàn)出明顯兩極分化清晰完整的人框置信度能到0.85以上嚴(yán)重遮擋的人框置信度只有0.4上下。針對這個(gè)現(xiàn)象我在推理階段把置信度閾值調(diào)低到0.25同時(shí)開啟了二次篩選機(jī)制用NMS來抑制重復(fù)框。這個(gè)方案是我在密集場景下反復(fù)測試后確定下來的比固定閾值方案更靈活。逆光和弱光場景下模型表現(xiàn)比預(yù)期好因?yàn)閿?shù)據(jù)增強(qiáng)里加入了亮度和對比度的調(diào)整模型對光照變化有了一定魯棒性。但在極端暗光下漏檢率還是會(huì)明顯上升這屬于數(shù)據(jù)分布本身的問題需要補(bǔ)充更多的低光樣本后續(xù)還要定向優(yōu)化。我還做了消融實(shí)驗(yàn)來驗(yàn)證數(shù)據(jù)增強(qiáng)的貢獻(xiàn)。同一份數(shù)據(jù)關(guān)閉增強(qiáng)訓(xùn)練的模型在密集遮擋樣本上的漏檢率比開啟增強(qiáng)高了將近10個(gè)百分點(diǎn)充分說明數(shù)據(jù)增強(qiáng)在密集行人場景中的關(guān)鍵作用。如果你時(shí)間緊張只能做一項(xiàng)優(yōu)化優(yōu)先調(diào)整數(shù)據(jù)增強(qiáng)策略收益最大。4. 系統(tǒng)界面設(shè)計(jì)與功能集成4.1 登錄注冊模塊的設(shè)計(jì)與實(shí)現(xiàn)系統(tǒng)的用戶模塊是容易被人忽視但其實(shí)是完整項(xiàng)目重要加分項(xiàng)的部分。市面上很多檢測Demo只有檢測功能沒有用戶體系做畢設(shè)或者項(xiàng)目展示的時(shí)候有登錄注冊功能會(huì)顯得系統(tǒng)更完整、更有工程實(shí)踐的感覺。我實(shí)現(xiàn)的登錄注冊模塊基于輕量級(jí)的用戶管理邏輯。用戶注冊時(shí)提交用戶名和密碼后端先判斷用戶名是否已存在然后對密碼進(jìn)行加密存儲(chǔ)。密碼絕對不能明文保存到數(shù)據(jù)庫我用了常見的不可逆哈希方式加鹽處理以后再存。登錄時(shí)取出數(shù)據(jù)庫中的哈希值對輸入密碼做同樣的哈希運(yùn)算再比對。整個(gè)會(huì)話保持使用簡單的會(huì)話機(jī)制用戶登錄成功后拿到一個(gè)會(huì)話標(biāo)識(shí)后續(xù)請求帶上這個(gè)標(biāo)識(shí)就能訪問受保護(hù)的檢測功能。前端登錄頁面的設(shè)計(jì)遵循簡潔實(shí)用的原則一個(gè)居中的登錄表單包含用戶名、密碼和一個(gè)登錄按鈕下面放一個(gè)注冊鏈接。注冊頁面除了用戶名和密碼還加了一次確認(rèn)密碼的輸入框前端這邊就先校驗(yàn)兩次密碼是否一致避免無效請求打到后端。整個(gè)頁面用CSS做了基本的樣式美化邊框、陰影、圓角這些細(xì)節(jié)都要有視覺上像一個(gè)正經(jīng)的軟件界面。因?yàn)橛脩魯?shù)據(jù)存儲(chǔ)在本地的SQLite數(shù)據(jù)庫里整個(gè)注冊登錄流程不需要外部數(shù)據(jù)庫服務(wù)部署的時(shí)候零成本。這一條在真實(shí)項(xiàng)目里非常重要用戶拿到源碼以后跑起來立刻能用不需要額外安裝MySQL之類的組件。我在設(shè)計(jì)這個(gè)系統(tǒng)的時(shí)候原則就是能內(nèi)置的絕不外接降低復(fù)現(xiàn)門檻。4.2 檢測主界面與交互邏輯檢測主界面是整個(gè)系統(tǒng)的核心頁面我用網(wǎng)格布局分成幾個(gè)功能區(qū)。頁面頂部是標(biāo)題欄顯示系統(tǒng)名稱和當(dāng)前登錄用戶右側(cè)有退出登錄按鈕。中間主體區(qū)域分為左右兩列左側(cè)是操作區(qū)右側(cè)是顯示區(qū)。操作區(qū)里放三個(gè)表單圖片檢測模式支持上傳本地圖片視頻檢測模式支持上傳視頻文件還有一個(gè)攝像頭檢測模式調(diào)用本機(jī)攝像頭做實(shí)時(shí)檢測。每個(gè)模式對應(yīng)一個(gè)開始檢測按鈕和一個(gè)停止按鈕。選擇圖片上傳后前端會(huì)把圖片以二進(jìn)制流的形式通過HTTP接口發(fā)給后端。后端收到圖片后調(diào)用模型進(jìn)行推理推理完成后把檢測結(jié)果以JSON格式返回包含檢測框坐標(biāo)、置信度、目標(biāo)數(shù)量。前端拿到這個(gè)JSON數(shù)據(jù)之后用JavaScript在圖片的Canvas畫布上繪制矩形框和標(biāo)簽文字。這種前后端分離的方式有一個(gè)明顯優(yōu)勢用戶點(diǎn)擊開始檢測之后頁面不會(huì)卡死等待而是有一個(gè)加載狀態(tài)動(dòng)畫等結(jié)果返回后就能看到畫面。關(guān)于視頻檢測我在處理上采用了逐幀推理加抽幀繪畫的策略。視頻文件上傳到后端后后端用OpenCV逐幀讀取每幀都調(diào)用模型推理檢測結(jié)果實(shí)時(shí)繪制后編碼成新的視頻返回前端。這里最需要注意的性能瓶頸是逐幀推理速度如果模型推理一幀要50毫秒渲染一幀再要幾十毫秒視頻播放的流暢性就會(huì)打折。為了提升實(shí)時(shí)性我做了兩個(gè)層面的優(yōu)化一是把每幀的分辨率在進(jìn)入模型前等比縮小到640像素以內(nèi)二是視頻處理線程和結(jié)果返回線程分開避免IO阻塞推理。注意視頻幀處理完要嚴(yán)格釋放內(nèi)存不然長時(shí)間運(yùn)行會(huì)出現(xiàn)內(nèi)存占用持續(xù)增長的情況。OpenCV的Mat對象在Python里雖然有垃圾回收機(jī)制但幀率高了以后回收不及時(shí)的情況還是會(huì)出現(xiàn)。4.3 后端服務(wù)設(shè)計(jì)與模型推理集成后端服務(wù)我用Flask來實(shí)現(xiàn)這個(gè)框架足夠輕網(wǎng)絡(luò)請求的處理能力對這個(gè)體量的項(xiàng)目來說綽綽有余。啟動(dòng)的時(shí)候加載模型權(quán)重也就是把訓(xùn)練好的YOLOv12模型讀進(jìn)內(nèi)存初始化一次后續(xù)推理直接復(fù)用。這里有個(gè)性能關(guān)鍵點(diǎn)絕對不能在每個(gè)請求里重新加載模型那樣會(huì)讓響應(yīng)時(shí)間退化到不可接受。模型加載是耗時(shí)操作在應(yīng)用啟動(dòng)時(shí)只做一次后面所有請求共用同一個(gè)模型實(shí)例。后端接口總共設(shè)計(jì)了三個(gè)核心的檢測接口。一個(gè)是處理圖片檢測的接收POST請求二進(jìn)制圖片數(shù)據(jù)作為請求體處理后返回檢測結(jié)果的JSON一個(gè)是處理視頻檢測的接收視頻文件流按幀處理還有一個(gè)是攝像頭檢測模式調(diào)用的這個(gè)模式實(shí)際上是直接把攝像頭幀推送到后端檢測接口得到結(jié)果后返回給前端繪制。三個(gè)接口的邏輯大同小異核心都走同一個(gè)推理函數(shù)保證代碼復(fù)用。模型推理部分我額外封裝了一個(gè)推理類這個(gè)類接收圖片返回檢測結(jié)果列表。推理類內(nèi)部做這幾件事情讀取圖片并預(yù)處理到模型輸入尺寸執(zhí)行模型前向推理對模型輸出的檢測框做解碼和閾值過濾再用NMS壓制重復(fù)框最后把坐標(biāo)換算回原圖尺寸。這樣的封裝讓后端路由代碼保持簡潔后期想更換模型或者調(diào)整推理策略只需要修改推理類里的實(shí)現(xiàn)。我還給數(shù)據(jù)格式做了統(tǒng)一約定。前端向后端提交圖片或者是視頻流后端響應(yīng)統(tǒng)一返回JSON格式如下{ success: true, count: 42, results: [ {box: [120, 80, 260, 400], confidence: 0.92}, {box: [400, 150, 520, 380], confidence: 0.87} ] }前端拿到這個(gè)JSON后遍歷results數(shù)組中的每個(gè)檢測框數(shù)據(jù)就能在Canvas上快速繪制出所有檢測框。前后端通過這種約定好的數(shù)據(jù)結(jié)構(gòu)解耦調(diào)試時(shí)兩邊可以獨(dú)立測試非常方便。5. 部署經(jīng)驗(yàn)與常見問題排查5.1 模型推理速度優(yōu)化實(shí)戰(zhàn)模型訓(xùn)練好了系統(tǒng)也跑通了但實(shí)際部署時(shí)發(fā)現(xiàn)推理速度是一個(gè)繞不開的問題。在GPU上推理單幀640x640的圖片YOLOv12大概在幾十毫秒量級(jí)這個(gè)速度看起來不慢但對視頻流來說幀率只能到十幾幀每秒。要做到接近實(shí)時(shí)的檢測體驗(yàn)還需要做推理優(yōu)化的功課。第一個(gè)手段是開啟半精度推理。PyTorch的模型默認(rèn)是FP32精度改成FP16之后模型的顯存占用大約減半推理速度也能提升不少而且對檢測精度的影響極小。這個(gè)優(yōu)化幾乎是零成本我直接把模型在推理時(shí)轉(zhuǎn)成半精度模式實(shí)測下來對密集場景的檢測框坐標(biāo)精度沒有明顯影響。第二個(gè)手段是動(dòng)態(tài)分辨率調(diào)整。密集行人場景下很多人以為輸入分辨率越大檢測越準(zhǔn)實(shí)際上對視頻流而言過大分辨率會(huì)拖慢推理速度。我把輸入分辨率設(shè)置為可配置項(xiàng)圖片檢測用高分辨率保精度視頻檢測用低分辨率保速度做到各有側(cè)重。第三個(gè)手段是批量推理。處理視頻幀時(shí)把多幀圖片打包成一個(gè)批次喂給模型相比逐幀推理能提升吞吐量。我實(shí)測批次大小為4的時(shí)候整體處理速度比逐幀快了一倍還多代價(jià)只是多占一點(diǎn)顯存。5.2 環(huán)境配置與運(yùn)行問題速查做完整備錄一遍我在環(huán)境配置和運(yùn)行階段碰到了不少問題很多問題屬于典型情況在這里列一個(gè)速查表以后你遇到可以照著排查現(xiàn)象可能原因解決辦法模型加載報(bào)錯(cuò)提示找不到權(quán)重文件路徑配置錯(cuò)誤或權(quán)重文件未放置到對應(yīng)目錄檢查config文件中的模型路徑確認(rèn)是絕對路徑還是相對路徑檢測結(jié)果框坐標(biāo)明顯偏移推理時(shí)圖片預(yù)處理尺寸和還原尺寸不匹配確認(rèn)輸入尺寸是640x640輸出坐標(biāo)要按縮放比例換算回原圖攝像頭調(diào)用失敗OpenCV報(bào)錯(cuò)攝像頭被其他程序占用或權(quán)限不足關(guān)閉其他占用攝像頭的軟件或者檢查瀏覽器攝像頭權(quán)限設(shè)置Flask啟動(dòng)后端口被占用端口已被其他進(jìn)程使用換一個(gè)端口或者在啟動(dòng)時(shí)配置端口復(fù)用視頻檢測非??D推理速度跟不上視頻幀率降低輸入分辨率開啟半精度推理或者降低渲染幀率注冊用戶登錄后提示不存在數(shù)據(jù)庫文件路徑錯(cuò)誤或表結(jié)構(gòu)不一致檢查數(shù)據(jù)庫文件是否正常生成確認(rèn)表字段名一致環(huán)境依賴沖突的問題是另一個(gè)高頻問題。我見過不少人在沒有虛擬環(huán)境的情況下直接把各種依賴庫裝到全局環(huán)境結(jié)果版本沖突torch和numpy版本對不上模型推理時(shí)出現(xiàn)各種莫名其妙的報(bào)錯(cuò)。強(qiáng)烈建議所有Python項(xiàng)目都用虛擬環(huán)境管理依賴這一點(diǎn)怎么強(qiáng)調(diào)都不過分。5.3 項(xiàng)目擴(kuò)展與后續(xù)優(yōu)化方向目前這個(gè)系統(tǒng)已經(jīng)完整跑通了密集行人檢測的整個(gè)鏈路但實(shí)際用起來還有不少可以改進(jìn)的地方。如果你把這個(gè)項(xiàng)目作為基礎(chǔ)想往更深入的方向擴(kuò)展我覺得有幾個(gè)方向值得投入精力。第一個(gè)方向是行人跟蹤。當(dāng)前系統(tǒng)只能檢測單幀圖片里的行人還無法在視頻流中跟蹤同一個(gè)人的運(yùn)動(dòng)軌跡。加上跟蹤算法以后就能實(shí)現(xiàn)人流統(tǒng)計(jì)、軌跡繪制、異常行為檢測等更高級(jí)的功能這在安防監(jiān)控場景里是剛需。第二個(gè)方向是模型蒸餾和端側(cè)部署。把YOLOv12大模型的檢測能力蒸餾到輕量級(jí)模型上再通過TensorRT或者其他推理框架優(yōu)化可以部署到邊緣計(jì)算設(shè)備上比如Jetson系列或者移動(dòng)端。這樣系統(tǒng)的應(yīng)用場景就從單機(jī)桌面擴(kuò)展到了邊緣端。第三個(gè)方向是UI層面的升級(jí)。當(dāng)前的前端界面功能完整但視覺設(shè)計(jì)和交互體驗(yàn)還可以優(yōu)化??梢杂酶F(xiàn)代的框架重寫前端把界面做得更有產(chǎn)品感比如加入歷史檢測記錄、統(tǒng)計(jì)圖表展示、檢測結(jié)果導(dǎo)出等模塊讓系統(tǒng)更像一個(gè)正式的產(chǎn)品而非實(shí)驗(yàn)Demo。我做這類系統(tǒng)性項(xiàng)目的最大心得是框架和模型本身都不是門檻真正的門檻在于把數(shù)據(jù)、訓(xùn)練、部署、界面這幾個(gè)環(huán)節(jié)的細(xì)節(jié)串聯(lián)起來不放過任何一個(gè)可能出問題的環(huán)節(jié)。像數(shù)據(jù)集質(zhì)量檢查、訓(xùn)練參數(shù)調(diào)整、路徑管理、依賴環(huán)境整理這些瑣碎但關(guān)鍵的細(xì)節(jié)決定了最終交付的是不是一套別人拿到就能跑起來的完整系統(tǒng)。最后分享一個(gè)小經(jīng)驗(yàn)項(xiàng)目代碼里所有路徑盡量使用相對路徑不要寫死絕對路徑。我當(dāng)初為了圖省事在配置里寫了自己的磁盤目錄結(jié)果交付的時(shí)候只能逐行改代碼既浪費(fèi)時(shí)間又容易出錯(cuò)。統(tǒng)一用相對路徑后別人解壓源碼換到任何磁盤位置都能直接運(yùn)行這才是工程化項(xiàng)目該有的姿態(tài)。