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