據(jù)集構建到模型部署全流程解析)
簡介面向YOLOv8目標檢測與圖像分類任務的花卉數(shù)據(jù)集包含daisy、dandelion、roses、sunflowers、tulips五個常見類別覆蓋不同角度、光照與背景下的花朵圖像可直接用于訓練花卉識別模型、評估分類算法也可作為高校計算機視覺課程的教學案例。壓縮包共2000個文件其中1999張JPG圖像構成主要樣本集另附1個Python腳本便于做數(shù)據(jù)劃分、格式檢查或二次擴展整體大小約218.93MB目錄結(jié)構簡潔清晰可無縫接入YOLOv8訓練流程省去大量數(shù)據(jù)準備時間。圍繞花卉分類系統(tǒng)資源還從組織識別、科學研究、園藝農(nóng)業(yè)應用、瀕危物種保護和科普教育等方向展開使用者在利用圖像完成訓練、驗證與推理的同時也能理解分類任務在植物學研究和產(chǎn)業(yè)實踐中的實際價值。已有621人瀏覽學習該資源適合希望從數(shù)據(jù)到模型完整跑通流程的初學者同樣適合用于算法對比、課程設計或后續(xù)數(shù)據(jù)增強研究的開發(fā)者。1. 花卉分類的瓶頸在數(shù)據(jù)一套 YOLOv8 五類數(shù)據(jù)集的定位花卉圖像識別的公開實驗很多真到落地時問題幾乎都堆在數(shù)據(jù)集環(huán)節(jié)。ImageNet 風格的花卉數(shù)據(jù)集是單標簽整圖分類類別裁切范圍、背景占比差異大直接轉(zhuǎn)目標檢測訓練框的語義就亂了。這套 YOLOv8 格式的五類花卉數(shù)據(jù)集daisy、dandelion、roses、sunflowers、tulips把數(shù)據(jù)組織成了檢測任務的標準形態(tài)圖像與 txt 標簽一一對應標簽是 class_id 加歸一化 bbox 坐標補一個 data.yaml 就能直接進入 ultralytics 訓練流程。做畢業(yè)設計的人可以省掉標注和格式轉(zhuǎn)換這兩件最耗時的事做邊緣端花卉識別的工程師可以拿它當基線數(shù)據(jù)先把檢測頭、增強策略和部署鏈路跑通再按業(yè)務場景擴數(shù)據(jù)。提醒一句解壓后先確認完整樣本量與類別分布再開始訓練別被預覽圖帶偏預期。2. 數(shù)據(jù)集目錄結(jié)構與 YOLOv8 標簽格式解析2.1 目錄組織與 train/val 劃分慣例YOLO 生態(tài)里數(shù)據(jù)集的標準組織方式是 images 與 labels 兩個目錄平級各自下面按 train、val 分子目錄。這套五類花卉數(shù)據(jù)集的目錄結(jié)構沿用了這個慣例解壓后你會看到 images/train 下是 jpg 圖像labels/train 下是逐圖對應的 txt 標注val 目錄同理。文件名主體一一對應、擴展名不同這是 ultralytics 數(shù)據(jù)加載器能夠自動匹配的前提。flower_dataset/ ├── images/ │ ├── train/ │ │ ├── 2431737309_1468526f8b.jpg │ │ └── ... │ └── val/ ├── labels/ │ ├── train/ │ │ ├── 2431737309_1468526f8b.txt │ │ └── ... │ └── val/ └── data.yaml這套劃分方式對檢測任務來說是最省事的YOLO 的 dataloader 不做額外解析只要路徑配置正確訓練和驗證階段會自動讀取對應目錄下的 txt。如果原包沒有提供 val 劃分需要自己拆分時常見做法是 train:val8:2并用分層采樣保證五個類別在兩個集合里的比例接近原始分布。直接用 random.shuffle 切分的問題在于dandelion 這類小類別樣本量少隨機切分可能讓驗證集里某個類別只有個位數(shù)樣本導致 mAP 指標方差很大一次實驗的結(jié)果不可信。分層切分可以用 sklearn 的 train_test_split 實現(xiàn)按圖片名對應的主標簽傳入 stratify 參數(shù)。from sklearn.model_selection import train_test_split from pathlib import Path img_files sorted(Path(images).glob(*.jpg)) def main_label(img_path): txt Path(labels) / (img_path.stem .txt) counts {} for line in txt.read_text().strip().splitlines(): cid int(line.split()[0]) counts[cid] counts.get(cid, 0) 1 return max(counts, keycounts.get) labels [main_label(p) for p in img_files] train_idx, val_idx train_test_split( range(len(img_files)), test_size0.2, stratifylabels, random_state42 )這段代碼先統(tǒng)計每張圖的主類別再按主類別做分層切分保證驗證集里五類比例與全集一致。random_state 固定下來后續(xù)多次實驗的劃分可復現(xiàn)對比不同超參數(shù)時不會引入數(shù)據(jù)劃分噪聲。stratify 參數(shù)要求每個類別的樣本數(shù)不小于 2否則會報錯真遇到這種情況說明該類別數(shù)據(jù)量太少需要考慮先做數(shù)據(jù)擴充而不是強行劃分。2.2 labels 里的五類標注規(guī)則每個 txt 文件的一行對應一個目標五個字段依次是 class_id、cx、cy、w、h全部為歸一化數(shù)值。cx、cy 是 bbox 中心點相對圖像寬高的比例取值在 0 到 1 之間w、h 是框的寬高相對圖像寬高的比例同樣在 0 到 1 之間。類別編號從 0 開始編號與類別名的對應關系如下表。class_id類別名典型視覺特征0daisy白色細長花瓣、黃色花心單頭為主1dandelion黃色放射狀花瓣花莖中空2roses多層螺旋花瓣紅粉色調(diào)居多3sunflowers大型黃色花盤花徑占比大4tulips杯狀單層花瓣直立花莖這個編號順序必須與 data.yaml 中 names 列表完全一致訓練腳本不會自動糾正順序?qū)戝e一位整類全錯。一個容易忽略的細節(jié)是roses 和 tulips 經(jīng)常成簇出現(xiàn)一張圖里可能有十幾個框而 dandelion 通常單株出現(xiàn)標簽文件行數(shù)差異大是正?,F(xiàn)象不代表數(shù)據(jù)有問題。提示標簽里允許同一張圖存在多個類別但每行只能有一個類別 ID多類別混合圖在自然拍攝的花卉場景里很常見標注時不要把一朵花拆成兩個框。真正需要警惕的是框的邊界歸一化坐標允許 cx 或 cy 落在圖像邊緣但 w 和 h 不能為 0 或負數(shù)也不能超過 1。標注工具導出時偶爾會產(chǎn)生邊角越界的框這類臟數(shù)據(jù)對 loss 的影響在訓練初期不明顯后期會持續(xù)拉低定位精度所以訓練前做一輪體檢是值得的。2.3 用腳本核對 bbox 坐標合法性拿到數(shù)據(jù)集先做一次全量體檢比訓練到一半再排查要劃算得多。下面這個腳本遍歷 labels 目錄檢查每個 txt 的行數(shù)、字段數(shù)和坐標范圍。from pathlib import Path import cv2 label_root Path(labels/train) img_root Path(images/train) bad 0 for lp in sorted(label_root.glob(*.txt)): img_path img_root / (lp.stem .jpg) if not img_path.exists(): print(f[missing] {img_path}) bad 1 continue h, w cv2.imread(str(img_path)).shape[:2] for line in lp.read_text().strip().splitlines(): parts line.split() if len(parts) ! 5: print(f[field] {lp.name}: {line}) bad 1 continue cid, cx, cy, bw, bh map(float, parts) if not (0 cx 1 and 0 cy 1): print(f[center] {lp.name}: {line}) bad 1 if bw 0 or bh 0 or bw 1 or bh 1: print(f[size] {lp.name}: {line}) bad 1 print(ftotal issues: {bad})腳本對每個標簽文件做三類檢查圖片缺失、字段數(shù)量不對、坐標越界。越界檢查基于歸一化約定cx、cy 必須落在 [0,1]w、h 必須在 (0,1]。如果原標注是從 COCO 或 VOC 格式轉(zhuǎn)換來的轉(zhuǎn)換時最容易犯的錯誤是把像素坐標直接除以圖片短邊而不是各自的長邊導致寬高比失真這類問題能從這里查出一部分。檢查通過后再進訓練后續(xù)的 loss 波動才不會讓人懷疑數(shù)據(jù)本身檢查有報錯也不要慌把異常文件單獨移到一個 debug 目錄不影響其余數(shù)據(jù)訓練。3. 基于 ultralytics 訓練五類花卉模型的配置與超參數(shù)3.1 data.yaml 的編寫要點ultralytics 訓練入口只認一個 yaml 文件把數(shù)據(jù)集路徑、類別數(shù)、類別名寫對就行。針對這套五類花卉數(shù)據(jù)集data.yaml 內(nèi)容如下path: /home/user/flower_dataset train: images/train val: images/val nc: 5 names: 0: daisy 1: dandelion 2: roses 3: sunflowers 4: tulipspath 寫絕對路徑最省心train 和 val 相對 path 解析。常見的坑有三個一是 path 寫在注釋里被忽略訓練時直接報 dataset not found二是 names 用 1 起始編號與標簽文件里的 0 起始編號錯位導致所有框的類別整體平移一位三是每類圖片數(shù)量差距大時不加任何提示模型悶頭訓練最后小類別 mAP 近乎為 0。檢查 yaml 最直接的方法是先用代碼打印類別分布而不是直接開跑。from ultralytics.data import YOLODataset ds YOLODataset(flower.yaml) cnt {name: 0 for name in ds.names.values()} for lb in ds.labels: for c in lb[cls]: cnt[ds.names[int(c)]] 1 print(cnt)這段代碼遍歷訓練集所有標簽逐類累加目標數(shù)量。注意這里遍歷的是 lb[cls] 的全部元素不是只取第一個密集標注的圖可能同時包含多個類別只取第一個會把多類別圖統(tǒng)計成單類別。輸出結(jié)果用來判斷是否需要做類別重加權或過采樣這直接影響后續(xù)訓練對稀有類別的關注程度。3.2 訓練命令與關鍵超參數(shù)數(shù)據(jù)集檢查通過后訓練命令可以寫得非常簡潔yolo detect train \ modelyolov8n.pt \ dataflower.yaml \ epochs100 \ imgsz640 \ batch16 \ lr00.01 \ optimizerauto \ patience20幾個參數(shù)單獨說。modelyolov8n.pt 是預訓練權重對五類花卉這種中等規(guī)模任務n 版本足夠打出基線如果最終要部署到邊緣設備n 也是性價比最高的選擇。imgsz640 是訓練與推理統(tǒng)一的分辨率花卉圖像長寬比不一時ultralytics 會自動做 letterbox 填充不必手動預處理。batch16 在 8GB 顯存的卡上比較穩(wěn)妥顯存不夠就降到 8用 GTX 1660 Ti 這類 6GB 卡跑的話建議 batch8、關閉 mosaic 或者把 imgsz 降到 480否則容易 OOM。patience20 是早停窗口花卉分類任務通常在 60 到 80 輪收斂20 輪沒有提升就停能省不少時間。參數(shù)默認值本數(shù)據(jù)集的建議設置理由imgsz640480~640花卉目標占比中等640 保留花瓣紋理小顯存降 480batch168~16視顯存而定小于 8 時 loss 波動明顯lr00.010.005~0.01數(shù)據(jù)量小時 lr 過大容易震蕩optimizerautoSGD 或 AdamWauto 會按模型自動選手動指定更好復現(xiàn)mosaic1.00.5~1.0密集花卉被裁剪后容易漏檢小目標關于 lr0如果每類只有幾百張圖0.01 配余弦退火問題不大如果總量只有幾十張建議降到 0.005并適當延長 warmup 輪數(shù)。訓練完成后看 runs/detect/train 下的 results.csv比看終端輸出更直觀里面每一列對應一個指標可以直接用 pandas 讀取繪圖。3.3 類別不均衡與數(shù)據(jù)增強的取舍五類花卉天然存在不均衡roses 和 sunflowers 樣本多dandelion 樣本少。不處理這種不均衡模型會傾向于把不確定的框判給大類。常見處理方式有三種類別重加權、過采樣小類、調(diào)整增強強度。ultralytics 可以用 class weights 參數(shù)傳入每個類別的權重向量但需要手動算不如直接在數(shù)據(jù)層面處理來得直觀。# augment 相關參數(shù)可以在訓練命令中通過 augmentTrue 啟用 hsv_h: 0.015 hsv_s: 0.5 hsv_v: 0.4 fliplr: 0.5 mosaic: 0.5 mixup: 0.1這些增強參數(shù)的作用對象是整張圖。hsv 擾動模擬不同光照下的花色變化對花卉這種顏色敏感的類別很有效fliplr 水平翻轉(zhuǎn)不改變花的語義可以放心開mosaic 和 mixup 對小樣本類別有正則化作用但 mosaic 會把四張圖拼在一起花卉邊緣被切掉后原本就小的 dandelion 目標可能只剩半個所以建議從默認的 1.0 降到 0.5。跑一輪對比實驗一組關閉 mosaic一組保持 0.5觀察 val 集上 dandelion 類別的 mAP50 差異這個數(shù)字比整體 mAP 更能反映增強策略對弱類別的實際影響。mixup 對花卉這種細節(jié)紋理敏感的任務效果不穩(wěn)定值不要超過 0.2否則模型會學到兩張圖疊在一起的混合特征。4. 訓練過程評估與數(shù)據(jù)質(zhì)量回溯4.1 從 loss 曲線讀訓練狀態(tài)訓練結(jié)束后runs/detect/train 目錄下會有 results.csv 和一組自動生成的曲線圖。對五類花卉這個任務重點關注三組曲線train/box_loss、train/cls_loss、val/box_loss 與 val/cls_loss。訓練正常的信號是曲線同步下降并在后半程趨于平緩val 曲線沒有明顯回升說明沒有過擬合。用下面這段代碼直接讀取 results.csv 畫曲線比打開自動生成的圖更靈活也能自定義保存分辨率import pandas as pd import matplotlib.pyplot as plt df pd.read_csv(runs/detect/train/results.csv) df.columns [c.strip() for c in df.columns] fig, ax plt.subplots(1, 2, figsize(12, 4)) ax[0].plot(df[epoch], df[train/box_loss], labeltrain box) ax[0].plot(df[epoch], df[val/box_loss], labelval box) ax[1].plot(df[epoch], df[train/cls_loss], labeltrain cls) ax[1].plot(df[epoch], df[val/cls_loss], labelval cls) for a in ax: a.legend() a.set_xlabel(epoch) plt.tight_layout() plt.savefig(loss_curves.png, dpi150)常見但容易被誤判的情況是train/cls_loss 一直下降val/cls_loss 在第 30 輪開始反彈而 box_loss 還在降。這通常說明分類分支過擬合bbox 回歸還在正常進步。處理辦法不是調(diào)低學習率而是增加數(shù)據(jù)增強強度或減少 epochs也可以先確認是不是類別不均衡把分類分支帶偏了回看第 3.3 節(jié)的增強參數(shù)。loss 曲線整體偏高但趨勢正常往往不是模型問題而是標簽里 bbox 框得偏大或偏小檢查標注就對了。4.2 混淆矩陣與 PR 曲線怎么讀val 階段生成的 confusion_matrix.png 是五類數(shù)據(jù)最值得看的圖。行列都是五個類別加一個 background對角線越亮越好。對花卉分類最容易混淆的是 roses 和 tulips兩者花型接近、顏色重疊混淆矩陣里這兩個非對角線格子如果明顯偏亮說明模型學到了顏色和形狀的共用特征而沒學到區(qū)分性細節(jié)比如 tulips 的杯狀花冠和 roses 的螺旋花心。PR 曲線看的是每個類別在不同置信度閾值下的精確率與召回率權衡。dandelion 的曲線面積如果明顯小于 roses大概率不是模型能力問題而是該類別的目標占比低、標注框偏小。此時優(yōu)先檢查標注框是否過緊很多標注工具的自動貼邊功能會裁掉花瓣邊緣導致模型學到的特征不完整?,F(xiàn)象優(yōu)先排查項對應處理roses/tulips 混淆嚴重標注框是否包含完整花冠重標或補充特寫樣本dandelion 召回率低小目標占比、mosaic 增強降低 mosaic提高 imgsz所有類別 mAP 都不高標簽坐標是否正確回跑 2.3 節(jié)腳本val loss 曲線抖動batch 過小或 lr 過高減小 lr0增大 batch這張表是排查順序的參考按數(shù)據(jù)、增強、超參的順序走不要一上來就動網(wǎng)絡結(jié)構。C2f 模塊和 head 結(jié)構的改動留到基線穩(wěn)定之后再做否則問題混在一起根本定位不到根因。4.3 數(shù)據(jù)質(zhì)量回溯壞樣本對指標的影響訓練結(jié)果異常時先把預測結(jié)果可視化而不是盯著指標猜。用 ultralytics 的 predict 跑驗證集保存置信度較低的預測結(jié)果直接看模型到底漏了什么。yolo detect predict \ modelruns/detect/train/weights/best.pt \ sourceflower_dataset/images/val \ conf0.3 \ save_txtFalse \ saveTrue保存下來的圖片里沒有框的花就是漏檢樣本。對五類花卉而言最常見的問題是背景復雜、花朵被葉片遮擋以及逆光條件下花瓣與背景對比度低。這類壞樣本不需要馬上刪掉而是記錄文件名檢查對應標簽是否存在標注遺漏。很多時候模型沒學會某個特征不是網(wǎng)絡能力不夠而是標注里把遮擋的花漏標了模型把遮擋的花學成了負樣本。這種數(shù)據(jù)一致性問題通過可視化能很快定位比反復調(diào)參有效得多。定位到具體壞樣本后用 LabelImg 或 X-AnyLabeling 補上遺漏框重新訓練一輪類別 mAP 的提升往往立竿見影。5. 模型導出與端側(cè)部署ONNX 轉(zhuǎn)換與 NMS 參數(shù)調(diào)優(yōu)5.1 導出 ONNX 并固定輸入尺寸訓練完成后導出部署格式是常見環(huán)節(jié)。對邊緣設備優(yōu)先導出 ONNX再轉(zhuǎn)成對應平臺格式。導出的關鍵參數(shù)是 imgsz 必須與推理時的預處理一致yolo export modelbest.pt formatonnx imgsz640 opset12 simplifyTrueopset 版本別追新RK3588 這類平臺的 NPU 工具鏈對 opset 的支持往往滯后12 到 14 是兼容性較好的區(qū)間。simplifyTrue 會去掉一些冗余算子但導出后務必用 onnxruntime 跑一遍推理確認輸出形狀和數(shù)值范圍正常simplify 偶爾會誤刪有實際作用的節(jié)點。端側(cè)部署時如果量化工具鏈支持先用 val 集的一個子集做校準數(shù)據(jù)這類數(shù)據(jù)分布與真實場景越接近INT8 量化后的精度損失越小。5.2 推理側(cè)處理密集花卉的 NMS 參數(shù)花卉場景與通用目標檢測有個顯著差異roses 和 tulips 密集排列時默認 NMS 的 IoU 閾值 0.45 會把相鄰花朵合并成一個框。部署時把 NMS IoU 閾值適當降低到 0.3 到 0.35能顯著減少漏檢。同時 score_threshold 設為 0.25 左右即可花卉分類的類間相似度高閾值太高會把低置信度的真目標全濾掉導致召回率驟降。這兩個參數(shù)在端側(cè)通常暴露為配置文件里的 nms_iou_thresh 和 conf_thresh優(yōu)化順序是先調(diào) NMS 再調(diào)置信度因為 NMS 決定框的數(shù)量上限置信度只是從這些框中做二次篩選。用驗證集上的 PR 曲線輔助選閾值PR 曲線拐點對應的置信度就是 conf_thresh 的合理初始值不需要反復試。最后再做一次端到端驗證用一段包含多株花簇的實拍視頻確認漏檢率和誤檢率都達標整個鏈路才算真正跑通。本文還有配套的精品資源點擊獲取