超市商品識別:從選型到落地的完整方案)
簡介目標(biāo)檢測是計算機視覺的核心任務(wù)旨在從圖像中定位并分類多個物體。YOLO作為單階段檢測算法的代表一次前向傳播即可完成定位與分類憑借實時性和對小目標(biāo)的良好支持在工業(yè)場景中得到廣泛應(yīng)用。結(jié)合Python生態(tài)中的PyQt5與OpenCV能夠快速搭建具備圖形界面的桌面視覺應(yīng)用支持圖片、攝像頭和RTSP視頻流等多種輸入源。基于這一技術(shù)組合可以實現(xiàn)超市商品識別、自助結(jié)算等實用系統(tǒng)解決傳統(tǒng)圖像處理在光照變化和相似外觀區(qū)分上的痛點。本文從技術(shù)選型、環(huán)境配置到核心代碼實現(xiàn)完整梳理了一套可落地的工程方案為開發(fā)者提供從模型訓(xùn)練到界面交互的實戰(zhàn)參考。 做超市商品識別這個項目說實話最開始我是被朋友拉去救場的。他們想做一個自助結(jié)算的原型機找的幾家外包報價離譜而且交付的模型在真實貨架上一測就露餡小瓶飲料和洗發(fā)水經(jīng)常分不清。后來這個項目落到我手上我用YOLOPyQt5重新搭了一套圖片、攝像頭、RTSP視頻流都能跑界面也做成了帶操作按鈕的桌面程序客戶看了演示直接拍板。這篇文章就把整套方案的選型思路、核心代碼、踩坑記錄都攤開講給想快速落地同類項目的朋友一個參考。文章適合有Python基礎(chǔ)、想了解YOLO實際工程落地或正在做桌面端視覺應(yīng)用的開發(fā)者新手也能跟著環(huán)境配置部分一步步跑起來。1. 項目整體設(shè)計與技術(shù)選型思路1.1 為什么超市商品識別選擇了YOLO方案超市商品識別這個場景第一眼看過去好像不難但真正做起來全是坑。貨架上的商品密集擺放同類商品不同口味的外包裝高度相似光照變化大還有反光、遮擋、變形的問題。最典型的例子就是可樂和雪碧瓶身形狀一樣顏色一深一淺傳統(tǒng)圖像處理靠顏色直方圖去區(qū)分換個燈光環(huán)境就廢了。更別說同一個商品換個角度、被其他商品擋住一半模板匹配類算法基本全部失效。YOLO屬于單階段目標(biāo)檢測算法一次前向傳播同時完成目標(biāo)定位和分類速度快特別適合超市這種需要實時反饋的場景。而且YOLO家族發(fā)展到現(xiàn)在對小目標(biāo)的檢測能力已經(jīng)有了很大提升密集排列的飲料瓶、牙膏盒都不在話下。對比一下傳統(tǒng)方案和YOLO方案的差異就很清楚了對比維度傳統(tǒng)圖像處理方案YOLO方案目標(biāo)定位需要手寫特征滑動窗口復(fù)雜度高端到端回歸邊界框天然支持多目標(biāo)光照魯棒性對光照極其敏感需大量預(yù)處理CNN特征對光照變化有較強適應(yīng)力相似外觀區(qū)分紋理、顏色特征區(qū)分度不足可學(xué)習(xí)深層語義特征區(qū)分相似SKU實時性能多階段串行處理慢單階段GPU加速輕松跑實時新增品類每增加一類都要重新設(shè)計特征只需補充標(biāo)注數(shù)據(jù)重新訓(xùn)練即可人工設(shè)計特征的時代已經(jīng)過去了讓模型自己從數(shù)據(jù)里學(xué)特征才是正解。YOLO在準(zhǔn)確率和召回率之間能做到很好的平衡推理速度也夠用是商品識別這類落地項目最穩(wěn)妥的算法底座。1.2 技術(shù)棧選型的真實考量整套系統(tǒng)我選的是PythonYOLOPyQt5OpenCV的組合這個組合不是隨便湊的每一步都有明確考量。Python作為主語言是因為整個深度學(xué)習(xí)生態(tài)它的支持最好。Ultralytics官方Y(jié)OLO包、PyTorch推理框架、OpenCV圖像處理庫全是Python優(yōu)先支持算法驗證和工程落地的效率都很高。雖然Python在GUI性能和啟動速度上不如C但對于商用原型機和中小型項目來說開發(fā)效率的收益遠(yuǎn)大于這點性能損耗。YOLO模型選用Ultralytics YOLOv8。需要注意一點YOLOv8的Ultralytics版本使用的是AGPL-3.0協(xié)議如果是商用項目要么購買企業(yè)授權(quán)要么就要認(rèn)真評估合規(guī)風(fēng)險。這個我在后面專門說。模型本身支持圖片、視頻流、攝像頭等多種輸入源一鍵推理接口封裝得很好對快速交付非常友好。PyQt5做桌面界面看中的是它的成熟穩(wěn)定和控件豐富程度。Qlabel顯示圖像、QPushButton綁定操作、QThread處理多線程這套組合在工業(yè)視覺項目里已經(jīng)被驗證過無數(shù)次了。相比PySide6PyQt5的文檔和踩坑案例更多遇到問題基本都能搜到解決方案。OpenCV負(fù)責(zé)視頻流的讀取和圖像預(yù)處理。VideoCapture配合多線程可以穩(wěn)定拉取USB攝像頭和RTSP網(wǎng)絡(luò)攝像頭的數(shù)據(jù)流轉(zhuǎn)成YOLO輸入格式也方便。整個鏈路從圖像采集到結(jié)果展示用這四個開源組件就能完整覆蓋。1.3 商用落地前必須想清楚的三件事技術(shù)方案能跑通只是第一步真正商用落地還得想清楚三件事。第一件是模型訓(xùn)練數(shù)據(jù)從哪來。超市商品SKU動輒幾千個每個品類的有效標(biāo)注樣本至少需要一兩百張這還不算同品類的不同包裝、不同批次。實際項目中我通常先用公開數(shù)據(jù)集把模型預(yù)訓(xùn)練到能用的程度再用真實貨架照片做遷移學(xué)習(xí)。拍照的時候要注意覆蓋不同光照、不同角度、不同擺放姿態(tài)最好讓客戶提供多門店的實拍素材這樣模型的泛化能力才有保障。第二件是推理硬件成本。用一個RTX 3060級別顯卡跑YOLOv8s模型一張圖大約20到40毫秒客戶現(xiàn)場如果是普通辦公電腦沒有獨立顯卡CPU推理就要慢很多。所以項目開始前一定要確認(rèn)客戶現(xiàn)場的硬件條件如果沒有GPU要么選YOLOv8n這種輕量模型要么建議客戶加一塊顯卡這兩者的方案差距很大事先不確認(rèn)清楚后面會很難辦。第三件事是后續(xù)維護(hù)責(zé)任邊界。商品包裝更新?lián)Q代是常態(tài)模型部署上線之后新增SKU、舊SKU下架誰來負(fù)責(zé)數(shù)據(jù)更新和模型重訓(xùn)都要在合同里寫清楚。不然客戶每周都有新品上架全指望你免費迭代這個項目就變成一個填不滿的坑了。2. 環(huán)境準(zhǔn)備與基礎(chǔ)依賴配置2.1 從零搭建Python虛擬環(huán)境不管你是Windows還是Linux機器第一步都是創(chuàng)建一個獨立的Python環(huán)境千萬別直接往系統(tǒng)Python里裝一大堆包。我之前吃過虧系統(tǒng)Python環(huán)境被裝亂了連pip都用不了最后只能重裝系統(tǒng)那種痛苦希望你不要體驗。# 創(chuàng)建虛擬環(huán)境 python -m venv venv_supermarket # 激活虛擬環(huán)境 # Windows venv_supermarket\Scripts\activate # Linux/Mac source venv_supermarket/bin/activate虛擬環(huán)境激活后再安裝依賴包。下面是我的requirements.txt版本都經(jīng)過實測驗證直接用不會出問題。ultralytics8.0.222 PyQt55.15.9 opencv-python4.8.1.78 numpy1.24.4 Pillow10.0.0 torch2.0.1 torchvision0.15.2提示PyTorch的安裝建議去PyTorch官網(wǎng)用CUDA匹配的命令安裝不要直接pip install torch。GPU版本的torch對顯存利用率和推理速度的影響非常大CPU版本在視頻流場景下很容易成為性能瓶頸。2.2 PyQt5安裝中的兩個高頻坑PyQt5的安裝本身不復(fù)雜但有兩個坑我每次遇到都有人問。第一個坑是pip安裝速度極慢或者直接超時。PyQt5的wheel包體積不小幾十兆到上百兆都有國內(nèi)網(wǎng)絡(luò)直連官方PyPI源經(jīng)常下載到一半就斷了。解決方法是使用國內(nèi)鏡像源速度能提升十倍以上。pip install PyQt5 -i https://pypi.tuna.tsinghua.edu.cn/simple第二個坑是界面中文亂碼。PyQt5的默認(rèn)字體對中文支持不好界面上按鈕、標(biāo)簽一遇到中文就顯示成方塊。解決辦法是在程序啟動時統(tǒng)一設(shè)置字體我習(xí)慣用微軟雅黑Windows和Linux的兼容性都還不錯。from PyQt5.QtGui import QFont app.setFont(QFont(Microsoft YaHei, 9))2.3 商品識別模型權(quán)重與數(shù)據(jù)標(biāo)注準(zhǔn)備項目里我用的預(yù)訓(xùn)練權(quán)重是yolov8s.pt和yolov8n.pt分別應(yīng)對有GPU和無GPU兩種現(xiàn)場條件。如果你做的是全新品類的識別千萬不要直接拿COCO預(yù)訓(xùn)練權(quán)重去識別你的商品COCO的80個類別里沒有洗發(fā)水、薯片、飲料這些具體SKU直接用的話什么都檢測不出來。必須要用你自己標(biāo)注的商品數(shù)據(jù)重新訓(xùn)練。數(shù)據(jù)標(biāo)注工具我用的是labelImg老牌穩(wěn)定支持YOLO格式的txt標(biāo)注文件直接導(dǎo)出。每張圖片的標(biāo)注文件格式是class_index x_center y_center width height其中x_center、y_center、width、height都是歸一化到0-1區(qū)間的比例值不是像素坐標(biāo)。訓(xùn)練完成后生成best.pt權(quán)重文件這個就是后面部署推理用的核心模型文件。標(biāo)注的時候有個細(xì)節(jié)一個商品如果被遮擋超過一半我通常還是會把沒被遮擋的部分標(biāo)出來但會打上低置信度的標(biāo)簽。這樣模型能學(xué)到部分遮擋情況下的特征。完全無法辨認(rèn)的目標(biāo)就不標(biāo)避免給模型傳遞錯誤信息。3. 核心功能模塊實現(xiàn)與關(guān)鍵代碼拆解3.1 圖片檢測模塊從單張圖片開始驗證效果圖片檢測是整套系統(tǒng)的基礎(chǔ)模塊也是效果驗證最快的方式。模型拿到一張圖片輸出檢測框、類別和置信度畫框顯示出來。這個模塊的實現(xiàn)邏輯很清晰。from ultralytics import YOLO import cv2 # 加載訓(xùn)練好的模型 model YOLO(weights/best.pt) # 執(zhí)行推理 results model.predict( sourcetest_images/shelf_01.jpg, conf0.35, # 置信度閾值 iou0.45, # NMS IoU閾值 imgsz640, # 輸入尺寸 devicecuda:0, # 使用GPU無GPU則填cpu ) # 輸出檢測結(jié)果 for r in results: boxes r.boxes for box in boxes: cls_id int(box.cls[0]) conf float(box.conf[0]) x1, y1, x2, y2 [int(p) for p in box.xyxy[0]] label f{model.names[cls_id]} {conf:.2f} print(f檢測到: {label}坐標(biāo): ({x1}, {y1}, {x2}, {y2}))這里有一個非常重要的參數(shù)conf置信度閾值。閾值設(shè)高了漏檢多貨架上密集擺放的商品容易漏掉后排的閾值設(shè)低了誤檢多相似的包裝很容易被認(rèn)錯。我在實際項目中一般先用0.25跑一遍看效果再根據(jù)檢測結(jié)果逐步上調(diào)到0.35到0.4之間找到一個漏檢和誤檢平衡的點。如果單獨跑predict沒有出現(xiàn)任何報錯但結(jié)果圖里什么都沒有先別懷疑代碼直接用下面這段代碼把推理后的圖像保存出來看看確認(rèn)模型是否真的輸出了空結(jié)果以及畫框是否成功。annotated_frame results[0].plot() cv2.imwrite(output/shelf_result.jpg, annotated_frame)3.2 視頻流檢測模塊本地視頻、攝像頭、RTSP全支持視頻流檢測是這套系統(tǒng)的重頭戲。商品識別如果只能看靜態(tài)圖片實用性會大打折扣接入攝像頭或者RTSP視頻流才能真正用于超市的實時監(jiān)控和自助結(jié)算場景。視頻流處理的關(guān)鍵在于逐幀讀取和多線程并發(fā)不然界面會卡成PPT。OpenCV的VideoCapture可以統(tǒng)一處理本地視頻文件、USB攝像頭和RTSP網(wǎng)絡(luò)流只是source參數(shù)不同# 本地視頻 cap cv2.VideoCapture(test_videos/checkout.mp4) # USB攝像頭 cap cv2.VideoCapture(0) # RTSP網(wǎng)絡(luò)攝像頭流 cap cv2.VideoCapture(rtsp://admin:password192.168.1.100:554/stream1)RTSP接入的關(guān)鍵在于協(xié)議參數(shù)很多攝像頭默認(rèn)配置用OpenCV打開會黑屏或者斷流。我一般會加上ffmpeg后端參數(shù)并且關(guān)掉緩沖來降低延遲cap cv2.VideoCapture( rtsp://admin:password192.168.1.100:554/stream1, cv2.CAP_FFMPEG ) cap.set(cv2.CAP_PROP_BUFFERSIZE, 1) # 降低緩沖減少延遲幀率控制也需要關(guān)注。如果攝像頭是30幀但模型推理只有10幀的處理能力直接逐幀推理會導(dǎo)致積壓和延遲越來越大。標(biāo)準(zhǔn)做法是設(shè)置一個目標(biāo)FPS通過控制幀間隔來做丟幀處理。target_fps 15 frame_interval int(1000 / target_fps) last_time cv2.getTickCount() while True: ret, frame cap.read() if not ret: break current_time cv2.getTickCount() elapsed (current_time - last_time) / cv2.getTickFrequency() * 1000 if elapsed frame_interval: results model.predict(frame, conf0.35, iou0.45, imgsz640) annotated results[0].plot() # 顯示或推送到界面 last_time current_time3.3 PyQt5桌面界面設(shè)計布局與交互邏輯PyQt5的界面我采用左右分欄布局左側(cè)是實時畫面顯示區(qū)右側(cè)是結(jié)果信息區(qū)。操作按鈕放在底部包括打開圖片、打開攝像頭、打開視頻流、停止檢測、保存截圖這幾個核心功能。核心控件三件套是QLabel顯示畫面、QPushButton操作按鈕、QTextEdit日志信息。界面代碼如下class MainWindow(QMainWindow): def __init__(self): super().__init__() self.setWindowTitle(超市商品識別系統(tǒng)) self.setMinimumSize(1280, 800) # 中間畫面顯示 self.video_label QLabel(self) self.video_label.setAlignment(Qt.AlignCenter) self.video_label.setMinimumSize(960, 600) self.video_label.setStyleSheet(background-color: #1e1e1e; color: #ffffff;) # 右側(cè)信息面板 self.info_text QTextEdit(self) self.info_text.setReadOnly(True) # 按鈕區(qū) self.btn_image QPushButton(打開圖片) self.btn_camera QPushButton(打開攝像頭) self.btn_stream QPushButton(打開視頻流) self.btn_stop QPushButton(停止檢測) self.btn_stop.setEnabled(False) # 用布局管理器排列 layout self._build_layout() # ...省略布局細(xì)節(jié)界面設(shè)計有個值得強調(diào)的思路信號與槽機制是PyQt5的核心。按鈕點擊后觸發(fā)信號槽函數(shù)里啟動相應(yīng)的檢測任務(wù)。這里有個關(guān)鍵點所有耗時操作不能在主線程里執(zhí)行否則界面會卡死。檢測任務(wù)要放到QThread工作線程里通過信號把檢測結(jié)果傳回主線程更新界面。from PyQt5.QtCore import QThread, pyqtSignal class DetectionThread(QThread): frame_ready pyqtSignal(object) # 畫面更新信號 result_ready pyqtSignal(dict) # 檢測結(jié)果信號 def __init__(self): super().__init__() self.running False self.source None self.model YOLO(weights/best.pt) def run(self): cap cv2.VideoCapture(self.source) while self.running: ret, frame cap.read() if not ret: break results self.model.predict(frame, conf0.35, iou0.45) annotated results[0].plot() # 將OpenCV BGR圖像轉(zhuǎn)為RGB再轉(zhuǎn)成QImage用于界面顯示 rgb_image cv2.cvtColor(annotated, cv2.COLOR_BGR2RGB) h, w, ch rgb_image.shape qimage QImage(rgb_image.data, w, h, ch * w, QImage.Format_RGB888) self.frame_ready.emit(qimage)這個線程類是整個視頻檢測模塊的核心。main window拿到frame_ready信號后把QImage顯示到QLabel上界面就實時刷新了。結(jié)果信息每次檢測后統(tǒng)計各類商品數(shù)量通過result_ready信號傳給界面右側(cè)顯示。4. 線程架構(gòu)、推理性能與界面交互的最優(yōu)實踐4.1 多線程架構(gòu)別把主線程拖死PyQt5用戶界面運行在GUI主線程里如果在主線程里直接調(diào)用模型推理視頻流一來界面就全卡住按鈕點了沒反應(yīng)最小化都費勁。所有的耗時操作包括視頻讀取、模型推理、圖像處理都必須放到單獨的工作線程里。我推薦用QThread方案結(jié)構(gòu)清晰信號與槽天然適合跨線程通信。檢測線程拿到每一幀推理完通過信號把結(jié)果發(fā)回主線程主線程只負(fù)責(zé)顯示兩邊各干各的事互不阻塞。更復(fù)雜的場景還可以引入任務(wù)隊列。視頻讀取線程只負(fù)責(zé)讀幀往隊列里塞推理線程從隊列里取幀處理顯示線程展示結(jié)果。三個線程用Queue解耦好處是每一幀的耗時波動不會影響其他環(huán)節(jié)。比如某一幀推理特別慢讀幀線程不會卡住隊列可以緩沖顯示線程也不會因為這一幀拖慢后續(xù)幀。4.2 推理參數(shù)工程化調(diào)優(yōu)不只是調(diào)conf和iou很多人只調(diào)conf和iou兩個參數(shù)就完事了實際上還有幾個參數(shù)對最終效果影響巨大。imgsz參數(shù)決定輸入模型的圖像尺寸。默認(rèn)640如果你貨架上的商品都很小可以試960小目標(biāo)的檢出率會明顯提升。但代價是推理時間翻倍這個要根據(jù)實際硬件來權(quán)衡。我用RTX 3060測試640尺寸約25毫秒/幀960尺寸約60毫秒/幀流暢度差距明顯。半精度推理是白撿的性能提升。GPU推理時把模型和輸入轉(zhuǎn)為fp16推理速度可以提升30%到50%精度損失在絕大多數(shù)場景下肉眼不可見。只需在predict時加一個參數(shù)results model.predict(frame, conf0.35, iou0.45, imgsz640, halfTrue)批處理vs單幀推理。如果做的是離線批量識別幾百張圖片可以一次性傳入整個圖片列表模型自動批處理吞吐量會高很多。但視頻流場景必須逐幀推理批次大小固定為1此時線程架構(gòu)比推理參數(shù)更影響整體流暢度。4.3 界面流暢度優(yōu)化QImage格式轉(zhuǎn)換的小技巧視頻流畫面從OpenCV到PyQt5展示中間必須經(jīng)過數(shù)據(jù)類型轉(zhuǎn)換。這個轉(zhuǎn)換如果做不好性能差距可以到好幾倍。OpenCV的圖像格式是BGRPyQt5的QImage是RGB。很多人用cv2.cvtColor一個個通道轉(zhuǎn)換速度很慢。我的做法是直接用QImage的Format_RGB888格式配合numpy數(shù)組的內(nèi)存布局一次性轉(zhuǎn)換到位避免逐像素操作。def convert_cv_to_qimage(cv_img): rgb_image cv2.cvtColor(cv_img, cv2.COLOR_BGR2RGB) h, w, ch rgb_image.shape bytes_per_line ch * w return QImage(rgb_image.data, w, h, bytes_per_line, QImage.Format_RGB888)還要注意QLabel顯示大圖時使用scaled縮放會消耗不少CPU。商品識別畫面通常是1920x1080的而界面顯示區(qū)域可能只有960x600直接setPixmap原始尺寸會讓界面刷新變慢。正確做法是做一次帶比例縮放的resizepixmap QPixmap.fromImage(qimage) scaled_pixmap pixmap.scaled( self.video_label.size(), Qt.KeepAspectRatio, Qt.SmoothTransformation ) self.video_label.setPixmap(scaled_pixmap)5. 實際項目中的典型問題與排查經(jīng)驗5.1 線上環(huán)境常見問題速查表做過的項目多了踩過的坑也多了。我把商品識別項目里最常遇到的幾個問題整理成一張速查表遇到對應(yīng)癥狀可以直接按表排查。癥狀問題原因解決方案啟動后窗口假死模型加載放到了主線程模型初始化放到檢測線程的run方法里視頻畫面卡頓但CPU占用不高未加幀間間隔無限循環(huán)讀幀按目標(biāo)FPS控制幀處理間隔檢測框錯位輸入圖像尺寸與顯示尺寸不一致圖像resize時記錄縮放比例坐標(biāo)按比例映射中文標(biāo)簽顯示亂碼PyQt5默認(rèn)字體不支持中文程序啟動時統(tǒng)一設(shè)置QFont中文字體GPU顯存占用持續(xù)上漲推理結(jié)果未釋放或video capture緩存堆積每次循環(huán)結(jié)束時顯式del results控制隊列長度RTSP斷流后無法自動恢復(fù)沒有重連機制檢測線程捕獲異常后自動延遲重連小商品總檢測不到imgsz太小小目標(biāo)特征丟失提升imgsz至960或裁剪感興趣區(qū)域后檢測5.2 一個最典型的排查案例有一次客戶反饋說攝像頭接入后畫面斷斷續(xù)續(xù)檢測結(jié)果還經(jīng)常延遲好幾秒。我遠(yuǎn)程看了日志發(fā)現(xiàn)是RTSP拉流后每幀都做推理但攝像頭是25幀推理只有8幀的處理能力隊列里積壓了大量幀延遲越來越大。排查思路是先把推理性能和推流性能分開測。用一段本地視頻測試發(fā)現(xiàn)推理穩(wěn)定在8幀左右排除了模型本身的問題。再單獨拉RTSP測試發(fā)現(xiàn)視頻讀取本身沒問題。最后定位到問題就是沒有做幀丟棄和隊列長度控制。解決方案是加了一個有界隊列隊列滿時直接丟棄最舊的幀保證處理的一定是最新畫面。修改后延遲降到300毫秒以內(nèi)客戶現(xiàn)場體驗完全可接受。暴露這個案例是想說明視頻處理項目里80%的性能問題都不是算法的問題而是架構(gòu)設(shè)計的問題。幀的生產(chǎn)速度和消費速度不匹配就必須引入緩沖和丟幀策略這個思想在任何視頻AI項目里都通用。5.3 訓(xùn)練數(shù)據(jù)不充分的應(yīng)急方案有些項目時間很緊客戶給的圖片只有幾十張直接訓(xùn)練出來的模型泛化能力很差。這個階段我一般會做兩件事。第一是數(shù)據(jù)增強。用albumentations庫做隨機水平翻轉(zhuǎn)、亮度對比度擾動、隨機裁剪縮放、加噪聲把幾十張圖片膨脹到兩三百張。注意翻轉(zhuǎn)操作要謹(jǐn)慎商品上的文字翻轉(zhuǎn)后會變成反的這類樣本應(yīng)去掉或者特殊處理否則模型會學(xué)到錯誤特征。第二是加載預(yù)訓(xùn)練權(quán)重做遷移學(xué)習(xí)。用COCO預(yù)訓(xùn)練模型作為初始權(quán)重凍結(jié)前幾層卷積特征提取層只訓(xùn)練后面的檢測頭。這樣即使數(shù)據(jù)量少也能利用到預(yù)訓(xùn)練模型學(xué)到的通用視覺特征。做法是在訓(xùn)練腳本里設(shè)置model YOLO(yolov8s.pt) # 加載預(yù)訓(xùn)練權(quán)重 # freeze層數(shù)可以根據(jù)數(shù)據(jù)量調(diào)整 results model.train( datasupermarket.yaml, epochs100, imgsz640, freeze10, # 凍結(jié)前10層 lr00.001, # 學(xué)習(xí)率調(diào)低防止破壞預(yù)訓(xùn)練特征 batch16, )數(shù)據(jù)量不足時訓(xùn)練輪數(shù)不能開太大否則會過擬合。我一般控制在100輪左右同時用早停策略驗證集損失連續(xù)20輪不下降就自動停止。6. 項目交付與持續(xù)迭代的實操細(xì)節(jié)6.1 客戶現(xiàn)場的模型更新流程模型訓(xùn)練完善后客戶現(xiàn)場要更新模型怎么辦很多項目死在交付后的維護(hù)環(huán)節(jié)因為每次都在客戶機器上手動換文件、重啟程序既低效又容易出錯。我的做法是把模型文件放到一個固定的models目錄程序啟動時掃描目錄下所有.pt文件界面上加一個下拉框切換模型。客戶拿到新模型文件放進(jìn)目錄后在界面上一選程序自動重新加載并生效完全不需要重啟。代碼邏輯很簡單def reload_model(self, model_path): if hasattr(self, detection_thread) and self.detection_thread.isRunning(): self.detection_thread.stop() self.detection_thread.wait() self.detection_thread DetectionThread() self.detection_thread.set_model(model_path) self.detection_thread.start()這個流程極大降低了客戶的維護(hù)門檻后期新增SKU或優(yōu)化識別效果時客戶自己就能操作不需要每次叫你去現(xiàn)場。6.2 誤檢率和漏檢率如何平衡商品識別項目驗收時客戶最關(guān)心的就是誤檢率和漏檢率。這兩個指標(biāo)此消彼長。你把conf閾值調(diào)高漏檢減少但誤檢增加因為模型不確定的樣本會被當(dāng)作負(fù)樣本過濾掉調(diào)低conf閾值模型更容易把相似的誤檢為同一類但漏檢會減少。沒有一個參數(shù)是萬能解。我的經(jīng)驗是分場景定策略。自助結(jié)算場景寧可多問一句也不放過任何商品適合用高召回率即把conf調(diào)低到0.2左右盤點機器人場景追求的是準(zhǔn)確統(tǒng)計庫存寧可漏檢也能事后補充適合用高精度conf調(diào)到0.5以上。實操中我會在程序里加一個精確度模式切換下拉框讓現(xiàn)場人員根據(jù)實際場景選擇模式不同模式自動切換不同的conf和iou參數(shù)組合。這樣既保證了靈活性也讓客戶感受到系統(tǒng)的人性化設(shè)計。6.3 關(guān)于商用授權(quán)的一點提醒最后這個話題一定要提千萬不要忽略。如果你用的是Ultralytics官方Y(jié)OLOv8它默認(rèn)是AGPL-3.0協(xié)議這個協(xié)議要求任何基于它的衍生作品都必須以相同協(xié)議開源。換句話說如果你直接把它封裝成商業(yè)軟件賣給客戶又不開放自己軟件的源代碼嚴(yán)格來說是存在合規(guī)風(fēng)險的。我在商用項目中會提前做合規(guī)評估。方案一是購買Ultralytics的企業(yè)授權(quán)價格按項目規(guī)模計算預(yù)算充足又追求省事的客戶可以選這個。方案二是自行實現(xiàn)或選用其他寬松協(xié)議的目標(biāo)檢測模型比如YOLOv5的某些開源版本用的是GPL協(xié)議情況也不同需要具體分析。方案三是在合同中明確告知客戶模型算法的授權(quán)限制把風(fēng)險轉(zhuǎn)移給客戶決策。不要因為這個事情翻車技術(shù)再好授權(quán)問題沒有理清項目交付后還可能面臨法律風(fēng)險。我在項目交付前都會把這一項列成文檔和客戶核對確認(rèn)保護(hù)自己也保護(hù)客戶。這套系統(tǒng)的完整落地思路到這里就差不多講完了。從YOLO選型、PyQt5界面設(shè)計到線程架構(gòu)、參數(shù)調(diào)優(yōu)再到客戶現(xiàn)場交付的細(xì)節(jié)都是我在項目里一步步驗證過的方法。最后再說一個我個人的操作習(xí)慣每次上線之前我都會找一批客戶現(xiàn)場完全沒見過的照片跑一遍模型專門看那些置信度徘徊在0.3到0.4之間的樣本。這批樣本往往能暴露模型泛化能力的真實水平比看訓(xùn)練集指標(biāo)有效得多。多花半小時做這個驗證能幫你在客戶現(xiàn)場少熬三個通宵。本文還有配套的精品資源點擊獲取