戰(zhàn):從數(shù)據(jù)準(zhǔn)備到部署優(yōu)化)
1. 項(xiàng)目全貌與系統(tǒng)框架拆解先交代一下背景。我前陣子接了一個(gè)跟軌道檢測相關(guān)的視覺項(xiàng)目需求很直接從軌道巡檢車拍回來的高清圖像里自動(dòng)標(biāo)出鋼軌表面存在的裂紋、擦傷、剝落之類缺陷。數(shù)據(jù)量不算大也就幾千張標(biāo)注圖但場景很典型——戶外光照變化大、鋼軌表面反光強(qiáng)、缺陷形態(tài)又碎又小。方案從傳統(tǒng)圖像處理一路對(duì)比到多個(gè)檢測模型最后還是定在YOLOv5上。這篇就把整套代碼邏輯從頭到尾拆一遍為什么選它、數(shù)據(jù)怎么組織、訓(xùn)練怎么調(diào)、推理怎么做以及那些文檔里不會(huì)寫的坑。先說結(jié)論YOLOv5這套框架在工業(yè)缺陷檢測里確實(shí)夠穩(wěn)。社區(qū)生態(tài)成熟、代碼結(jié)構(gòu)清楚、部署鏈路完整從訓(xùn)練到導(dǎo)出再到落地推理幾乎每一步都有現(xiàn)成方案可以抄。拿它做鋼軌表面缺陷檢測本身就是一條被反復(fù)驗(yàn)證過的路徑我這邊做的主要工作是把它適配到軌道場景的具體細(xì)節(jié)上——數(shù)據(jù)組織、參數(shù)配置、后處理策略以及針對(duì)小缺陷的幾個(gè)關(guān)鍵調(diào)整。這個(gè)內(nèi)容適合誰看如果你正在做工業(yè)質(zhì)檢、缺陷識(shí)別相關(guān)的視覺項(xiàng)目或者剛接觸YOLOv5想找一個(gè)真實(shí)場景的完整案例這篇文章都能給你省不少時(shí)間。我會(huì)把代碼倉庫的核心模塊、訓(xùn)練流程、推理腳本都過一遍重點(diǎn)講清楚那些不跑一遍根本發(fā)現(xiàn)不了的問題。整個(gè)系統(tǒng)從功能上可以分為五塊數(shù)據(jù)準(zhǔn)備環(huán)節(jié)負(fù)責(zé)把巡檢圖像轉(zhuǎn)成訓(xùn)練所需的格式模型訓(xùn)練環(huán)節(jié)負(fù)責(zé)擬合缺陷特征驗(yàn)證評(píng)估環(huán)節(jié)負(fù)責(zé)衡量模型效果推理檢測環(huán)節(jié)負(fù)責(zé)把模型用起來最后的部署優(yōu)化環(huán)節(jié)負(fù)責(zé)讓模型跑得更快。下面按照這個(gè)鏈路逐一展開。因?yàn)閅OLOv5的代碼生態(tài)已經(jīng)很成熟倉庫結(jié)構(gòu)和基礎(chǔ)邏輯大多數(shù)人都眼熟我不會(huì)逐行復(fù)述源碼而是挑出跟鋼軌缺陷檢測強(qiáng)相關(guān)的部分做深度解析——數(shù)據(jù)怎么配、anchor怎么調(diào)、小目標(biāo)怎么處理、后處理參數(shù)怎么設(shè)這些才是真正決定模型能不能用的地方。1.1 鋼軌缺陷檢測的痛點(diǎn)決定了技術(shù)路線鋼軌表面缺陷檢測這個(gè)場景跟通用目標(biāo)檢測有一個(gè)顯著區(qū)別缺陷目標(biāo)極小。典型的鋼軌表面裂紋寬度可能只有兩三個(gè)像素長度幾十個(gè)像素在整張1920×1080的巡檢圖像里占比非常低。如果直接用默認(rèn)參數(shù)訓(xùn)練YOLOv5小目標(biāo)漏檢問題會(huì)非常突出。另一個(gè)痛點(diǎn)是背景干擾。鋼軌表面本身就有紋理、銹跡、水漬、油污再加上戶外拍攝的光照變化和相機(jī)反光很多背景區(qū)域長得比缺陷更像缺陷。用傳統(tǒng)視覺方案去處理比如邊緣檢測加形態(tài)學(xué)過濾面對(duì)固定場景還能湊合一換光照、一換鋼軌型號(hào)就全線崩潰。反觀深度檢測模型YOLOv5這類單階段檢測器天然就比傳統(tǒng)方案抗干擾因?yàn)樗鼘W(xué)的是高維語義特征而非手工設(shè)計(jì)的低層特征。在實(shí)測對(duì)比中同一個(gè)鋼軌表面缺陷數(shù)據(jù)集傳統(tǒng)方案的最好成績也只有不到六成的召回率而YOLOv5s在相同數(shù)據(jù)上能達(dá)到九成以上的召回率。這個(gè)差距是決定性的。1.2 為什么最終沒有選YOLOv8或其他框架每次提到選型總有人問現(xiàn)在YOLOv8都出來了為什么還用v5答案不復(fù)雜。YOLOv5的生態(tài)積累足夠深文檔、教程、預(yù)訓(xùn)練權(quán)重、部署方案都是最齊全的。對(duì)于我們這個(gè)場景模型的絕對(duì)精度差異并不大但調(diào)試便利性和可參考案例的豐富程度差別很大。遇到問題想搜解決方案v5版本基本都能搜到v8相對(duì)少很多。還有一個(gè)實(shí)際考量是部署兼容性。鋼軌巡檢系統(tǒng)的落地環(huán)境以工業(yè)PC為主有些還是老舊工控機(jī)對(duì)CUDA版本和驅(qū)動(dòng)版本有嚴(yán)格限制。YOLOv5對(duì)PyTorch版本的要求更寬泛ONNX導(dǎo)出也更穩(wěn)定在受限的工業(yè)環(huán)境里不容易翻車。至于最新版本帶來的速度提升在鋼軌巡檢這個(gè)每秒處理一幀就夠用的場景里并不構(gòu)成核心優(yōu)勢。2. 數(shù)據(jù)準(zhǔn)備與標(biāo)注規(guī)范——決定模型上限的第一步在這個(gè)項(xiàng)目里數(shù)據(jù)準(zhǔn)備占掉了大約六成的工作量。模型結(jié)構(gòu)可以抄現(xiàn)成的訓(xùn)練參數(shù)可以照搬但數(shù)據(jù)不行——每個(gè)場景的數(shù)據(jù)都得自己采集、自己清洗、自己標(biāo)注。而且數(shù)據(jù)質(zhì)量直接決定模型上限后面所有的調(diào)參優(yōu)化都只能在這個(gè)上限內(nèi)做文章。2.1 缺陷類別定義與標(biāo)注規(guī)范我這邊將鋼軌表面缺陷劃成了四類裂紋、擦傷、剝落、壓潰。這個(gè)分類跟軌道維護(hù)人員的習(xí)慣保持一致。如果分類粒度太粗不同形態(tài)的缺陷混在一起模型訓(xùn)練時(shí)特征沖突精度上不去如果粒度太細(xì)比如把裂紋按長度再細(xì)分幾個(gè)等級(jí)類間差異又太小標(biāo)注一致性很難保證模型也學(xué)不出區(qū)分度。標(biāo)注規(guī)范這件事特別重要也是很多項(xiàng)目翻車的地方。鋼軌裂紋形態(tài)不規(guī)則標(biāo)注時(shí)最常用的原則是“最小外接矩形”——框住缺陷的主體區(qū)域即可不需要把每一條細(xì)小分叉都包進(jìn)去。但如果多人協(xié)作標(biāo)注每個(gè)人的框選習(xí)慣不一樣最終數(shù)據(jù)里同類缺陷的框大小差異會(huì)非常大直接影響回歸頭的收斂效果。我處理這個(gè)問題的方法是先做標(biāo)注規(guī)范文檔再對(duì)標(biāo)注結(jié)果做一致性抽檢。具體做法是計(jì)算每個(gè)類別的平均寬高比分布如果某個(gè)標(biāo)注者的結(jié)果明顯偏離群體平均值就要回頭重新校對(duì)。實(shí)測下來這一步能有效避免訓(xùn)練時(shí)box_loss震蕩的問題。2.2 鋼軌缺陷數(shù)據(jù)集的目錄結(jié)構(gòu)與格式Y(jié)OLOv5的數(shù)據(jù)組織遵循固定的目錄規(guī)則鋼軌缺陷數(shù)據(jù)集按照這個(gè)規(guī)則組織后訓(xùn)練時(shí)不需要額外寫數(shù)據(jù)加載邏輯。核心是images和labels兩個(gè)主目錄各自再拆成train和val子集。標(biāo)注文件跟圖片一一對(duì)應(yīng)是同名的txt文件每行代表一個(gè)目標(biāo)框。標(biāo)注文件每行的格式是五個(gè)數(shù)值類別索引、歸一化中心x坐標(biāo)、歸一化中心y坐標(biāo)、歸一化寬度、歸一化高度。注意YOLOv5的坐標(biāo)全部是歸一化后的值歸一化基準(zhǔn)是圖片寬高而不是邊長。如果轉(zhuǎn)換標(biāo)注時(shí)用錯(cuò)基準(zhǔn)模型訓(xùn)練后會(huì)出現(xiàn)預(yù)測框整體偏移一個(gè)方向的問題而且loss降不下去。對(duì)于鋼軌缺陷這種小目標(biāo)數(shù)據(jù)有一個(gè)額外建議原始高清圖不要直接縮放到訓(xùn)練尺寸。一張1920×1080的圖直接縮到640分辨率很多細(xì)小裂紋會(huì)直接消失。更好的做法是先用切片腳本把大圖切成若干小塊保留缺陷的原始像素信息再做縮放。鋼軌巡檢圖像切成四個(gè)512×512的小塊后小缺陷的保留效果明顯改善。2.3 數(shù)據(jù)增強(qiáng)策略在鋼軌場景的取舍YOLOv5內(nèi)置的Mosaic增強(qiáng)在大多數(shù)場景都好用但鋼軌缺陷檢測這里要留個(gè)心眼。Mosaic會(huì)把四張圖拼在一起訓(xùn)練如果四張圖的亮度差異太大模型會(huì)學(xué)到一些奇怪的亮度特征。我的做法是開啟Mosaic但把mixup概率降到很低同時(shí)強(qiáng)化HSV增強(qiáng)里的飽和度變化因?yàn)殇撥壉砻嫒毕莸念伾卣鞅緛砭鸵园瞪珵橹黠柡投葦_動(dòng)有助于模型忽略顏色干擾、專注形狀特征。鋼軌場景還需要增加一種平移和旋轉(zhuǎn)的增強(qiáng)強(qiáng)度。巡檢圖像中缺陷出現(xiàn)的位置隨機(jī)性強(qiáng)角度也隨機(jī)適度加大仿射變換的幅度可以提升泛化能力。但不要開太大否則缺陷形變失真模型反而學(xué)到不真實(shí)的形態(tài)。3. 核心訓(xùn)練邏輯與代碼模塊拆解數(shù)據(jù)和配置準(zhǔn)備好之后真正進(jìn)入訓(xùn)練環(huán)節(jié)。YOLOv5的訓(xùn)練代碼雖然看起來龐大但核心邏輯并不復(fù)雜。我按從數(shù)據(jù)讀取到損失計(jì)算這條主線來拆把關(guān)鍵模塊和代碼邏輯講清楚。3.1 數(shù)據(jù)加載與標(biāo)簽匹配機(jī)制YOLOv5的數(shù)據(jù)加載響主要實(shí)現(xiàn)在datasets.py中核心類繼承自PyTorch的Dataset。讀取流程是按索引取圖片路徑和對(duì)應(yīng)標(biāo)注文件讀取后做Mosaic等在線增強(qiáng)然后做Letterbox縮放統(tǒng)一尺寸最后歸一化并轉(zhuǎn)為Tensor。這里重點(diǎn)是構(gòu)建了合理的預(yù)處理鏈路。標(biāo)簽匹配機(jī)制是YOLOv5的核心設(shè)計(jì)之一。模型每個(gè)輸出位置有多個(gè)anchor輸入標(biāo)注框首先計(jì)算與這些anchor的寬高比匹配度高的分配為正樣本參與預(yù)測和損失回傳匹配度低的歸為背景。這組anchor對(duì)鋼軌缺陷這種長寬比差異大的場景需要調(diào)整策略——鋼軌裂紋的長寬比可以到10比1但默認(rèn)的anchor分布并沒有覆蓋這個(gè)極端范圍。我這邊處理方式是先用自己的數(shù)據(jù)集跑一次自動(dòng)聚類用k-means生成更適合鋼軌缺陷的anchor尺寸然后在模型配置文件中覆蓋默認(rèn)值。這是一個(gè)容易被忽視的步驟但對(duì)小缺陷檢測效果的提升非常明顯。實(shí)測中僅調(diào)整anchor這一步就讓mAP提升了約3個(gè)百分點(diǎn)。3.2 損失函數(shù)設(shè)計(jì)與關(guān)鍵參數(shù)調(diào)節(jié)YOLOv5的損失由三部分組成分類損失BCE、目標(biāo)置信度損失BCE和定位損失CIoU。在鋼軌缺陷場景中這三部分的表現(xiàn)各有各的問題。分類損失容易出現(xiàn)過擬合傾向因?yàn)槟承┤毕蓊悇e樣本數(shù)量偏多。解決思路是開啟類別權(quán)重給樣本少的類別提高損失權(quán)重。置信度損失在缺陷檢測中經(jīng)常出現(xiàn)“什么都檢測成目標(biāo)”的現(xiàn)象原因是鋼軌表面紋理復(fù)雜大量背景區(qū)域被誤判為含目標(biāo)。定位損失對(duì)缺陷這類小目標(biāo)本身就比較嚴(yán)格因?yàn)镃IoU會(huì)對(duì)中心點(diǎn)距離和寬高比差異敏感小目標(biāo)的微小像素偏差就會(huì)導(dǎo)致?lián)p失值大幅波動(dòng)。為了解決小目標(biāo)定位難的問題我做了兩個(gè)調(diào)整。第一個(gè)是增加輸入分辨率把默認(rèn)的640改成960讓小目標(biāo)占據(jù)更多像素。第二個(gè)是開啟YOLOv5的P2檢測層專門為小目標(biāo)增加一層高分辨率特征圖輸出。這兩個(gè)調(diào)整配合后細(xì)裂紋的召回率提升非常顯著。3.3 訓(xùn)練過程解析——loss曲線的真實(shí)含義YOLOv5訓(xùn)練時(shí)終端會(huì)實(shí)時(shí)打印三類損失box_loss、obj_loss、cls_loss。很多人盯著這三個(gè)數(shù)看半天也不知道到底正常不正常這里說下我的判斷經(jīng)驗(yàn)。健康的loss曲線應(yīng)該是三線同步下降在前50個(gè)epoch下降明顯之后逐漸平緩。如果box_loss一直高位震蕩不下降多半是標(biāo)注問題——框選不準(zhǔn)確或尺寸不一致模型怎么擬合都擬合不了。如果obj_loss降得很慢說明前景和背景的區(qū)分度不夠需要回到數(shù)據(jù)增強(qiáng)上做調(diào)整。如果cls_loss降得快但驗(yàn)證集mAP不高大概率是過擬合了需要加大增強(qiáng)強(qiáng)度或增加樣本量。我第一版訓(xùn)練時(shí)遇到過一個(gè)很典型的問題cls_loss在后期突然反彈。排查下來是因?yàn)轵?yàn)證集和訓(xùn)練集有圖片泄露——數(shù)據(jù)增強(qiáng)過程中生成了大量視覺上非常接近的變體被錯(cuò)誤地劃到了驗(yàn)證集。修正劃分邏輯后cls_loss曲線立刻恢復(fù)健康。4. 訓(xùn)練調(diào)參與性能評(píng)估的完整實(shí)操這一節(jié)把訓(xùn)練環(huán)節(jié)的可落地細(xì)節(jié)完整過一遍。包括硬件基準(zhǔn)、超參數(shù)設(shè)置、訓(xùn)練命令、性能評(píng)估指標(biāo)以及調(diào)參的優(yōu)先級(jí)策略。4.1 硬件環(huán)境與訓(xùn)練超參數(shù)配置訓(xùn)練環(huán)境方面我用的是一張24G顯存的顯卡。鋼軌缺陷數(shù)據(jù)集不算大單卡完全夠用。如果你只有一張8G顯存的卡也不是不能跑就是把batch size調(diào)小、輸入尺寸降到640即可代價(jià)是訓(xùn)練時(shí)間變長。下面是我為鋼軌缺陷場景最終采用的訓(xùn)練參數(shù)組合超參數(shù)推薦值說明輸入尺寸960×960比默認(rèn)640更能保留小缺陷細(xì)節(jié)Batch Size32根據(jù)顯存調(diào)節(jié)不宜過小否則BN層不穩(wěn)定初始學(xué)習(xí)率0.01配合余弦退火衰減曲線使用動(dòng)量0.937延續(xù)默認(rèn)值權(quán)重衰減0.0005防止過擬合Epoch300早停機(jī)制為patience50預(yù)訓(xùn)練權(quán)重YOLOv5m比s精度高比l訓(xùn)練快均衡選擇學(xué)習(xí)率這塊值得多說一句。YOLOv5默認(rèn)使用SGD加上余弦退火調(diào)度。我試過用AdamW收斂確實(shí)更快更穩(wěn)但最終精度略低于SGD。工業(yè)項(xiàng)目中模型的最終精度比訓(xùn)練速度重要所以最終用了SGD加余弦退火組合。4.2 模型規(guī)模選型與訓(xùn)練命令示例YOLOv5的模型規(guī)模從n、s、m、l到x共五檔。對(duì)于鋼軌缺陷檢測直接用x級(jí)模型是沒必要的——缺陷類別少、語義復(fù)雜度有限大模型帶來的精度收益有限但推理成本大幅增加。折中方案是YOLOv5m精度比s有明顯提升速度又比l快很多。訓(xùn)練時(shí)的命令行示例cd yolov5 python train.py \ --data rail_surface.yaml \ --weights yolov5m.pt \ --img 960 \ --batch 32 \ --epochs 300 \ --device 0 \ --cache \ --patience 50其中rail_surface.yaml是數(shù)據(jù)集配置文件必須保證類別名稱順序跟標(biāo)注文件中的索引完全一致這是一個(gè)很容易出錯(cuò)的地方。如果yaml里第一個(gè)類別是crack但標(biāo)注文件中索引0代表scratch訓(xùn)練不會(huì)報(bào)錯(cuò)但評(píng)估結(jié)果全亂。4.3 評(píng)估指標(biāo)怎么讀——不只是看mAP模型訓(xùn)練完成后可以用以下命令跑一輪驗(yàn)證python val.py --data rail_surface.yaml --weights runs/train/exp/weights/best.pt --img 960輸出指標(biāo)中mAP0.5是最常用的衡量指標(biāo)但在鋼軌缺陷場景里我個(gè)人更關(guān)注每個(gè)類別單獨(dú)算的召回率。四類缺陷樣本量差異較大平均數(shù)據(jù)可能把某些類別的劣勢掩蓋掉。比如整體mAP可能有0.85但單獨(dú)看裂紋召回率只有0.7這個(gè)差距必須單獨(dú)觀察。另一個(gè)需要關(guān)注的指標(biāo)是F1分?jǐn)?shù)在0.25到0.5置信度區(qū)間的表現(xiàn)。工業(yè)場景中置信度閾值設(shè)置直接影響誤報(bào)率和漏報(bào)率。如果模型在0.25置信度下的F1明顯高于0.5置信度說明模型對(duì)低置信度的檢測結(jié)果還有信息量可以在推理時(shí)適當(dāng)降低閾值并配合更嚴(yán)格的NMS來抑制重復(fù)框。5. 推理代碼實(shí)現(xiàn)與部署優(yōu)化訓(xùn)練完成之后真正的挑戰(zhàn)才開始。模型要在巡檢車上跑起來還要跟現(xiàn)有的軌道巡檢軟件集成。這一節(jié)講推理側(cè)的代碼實(shí)現(xiàn)和部署優(yōu)化也是項(xiàng)目從技術(shù)驗(yàn)證走向產(chǎn)品化的關(guān)鍵環(huán)節(jié)。5.1 自定義推理腳本實(shí)現(xiàn)YOLOv5自帶的detect.py可以直接用來做單張圖片推理或者視頻推理但實(shí)際集成場景中通常需要把檢測邏輯嵌入到現(xiàn)有的巡檢軟件框架里。這時(shí)最好寫一個(gè)自己的推理封裝核心代碼邏輯如下import cv2 import torch from models.experimental import attempt_load from utils.general import non_max_suppression, scale_coords from utils.plots import Annotator def load_model(weights_path, device): model attempt_load(weights_path, devicedevice) return model def letterbox(img, new_shape960): # 保持寬高比縮放并填充邊緣 shape img.shape[:2] r min(new_shape / shape[0], new_shape / shape[1]) new_unpad int(round(shape[1] * r)), int(round(shape[0] * r)) dw (new_shape - new_unpad[1]) / 2 dh (new_shape - new_unpad[0]) / 2 img_resized cv2.resize(img, new_unpad, interpolationcv2.INTER_LINEAR) top, bottom int(round(dh - 0.1)), int(round(dh 0.1)) left, right int(round(dw - 0.1)), int(round(dw 0.1)) img_padded cv2.copyMakeBorder(img_resized, top, bottom, left, right, cv2.BORDER_CONSTANT, value(114, 114, 114)) return img_padded def detect(img, model, device, conf_thres0.25, iou_thres0.45): img_letterboxed letterbox(img) img_tensor torch.from_numpy(img_letterboxed).to(device) img_tensor img_tensor.permute(2, 0, 1).float().div(255).unsqueeze(0) pred model(img_tensor)[0] pred non_max_suppression(pred, conf_thres, iou_thres) return pred這段代碼有兩個(gè)細(xì)節(jié)值得注意。一是letterbox的填充邏輯不能省訓(xùn)練時(shí)輸入圖片是經(jīng)過letterbox處理的推理時(shí)不處理的話輸入分布不一致檢測效果會(huì)明顯退化。二是NMS的iou閾值在鋼軌缺陷場景中不宜設(shè)得太低因?yàn)槊芗鸭y區(qū)域會(huì)有大量互相重疊的預(yù)測框如果iou_thres設(shè)成0.7以上重疊框會(huì)大量輸出后處理時(shí)還要再過濾。5.2 推理坐標(biāo)換算——最容易出錯(cuò)的環(huán)節(jié)推理完成后得到的目標(biāo)框坐標(biāo)是基于縮放后圖像尺寸的需要按letterbox的反向邏輯映射回原圖坐標(biāo)。這一步出錯(cuò)的表現(xiàn)是框的位置偏離真實(shí)際目標(biāo)通常偏向圖像中心方向。def scale_boxes(orig_shape, pred, letterbox_shape): # pred為NMS后的檢測結(jié)果格式為[x1, y1, x2, y2, conf, cls] pred[:, :4] scale_coords(letterbox_shape, pred[:, :4], orig_shape).round() return predYOLOv5的utils里已經(jīng)封裝好了scale_coords函數(shù)直接用就行。但注意傳入的letterbox_shape必須是縮放填充后的完整尺寸而不是原始尺寸。我見過不少人在這一步傳錯(cuò)參數(shù)導(dǎo)致所有檢測框都偏移。5.3 模型導(dǎo)出與單幀性能優(yōu)化訓(xùn)練好的PyTorch模型可以直接部署但工業(yè)場景中通常建議先導(dǎo)出為ONNX或TensorRT格式。ONNX的跨平臺(tái)兼容性最好TensorRT在NVIDIA顯卡上有最高推理速度。python export.py --weights runs/train/exp/weights/best.pt --img 960 --include onnx導(dǎo)出后可以用ONNX Runtime加載運(yùn)行比原生PyTorch推理快不少。實(shí)測中同一個(gè)模型PyTorch單幀推理耗時(shí)約45ms轉(zhuǎn)成ONNX后降到28ms轉(zhuǎn)成TensorRT后進(jìn)一步降到約15ms。對(duì)于鋼軌巡檢這種對(duì)實(shí)時(shí)性沒有極端要求的場景ONNX格式已經(jīng)夠用。除了模型格式推理側(cè)的優(yōu)化還有兩個(gè)方向。第一個(gè)是預(yù)處理優(yōu)化把圖像縮放方式從逐幀動(dòng)態(tài)計(jì)算改成提前分配固定緩存。第二個(gè)是批量推理如果巡檢系統(tǒng)同時(shí)處理多路相機(jī)圖像把多幀打包成一個(gè)batch推理能顯著提升整體吞吐量。6. 常見問題排查與調(diào)優(yōu)實(shí)錄這部分是實(shí)際踩坑的記錄。我在鋼軌缺陷檢測項(xiàng)目里遇到的問題多數(shù)都是YOLOv5在工業(yè)數(shù)據(jù)上很典型的問題。整理成速查表形式方便遇到問題時(shí)快速定位。6.1 鋼軌缺陷檢測高頻問題速查表問題現(xiàn)象可能原因解決方案box_loss高位震蕩標(biāo)注框尺寸不一致、錯(cuò)誤標(biāo)注重新審核標(biāo)注統(tǒng)一標(biāo)注規(guī)范裂紋類目漏檢嚴(yán)重小目標(biāo)在640下像素太少提升輸入尺寸至960開啟P2層調(diào)整anchor誤報(bào)率高、背景被識(shí)別成缺陷光照不均、訓(xùn)練數(shù)據(jù)背景多樣性不足增加HSV飽和度和曝光擾動(dòng)采集更多背景負(fù)樣本驗(yàn)證集mAP高于訓(xùn)練集數(shù)據(jù)劃分時(shí)序錯(cuò)誤導(dǎo)致泄露按原始圖片切分而不是按增強(qiáng)后圖片切分導(dǎo)出ONNX后輸出shape不一致PyTorch版本與ONNX版本不兼容鎖定torch1.x穩(wěn)定版本導(dǎo)出時(shí)指定opset12推理時(shí)檢測框整體偏移letterbox參數(shù)配置錯(cuò)誤、scale_coords傳參錯(cuò)誤檢查預(yù)處理與坐標(biāo)映射環(huán)節(jié)參數(shù)6.2 小目標(biāo)檢測優(yōu)化的三次迭代實(shí)例這個(gè)項(xiàng)目最有代表性的一段優(yōu)化經(jīng)歷就是解決細(xì)裂紋漏檢問題。第一版模型在960輸入尺寸下整體mAP到了0.87但單獨(dú)看裂紋類目召回率只有0.72。這個(gè)表現(xiàn)在工業(yè)場景里基本不可用因?yàn)槁┑袅鸭y比多報(bào)幾個(gè)誤檢嚴(yán)重得多。我的第一次調(diào)整是改anchor。讓YOLOv5在數(shù)據(jù)上聚類生成新anchor然后重新訓(xùn)練。跑完看結(jié)果裂紋召回率只提高到了0.76提升有限。主要原因是光調(diào)anchor不夠模型提取小目標(biāo)特征的能力還得靠網(wǎng)絡(luò)結(jié)構(gòu)配合。第二次調(diào)整是開啟P2檢測層。在模型配置里增加一層更高分辨率的輸出特征層讓小目標(biāo)對(duì)應(yīng)的特征圖從80×80細(xì)分成160×160獲得的特征信息更密集。這次效果明顯裂紋召回率提高到0.83。第三次調(diào)整是把推理時(shí)的置信度閾值從默認(rèn)的0.25降到0.15配合一個(gè)專門的NMS后處理邏輯先保留低置信度但跟高置信度框高度重疊的裂紋候選框。這一步把召回率提上了0.88。代價(jià)是誤報(bào)率增加了但再通過驗(yàn)證集的置信度校準(zhǔn)最終在誤報(bào)可控的前提下把裂紋召回率穩(wěn)定在了0.86左右。6.3 部署環(huán)境適配的幾個(gè)坑工業(yè)落地場景中部署機(jī)器的軟件環(huán)境比訓(xùn)練機(jī)器復(fù)雜得多。我遇到過的典型問題是巡檢電腦的顯卡驅(qū)動(dòng)版本太老只支持CUDA 10.2以下的版本而訓(xùn)練環(huán)境里的PyTorch和CUDA版本都更高。導(dǎo)出的ONNX模型在推理機(jī)上直接加載失敗。解決方案是模型側(cè)不做修改純粹靠導(dǎo)出時(shí)的兼容性參數(shù)來適配。把ONNX的opset版本設(shè)為12是兼容性最好的一個(gè)版本同時(shí)把動(dòng)態(tài)輸入改為固定尺寸輸入。這樣導(dǎo)出后的模型幾乎可以在任何ONNX Runtime版本上運(yùn)行不再依賴訓(xùn)練時(shí)的CUDA環(huán)境。如果部署機(jī)器沒有NVIDIA顯卡只能用CPU推理那YOLOv5m模型跑960輸入的單幀時(shí)間可能接近300ms明顯偏慢。建議是訓(xùn)練一個(gè)YOLOv5s模型專用于CPU環(huán)境的輕量部署。小模型在鋼軌缺陷上精度差不了太多但CPU推理速度能快近一倍。有條件的話也可以用OpenVINO工具做推理優(yōu)化實(shí)測CPU推理性能能有3倍左右的提升。7. 項(xiàng)目維護(hù)與模型迭代的經(jīng)驗(yàn)總結(jié)項(xiàng)目上線不是終點(diǎn)模型還需要隨著采集數(shù)據(jù)量的增加做持續(xù)迭代。重新訓(xùn)練模型前要把新采集的圖像經(jīng)過同樣的標(biāo)注流程加入數(shù)據(jù)集然后重跑一遍訓(xùn)練、評(píng)估、導(dǎo)出流程。這個(gè)過程有幾個(gè)細(xì)節(jié)要注意新增數(shù)據(jù)必須按同樣的規(guī)范標(biāo)注新增數(shù)據(jù)在隨機(jī)劃分時(shí)要保證同一個(gè)缺陷不漏泄到驗(yàn)證集里模型迭代后要做回歸測試確認(rèn)新模型沒有在舊數(shù)據(jù)上出現(xiàn)性能回退。我在實(shí)際維護(hù)過程中還發(fā)現(xiàn)了一個(gè)提高迭代質(zhì)量的技巧每次收集到的新圖像先人工快速篩選一遍把模糊、過曝、純背景的丟出去避免無效數(shù)據(jù)稀釋模型的學(xué)習(xí)效果。鋼軌巡檢車跑一天下來的數(shù)據(jù)量很大真正含有新缺陷形態(tài)的圖像占比不高做好篩選能大幅提升每次迭代的效果。這個(gè)項(xiàng)目后續(xù)還可以往兩個(gè)方向擴(kuò)展。一是把單幀檢測擴(kuò)展到視頻序列檢測利用時(shí)序信息過濾誤檢這在連續(xù)性巡檢場景中效果會(huì)很好。二是加入缺陷等級(jí)分類讓系統(tǒng)不僅能檢測缺陷位置還能輸出缺陷嚴(yán)重程度給維護(hù)人員的維修決策提供參考。