OLOv8品質(zhì)分級:小樣本目標檢測實戰(zhàn))
簡介面向YOLO系列目標檢測任務的高質(zhì)量雞蛋品質(zhì)分級數(shù)據(jù)集覆蓋血染雞蛋、棕色雞蛋、臟兮兮雞蛋、白雞蛋及鈣沉積蛋五類典型樣本適合用于農(nóng)產(chǎn)品質(zhì)檢場景的模型訓練與算法驗證。壓縮包共1846個文件包含615張JPG原圖、615個YOLO格式TXT標簽、615個VOC格式XML標簽并附帶可直接使用的data.yaml配置整體僅25.41MB。數(shù)據(jù)集已劃分訓練集與驗證集標簽格式規(guī)范且雙格式并存可無縫切換YOLOv5、YOLOv7、YOLOv8、YOLOv9、YOLOv10、YOLO11等主流版本免去標注與整理數(shù)據(jù)的繁瑣步驟。目前已有104人學習下載適合需要快速上手目標檢測或開展雞蛋品質(zhì)分揀算法研習的開發(fā)者導入項目后即可開始訓練與指標評估。1. 615張帶標簽的雞蛋圖憑什么值得你花一個下午從頭訓一遍禽蛋分揀線上最累的崗位一定是目檢工位傳送帶每小時過幾千枚蛋眼睛得同時盯蛋殼顏色、血跡、糞便殘留和表面凸起旺季干兩個小時就開始漏檢。這個標題里的數(shù)據(jù)集把這類活兒壓縮成了一個YOLO目標檢測任務——血染雞蛋、棕色雞蛋、臟兮兮的雞蛋、白雞蛋、鈣沉積蛋五個品質(zhì)類別615張圖像全部帶標注解壓之后就是一份能直接喂給YOLO系列模型訓練的數(shù)據(jù)集。它解決的問題很具體用一份小樣本把「蛋殼表面缺陷分類」從人工目檢變成可自動判別的檢測模型適合禽蛋自動化分選、養(yǎng)殖場出場品控以及想拿農(nóng)業(yè)數(shù)據(jù)集練手YOLO流程的人。615張圖不算多但恰好夠你把一份數(shù)據(jù)從標注格式檢查一路跑到權(quán)重落地的完整鏈路走通。2. 五個雞蛋品質(zhì)類別的視覺特征與標注邊界先分得清才談訓練2.1 血染蛋、臟蛋、鈣沉積蛋長什么樣做檢測任務的第一步不是跑模型而是先搞清楚這五類物體在你的圖像里到底長什么樣。同一個詞在不同人手里可能對應完全不同的視覺形態(tài)比如「臟兮兮的雞蛋」有人理解成沾泥塊有人理解成表面帶灰褐色斑這兩種理解標出來的標簽會讓模型學到完全不同的特征。下表是我按常見分級線和這個數(shù)據(jù)集標題的命名習慣整理的視覺特征基線類別典型視覺特征易混淆對象血染雞蛋蛋殼表面有鮮紅或暗紅色血跡點狀或片狀邊界清晰臟蛋上的紅褐色泥斑棕色雞蛋殼色均勻的棕褐色無斑無附著物光照偏暖時的臟蛋臟兮兮的雞蛋糞便、泥土、飼料殘渣附著多為深色不規(guī)則塊血染蛋、鈣沉積蛋白雞蛋殼色均勻的白色或淡米白表面干凈鈣沉積蛋的白色鈣斑鈣沉積蛋蛋殼表面有凸起的白色鈣質(zhì)顆粒呈沙粒狀或條帶狀粗糙白雞蛋、臟蛋血染蛋在食品安全層面是硬指標必須挑出來——血跡通常意味著母雞生殖道損傷或蛋殼破裂后污染消費者打開蛋殼看到血跡會直接投訴。臟雞蛋屬于衛(wèi)生缺陷臟污可能攜帶病菌同樣需要剔除。鈣沉積蛋嚴格來說不影響食用安全但影響外觀售價做零售分級時會被降級。棕色和白色是正常的殼色類別用來做基礎分選。你需要把這五類當成五個獨立的檢測目標而不是按「合格/不合格」二分法去處理——YOLO輸出的是類別置信度多分類能讓后續(xù)分揀邏輯更靈活。2.2 易混樣本的邊界怎么定最有爭議的邊界是「臟兮兮的雞蛋」和「鈣沉積蛋」。臟蛋是污物附著在殼表面顏色偏深、形狀不規(guī)則、邊緣通常比較毛糙鈣沉積蛋是蛋殼本身的碳酸鈣異常堆積手感粗糙、顏色和蛋殼同源白蛋上就是白色棕蛋上就是淺褐色邊緣往往有顆粒感。標注時如果拿不準我的習慣是看兩件事第一附著物的顏色是否和殼色有跳變有跳變更可能是臟污第二用指甲刮一下概念上能不能刮掉鈣沉積是刮不掉的殼體結(jié)構(gòu)。這個判斷標準要在動手訓練前統(tǒng)一好不然后面清洗標簽時會發(fā)現(xiàn)同一張圖在不同人手里標成了兩類。另一個容易翻車的邊界是血染蛋和帶紅褐色泥斑的臟蛋。血跡的顏色飽和度高、偏鮮紅而且通常呈噴濺狀或條狀泥斑是暗沉的土褐色邊緣過渡自然。標注時不要只看局部顏色要看整體分布——血跡往往出現(xiàn)在蛋殼的鈍端或中部泥斑多出現(xiàn)在與地面接觸的側(cè)下方。如果一張圖里一枚蛋同時有血跡和鈣沉積按數(shù)據(jù)集標題的類別粒度我一般會把它歸到更嚴重的血染蛋并且只給一個框避免一枚蛋出兩個重疊框把模型搞暈。2.3 為什么不直接用OpenCV閾值分割非要上YOLO雞蛋分級看起來像是「按顏色分分類」的簡單問題實際做過的都知道用傳統(tǒng)圖像處理做蛋殼缺陷檢測會翻車翻到懷疑人生。核心原因是蛋殼顏色本身方差太大白雞蛋在偏黃燈光下拍出來像棕色棕色雞蛋在偏白燈光下拍出來像臟蛋而臟污和鈣沉積都是局部對比度變化不是全局顏色特征。用固定閾值分割血跡稍微換個光源角度紅色分量就變了用邊緣檢測找鈣沉積蛋殼本身的氣孔和反光邊緣全都會被誤判成缺陷。YOLO解決的是「在什么位置有什么類別」的語義問題。它不關心具體像素的絕對顏色值而是學習局部紋理組合——血跡的紅色斑塊加上它和殼色的對比關系鈣沉積的顆粒紋理加上邊緣走向。這也是為什么615張這種規(guī)模的數(shù)據(jù)集也能用YOLO的卷積特征提取能力足夠強小數(shù)據(jù)集配合遷移學習比你在OpenCV里調(diào)三天閾值要靠譜得多。代價是你需要投入時間理解標注格式、目錄結(jié)構(gòu)和訓練參數(shù)但這筆投入的回報是模型能適應產(chǎn)線上的光照波動。3. 把615張標注圖整理成YOLO能吃的格式目錄、標簽文件與一條龍校驗腳本3.1 標準目錄結(jié)構(gòu)與data.yaml數(shù)據(jù)集資源拿到的原始形態(tài)可能解壓后直接是一堆圖和對應文本標簽也可能已經(jīng)按train/val分好。無論哪種訓練前我建議先統(tǒng)一成YOLO標準目錄即images下放圖像、labels下放同名txt標簽train和val分開。這樣YOLO的data.yaml可以直接引用不用在訓練命令里做各種路徑映射。dataset/ ├── images/ │ ├── train/ │ │ ├── egg_001.jpg │ │ └── ... │ └── val/ │ ├── egg_502.jpg │ └── ... ├── labels/ │ ├── train/ │ │ ├── egg_001.txt │ │ └── ... │ └── val/ │ └── egg_502.txt └── data.yaml為什么拆train和val而不是全部拿去訓練因為615張圖全量訓練出來的權(quán)重你無法判斷它是真的學到了泛化特征還是把圖像背景背下來了。驗證集就是給你當「考官」的它必須和訓練集完全隔離。拆分的比例常見是8:2也就是約490張訓練、125張驗證。驗證集再少模型評估的置信區(qū)間會變大驗證集太多訓練數(shù)據(jù)不足的問題會更突出。如果你后續(xù)要嚴謹?shù)卣{(diào)超參建議從訓練集里再劃一小部分做測試集但615張的體量就別再分了把val當測試用是主流做法。3.2 讀懂一行標簽class cx cy w h 歸一化坐標YOLO標簽文件是純文本每行一個目標格式從左到右依次是類別編號、歸一化后的目標中心點x坐標、y坐標、歸一化寬度、歸一化高度。所謂歸一化是指除以圖像的寬或高所以坐標值永遠在0到1之間。比如一張640×480的圖里有一枚蛋它的檢測框左上角在(100, 80)右下角在(300, 400)那標簽行應該這樣算class_id 0 # 假設血染蛋是0號類別 center_x (100 300) / 2 / 640 0.3125 center_y (80 400) / 2 / 480 0.5 width (300 - 100) / 640 0.3125 height (400 - 80) / 480 0.6667對應的一行標簽文本就是0 0.3125 0.5 0.3125 0.6667。理解這個格式很重要因為后面清洗標簽時只有知道坐標值應該在什么范圍內(nèi)才能判斷哪些行是異常的。順便提醒類別編號從0開始不要寫成1。如果數(shù)據(jù)集里的類別順序是血染、棕色、臟、白、鈣沉積那編號就是0到4這個順序必須寫到data.yaml的names列表里不能錯位。用Python把txt里的歸一化坐標還原成像素框畫在圖上是最快的可視化驗證方式import cv2 def draw_yolo_label(image_path, label_path, class_names): img cv2.imread(image_path) h, w img.shape[:2] with open(label_path, r, encodingutf-8) as f: for line in f.readlines(): parts line.strip().split() if len(parts) ! 5: continue cls_id, cx, cy, bw, bh int(parts[0]), float(parts[1]), float(parts[2]), float(parts[3]), float(parts[4]) x1 int((cx - bw / 2) * w) y1 int((cy - bh / 2) * h) x2 int((cx bw / 2) * w) y2 int((cy bh / 2) * h) cv2.rectangle(img, (x1, y1), (x2, y2), (0, 255, 0), 2) cv2.putText(img, class_names[cls_id], (x1, max(30, y1 - 10)), cv2.FONT_HERSHEY_SIMPLEX, 0.6, (0, 255, 0), 2) cv2.imshow(check, img) cv2.waitKey(0) class_names [blood, brown, dirty, white, calcium] draw_yolo_label(dataset/images/train/egg_001.jpg, dataset/labels/train/egg_001.txt, class_names)這段腳本的核心作用是把抽象的坐標數(shù)字轉(zhuǎn)換成你眼睛能直接判斷的框。邏輯上先讀圖像尺寸然后把歸一化坐標還原成像素坐標最后用OpenCV畫框和類別名。如果框明顯框偏了或者類別名和蛋的實際狀態(tài)對不上就是標簽有問題需要重新標注。參數(shù)說明class_names的順序必須和data.yaml里的names保持一致否則畫出來的類別名就是錯的x1、y1、x2、y2計算時減去的bw/2和bh/2是為了把中心點坐標換算成左上角坐標。3.3 用Python清洗標簽類別越界、坐標越界、空標簽拿到手的標簽不一定干凈尤其是來自多個人協(xié)作標注的數(shù)據(jù)集。我自己拿到任何數(shù)據(jù)集的第一件事都是跑一遍清洗腳本把明顯異常的標簽挑出來。常見問題有幾個類別編號超過names長度比如只有5類卻出現(xiàn)5這個編號、坐標值為負或超過1、寬或高為0、txt文件內(nèi)容為空、圖像存在但txt不存在或反過來。import os def validate_dataset(images_dir, labels_dir, num_classes5): img_files os.listdir(images_dir) for img_file in img_files: stem os.path.splitext(img_file)[0] label_path os.path.join(labels_dir, stem .txt) if not os.path.exists(label_path): print(f[缺失標簽] {img_file}) continue with open(label_path, r, encodingutf-8) as f: lines f.readlines() if len(lines) 0: print(f[空標簽] {img_file}) continue for line in lines: parts line.strip().split() if len(parts) ! 5: print(f[格式異常] {img_file}: {line.strip()}) continue cls_id int(parts[0]) if cls_id 0 or cls_id num_classes: print(f[類別越界] {img_file}: class{cls_id}) for v in parts[1:]: val float(v) if val 0 or val 1: print(f[坐標越界] {img_file}: {line.strip()}) break validate_dataset(dataset/images/train, dataset/labels/train)腳本邏輯不復雜但很實用第一層循環(huán)遍歷每張圖像檢查同名txt是否存在存在后再逐行檢查格式、類別編號和坐標范圍。參數(shù)說明num_classes根據(jù)數(shù)據(jù)集的類別數(shù)量傳這里是5坐標值允許恰好等于1嗎理論上中心點等于1時框已經(jīng)完全貼邊甚至越界實踐中我看到大于0.99就建議人工復核因為蛋的圖像不太可能正好占滿整條邊。另外檢查labels里是否存在沒有對應圖像的txt這個方向的缺失同樣需要處理否則訓練時YOLO會跳過這些圖并對不上樣本數(shù)。3.4 按比例拆分train/val并固定隨機種子如果數(shù)據(jù)資源本身沒有劃分train/val你需要自己拆。拆分的要點是隨機且可復現(xiàn)不能每次運行腳本得到不同的劃分——否則你無法比較兩次訓練的實驗結(jié)果。固定隨機種子是最有效的做法同時建議在拆分時按圖像文件名的順序打亂避免把所有同一批拍攝的照片都分到訓練集里導致驗證集在光照條件上和訓練集差異過大。import os import random import shutil random.seed(42) images_dir dataset/all_images labels_dir dataset/all_labels train_img_dir dataset/images/train val_img_dir dataset/images/val train_lbl_dir dataset/labels/train val_lbl_dir dataset/labels/val for d in [train_img_dir, val_img_dir, train_lbl_dir, val_lbl_dir]: os.makedirs(d, exist_okTrue) img_files [f for f in os.listdir(images_dir) if f.lower().endswith((.jpg, .jpeg, .png))] random.shuffle(img_files) val_count int(len(img_files) * 0.2) val_files img_files[:val_count] train_files img_files[val_count:] for f in train_files: stem os.path.splitext(f)[0] shutil.copy(os.path.join(images_dir, f), os.path.join(train_img_dir, f)) shutil.copy(os.path.join(labels_dir, stem .txt), os.path.join(train_lbl_dir, stem .txt)) for f in val_files: stem os.path.splitext(f)[0] shutil.copy(os.path.join(images_dir, f), os.path.join(val_img_dir, f)) shutil.copy(os.path.join(labels_dir, stem .txt), os.path.join(val_lbl_dir, stem .txt)) print(ftrain: {len(train_files)}, val: {len(val_files)})說明一下這段的邏輯先按8:2比例算出val的數(shù)量然后從打亂后的列表頭部取val。random.seed(42)這一行是關鍵參數(shù)它讓shuffle的結(jié)果在每次運行時都一樣。實際數(shù)據(jù)拆分時還要注意一個文件名對應一個標簽文件復制圖像時必須同步復制同名txt少復制一個訓練時就少一個監(jiān)督信號。另外如果你的數(shù)據(jù)集里有重復圖像不同文件名但內(nèi)容完全相同這一步無法去重需要另寫哈希去重邏輯——重復圖同時進train和val是數(shù)據(jù)泄漏會讓驗證指標虛高。4. 用YOLOv8訓練雞蛋品質(zhì)分級模型yolo v8 anaconda環(huán)境配置到出權(quán)重4.1 建環(huán)境裝ultralyticsanaconda三行命令訓練YOLOv8推薦用anaconda建獨立環(huán)境避免把系統(tǒng)Python搞亂。YOLOv8對Python版本沒有苛刻要求3.9到3.11都能跑我習慣用3.10。裝ultralytics包時會自動帶上torchCPU版也能訓練但速度很慢有NVIDIA顯卡的話先確認驅(qū)動和CUDA可用再裝GPU版torch。conda create -n yolov8 python3.10 -y conda activate yolov8 pip install ultralytics第一行創(chuàng)建獨立環(huán)境第二行激活第三行安裝ultralytics。說明一下pip install ultralytics會把torch、torchvision、opencv-python這些依賴一起裝上裝的是CPU版還是GPU版取決于你的pip源和已有環(huán)境。如果你需要GPU加速建議先按PyTorch官網(wǎng)給的命令安裝對應CUDA版本的torch然后再pip install ultralytics它會檢測到torch已存在而跳過重裝。裝完后命令行輸入yolo應該能看到usage信息看不到就是裝失敗了。4.2 寫data.yaml的五個必填項YOLO訓練的數(shù)據(jù)配置放在一個yaml文件里這個文件的路徑在訓練命令里用data參數(shù)指定。五個必填項是path數(shù)據(jù)集根目錄的絕對路徑或相對路徑、train訓練圖像目錄相對path的路徑、val驗證圖像目錄相對path的路徑、nc類別數(shù)量、names類別名列表。path: /home/user/dataset train: images/train val: images/val nc: 5 names: 0: blood 1: brown 2: dirty 3: white 4: calcium為什么path推薦用絕對路徑因為很多翻車現(xiàn)場都是相對路徑寫錯YOLO解析路徑的邏輯是把path和train拼接如果你的當前工作目錄不是dataset的父目錄相對路徑就會指到不存在的地方。names列表的順序必須和標簽文件里的class_id一一對應這一點我在前面反復強調(diào)因為一旦錯位所有類別的預測結(jié)果都錯了但loss表現(xiàn)很正常極難排查。nc和names的長度不一致時ultralytics會報錯所以這兩項要同步改。4.3 訓練命令與一組不容易翻車的參數(shù)615張圖是小數(shù)據(jù)集不需要從零訓練直接加載YOLOv8的預訓練權(quán)重做遷移學習是標準做法。預訓練權(quán)重在COCO上見過數(shù)萬種物體的通用特征你的蛋殼紋理對它來說是錦上添花而非從零學起。訓練命令如下yolo detect train \ datadataset/data.yaml \ modelyolov8n.pt \ epochs150 \ imgsz640 \ batch16 \ patience20 \ projectegg_quality \ nameexp1逐個參數(shù)說modelyolov8n.pt表示用nano版預訓練權(quán)重作為起點nano體積小、訓練快適合小數(shù)據(jù)集如果你追求更高精度可以換yolov8s.pt但615張圖用nano就夠大模型反而更容易過擬合。epochs150在遷移學習下是合理范圍驗證集指標通常在50到100輪之間穩(wěn)定這里給到150是為了讓loss曲線有明顯平臺期。patience20是早停參數(shù)連續(xù)20輪驗證指標不提升就停止訓練省時間的同時也防止過擬合。batch16顯存占用約4到6GB如果你的顯卡顯存只有4GB需要降到8或4。imgsz640是訓練時resize的尺寸蛋是相對大的目標640夠用不需要上到1280。訓練啟動后屏幕上會滾動epoch進度條每輪結(jié)束會打印box_loss、cls_loss、dfl_loss和驗證集的precision、recall、mAP50、mAP50-95。這是你判斷訓練健康度的直接窗口。如果loss是穩(wěn)步下降然后趨平說明正常如果loss反復橫跳可能batch太小或?qū)W習率不合適可以先不管等訓練完看最終權(quán)重效果。4.4 訓練過程中要盯住的四個關鍵輸出訓練不是只能干等進度條。ultralytics會在project/name目錄下持續(xù)產(chǎn)出訓練產(chǎn)物你要看的是這幾個文件weights/best.pt和weights/last.pt是權(quán)重文件best.pt是驗證集指標最優(yōu)的一版last.pt是最后一輪的狀態(tài)results.png是loss曲線和指標曲線的匯總圖confusion_matrix.png是驗證集上的混淆矩陣val_batch*.jpg是驗證集圖像的預測可視化。第一個關鍵輸出是results.png里的兩對曲線訓練集loss和驗證集loss。訓練loss下降、驗證loss不降甚至在后期回升是過擬合的典型征兆。第二個是confusion_matrix.png重點看對角線上的數(shù)值是否高——對角線亮說明每個類別都能正確識別如果某一行的顏色很暗說明這個類別幾乎沒被預測對。第三個是val_batch*.jpg直接看模型在真實圖上畫框的位置和類別名人工目檢比任何指標都直觀。第四個是訓練日志里每輪的mAP50它比loss更貼近你的業(yè)務需求——loss是模型內(nèi)部的優(yōu)化目標mAP50才是外部可感知的檢測質(zhì)量。5. 小樣本訓練的常見問題與排查615張圖的五個翻車現(xiàn)場5.1 類別不平衡導致某一類幾乎不報現(xiàn)象訓練完成后用測試圖驗證棕色雞蛋和白雞蛋檢測得很準但血染蛋幾乎不出框偶爾出一兩次還是錯的。看訓練日志里的per-class mAP會發(fā)現(xiàn)血染蛋那欄明顯偏低其他類別都接近0.9。原因615張圖里五類的分布并不均勻。血染蛋的采集成本高——正常產(chǎn)蛋流程里血染蛋的出現(xiàn)率本身就低所以標注樣本里它占比可能不到10%。YOLO的cls_loss是逐圖累加的類別數(shù)量少的類別對loss的貢獻被淹沒模型學成了「絕大多數(shù)情況下是棕色或白色」的偏置。解決先統(tǒng)計每類樣本數(shù)確認失衡程度然后做兩件事。第一對樣本少的類別做數(shù)據(jù)增強比如把血染蛋的圖像做水平翻轉(zhuǎn)、旋轉(zhuǎn)、亮度抖動復制成多份加入訓練集第二在訓練命令里開啟ultralytics的class weight選項讓loss對樣本少的類別加大懲罰權(quán)重。常用的做法是直接把少類別的圖像復制幾份進訓練目錄簡單粗暴但有效615張圖的體量下不會把訓練時間拖垮。增強時注意別對蛋做翻轉(zhuǎn)以外的強變換比如旋轉(zhuǎn)90度對橢圓形的蛋來說會改變朝向分布反而引入偏差。5.2 訓練loss正常但val的mAP50始終上不去現(xiàn)象訓練集的boxes loss和cls loss都正常下降驗證集的mAP50在0.6附近怎么都上不到0.8看預測圖發(fā)現(xiàn)模型把蛋框得七扭八歪框的尺寸不對。原因最常見的是圖像和標簽錯位。數(shù)據(jù)集在傳遞過程中可能有人重新命名過圖像文件但沒同步更新txt文件名或者不同來源的圖像混在一起后標簽張冠李戴。模型學到的框位置和圖像內(nèi)容不一致訓練loss看起來正常是因為它擬合的是錯誤的對應關系但驗證時錯位不會消失指標自然上不去。解決用第3章的清洗腳本逐張核對更狠一點的方法是隨機抽20張圖用可視化腳本把框畫出來人工對比框內(nèi)的蛋是否和類別名匹配。我做數(shù)據(jù)集校驗時有個笨辦法寫個腳本統(tǒng)計每張圖的平均標注框面積如果某張圖的框面積明顯異常超出所有圖框面積的3倍標準差多半是標簽坐標寫錯了。這類問題越早發(fā)現(xiàn)越省事等訓練完再排查你連是數(shù)據(jù)問題還是模型問題都分不清。5.3 標簽越界或錯位圖像與txt文件一對不上就白練現(xiàn)象訓練過程中epoch還在正常跑但某個epoch結(jié)束后打印的val set樣本數(shù)和你的驗證集文件數(shù)對不上或者訓練完檢出的框全都在圖像邊緣框的一半在圖像外。原因標簽坐標越界。可能是標注工具導出時沒有按YOLO格式歸一化某些坐標值大于1或者txt文件的某一行多了空格導致解析出錯。YOLO在訓練時對越界坐標會做裁剪或忽略但大量越界會讓模型學到錯誤的框位置先驗。解決跑一遍第3.3節(jié)的校驗腳本把所有坐標越界的txt行打印出來逐個修復。修復的方式是如果只是輕微越界數(shù)值在1.0到1.2之間可以直接clip到0到1如果越界嚴重坐標是幾百的像素值說明這行標簽的坐標系根本不是歸一化格式需要從標注源頭重新導出。修復后重跑校驗腳本確認無異常再重新訓練。這個坑最氣人的地方在于它不報錯只有最終結(jié)果不對勁時你才反應過來。5.4 過擬合訓練mAP高、驗證mAP低現(xiàn)象訓練集上的mAP50達到0.95以上驗證集只有0.65差距穩(wěn)定在0.3左右??磖esults.png訓練loss一路向下驗證loss在40輪之后開始回升。原因615張圖的體量本身偏小如果預訓練權(quán)重的特征在你這個任務上適配度不夠模型就會去記憶訓練集的紋理細節(jié)而不是提煉「血跡」「鈣沉積」這類泛化特征。另一個常見推手是開了過強的數(shù)據(jù)增強mosaic在圖像拼接時會生成大量合成樣本小數(shù)據(jù)集上模型容易把合成的偽紋理當真特征。解決第一把epochs減到80配合patience15早停避免后期純粹在擬合訓練集噪聲第二調(diào)整增強參數(shù)ultralytics的data.augment里把mosaic設為0或0.5把hsv_h和hsv_s調(diào)低蛋殼的顏色是分類的核心特征增強過頭會把棕色變綠色第三換小模型yolov8n.pt換成可訓練參數(shù)更少的版本或者把模型輸入分辨率從640降到480參數(shù)少了過擬合的空間也就小了。5.5 loss曲線震蕩不收斂現(xiàn)象訓練了50輪loss曲線像鋸齒一樣上下波動沒有明顯的下降趨勢mAP50在0.2附近反復橫跳。原因這類情況在小數(shù)據(jù)集上通常是學習率問題。默認lr00.01在大部分數(shù)據(jù)集上都適用但樣本類別方差大的數(shù)據(jù)集會遇到梯度方向來回沖突的情況固定學習率過高會讓權(quán)重在最優(yōu)解附近反復橫跳。另一個可能是batch太小比如只有2、4每個batch的梯度估計噪聲太大。解決把lr0調(diào)低到0.001觀察10輪是否出現(xiàn)下降趨勢。如果是因為數(shù)據(jù)本身噪聲大可以在data.yaml里保留少量背景圖沒有目標的圖像作為負樣本幫模型穩(wěn)定背景特征。還有種容易被忽略的原因標簽文件里混入了重復行同一枚蛋被標注了兩次模型在該位置收到兩個互相競爭的監(jiān)督信號。用腳本檢查txt里是否有完全重復的行有就刪除。6. 從best.pt到分級產(chǎn)線置信度門限、推理驗證與驗收口徑6.1 用一張沒見過的蛋圖跑推理訓練完成后最快驗證效果的方式是拿一堆訓練集之外的圖片跑推理而不是只看指標。命令行一鍵推理yolo detect predict \ modelegg_quality/exp1/weights/best.pt \ sourcetest_images/ \ conf0.25 \ iou0.45 \ saveTruesource指向你沒見過的測試圖目錄saveTrue會把畫完框的圖保存到runs/detect/predict目錄。conf0.25表示置信度低于0.25的預測將被丟棄iou0.45表示兩個重疊框的IoU超過0.45時只保留得分高的。這兩個參數(shù)是你實際部署時最常動的兩個旋鈕。6.2 調(diào)整置信度門限和NMS IoU兩個參數(shù)先看conf。血染蛋是食品安全相關的缺陷漏檢的代價遠高于誤檢所以血染蛋的conf要調(diào)低到0.15甚至0.1寧可把正常的棕色蛋誤判成血染蛋送去人工復核也不能讓一顆血染蛋流入包裝線。而外觀分選棕色vs白色這種不影響安全的任務conf可以調(diào)到0.4以上減少誤檢帶來的分揀抖動。再看iou。如果圖像里蛋與蛋緊挨著甚至部分重疊實際產(chǎn)線傳送帶上經(jīng)?;ハ嘤|碰默認0.45的IoU可能把兩枚靠在一起的蛋合并成一個框。把iou調(diào)到0.3模型會把重疊區(qū)域小于30%的都當成獨立目標保留。這兩個參數(shù)沒有標準答案我的習慣是拿50張典型測試圖跑幾組conf和iou組合直接看保存的預測圖選一組肉眼權(quán)衡最順眼的。6.3 產(chǎn)線驗收的最終口徑模型好壞的最終話事人是混淆矩陣和逐類precision/recall不是那個漂亮的mAP50。mAP是置信度閾值滑動平均的綜合分但產(chǎn)線上你只能用某一個固定閾值工作。把best.pt輸出成一個趁手的部署格式再用固定的conf跑一遍驗證集統(tǒng)計每類的精確率和召回率。血染蛋的recall要達到0.98以上才敢上線鈣沉積蛋的precision則要更高否則把好蛋降級造成的損失是實打?qū)嵉睦麧櫫魇?。如果你要用GPU推理加速到毫秒級把權(quán)重導出成ONNX格式用TensorRT走一遍int8量化——615張圖訓出來的權(quán)重在量化后通常還能保持原有精度的九成以上。這類小數(shù)據(jù)集項目的通病是「練完就覺得完事了」其實部署端的參數(shù)適配和驗收口徑才決定這個模型到底能不能用。我做過的每個視覺檢測項目幾乎都要在conf和iou上磨掉小半天就為了一句話說得出口在這個固定閾值下血染蛋的漏檢率是百分之幾。希望這個從615張圖跑通全流程的方子能幫你少走點彎路也希望你的第一版權(quán)重別像我當年一樣在驗證集上看著挺好一上產(chǎn)線就被燈光晃得滿地找牙。本文還有配套的精品資源點擊獲取