:從YOLOv5到Y(jié)OLOv10的選型與部署)
鋼材表面質(zhì)量把控這件事在很長一段時間里都靠質(zhì)檢員肉眼盯。帶鋼在產(chǎn)線上以每分鐘幾百米的速度跑缺陷轉(zhuǎn)瞬即逝人盯久了必然疲勞漏檢幾乎無法避免。這也是基于深度學習的表面缺陷檢測這幾年在金屬加工行業(yè)里反復被討論的原因。而真正談到落地繞不開的就是YOLO這一系列檢測算法——從YOLOv5到Y(jié)OLOv7、YOLOv8再到新出的YOLOv10同一個任務在不同的版本上跑性能和坑都大不一樣。這篇文章是我在鋼材表面缺陷檢測項目上從零到一的完整記錄數(shù)據(jù)集怎么準備、YOLOv5怎么訓練、同一份數(shù)據(jù)下YOLOv7/8/10到底誰更強、部署到真實質(zhì)檢環(huán)節(jié)會遇到哪些實驗室里想不到的問題。適合準備拿工業(yè)視覺課題練手的人也適合已經(jīng)在做質(zhì)檢系統(tǒng)但想換一套更可靠模型的工程師。1. 表面缺陷檢測為什么會選中目標檢測這條路1.1 人工質(zhì)檢和傳統(tǒng)視覺的局限先聊產(chǎn)線現(xiàn)狀。鋼材表面質(zhì)檢的傳統(tǒng)方案一靠人眼二靠常規(guī)圖像處理。人眼的短板是客觀生理限制質(zhì)檢員盯著一塊勻速運動的帶鋼表面注意力最多維持二十來分鐘疲勞之后細小缺陷的漏檢率會肉眼可見地上升。更麻煩的是一條產(chǎn)線的質(zhì)檢位往往要求連續(xù)運轉(zhuǎn)好幾個小時漏檢帶來的客訴和退貨成本遠高于多招一個質(zhì)檢員的成本。傳統(tǒng)圖像處理閾值分割、邊緣提取、模板匹配在單一背景的樣品圖上很有說服力但鋼材表面本身就不是干凈背景——有氧化色差、有油污殘留、有紋理起伏這些干擾在圖像上的表現(xiàn)和真實缺陷高度相似。規(guī)則只要定得稍微嚴一點誤檢率就飆升定得松一點漏檢又回來了。我見過有人用形態(tài)學運算試圖把劃傷和紋理噪聲分開現(xiàn)場一換鋼種整套參數(shù)立刻失效。1.2 缺陷的本質(zhì)是找框加分類的問題把問題抽象一下無論裂紋、夾雜還是劃傷在圖像里都是一個局部區(qū)域有位置、有大小、有類別屬性。這正好落在目標檢測的模型輸出空間里——矩形框標出位置分類頭給出缺陷類型。所以表面缺陷檢測天然適合目標檢測架構(gòu)而不是圖像分類或語義分割。分類模型給不出位置信息沒法指導現(xiàn)場定位缺陷分割模型需要像素級標注成本高到工業(yè)數(shù)據(jù)規(guī)模根本撐不起來。綜合精度、速度、標注成本三者目標檢測是那個最平衡的選擇。這也是我在這個項目里始終堅持檢測路線而不是分割路線的原因。1.3 六類典型缺陷各自的脾氣鋼材表面缺陷數(shù)據(jù)集里最常出現(xiàn)的六個類別識別難度差異非常大我這里逐個說一下它們的脾氣裂紋細密的龜裂紋理顏色接近背景邊界模糊模型最容易漏檢。夾雜點狀或短條狀的異物壓入對比度中等形狀不固定。斑塊大面積灰暗區(qū)域邊緣柔和極易和光照不均混淆。麻點密集的小凹坑典型的小目標問題。氧化鐵皮壓入深色不規(guī)則塊狀與背景差異明顯但形狀多變。劃傷細長線條長寬比很極端標注框很容易把無關(guān)背景包進去。這六類的共性是類內(nèi)差異大、類間差異小。同一個劃傷有的又深又長有的淺得像一層水印不同類型的缺陷之間比如斑塊和氧化鐵皮壓入肉眼看起來都是深色塊。模型要在這種數(shù)據(jù)上把類別分開不是單純堆參數(shù)就能解決的。1.4 為什么最終落在了YOLO家族工業(yè)實時性要求讓兩階段檢測器先提候選框再分類基本出局YOLO這類單階段算法用一次前向同時完成定位和分類在速度和精度之間取得了很好的平衡。而且YOLO系列版本迭代快、社區(qū)資料多、部署方案成熟從訓練到導出再到嵌入式推理每個環(huán)節(jié)都有現(xiàn)成方案。對一個落地項目來說這比理論上更優(yōu)但資料稀少的算法重要得多。2. 數(shù)據(jù)集準備先給模型定好天花板2.1 公開數(shù)據(jù)和現(xiàn)場數(shù)據(jù)怎么配合我做對比實驗用的是公開的冷軋帶鋼表面缺陷數(shù)據(jù)集六類缺陷每類約三百張樣本按8:2切成訓練集和驗證集。公開數(shù)據(jù)的好處是標注規(guī)范、類別齊全適合做算法驗證和版本橫向?qū)Ρ葔奶幨潜尘疤蓛艉驼鎸嵁a(chǎn)線的光照、氧化色、油污環(huán)境存在差距。如果目標是部署上線我的建議是公開數(shù)據(jù)打底現(xiàn)場數(shù)據(jù)微調(diào)。先用公開數(shù)據(jù)把模型的基本能力訓出來再采集幾百張現(xiàn)場圖片做增量訓練?,F(xiàn)場圖片哪怕只有兩三百張對真實場景的適配效果也遠超純公開數(shù)據(jù)。沒有現(xiàn)場數(shù)據(jù)就直接上產(chǎn)線早晚會在某個鋼種切換的時刻遭遇大規(guī)模誤檢。2.2 標注格式和目錄組織YOLO系列統(tǒng)一使用txt格式的標注文件每個圖像對應一個同名txt每一行代表一個目標框內(nèi)容是類別id 歸一化中心x 歸一化中心y 歸一化寬 歸一化高。我整理了一個固定目錄結(jié)構(gòu)方便后續(xù)換模型時直接復用defect-dataset/ ├── images/ │ ├── train/ │ └── val/ ├── labels/ │ ├── train/ │ └── val/ └── defect.yaml如果你手里的標注是VOC的xml或者COCO的json需要先轉(zhuǎn)成YOLO格式。下面這個Python腳本是我一直在用的轉(zhuǎn)換輔助邏輯很簡單讀取xml里的obj把xmin、ymin、xmax、ymax換算成歸一化的cx、cy、w、h寬高除以圖片寬高防止越界import os import xml.etree.ElementTree as ET def voc_to_yolo(xml_path, out_dir, img_w, img_h, class_names): tree ET.parse(xml_path) root tree.getroot() lines [] for obj in root.findall(object): name obj.find(name).text if name not in class_names: continue cls_id class_names.index(name) bbox obj.find(bndbox) xmin float(bbox.find(xmin).text) ymin float(bbox.find(ymin).text) xmax float(bbox.find(xmax).text) ymax float(bbox.find(ymax).text) cx ((xmin xmax) / 2) / img_w cy ((ymin ymax) / 2) / img_h w (xmax - xmin) / img_w h (ymax - ymin) / img_h lines.append(f{cls_id} {cx:.6f} {cy:.6f} {w:.6f} {h:.6f}) name os.path.splitext(os.path.basename(xml_path))[0] with open(os.path.join(out_dir, name .txt), w) as f: f.write(\n.join(lines))有個細節(jié)很多人會忽略坐標系和歸一化之前必須確認圖片尺寸和標注軟件里的尺寸一致。我遇到過標注軟件自動壓縮了預覽圖導出坐標和原圖尺寸對不上訓練時loss一直不降最后發(fā)現(xiàn)是標注坐標全偏了。2.3 數(shù)據(jù)增強里的一個關(guān)鍵取舍YOLO系列自帶一套挺強大的數(shù)據(jù)增強包括mosaic四圖拼接、mixup、HSV擾動、隨機翻轉(zhuǎn)、隨機平移縮放。對缺陷檢測來說mosaic對小目標尤其有效它把小缺陷放大到整圖比例模型能學到更多上下文。但這里有個容易踩的坑mosaic在訓練后期最好降權(quán)或關(guān)閉。因為mosaic生成的是拼接圖真實產(chǎn)線圖片不會長成這種四宮格樣子訓練到后期模型的分布會被拼接圖帶偏在正常驗證圖上反而發(fā)飄。我習慣把mosaic從1.0逐步降到0.3到0.5之間或者跑到一半epoch之后關(guān)掉。具體怎么設要看loss曲線遇到訓練loss一直降、驗證mAP卻不動甚至往下掉先懷疑數(shù)據(jù)增強和真實分布的偏差。類別不平衡也得單獨處理。公開數(shù)據(jù)里斑塊、裂紋樣本多麻點、氧化鐵皮壓入樣本少如果直接用原始分布訓練少樣本類別的AP會很難看。最簡單的解法是給少數(shù)類別多復制幾輪過采樣訓練時人為拉平各類別樣本比例。我實測過光這一步就能讓麻點和氧化鐵皮壓入的AP提高5個點以上。3. YOLOv5實戰(zhàn)訓練配置、參數(shù)和過程分析3.1 環(huán)境準備和工程擺放YOLOv5的依賴非常輕核心就是PyTorch和它的一套配套庫。我用的環(huán)境大概是這樣Python 3.8、PyTorch 1.13、CUDA 11.7、單張顯卡顯存12G。跑s模型、640分辨率、batch 16完全沒壓力。數(shù)據(jù)配置文件defect.yaml是訓練的第一步。文件內(nèi)容不長但每個字段都有講究path: ./defect-dataset train: images/train val: images/val nc: 6 names: 0: crazing 1: inclusion 2: patches 3: pitted_surface 4: rolled-in_scale 5: scratchespath字段是數(shù)據(jù)集根目錄train和val是相對路徑。nc必須和names里的類別數(shù)一致。有個低級但常見的錯誤names的索引順序和標注txt里的類別id對不上結(jié)果模型把裂紋當成了劃傷損失函數(shù)還以為自己在收斂。3.2 預訓練權(quán)重、分辨率和訓練參數(shù)訓練命令我貼一下后面逐個參數(shù)解釋python train.py \ --data defect.yaml \ --weights yolov5s.pt \ --img 640 \ --batch 16 \ --epochs 150 \ --patience 30 \ --hyp data/hyps/hyp.scratch-low.yamlweights用yolov5s.pt而不是從頭訓練。COCO預訓練權(quán)重里已經(jīng)包含大量通用物體特征遷移到鋼材缺陷這種小樣本數(shù)據(jù)上收斂速度和最終精度都明顯更好。工業(yè)數(shù)據(jù)集通常只有幾千張從頭訓純屬浪費算力。img 640是訓練分辨率。缺陷里很多是小目標有條件可以試1280對小缺陷檢測有明顯幫助但顯存和推理耗時都會漲。我的建議是640起步先把整體流程跑通再決定要不要升分辨率。batch 16在顯存允許時盡量大。大batch能讓梯度的方向更穩(wěn)定訓練曲線更平滑。epochs 150對不到兩千張圖的數(shù)據(jù)集來說足夠了。我開了早停patience 30如果連續(xù)30個epoch驗證集mAP沒有提升就自動停止能省掉無效訓練時間。hyp選擇low版本因為鋼材缺陷數(shù)據(jù)量小增強太猛容易把模型訓壞。3.3 訓練過程監(jiān)控的幾個觀察點訓練開始后不要盯著終端里的loss數(shù)字胡思亂想要看三樣東西loss曲線、驗證集mAP曲線、PR曲線。一個典型過程是這樣的前30個epoch訓練loss快速下降驗證集mAP從0直接爬到0.6附近這個階段模型在學大局特征到epoch 80左右loss降速變緩mAP在小范圍內(nèi)震蕩此時模型在打磨邊界細節(jié)。如果這個階段持續(xù)很久不漲大概率不是算力不夠而是數(shù)據(jù)問題——我遇到過標注邊界太松導致類別內(nèi)特征發(fā)散的情況。另外記得看每類的AP而不是只看mAP這個總指標。我在YOLOv5s上的初步結(jié)果六類平均mAP0.5在0.75左右但單看裂紋只有0.55。如果不拆開看類別根本不會知道是裂紋拖了后腿。3.4 遇到mAP怎么調(diào)都上不去怎么辦我最想強調(diào)的工作習慣是先查badcase再談調(diào)參。把驗證集里所有置信度在0.3到0.7之間的檢測框?qū)С龀蓤D片一張張過目至少要過一百張。絕大多數(shù)時候你會發(fā)現(xiàn)模型犯錯是有規(guī)律的裂紋被標成背景麻點被一個更大的框錯誤覆蓋斑塊和氧化鐵皮壓入被互相混認。這些規(guī)律指向的是數(shù)據(jù)問題而不是模型問題——裂紋樣本的標注邊界是不是太含糊麻點的框是不是經(jīng)常把兩個挨著的缺陷畫成一個我試過花了兩周調(diào)超參最后AP只漲了一個點而重新洗了一遍標注之后裂紋AP直接漲了七八個點。這件事給我的教訓是先把評估集搞干凈再動模型。4. YOLOv7、YOLOv8、YOLOv10的橫向?qū)崪y與選型判斷4.1 三個版本各自的核心變化YOLOv7主打的是結(jié)構(gòu)設計和訓練策略的改良E-ELAN結(jié)構(gòu)讓特征在不同層之間的流動更充分重參數(shù)化卷積把訓練期的復雜結(jié)構(gòu)在推理期折疊成單路卷積輔助訓練頭的設計讓淺層也能學到更強的特征。整體思路是在保持推理速度的前提下把精度往上抬一截。YOLOv8則做了架構(gòu)上的大調(diào)整檢測頭從anchor-based改成anchor-free不再需要預先定義錨框每個位置直接回歸目標框的四條邊主干里的C3模塊換成C2f模塊特征重用更充分檢測頭拆成分類和回歸兩個獨立分支并用DFL損失做邊界回歸。這些改動讓它在小目標和密集場景下更穩(wěn)。YOLOv10的核心訴求是端到端無痛推理它通過一對多和一對一聯(lián)合標簽分配策略讓模型推理階段完全不需要NMS后處理同時用輕量化分類頭、空間通道解耦下采樣、秩引導塊設計把網(wǎng)絡瘦身。少掉NMS那一步延遲和省算力的效果非常實在。做個類比v7是在原有的發(fā)動機結(jié)構(gòu)上做精細化調(diào)校v8是重新設計了點火和燃燒方式v10更激進直接把變速箱摘了讓動力系統(tǒng)直連車輪。4.2 同一份數(shù)據(jù)上的實測數(shù)據(jù)為了盡量公平我在完全相同的訓練集、驗證集、超參和訓練策略下微調(diào)了這幾個模型輸入分辨率統(tǒng)一640訓練150個epoch。表格里的數(shù)字是我某一次實驗的記錄不同輪次會有波動所以不要把它當絕對標準看趨勢就好模型參數(shù)量(M)mAP0.5mAP0.5:0.95單張推理耗時(ms,同GPU)YOLOv5s7.20.750.4810.5YOLOv736.90.790.5213.2YOLOv8s11.20.780.518.8YOLOv10s16.50.760.506.1幾個穩(wěn)定結(jié)論YOLOv7在這個任務上精度最高代價是模型大、推理稍慢YOLOv8s在精度和速度之間比較均衡YOLOv10s推理最快省掉NMS的額外耗時精度沒有明顯崩盤但也不是最強。值得注意的是v10對裂紋這類紋理型缺陷的AP普遍比v8低一到兩個點可能和輕量化主干對紋理特征的提取能力下降有關(guān)。4.3 實際項目里怎么選版本我的選型建議按場景來分如果做的是教學演示、快速驗證或者團隊對某個框架最熟YOLOv5s仍然是非常好的起點資料多、坑少、周邊工具齊全。如果質(zhì)檢工位對誤檢率要求高、現(xiàn)場的干擾物多YOLOv7的精度優(yōu)勢值得你拿算力去換。算力確實貴一點但漏一個缺陷導致的賠償可能比一臺顯卡貴十倍。如果要做多路并發(fā)檢測比如一條產(chǎn)線同時掛著四路相機YOLOv10的低延遲、免NMS特性可以顯著降低算力成本。如果后續(xù)還想擴展分割、姿態(tài)等任務選YOLOv8系列更順手整個家族的模型結(jié)構(gòu)和工具鏈是統(tǒng)一的。不要唯指標論。我之前在某個工位測試時發(fā)現(xiàn)某些版本在庫里AP數(shù)據(jù)很漂亮但導出到特定推理框架后個別算子不受支持被迫改圖重訓最后反而不如AP低零點幾個點的舊版本好部署。兼容性、生態(tài)成熟度、團隊熟悉度在工業(yè)項目里的權(quán)重比那1%的mAP差距高得多。5. 部署與落地模型跑起來只是開始5.1 ONNX與TensorRT導出訓練完只是第一步產(chǎn)線上跑的是經(jīng)過格式轉(zhuǎn)換的推理版本。通用流程是PyTorch權(quán)重先導出成ONNX再轉(zhuǎn)成TensorRT的engine格式做GPU加速。這么轉(zhuǎn)一圈推理耗時往往能再降三分之一以上特別是在TensorRT開FP16之后。導出時有幾個參數(shù)要提前想清楚固定輸入尺寸還是動態(tài)尺寸batch為1還是大于1。工業(yè)相機通常一次給一張圖固定尺寸、batch為1是最穩(wěn)妥的方案。千萬不要圖省事直接開動態(tài)尺寸個別算子會因為shape不確定而被迫退回慢速路徑加速效果大打折扣。另外導出后務必用同一張圖對比PyTorch原模型和導出版本的輸出確認框坐標和類別沒有漂移。數(shù)值精度上FP16可能讓置信度偏百分之零點幾但如果框的位置變了說明某個算子被錯誤替換這時候要回頭更新推理框架版本。5.2 現(xiàn)場誤檢的來源和兜底手段實驗室里再漂亮的指標到產(chǎn)線上都要重新面對現(xiàn)實污染。我總結(jié)過真實場景誤檢的幾大來源光照隨車間時段變化、不同鋼種表面氧化程度不同、相機鏡頭有灰塵和反光、鋼板上有水漬油漬殘留、質(zhì)檢員在板上留了記號筆痕。應對手段通常分四個層次采集現(xiàn)場負樣本把常見干擾物單獨處理或作為純背景圖片混入訓練集參與負樣本學習在推理端適當拉高置信度閾值寧可不報也不要每張圖亂報對同一物理位置的連續(xù)多幀輸出做時間維度的投票只有連續(xù)N幀都檢出同一個位置的缺陷才對外報警能濾掉大部分偶發(fā)誤檢在上位機做規(guī)則約束比如缺陷面積小到不構(gòu)成質(zhì)量影響、距帶鋼邊緣太近就不報警這些規(guī)則很適合過濾掉相機反光造成的邊界誤判。5.3 相機、光源與整個系統(tǒng)的延遲預算這其實是容易被算法工程師忽略的部分。鋼材產(chǎn)線的帶鋼運動速度、檢測幅寬、缺陷允許的最小尺寸共同決定了系統(tǒng)的幀率和延遲預算。舉個例子如果帶鋼速度是3米每秒檢測幅寬1米相機分辨率決定最小可檢缺陷尺寸那么相機觸發(fā)頻率、曝光時間、模型推理時間、結(jié)果回傳PLC的時間加起來必須控制在一個運動周期以內(nèi)否則缺陷即使被檢測到到達執(zhí)行機構(gòu)時也已經(jīng)跑過了報警位置。光源的選擇同樣關(guān)鍵明場照明適合找劃傷和麻點這類有方向性的缺陷暗場或低角度光源適合突顯壓入的氧化鐵皮。很多項目最后模型精度高但現(xiàn)場效果差問題不在模型而在圖像采集那一端。5.4 讓模型持續(xù)進化的回流閉環(huán)模型部署上線不是終點。我的做法是建立一套臟數(shù)據(jù)回流機制每兩周收集一次現(xiàn)場的誤檢和漏檢圖片人工復核后補充進訓練集和驗證集做一輪增量訓練再替換線上模型。鋼材質(zhì)檢的特點就是鋼種和工藝會變?nèi)毕莘植家哺兡P捅仨毘掷m(xù)適配否則上線三個月之后精度就會悄悄滑坡。順便說一個部署工程師常踩的坑評估新模型時直接拿新圖片和舊模型的輸出做對比而不去復盤新模型為什么變了。有時候新模型改了置信度分布把所有框的分數(shù)整體壓低導致報警策略的閾值失效。這種情況要先對齊置信度分布再去比對檢測效果否則會被正常的分布偏移當成故障來排查。6. 復盤這次折騰下來最想保留的幾個習慣第一永遠先把評估集整理干凈。不管是公開數(shù)據(jù)還是現(xiàn)場數(shù)據(jù)標注質(zhì)量決定了模型能力的天花板模型結(jié)構(gòu)和超參只是決定在天花板底下能飛多高。第二一切結(jié)論都要落到每類AP和badcase上。總mAP會騙人單類AP不會。裂紋、麻點這類難例的AP比綜合指標更能反映模型能不能上產(chǎn)線。第三選型時要把部署鏈路當一個整體來評估。同是YOLO家族v5、v7、v8、v10的導出兼容性和周邊生態(tài)完全不同選型不是選模型是選一整套從數(shù)據(jù)到部署的方案。第四建立持續(xù)迭代的機制比任何一次訓練都重要?,F(xiàn)場數(shù)據(jù)會變模型必須跟著變設計好回流和重訓的節(jié)奏系統(tǒng)才真正能用。我最后想說的是鋼材表面缺陷檢測這個任務模型本身只占整個項目的一小半工作量。前期數(shù)據(jù)、中期選型、后期部署每一環(huán)都是在為模型的可落地性打工。如果你正在做類似的項目別急著換更先進的模型版本先把數(shù)據(jù)和評估流程做扎實回報會比想象中大得多。