檢測(cè)實(shí)戰(zhàn):人行道與盲道障礙物檢測(cè)系統(tǒng)搭建全流程)
1. 這個(gè)檢測(cè)系統(tǒng)到底在解決什么問(wèn)題1.1 為什么把目標(biāo)鎖在人行道和盲道障礙物先說(shuō)一個(gè)我實(shí)際跑項(xiàng)目時(shí)遇到的場(chǎng)景。某個(gè)城市做市政設(shè)施巡檢人工巡查盲道占用、破損、違規(guī)施工這些問(wèn)題效率低不說(shuō)漏檢率還特別高。一條路幾公里走下來(lái)光拍照記錄就得大半天回去還得人工整理照片、填表格、派工單整個(gè)流程又慢又容易出錯(cuò)。人行道和盲道障礙物檢測(cè)本質(zhì)上就是把“城市道路是否通暢、無(wú)障礙設(shè)施是否完好”這件事從人工肉眼巡查變成算法自動(dòng)識(shí)別。核心目標(biāo)物包括幾類占道停放的車輛、施工擋板、堆放的建材雜物、破損缺失的盲道磚、違規(guī)設(shè)置的立柱或路障以及井蓋缺失這類安全隱患。每類目標(biāo)對(duì)算法來(lái)說(shuō)就是一個(gè)類別檢測(cè)系統(tǒng)要做的是在圖像、視頻、攝像頭畫面里實(shí)時(shí)圈出這些障礙物的位置并標(biāo)出類別置信度。這個(gè)系統(tǒng)的價(jià)值在于替代重復(fù)性人力勞動(dòng)。傳統(tǒng)人工巡檢的痛點(diǎn)是三個(gè)一是效率低二是標(biāo)準(zhǔn)不統(tǒng)一三是問(wèn)題發(fā)現(xiàn)之后難以形成可追溯的記錄。算法檢測(cè)天然適合這類重復(fù)、規(guī)則相對(duì)固定的視覺(jué)任務(wù)。只要標(biāo)注數(shù)據(jù)足夠規(guī)范模型就能在一張照片里同時(shí)定位多個(gè)障礙物還能直接輸出結(jié)構(gòu)化結(jié)果后續(xù)對(duì)接上報(bào)系統(tǒng)、生成工單就很方便。這個(gè)項(xiàng)目適合誰(shuí)看如果你是做智慧城市、市政巡檢、無(wú)障礙設(shè)施管理相關(guān)工作的算法工程師或?qū)W生或者你正在找一個(gè)人工智能目標(biāo)檢測(cè)的完整實(shí)戰(zhàn)項(xiàng)目來(lái)練手這篇內(nèi)容會(huì)從數(shù)據(jù)準(zhǔn)備、模型訓(xùn)練到部署推理帶你完整走一遍。如果你是初學(xué)者想弄明白YOLO系列模型怎么落地到真實(shí)場(chǎng)景也可以跟著思路復(fù)現(xiàn)。1.2 系統(tǒng)整體能力拆解圖像、視頻、攝像頭三種入口這個(gè)檢測(cè)系統(tǒng)在功能設(shè)計(jì)上分了三個(gè)入口分別是單張圖像檢測(cè)、視頻文件檢測(cè)和攝像頭實(shí)時(shí)檢測(cè)。三種入口的數(shù)據(jù)流不一樣處理邏輯也有差異。圖像檢測(cè)最簡(jiǎn)單輸入一張圖片經(jīng)過(guò)模型推理輸出標(biāo)注了檢測(cè)框和類別的圖片同時(shí)可以保存檢測(cè)結(jié)果。視頻檢測(cè)是把視頻逐幀拆開按照設(shè)定的抽幀間隔逐幀推理再把結(jié)果寫回視頻或者輸出成帶標(biāo)注的視頻文件。攝像頭實(shí)時(shí)檢測(cè)對(duì)性能要求最高需要邊采集畫面邊推理還要保證畫面流暢、輸出延遲盡量低。我最初做這個(gè)系統(tǒng)時(shí)先把圖像檢測(cè)跑通再把圖像檢測(cè)函數(shù)改造成視頻檢測(cè)最后才做攝像頭實(shí)時(shí)檢測(cè)。這個(gè)順序非常重要因?yàn)槊恳徊降膱?bào)錯(cuò)和調(diào)試范圍都是可控的。如果你一上來(lái)就寫攝像頭程序很難分清是圖像讀取問(wèn)題、模型推理問(wèn)題還是顯示問(wèn)題。三種入口的共用部分是同一個(gè)模型推理核心只不過(guò)換不同的數(shù)據(jù)來(lái)源和輸出方式。這個(gè)設(shè)計(jì)思路在工程上叫做“數(shù)據(jù)源解耦”也就是把“從哪讀數(shù)據(jù)”和“怎么分析數(shù)據(jù)”分開后面不管接入新的RTSP流、無(wú)人機(jī)圖傳還是手機(jī)推流只需要新增一個(gè)數(shù)據(jù)接入模塊檢測(cè)核心完全不用動(dòng)。1.3 技術(shù)底座為什么選擇PyTorch與YOLO系列模型標(biāo)題里寫的是“yolov13”這里我按YOLO系列框架來(lái)理解。YOLO系列模型是目前目標(biāo)檢測(cè)領(lǐng)域里落地最廣泛的一類算法核心思路是把整張圖片劃分成網(wǎng)格每個(gè)格子直接預(yù)測(cè)目標(biāo)框和類別一次前向推理就能輸出所有目標(biāo)的位置信息。相比傳統(tǒng)兩階段檢測(cè)器YOLO的優(yōu)勢(shì)是速度快、結(jié)構(gòu)簡(jiǎn)單、部署方便。選擇PyTorch框架主要是因?yàn)槿齻€(gè)原因。第一PyTorch的生態(tài)最完整YOLO系列幾乎所有開源實(shí)現(xiàn)都是基于它的遇到問(wèn)題能搜到大量現(xiàn)成經(jīng)驗(yàn)。第二PyTorch的調(diào)試體驗(yàn)好模型在前向傳播過(guò)程中可以隨時(shí)打印中間張量的形狀和值這在排查檢測(cè)框輸出異常時(shí)特別有用。第三PyTorch轉(zhuǎn)換到部署端比較方便既可以通過(guò)ONNX導(dǎo)出到其他推理框架也可以直接用原生TorchScript做加速推理。技術(shù)選型的本質(zhì)是降低復(fù)現(xiàn)成本。我在項(xiàng)目里堅(jiān)持用開源模型做預(yù)訓(xùn)練初始化而不是從頭訓(xùn)練。從頭訓(xùn)練一個(gè)目標(biāo)檢測(cè)模型需要上百萬(wàn)張標(biāo)注圖片和大量算力普通場(chǎng)景下根本跑不動(dòng)。用預(yù)訓(xùn)練權(quán)重做遷移學(xué)習(xí)相當(dāng)于模型已經(jīng)學(xué)會(huì)了“怎么識(shí)別物體”我們只需要微調(diào)它學(xué)會(huì)“這是人行道上的障礙物”這個(gè)特定任務(wù)數(shù)據(jù)量需求會(huì)降到幾千張級(jí)別普通顯卡也能訓(xùn)練。2. 數(shù)據(jù)集構(gòu)建障礙物檢測(cè)的命根子2.1 先定類別哪些東西必須被識(shí)別訓(xùn)練一個(gè)檢測(cè)模型前第一件事不是寫代碼而是明確要檢測(cè)哪些類別。類別定得太粗模型分不清具體問(wèn)題定得太細(xì)標(biāo)注工作量和模型難度都會(huì)暴漲。我在這個(gè)項(xiàng)目里選了六個(gè)核心類別基本覆蓋了人行道和盲道最常見(jiàn)的障礙物場(chǎng)景占道車輛包括自行車、電動(dòng)車、三輪車、機(jī)動(dòng)車停在人行道或盲道上的情況施工圍擋市政施工臨時(shí)設(shè)置的圍擋、擋板、水馬堆物堆料磚塊、沙石、雜物等堆放占用盲道障礙樁道路入口設(shè)置的固定立柱、石球等阻擋設(shè)施盲道破損盲道磚缺失、斷裂、隆起造成的不連續(xù)井蓋異常井蓋缺失、破損、移位形成的路面隱患這里有一個(gè)關(guān)鍵判斷類別不是越全越好。比如你看到一輛共享單車倒在盲道上這算“占道車輛”還是“倒伏單車”如果兩類都設(shè)標(biāo)注和模型都會(huì)很痛苦。實(shí)際項(xiàng)目中通常按處置方式分類因?yàn)橄到y(tǒng)下游對(duì)接的是市政工單不同處置方式對(duì)應(yīng)不同負(fù)責(zé)部門分類越貼近業(yè)務(wù)流程模型產(chǎn)出的結(jié)果越好用。2.2 數(shù)據(jù)采集場(chǎng)景多樣性的坑數(shù)據(jù)集構(gòu)建往往占用整個(gè)項(xiàng)目60%以上的時(shí)間而采集端最容易翻車。我踩過(guò)的一個(gè)典型坑是只在一個(gè)時(shí)間段、一種天氣下采集圖片導(dǎo)致模型在陰天或者夜晚場(chǎng)景下直接失效。為了提升泛化能力數(shù)據(jù)采集階段必須刻意覆蓋多種條件。我在模擬項(xiàng)目X里做了一個(gè)采集矩陣按時(shí)間段白天、傍晚、夜間、天氣晴天、陰天、雨后、區(qū)域商業(yè)區(qū)、居民區(qū)、學(xué)校周邊三個(gè)維度組合采集。如果條件受限至少保證有兩類光照環(huán)境差異明顯的樣本。還有一個(gè)很容易被忽視的問(wèn)題有些障礙物本身就是“稀缺樣本”。比如井蓋缺失日常巡檢中不常見(jiàn)但不代表不重要。這種類別樣本量不夠時(shí)模型很容易漏檢只能通過(guò)補(bǔ)采或用數(shù)據(jù)增強(qiáng)策略來(lái)緩解。你可以去市政養(yǎng)護(hù)單位溝通或者關(guān)注相關(guān)投訴平臺(tái)的圖片收集這類少見(jiàn)樣本。另外采集設(shè)備不用太講究手機(jī)拍攝就可以。但要注意拍攝角度盡量模擬巡檢人員的視角——手機(jī)平行或者略微俯視拍攝人行道避免全部都是高空俯拍的視角否則部署時(shí)攝像頭安裝角度不對(duì)模型識(shí)別效果會(huì)明顯下降。2.3 標(biāo)注規(guī)范與數(shù)據(jù)增強(qiáng)策略數(shù)據(jù)標(biāo)注是決定模型上限的環(huán)節(jié)。我用的標(biāo)注工具是LabelImg導(dǎo)出為YOLO格式的txt文件每行一個(gè)目標(biāo)格式為類別序號(hào) 中心點(diǎn)x歸一化坐標(biāo) 中心點(diǎn)y歸一化坐標(biāo) 目標(biāo)寬度歸一化 目標(biāo)高度歸一化。標(biāo)注規(guī)范上我總結(jié)了幾條實(shí)用原則遮擋目標(biāo)也要標(biāo)全邊界框框出目標(biāo)完整輪廓而不是只標(biāo)可見(jiàn)部分小目標(biāo)不能漏標(biāo)比如遠(yuǎn)處的小型障礙物漏標(biāo)會(huì)導(dǎo)致模型后期對(duì)小目標(biāo)不敏感同一個(gè)目標(biāo)在多張圖片里重復(fù)出現(xiàn)不要緊關(guān)鍵是目標(biāo)形態(tài)要多樣邊界框緊貼目標(biāo)主體不要為了“省事”把多個(gè)相鄰目標(biāo)框成一個(gè)標(biāo)注完成后我的建議是抽查至少20%的標(biāo)注樣本重點(diǎn)看有沒(méi)有漏標(biāo)和邊界框過(guò)松過(guò)緊的問(wèn)題。標(biāo)注質(zhì)量差模型訓(xùn)練出來(lái)精度一定差這個(gè)鍋甩不到模型頭上。數(shù)據(jù)增強(qiáng)方面YOLO系列自帶Mosaic增強(qiáng)、隨機(jī)透視變換、HSV色域變化等功能。實(shí)際訓(xùn)練時(shí)我開了Mosaic增強(qiáng)這個(gè)策略把四張圖片拼接成一張輸入相當(dāng)于變相擴(kuò)大了batch size能明顯提升小目標(biāo)檢測(cè)效果。色域變化也開著模擬不同光照條件讓模型對(duì)亮度變化更魯棒。3. 模型訓(xùn)練從環(huán)境配置到參數(shù)調(diào)優(yōu)3.1 環(huán)境安裝與硬件選型先說(shuō)環(huán)境。PyTorch的安裝比較直接我建議用conda建一個(gè)獨(dú)立環(huán)境避免跟系統(tǒng)其他庫(kù)沖突。深度學(xué)習(xí)框架的版本要跟CUDA版本匹配如果你的顯卡驅(qū)動(dòng)是較新的版本直接裝對(duì)應(yīng)版本的PyTorch即可。硬件方面模型訓(xùn)練一張入門級(jí)顯卡是可以跑起來(lái)的。我實(shí)測(cè)過(guò)在顯存6GB的卡上用640分辨率的輸入batch大小設(shè)為8可以正常訓(xùn)練。如果你的顯存只有4GB可以把輸入分辨率降到416或者把batch降到4。顯存不夠時(shí)會(huì)出現(xiàn)CUDA out of memory報(bào)錯(cuò)這時(shí)候優(yōu)先調(diào)小batch而不是換更復(fù)雜的模型。訓(xùn)練之前的目錄結(jié)構(gòu)也值得提前規(guī)劃好。我的項(xiàng)目目錄大概是這樣的project/ ├── data/ │ ├── images/ │ │ ├── train/ │ │ └── val/ │ └── labels/ │ ├── train/ │ └── val/ ├── models/ ├── runs/ ├── train.py ├── detect.py └── requirements.txt目錄清晰度會(huì)直接影響后期調(diào)試效率。我之前犯過(guò)錯(cuò)誤把所有圖片放在一個(gè)大目錄里沒(méi)有分訓(xùn)練集和驗(yàn)證集導(dǎo)致訓(xùn)練時(shí)驗(yàn)證集的loss完全不正常排查了半天才發(fā)現(xiàn)是驗(yàn)證集被混進(jìn)了訓(xùn)練集。3.2 模型配置文件與超參數(shù)選擇YOLO系列的訓(xùn)練入口通常由一個(gè)yaml配置文件控制里面寫明了數(shù)據(jù)路徑、類別數(shù)量、模型結(jié)構(gòu)等關(guān)鍵參數(shù)。我在模擬項(xiàng)目X里用的數(shù)據(jù)配置示例大概長(zhǎng)這樣path: ./data train: images/train val: images/val nc: 6 names: [vehicle, construction_fence, stacked_materials, barrier_pole, tactile_paving_damage, manhole_issue]這里nc表示類別數(shù)量names列表的順序必須和標(biāo)注txt文件里的類別序號(hào)一一對(duì)應(yīng)。我自己因?yàn)閚ames順序錯(cuò)位吃過(guò)虧模型輸出的標(biāo)簽跟實(shí)際目標(biāo)完全對(duì)不上查了很久才發(fā)現(xiàn)是配置文件里類別列表跟標(biāo)注時(shí)的類別表順序不一致。超參數(shù)方面初始學(xué)習(xí)率我設(shè)成0.01使用SGD優(yōu)化器配合余弦退火學(xué)習(xí)率調(diào)度。batch大小根據(jù)顯存調(diào)整輸出分辨率統(tǒng)一用640。訓(xùn)練輪數(shù)設(shè)置150輪左右但我不是死等150輪結(jié)束而是每訓(xùn)練一段時(shí)間就保存一次權(quán)重選驗(yàn)證集上mAP最高的那一個(gè)作為最終模型。3.3 訓(xùn)練過(guò)程的實(shí)測(cè)記錄與判斷標(biāo)準(zhǔn)訓(xùn)練時(shí)最直接的判斷標(biāo)準(zhǔn)是兩類loss曲線box_loss邊界框損失和cls_loss分類損失。我一般盯兩個(gè)指標(biāo)訓(xùn)練集loss和驗(yàn)證集loss。訓(xùn)練集loss持續(xù)下降驗(yàn)證集loss也跟著下降說(shuō)明模型在學(xué)習(xí)如果訓(xùn)練集loss還在降驗(yàn)證集loss開始反彈說(shuō)明過(guò)擬合了應(yīng)該提前停止或者增加數(shù)據(jù)增強(qiáng)。還有一個(gè)經(jīng)驗(yàn)值得分享訓(xùn)練初期loss下降慢很正常不用焦慮。第一輪loss可能在0.1以上幾十輪之后才降到0.03左右。真正需要警惕的是loss突然變成NaN這種情況通常是學(xué)習(xí)率過(guò)大或者某張異常數(shù)據(jù)觸發(fā)了梯度爆炸把學(xué)習(xí)率調(diào)小一個(gè)數(shù)量級(jí)就能解決。我訓(xùn)練了一個(gè)基于YOLO系列的模型最終在驗(yàn)證集上mAP達(dá)到0.82左右?guī)讉€(gè)主要類別的平均精度差異不大只有“盲道破損”這一類稍微低一點(diǎn)原因是破損形態(tài)差異特別大有的斷一塊有的裂一條縫。改進(jìn)方向是增加這類樣本數(shù)量而不是調(diào)整模型結(jié)構(gòu)。4. 推理部署圖像、視頻、攝像頭三種檢測(cè)模式實(shí)現(xiàn)4.1 圖像檢測(cè)單張圖片的推理管線圖像檢測(cè)是整個(gè)系統(tǒng)的地基代碼邏輯清晰方便后續(xù)擴(kuò)展。核心流程是讀取圖片、預(yù)處理、模型推理、后處理、結(jié)果繪制。首先加載模型權(quán)重。這里有一個(gè)容易踩坑的點(diǎn)加載時(shí)要指定類別數(shù)和配置文件否則模型結(jié)構(gòu)頭部的輸出維度跟你的數(shù)據(jù)不匹配直接報(bào)錯(cuò)。加載完成之后把模型切換成eval模式關(guān)閉梯度計(jì)算否則推理速度會(huì)慢上好幾倍。預(yù)處理環(huán)節(jié)模型期望的輸入是RGB圖像像素值歸一化到0到1之間并且resize成訓(xùn)練時(shí)的尺寸。這里特別提醒OpenCV默認(rèn)讀入的圖片是BGR通道順序不轉(zhuǎn)換的話檢測(cè)結(jié)果往往不對(duì)——最典型的現(xiàn)象是目標(biāo)框的位置基本正確但類別判斷完全混亂因?yàn)槟P涂吹降念伾ǖ栏銟?biāo)注時(shí)的訓(xùn)練數(shù)據(jù)不一致。推理完成后模型輸出的是原始的檢測(cè)張量還不能直接畫框需要經(jīng)過(guò)非極大值抑制處理把重疊的檢測(cè)框合并去掉置信度低于閾值的框。直覺(jué)上可以這么理解同一個(gè)目標(biāo)附近可能預(yù)測(cè)出好幾個(gè)框NMS的作用是保留最可信的那個(gè)把其他多余框清掉。畫框和寫類別名時(shí)字體和線條粗細(xì)要根據(jù)圖片分辨率調(diào)整。大圖上用固定粗細(xì)線可能不明顯小圖上又可能把目標(biāo)全遮住。我一般用相對(duì)值線寬取圖片寬度的千分之二左右。4.2 視頻檢測(cè)按幀抽檢與結(jié)果輸出視頻檢測(cè)本質(zhì)上就是“循環(huán)讀幀 圖像檢測(cè)”。但這里有一個(gè)重要性能考量視頻一秒鐘有25到30幀每一幀都推理一遍算力消耗大、速度慢而且相鄰幀的內(nèi)容高度重復(fù)逐幀檢測(cè)屬于浪費(fèi)。我通常設(shè)置一個(gè)抽幀間隔參數(shù)比如每3幀檢測(cè)一次或者每5幀檢測(cè)一次。這樣做的好處是推理次數(shù)減少視頻處理速度提升明顯。如果項(xiàng)目對(duì)實(shí)時(shí)性要求高甚至可以每10幀檢測(cè)一次然后把檢測(cè)結(jié)果直接復(fù)用到中間幀實(shí)際顯示效果不會(huì)有太大差別。對(duì)市政巡檢來(lái)說(shuō)目標(biāo)移動(dòng)速度慢抽幀策略完全夠用。視頻讀取方面使用OpenCV的VideoCapture讀取視頻文件循環(huán)里read()返回值判斷是否讀到了最后一幀。輸出方面可以使用VideoWriter寫視頻文件注意設(shè)置編碼格式和fps。另外一個(gè)容易忽略的點(diǎn)是保存檢測(cè)結(jié)果視頻時(shí)要保證輸出視頻的尺寸跟原始視頻一致。如果模型內(nèi)部做了resize畫框坐標(biāo)必須映射回原圖尺寸否則檢測(cè)框會(huì)偏離目標(biāo)位置。這個(gè)映射邏輯在圖像檢測(cè)里也得注意但視頻場(chǎng)景下因?yàn)檫B續(xù)幀播放偏移問(wèn)題會(huì)特別顯眼。4.3 攝像頭實(shí)時(shí)檢測(cè)延遲控制與界面顯示攝像頭實(shí)時(shí)檢測(cè)是三種模式里最考驗(yàn)工程能力的部分。核心難點(diǎn)不是模型推理而是“讀取幀的速度”和“處理幀的速度”不匹配導(dǎo)致畫面卡頓、延遲越來(lái)越高。先講一個(gè)基本框架。攝像頭畫面通過(guò)OpenCV的VideoCapture(0)打開如果攝像頭編號(hào)不唯一可以參數(shù)里指定具體設(shè)備。實(shí)時(shí)循環(huán)大概是這樣的邏輯讀取一幀畫面如果檢測(cè)線程空閑就交給檢測(cè)線程處理如果檢測(cè)還沒(méi)完成就先顯示上一幀的檢測(cè)結(jié)果不阻塞等待。import cv2 import torch import time # 假設(shè) model 是訓(xùn)練好的模型 model.eval() cap cv2.VideoCapture(0) cap.set(cv2.CAP_PROP_FRAME_WIDTH, 1280) cap.set(cv2.CAP_PROP_FRAME_HEIGHT, 720) # 跳幀計(jì)數(shù) frame_skip 2 frame_count 0 last_results None while True: ret, frame cap.read() if not ret: break # 如果到達(dá)跳幀間隔執(zhí)行檢測(cè) if frame_count % frame_skip 0: results detect_frame(model, frame) # 返回繪制后的圖像 last_results results # 優(yōu)先顯示最新檢測(cè)結(jié)果 display last_results if last_results is not None else frame cv2.imshow(Detection, display) if cv2.waitKey(1) 0xFF ord(q): break frame_count 1 cap.release() cv2.destroyAllWindows()延遲控制的另一個(gè)關(guān)鍵點(diǎn)是把圖像讀取和模型推理放到不同的線程或者至少不要在讀取幀的同一線程里跑模型推理。因?yàn)樵谕评砥陂g攝像頭緩沖區(qū)會(huì)持續(xù)積壓新幀讀到的幀越來(lái)越陳舊畫面延遲越來(lái)越大。把兩個(gè)操作解耦后檢測(cè)線程專注推理展示線程專注顯示延遲體驗(yàn)會(huì)好很多。攝像頭畫質(zhì)也會(huì)影響檢測(cè)效果。我建議把攝像頭分辨率設(shè)成1280x720不需要4K因?yàn)檫^(guò)高的分辨率對(duì)模型精度提升有限反而增加預(yù)處理耗時(shí)。光線較暗的環(huán)境里可以適當(dāng)開啟攝像頭的低照度模式或者加補(bǔ)光因?yàn)槟P驮诘凸庹障抡`檢率會(huì)明顯上升。5. 常見(jiàn)問(wèn)題與排查技巧實(shí)錄5.1 訓(xùn)練不收斂或loss波動(dòng)訓(xùn)練過(guò)程中最讓人頭疼的問(wèn)題就是loss不收斂。我遇到過(guò)幾種情況一種是loss一直維持在0.1上下不下降另一種是loss劇烈震蕩還有一種是loss直接變成NaN。loss不下降先檢查學(xué)習(xí)率是不是太小。YOLO系列默認(rèn)初始學(xué)習(xí)率是0.01如果基礎(chǔ)環(huán)境變了比如數(shù)據(jù)集規(guī)模特別小學(xué)習(xí)率可以降到0.001左右重新跑。學(xué)習(xí)率太大則表現(xiàn)為loss震蕩特別在訓(xùn)練后期需要配合余弦退火把學(xué)習(xí)率降下來(lái)。loss變NaN最常見(jiàn)的原因是梯度爆炸。我排查的第一件事是看數(shù)據(jù)集中有沒(méi)有異常標(biāo)注比如某個(gè)目標(biāo)框坐標(biāo)超過(guò)圖片邊界或者類別序號(hào)超出類別總數(shù)這類臟數(shù)據(jù)會(huì)直接破壞訓(xùn)練。第二個(gè)排查點(diǎn)是學(xué)習(xí)率把學(xué)習(xí)率調(diào)低一個(gè)數(shù)量級(jí)再試。還有一個(gè)比較少但真實(shí)存在的坑顯卡溫度的波動(dòng)導(dǎo)致硬件不穩(wěn)定也會(huì)偶發(fā)出現(xiàn)NaN這種情況下?lián)Q個(gè)時(shí)間段跑同樣的訓(xùn)練如果不再出現(xiàn)說(shuō)明不是代碼問(wèn)題。5.2 攝像頭推流延遲、卡頓攝像頭檢測(cè)最常見(jiàn)的問(wèn)題是畫面越來(lái)越卡、延遲越來(lái)越大。原因前面提過(guò)圖像讀取線程和推理線程沒(méi)有解耦導(dǎo)致顯示的是過(guò)期幀。遇到延遲問(wèn)題時(shí)我的排查順序是先看視頻讀取速度再看推理速度。先單獨(dú)測(cè)試攝像頭讀幀的速度如果本身就慢那可能是攝像頭驅(qū)動(dòng)或USB帶寬問(wèn)題換一個(gè)攝像頭試試。如果讀幀正常推理每幀耗時(shí)超過(guò)200毫秒那就需要優(yōu)化推理速度。推理提速有幾個(gè)方向一是直接把輸入分辨率從640降到416速度提升明顯精度稍微下降二是用半精度推理只要顯卡支持就能在保持精度基本不變的情況下大幅提速三是做TensorRT等專用加速這個(gè)在嵌入式設(shè)備上效果最明顯但部署復(fù)雜度會(huì)高一些。5.3 小目標(biāo)漏檢和誤檢人行道障礙物檢測(cè)里小目標(biāo)的問(wèn)題特別突出——比如遠(yuǎn)處的電動(dòng)車、很小的盲道磚破損。YOLO系列模型對(duì)越大越清晰的目標(biāo)效果越好小目標(biāo)天然吃虧。解決小目標(biāo)漏檢我的經(jīng)驗(yàn)是兩條路。第一條是數(shù)據(jù)層面保證訓(xùn)練集中小目標(biāo)樣本占比合理并且對(duì)所有小目標(biāo)框都嚴(yán)格標(biāo)注不能因?yàn)槟繕?biāo)小就順手忽略。第二條是推理層面使用多尺度推理對(duì)同一張圖片用原始分辨率、放大的分辨率各推理一次合并結(jié)果能提升小目標(biāo)召回率但推理耗時(shí)加倍這種策略適合離線處理不適合實(shí)時(shí)場(chǎng)景。誤檢的高發(fā)場(chǎng)景也有規(guī)律夜間路燈下的樹影、斑馬線旁的石墩子都可能被誤識(shí)別為障礙物。經(jīng)驗(yàn)上看誤檢往往集中在特定場(chǎng)景下統(tǒng)計(jì)錯(cuò)誤樣本中出現(xiàn)頻率最高的圖片形態(tài)再有針對(duì)性補(bǔ)充負(fù)樣本和圖譜往往能快速收斂問(wèn)題。不要一上來(lái)就加數(shù)據(jù)量很多情況下誤檢是訓(xùn)練數(shù)據(jù)里背景環(huán)境太單一導(dǎo)致的。5.4 模型加速與壓縮經(jīng)驗(yàn)之前在一個(gè)演示環(huán)境里我只用CPU跑推理。模型前向傳播一次就要幾百毫秒根本沒(méi)法做實(shí)時(shí)檢測(cè)。后面我用了兩個(gè)技巧一是把模型導(dǎo)出成TorchScript格式去掉動(dòng)態(tài)圖開銷二是使用半精度計(jì)算在支持的硬件上推理速度幾乎翻倍。還有一個(gè)實(shí)戰(zhàn)技巧是減少推理中的無(wú)用計(jì)算。比如對(duì)視頻檢測(cè)場(chǎng)景背景基本不變可以只在畫面變化明顯的區(qū)域做檢測(cè)但這個(gè)方法實(shí)現(xiàn)復(fù)雜容易引入新問(wèn)題我在實(shí)際項(xiàng)目里用得不多。更穩(wěn)妥的方案是固定輸入尺寸、減少NMS的候選框數(shù)量上限比如把每張圖片最多保留300個(gè)檢測(cè)框改成100個(gè)推理速度會(huì)有可感知的提升對(duì)典型場(chǎng)景影響不大。6. 這套系統(tǒng)的延伸方向與個(gè)人體會(huì)6.1 從檢測(cè)到上報(bào)對(duì)接工單系統(tǒng)模型檢測(cè)出障礙物只是第一步真正產(chǎn)生業(yè)務(wù)價(jià)值的是檢測(cè)結(jié)果能自動(dòng)觸發(fā)處置流程。我在模擬的項(xiàng)目里把檢測(cè)結(jié)果導(dǎo)出成帶時(shí)間戳、位置坐標(biāo)、現(xiàn)場(chǎng)照片的結(jié)構(gòu)化記錄再通過(guò)接口拉到市政巡查平臺(tái)上自動(dòng)生成待辦任務(wù)。這個(gè)方向?qū)ο到y(tǒng)的要求就不只是檢測(cè)精度了還有定位能力。單靠攝像頭畫面無(wú)法精確知道障礙物在哪條路的哪個(gè)具體位置所以部署時(shí)很多項(xiàng)目會(huì)接入經(jīng)緯度信息或者在巡檢車上加GPS模塊檢測(cè)到目標(biāo)的同時(shí)記錄當(dāng)時(shí)的定位。對(duì)接工單系統(tǒng)后發(fā)現(xiàn)問(wèn)題的確認(rèn)效率提升了現(xiàn)場(chǎng)復(fù)核時(shí)間也減少了。如果只做檢測(cè)不做閉環(huán)系統(tǒng)的價(jià)值會(huì)大打折扣。6.2 一些個(gè)人實(shí)操體會(huì)系統(tǒng)性來(lái)說(shuō)在這類目標(biāo)檢測(cè)項(xiàng)目里80%的時(shí)間都在和數(shù)據(jù)打交道。模型結(jié)構(gòu)、訓(xùn)練參數(shù)這些社區(qū)里的開源方案已經(jīng)很成熟了真正決定項(xiàng)目成敗的是你有沒(méi)有一套干凈規(guī)范的數(shù)據(jù)集。標(biāo)注質(zhì)量差、場(chǎng)景覆蓋不全再好的模型也救不回來(lái)。另外一點(diǎn)體會(huì)是算法模型要在真實(shí)場(chǎng)景里邊用邊改。在實(shí)驗(yàn)室驗(yàn)證集上mAP高不代表現(xiàn)場(chǎng)效果就好。攝像頭安裝高度、光線角度、畫面抖動(dòng)都會(huì)影響檢測(cè)效果。我建議項(xiàng)目上線后保留一段時(shí)間的現(xiàn)場(chǎng)數(shù)據(jù)持續(xù)補(bǔ)充訓(xùn)練集模型效果會(huì)越用越好而不是一錘子買賣。最后想分享的一個(gè)細(xì)節(jié)技巧是給模型寫推理腳本時(shí)盡量把預(yù)處理和后處理封裝成獨(dú)立函數(shù)參數(shù)用配置文件管理這樣后期換數(shù)據(jù)、換場(chǎng)景、調(diào)閾值時(shí)不需要改動(dòng)核心代碼只改配置就能完成能省掉很多重復(fù)調(diào)試的時(shí)間。