據(jù)集:從標注格式到YOLOv8訓練落地)
簡介這份農作物病害實例分割數(shù)據(jù)集面向農業(yè)AI診斷、精準農業(yè)監(jiān)測及植物病理學交叉研究場景適合從事YOLO實例分割任務開發(fā)與農業(yè)圖像算法驗證的工程師、科研人員及農業(yè)院校師生使用。資源包共582個文件以290張jpg圖像與290個txt標注文件為主體另含1個yaml配置和1個docx說明文檔壓縮包約58.81MB標注采用YOLO多邊形格式精確勾勒病害區(qū)域邊界。數(shù)據(jù)集總計290張圖片按訓練集258張、驗證集23張、測試集9張劃分覆蓋細菌性枯萎病、褐條病與花葉病三類典型病害兼顧細菌性與病毒性樣本類別代表性較強。已有89人學習關注。讀者可借助其直接開展實例分割模型訓練與部署用于病害區(qū)域自動識別、早期診斷系統(tǒng)搭建及農業(yè)物聯(lián)網(wǎng)實時監(jiān)測也可作為教學與科研中的標注范例和實驗基線降低數(shù)據(jù)采集與標注成本。1. 農作物病害實例分割數(shù)據(jù)集從標注格式到 YOLOv8 訓練落地的完整路徑拿到一個名為農作物病害實例分割數(shù)據(jù)集_20251117_001317.zip的壓縮包第一反應不應該是直接解壓丟進模型而是先搞清楚它到底以什么格式標注、類別怎么定義、掩碼是多邊形還是 RLE。農作物病害識別這件事分類模型只能告訴你「這片葉子有病」目標檢測能框出病斑位置但只有實例分割才能精確到每一個病斑的像素邊界——這在計算病害面積占比、評估嚴重程度、做精準施藥決策時是剛需。這個數(shù)據(jù)集面向的就是這類場景葉片上的多個獨立病斑需要被逐個分割出來而不是籠統(tǒng)地標一個框。適合已經(jīng)跑通過 YOLOv8 檢測任務、想往分割方向升級的工程師也適合農業(yè) AI 方向需要快速驗證實例分割方案可行性的團隊。下面從數(shù)據(jù)集結構拆解開始一步步走到訓練、評估和部署。2. 拆開壓縮包農作物病害實例分割數(shù)據(jù)集的目錄結構與標注格式判定2.1 先看目錄樹再決定怎么處理解壓之后別急著寫訓練腳本先花五分鐘把目錄結構摸清楚。常見的實例分割數(shù)據(jù)集組織方式有兩種COCO 風格的annotations/images/分離結構以及 YOLO 風格的images/labels/平行結構。前者標注文件是單個 JSON后者是每張圖對應一個 TXT。# 先看壓縮包內文件列表不解壓 unzip -l 農作物病害實例分割數(shù)據(jù)集_20251117_001317.zip | head -50 # 解壓到指定目錄 mkdir -p ./agri_disease_seg unzip 農作物病害實例分割數(shù)據(jù)集_20251117_001317.zip -d ./agri_disease_seg # 查看目錄樹只看兩層 find ./agri_disease_seg -maxdepth 2 -type d | sort邏輯說明unzip -l先窺探內容避免解壓出一堆無關文件。find -maxdepth 2控制輸出深度快速判斷是 COCO 還是 YOLO 結構。如果看到annotations/instances.json就是 COCO 風格如果看到labels/下全是.txt就是 YOLO 風格。參數(shù)說明-d指定解壓目標目錄建議單獨建目錄避免污染當前工作區(qū)。-maxdepth根據(jù)實際嵌套深度調整一般 2 到 3 層足夠判斷結構。2.2 判定標注格式多邊形、RLE 還是 YOLO 分割行實例分割的標注格式直接決定后續(xù)轉換腳本怎么寫。COCO 格式的segmentation字段可能是多邊形點列表[[x1,y1,x2,y2,...]]或 RLERun-Length Encoding。YOLO 分割格式則是每行class_id x1 y1 x2 y2 ...坐標是歸一化后的多邊形點。import json import os # 如果是 COCO 格式檢查 segmentation 字段類型 ann_path ./agri_disease_seg/annotations/instances.json if os.path.exists(ann_path): with open(ann_path, r) as f: coco json.load(f) # 看第一條標注的 segmentation 類型 seg coco[annotations][0][segmentation] if isinstance(seg, list): print(多邊形格式點數(shù), len(seg[0]) // 2) elif isinstance(seg, dict): print(RLE 格式size, seg.get(size)) # 統(tǒng)計類別 for cat in coco[categories]: print(cat[id], cat[name]) else: # 檢查 YOLO 格式 label_dir ./agri_disease_seg/labels if os.path.exists(label_dir): sample os.listdir(label_dir)[0] with open(os.path.join(label_dir, sample)) as f: line f.readline().strip() parts line.split() print(類別ID:, parts[0], 多邊形點數(shù):, (len(parts) - 1) // 2)邏輯說明COCO 的segmentation如果是 list 就是多邊形每個子列表是一串x,y交替的點如果是 dict 就是 RLE需要pycocotools解碼。YOLO 格式直接讀一行就能判斷第一個數(shù)是類別 ID后面全是歸一化坐標。參數(shù)說明len(seg[0]) // 2得到多邊形頂點數(shù)頂點太少比如少于 3 個說明標注質量可能有問題。類別統(tǒng)計用來確認病害種類數(shù)量常見的有早疫病、晚疫病、葉斑病等。2.3 類別分布與樣本均衡性檢查在動手訓練之前必須知道每個類別有多少個實例。農作物病害數(shù)據(jù)集經(jīng)常出現(xiàn)長尾分布——健康葉片樣本多某種罕見病害只有幾十個實例。不查清楚就訓練模型對少數(shù)類基本沒反應。from collections import Counter # 假設已加載 COCO 格式 cat_counter Counter() for ann in coco[annotations]: cat_counter[ann[category_id]] 1 id2name {c[id]: c[name] for c in coco[categories]} for cid, cnt in cat_counter.most_common(): print(f{id2name[cid]}: {cnt} 個實例) # 同時統(tǒng)計每張圖的實例數(shù)判斷是否有多病斑同圖的情況 img_ann_count Counter() for ann in coco[annotations]: img_ann_count[ann[image_id]] 1 multi sum(1 for v in img_ann_count.values() if v 1) print(f含多個病斑的圖像數(shù): {multi} / {len(coco[images])})邏輯說明Counter統(tǒng)計每個類別的實例總數(shù)most_common()按數(shù)量降序排列。第二個統(tǒng)計看有多少張圖包含多個病斑——這個比例高說明實例分割確實有必要檢測框會重疊。參數(shù)說明如果某個類別實例數(shù)少于 100訓練時需要過采樣或加類別權重。多病斑圖像占比超過 30% 就值得做實例分割而不是檢測。3. 從 COCO 到 YOLO 分割格式轉換腳本與四個邊界坑3.1 轉換腳本多邊形坐標歸一化與類別重映射YOLOv8 的分割訓練需要 YOLO 格式的標注每張圖一個 TXT每行class_id x1 y1 x2 y2 ...坐標是相對于圖像寬高的歸一化值。COCO 的多邊形坐標是絕對像素值需要除以寬高。import json import os from PIL import Image def coco_to_yolo_seg(coco_json, image_dir, output_label_dir): with open(coco_json, r) as f: coco json.load(f) # 建立 image_id - (file_name, width, height) 映射 img_info {} for img in coco[images]: img_info[img[id]] (img[file_name], img[width], img[height]) # 類別 ID 重映射為 0 起始連續(xù)整數(shù) cat_ids sorted([c[id] for c in coco[categories]]) cat_id_map {old: new for new, old in enumerate(cat_ids)} # 按 image_id 聚合標注 from collections import defaultdict img_anns defaultdict(list) for ann in coco[annotations]: img_anns[ann[image_id]].append(ann) os.makedirs(output_label_dir, exist_okTrue) for img_id, anns in img_anns.items(): fname, w, h img_info[img_id] label_name os.path.splitext(fname)[0] .txt lines [] for ann in anns: seg ann[segmentation] if not isinstance(seg, list): continue # 跳過 RLE需要單獨處理 cls_id cat_id_map[ann[category_id]] for poly in seg: # 歸一化并保留 6 位小數(shù) coords [] for i in range(0, len(poly), 2): x min(max(poly[i] / w, 0.0), 1.0) y min(max(poly[i1] / h, 0.0), 1.0) coords.append(f{x:.6f}) coords.append(f{y:.6f}) if len(coords) 6: # 至少 3 個點 lines.append(f{cls_id} .join(coords)) with open(os.path.join(output_label_dir, label_name), w) as f: f.write(\n.join(lines)) print(f轉換完成類別映射: {cat_id_map}) coco_to_yolo_seg( ./agri_disease_seg/annotations/instances.json, ./agri_disease_seg/images, ./agri_disease_seg/labels )邏輯說明先建立圖像 ID 到文件名和尺寸的映射再把類別 ID 重映射為從 0 開始的連續(xù)整數(shù)——YOLO 要求類別 ID 必須連續(xù)。按圖像聚合標注后逐條轉換坐標裁剪到[0,1]防止越界。參數(shù)說明:.6f保留 6 位小數(shù)精度足夠且文件不會太大。len(coords) 6確保至少 3 個點退化的多邊形直接丟棄。如果遇到 RLE 格式的segmentation需要用pycocotools的annToMask轉成二值掩碼再提取輪廓。3.2 坑一坐標越界與退化多邊形現(xiàn)象轉換后的 TXT 里有坐標小于 0 或大于 1訓練時報NaN loss或直接崩潰。原因COCO 標注中偶爾有多邊形頂點超出圖像邊界或者標注工具導出的坐標有浮點誤差。解決轉換時強制裁剪到[0,1]如上面腳本中的min(max(...))。同時過濾掉面積過小的多邊形——計算多邊形面積小于圖像面積 0.1% 的直接丟棄。3.3 坑二類別 ID 不連續(xù)導致訓練報錯現(xiàn)象YOLOv8 訓練啟動時報AssertionError: class id must be in range [0, nc)。原因COCO 的類別 ID 可能是 1, 3, 7 這種不連續(xù)的而 YOLO 要求從 0 開始連續(xù)編號。解決轉換時做重映射如腳本中的cat_id_map。同時生成data.yaml時names列表的順序必須和重映射后的 ID 一致。3.4 坑三圖像與標簽文件名不匹配現(xiàn)象訓練時提示No labels found但labels/目錄下明明有文件。原因圖像是.jpg標簽是.txt但文件名前綴不一致——比如圖像叫IMG_001.jpg標簽叫img_001.txt大小寫或前綴不同。解決轉換腳本中用os.path.splitext(fname)[0]統(tǒng)一取文件名主干確保一一對應。轉換后跑一遍校驗腳本檢查每個圖像是否有對應標簽。4. YOLOv8 實例分割訓練data.yaml 配置與關鍵超參設置4.1 data.yaml 的五個必填字段YOLOv8 分割訓練的配置文件比檢測多一個task字段且names必須與類別數(shù)嚴格對應。# data.yaml path: ./agri_disease_seg # 數(shù)據(jù)集根目錄 train: images/train # 訓練集圖像相對路徑 val: images/val # 驗證集圖像相對路徑 test: images/test # 測試集可選 task: segment # 關鍵指定分割任務 nc: 5 # 類別數(shù)根據(jù)實際修改 names: # 類別名稱順序必須與訓練標簽中的 ID 一致 0: 早疫病 1: 晚疫病 2: 葉斑病 3: 銹病 4: 健康邏輯說明path是根目錄train和val是相對于根目錄的路徑。task: segment告訴 YOLOv8 加載分割頭而不是檢測頭。names用字典或列表都行但順序不能錯。參數(shù)說明nc必須等于names的長度。如果類別數(shù)超過 10建議用列表形式寫names更緊湊。test字段可選不寫就不做測試集評估。4.2 訓練命令與 batch size 的顯存估算# 單卡訓練imgsz 根據(jù)圖像實際尺寸調整 yolo segment train \ data./data.yaml \ modelyolov8n-seg.pt \ epochs100 \ imgsz640 \ batch16 \ lr00.01 \ patience20 \ device0 \ projectagri_seg \ nameexp1邏輯說明modelyolov8n-seg.pt加載預訓練的分割模型n 是最小版本顯存不夠就換 n夠就換 s 或 m。imgsz640是輸入尺寸如果原始圖像是 1024 以上可以設 1024 但顯存翻倍。patience20表示 20 輪驗證指標不提升就早停。參數(shù)說明batch16在 8GB 顯存上跑 640 尺寸的 n 模型基本夠用。如果 OOM先降 batch 到 8再降 imgsz 到 512。lr00.01是初始學習率分割任務通常比檢測稍小0.005 到 0.01 之間比較穩(wěn)。4.3 訓練過程監(jiān)控看哪些指標、什么時候該停訓練啟動后終端會輸出每輪的box_loss、seg_loss、cls_loss和mAP50。分割任務重點看seg_loss和mask mAP50。# 訓練完成后查看結果 ls agri_seg/exp1/ # 關鍵文件results.csv每輪指標、weights/best.pt最佳權重、 # confusion_matrix.png混淆矩陣、val_batch0_pred.jpg驗證集預測可視化邏輯說明results.csv可以用 pandas 讀取畫曲線重點看metrics/mAP50(M)是否還在漲。如果seg_loss持續(xù)下降但mAP50不漲說明過擬合需要加數(shù)據(jù)增強或減模型復雜度。參數(shù)說明mAP50(M)是掩碼 IoU 閾值 0.5 時的平均精度分割任務的核心指標。mAP50-95(M)更嚴格但農作物病害場景下 0.5 就夠用。5. 避坑與排查農作物病害分割訓練中最容易翻車的五個地方5.1 坑一驗證集 mAP 很高但實際預測全是背景現(xiàn)象訓練日志里mAP50(M)到了 0.8但拿新圖預測時模型輸出全是背景沒有任何掩碼。原因驗證集和訓練集來自同一批圖像分布太相似。模型學會了「猜」驗證集的類別分布但沒有真正學到病斑的視覺特征。解決手動劃分驗證集時確保不同批次、不同光照條件的圖像分開。如果數(shù)據(jù)集本身多樣性不足用albumentations做離線增強擴充訓練集。預測時降低置信度閾值試試yolo segment predict conf0.1。5.2 坑二小病斑被完全忽略現(xiàn)象大塊病斑分割得很準但直徑小于 20 像素的早期病斑一個都檢不出來。原因YOLOv8 的 P3 特征圖 stride 是 8對應 640 輸入下最小感受野約 8 像素。小于這個尺寸的目標在淺層特征中信息太少。解決把imgsz提到 1024 或 1280讓 P3 特征圖覆蓋更多像素?;蛘咴跀?shù)據(jù)增強中加copy_paste把小病斑復制到其他位置增加樣本。如果顯存不夠用yolov8s-seg換yolov8n-seg小模型的特征提取能力更弱。5.3 坑三掩碼邊緣鋸齒嚴重現(xiàn)象預測出的病斑掩碼邊緣呈鋸齒狀和真實邊界差距大。原因YOLOv8 分割頭輸出的掩碼原型分辨率是 160x160輸入 640 時上采樣到原圖尺寸時細節(jié)丟失。解決訓練時設overlap_maskTrue默認開啟推理時用retina_masksTrue獲得更高分辨率的掩碼。如果還不夠換yolov8x-seg或yolov8l-seg大模型的原型掩碼通道更多。5.4 坑四類別不平衡導致少數(shù)類完全學不到現(xiàn)象早疫病和晚疫病樣本多mAP 正常銹病只有幾十個實例mAP 接近 0。解決在data.yaml同級目錄建一個hyp.yaml設置cls_pw1.0開啟類別權重?;蛘哂肳eightedRandomSampler做數(shù)據(jù)重采樣。最直接的辦法是離線過采樣把少數(shù)類的圖像復制多份文件名加后綴區(qū)分。5.5 坑五訓練 loss 震蕩不收斂現(xiàn)象seg_loss在 0.5 到 2.0 之間反復跳始終不下降。原因學習率太大或者 batch size 太小導致梯度噪聲大。解決先把lr0降到 0.001 試 10 輪。如果還震蕩把batch翻倍顯存允許的話。另外檢查數(shù)據(jù)標注是否有大量錯誤——用yolo segment train的--verbose模式看每批數(shù)據(jù)的損失分布異常高的批次對應的圖像大概率標注有問題。6. 掩碼后處理與面積計算把分割結果變成可用的病害評估指標6.1 從預測掩碼到病斑面積占比訓練完模型只是第一步實際業(yè)務要的是「這片葉子上病斑占了多少面積」。YOLOv8 預測返回的masks是二值掩碼直接算像素占比就行。from ultralytics import YOLO import numpy as np import cv2 model YOLO(agri_seg/exp1/weights/best.pt) results model.predict(test_leaf.jpg, conf0.25, retina_masksTrue) for r in results: if r.masks is None: print(未檢測到病斑) continue # masks.data 形狀 [N, H, W]N 是檢測到的實例數(shù) masks r.masks.data.cpu().numpy() img_h, img_w r.orig_shape total_pixels img_h * img_w for i, mask in enumerate(masks): # 調整掩碼到原圖尺寸 mask_resized cv2.resize(mask, (img_w, img_h), interpolationcv2.INTER_NEAREST) area_ratio mask_resized.sum() / total_pixels cls_name r.names[int(r.boxes.cls[i])] print(f病斑 {i}: 類別{cls_name}, 面積占比{area_ratio:.4f})邏輯說明retina_masksTrue讓預測返回原圖分辨率的掩碼避免手動上采樣。r.masks.data是[N, H, W]的張量每個通道對應一個實例的二值掩碼。cv2.resize用最近鄰插值保持二值性。參數(shù)說明conf0.25是置信度閾值農作物病害場景可以降到 0.15 提高召回。area_ratio就是病斑面積占比超過 0.3 通常意味著嚴重感染。6.2 多病斑合并與嚴重度分級一張葉子上可能有多個同類病斑業(yè)務上需要合并計算總感染面積。# 按類別合并掩碼 from collections import defaultdict cls_masks defaultdict(list) for i, mask in enumerate(masks): cls_name r.names[int(r.boxes.cls[i])] cls_masks[cls_name].append(mask) for cls_name, mask_list in cls_masks.items(): # 邏輯或合并同類掩碼 merged np.zeros_like(mask_list[0]) for m in mask_list: merged np.logical_or(merged, m 0.5) ratio merged.sum() / total_pixels # 分級 if ratio 0.05: level 輕微 elif ratio 0.15: level 中度 elif ratio 0.30: level 重度 else: level 極重 print(f{cls_name}: 總面積占比{ratio:.4f}, 嚴重度{level})邏輯說明np.logical_or合并同類掩碼避免重疊區(qū)域重復計算。分級閾值根據(jù)實際業(yè)務調整這里給的是通用參考值。參數(shù)說明m 0.5把概率掩碼二值化。分級閾值需要和農學專家確認不同作物的耐受度不同。6.3 一個容易忽略的細節(jié)掩碼面積計算時的圖像預處理還原如果推理時用了imgsz640但原圖是 2048x2048YOLOv8 內部會縮放。retina_masksTrue會自動還原到原圖尺寸但如果你手動處理masks.data必須自己 resize 回去。我一般直接在predict里加retina_masksTrue省掉這一步。另外注意r.orig_shape返回的是(height, width)順序別搞反了。這套流程跑下來從拿到壓縮包到算出病斑面積占比順利的話半天能跑通。最耗時間的往往是標注格式轉換和驗證集劃分——這兩步做扎實后面訓練基本不會出大問題。我自己的習慣是轉換完先拿 10 張圖可視化檢查一遍確認掩碼和原圖對齊了再啟動訓練能省下大量排查時間。希望幫到你。本文還有配套的精品資源點擊獲取