自動(dòng)計(jì)數(shù)畢設(shè)實(shí)戰(zhàn):從環(huán)境配置到界面聯(lián)調(diào))
簡(jiǎn)介這份資源面向計(jì)算機(jī)、人工智能、自動(dòng)化等專業(yè)的在校學(xué)生與教師提供一套基于YOLOv8的果園成熟果實(shí)自動(dòng)計(jì)數(shù)完整方案可用于畢業(yè)設(shè)計(jì)、課程設(shè)計(jì)或大作業(yè)。壓縮包共8個(gè)文件約15.91MB包含3個(gè)Python腳本、3個(gè)模型權(quán)重文件與2個(gè)說(shuō)明文本分別對(duì)應(yīng)可視化界面、模型訓(xùn)練與視頻檢測(cè)等核心環(huán)節(jié)并附有完整數(shù)據(jù)集與部署教程簡(jiǎn)單配置即可運(yùn)行。項(xiàng)目可輸出核心指標(biāo)曲線圖、混淆矩陣、F1分?jǐn)?shù)曲線、精確率-召回率曲線、驗(yàn)證集預(yù)測(cè)結(jié)果及標(biāo)簽分布圖便于答辯展示與結(jié)果分析。目前已有30人學(xué)習(xí)關(guān)注。讀者可直接獲得經(jīng)過測(cè)試的源碼、預(yù)訓(xùn)練權(quán)重與可視化頁(yè)面既能快速?gòu)?fù)現(xiàn)果實(shí)計(jì)數(shù)效果也能在此基礎(chǔ)上修改擴(kuò)展功能適合作為畢設(shè)保底方案或入門目標(biāo)檢測(cè)的實(shí)踐素材。1. 果園果實(shí)自動(dòng)計(jì)數(shù)這套 YOLOv8 畢設(shè)資源到底能不能直接跑果園里數(shù)果子這件事人工干一天下來(lái)眼睛發(fā)花數(shù)錯(cuò)率還高。這套資源的核心就是用 YOLOv8 做成熟果實(shí)的目標(biāo)檢測(cè)再把檢測(cè)框轉(zhuǎn)成計(jì)數(shù)結(jié)果配了一個(gè)可視化界面數(shù)據(jù)集和部署教程都打包在里面。拿到手之后不需要自己從零標(biāo)注、從零搭界面解壓完按教程走一遍就能跑起來(lái)。適合兩類人一類是畢設(shè)或課程設(shè)計(jì)時(shí)間緊、需要完整可演示系統(tǒng)的學(xué)生另一類是想快速驗(yàn)證 YOLOv8 在農(nóng)業(yè)計(jì)數(shù)場(chǎng)景下效果的從業(yè)者。資源里包含源碼、可視化界面、完整數(shù)據(jù)集和部署教程技術(shù)棧是 Python YOLOv8 圖形界面框架整體走的是“檢測(cè)即計(jì)數(shù)”的路線不涉及復(fù)雜的多目標(biāo)跟蹤。下面按實(shí)際拆包和復(fù)現(xiàn)的順序把環(huán)境配置、數(shù)據(jù)組織、訓(xùn)練調(diào)參、界面聯(lián)調(diào)和常見翻車點(diǎn)逐個(gè)講清楚。2. 環(huán)境配置與依賴安裝從零到能跑通第一張推理圖2.1 為什么優(yōu)先選 CPU 版先跑通再換 GPU很多人拿到 YOLOv8 項(xiàng)目第一反應(yīng)是裝 CUDA、配 cuDNN結(jié)果卡在驅(qū)動(dòng)版本上耗掉一整天。我的建議是先用 CPU 版本把推理和界面跑通確認(rèn)代碼邏輯沒問題再切 GPU 訓(xùn)練。原因很直接CPU 版安裝簡(jiǎn)單不會(huì)因?yàn)轱@卡驅(qū)動(dòng)和 PyTorch 版本不匹配導(dǎo)致 import 就報(bào)錯(cuò)。等推理通了再裝 GPU 版 PyTorch 做訓(xùn)練這時(shí)候即使出問題你也能確定是環(huán)境問題而不是代碼問題。常見做法是建一個(gè)獨(dú)立虛擬環(huán)境避免和系統(tǒng) Python 混在一起。Ubuntu 20.04 和 Windows 10/11 都適用下面以 conda 為例。# 創(chuàng)建虛擬環(huán)境Python 版本建議 3.9 或 3.10 conda create -n yolov8_fruit python3.10 -y conda activate yolov8_fruit # 安裝 CPU 版 PyTorch先跑通推理用 pip install torch torchvision --index-url https://download.pytorch.org/whl/cpu # 安裝 ultralytics 和界面依賴 pip install ultralytics opencv-python pillow pyqt5這里torch和torchvision走的是 CPU 源裝完大概幾百 MB。ultralytics是 YOLOv8 的官方庫(kù)版本建議鎖在 8.0.x 到 8.1.x 之間太新的版本有時(shí)會(huì)改 API 導(dǎo)致項(xiàng)目里的推理腳本報(bào)參數(shù)錯(cuò)誤。pyqt5是可視化界面的依賴如果項(xiàng)目用的是 tkinter 就換成tkinterPython 自帶不用額外裝。裝完之后跑一句yolo predict modelyolov8n.pt sourcehttps://ultralytics.com/images/bus.jpg驗(yàn)證環(huán)境能輸出檢測(cè)結(jié)果圖就說(shuō)明基礎(chǔ)環(huán)境沒問題。2.2 GPU 訓(xùn)練環(huán)境的切換與版本對(duì)齊CPU 推理通了之后如果要訓(xùn)練自己的數(shù)據(jù)集GPU 是繞不開的。這時(shí)候把 CPU 版 PyTorch 卸掉換成對(duì)應(yīng) CUDA 版本的 GPU 版。關(guān)鍵點(diǎn)是先確認(rèn)顯卡驅(qū)動(dòng)支持的 CUDA 最高版本再選 PyTorch 對(duì)應(yīng)的 CUDA 版本不要反過來(lái)。# 查看顯卡驅(qū)動(dòng)和 CUDA 支持版本 nvidia-smi # 卸載 CPU 版安裝 GPU 版以 CUDA 11.8 為例 pip uninstall torch torchvision -y pip install torch torchvision --index-url https://download.pytorch.org/whl/cu118 # 驗(yàn)證 GPU 是否可用 python -c import torch; print(torch.cuda.is_available())nvidia-smi右上角顯示的 CUDA Version 是驅(qū)動(dòng)支持的最高版本不是當(dāng)前安裝的版本。比如顯示 12.2你可以裝 CUDA 11.8 的 PyTorch也可以裝 12.1 的但不能裝 12.3 的。torch.cuda.is_available()返回 True 才算成功。如果返回 False先檢查驅(qū)動(dòng)版本再檢查 PyTorch 和 CUDA 是否匹配最后看是不是裝成了 CPU 版。這一步?jīng)]有后悔藥版本對(duì)不上就是跑不了 GPU。注意如果項(xiàng)目里 requirements.txt 鎖定了 torch 版本優(yōu)先按它來(lái)不要自己升級(jí)。版本沖突是 YOLOv8 項(xiàng)目里最常見的翻車原因之一。3. 數(shù)據(jù)集組織與標(biāo)注格式轉(zhuǎn)換讓 YOLOv8 認(rèn)得你的果園圖片3.1 目錄結(jié)構(gòu)與 data.yaml 的對(duì)應(yīng)關(guān)系YOLOv8 對(duì)數(shù)據(jù)集的目錄結(jié)構(gòu)有固定要求不是隨便放幾個(gè)文件夾就能訓(xùn)練。標(biāo)準(zhǔn)結(jié)構(gòu)是 images 和 labels 分開各自下面再分 train、val、test。資源里如果已經(jīng)帶了完整數(shù)據(jù)集先檢查目錄是不是這個(gè)結(jié)構(gòu)不是的話按下面調(diào)整。fruit_dataset/ ├── images/ │ ├── train/ # 訓(xùn)練集圖片 │ ├── val/ # 驗(yàn)證集圖片 │ └── test/ # 測(cè)試集圖片可選 ├── labels/ │ ├── train/ # 訓(xùn)練集標(biāo)注 txt │ ├── val/ # 驗(yàn)證集標(biāo)注 txt │ └── test/ # 測(cè)試集標(biāo)注 txt └── data.yaml # 數(shù)據(jù)集配置文件data.yaml是訓(xùn)練時(shí)的入口配置內(nèi)容必須和實(shí)際路徑對(duì)應(yīng)。常見寫法如下path: ./fruit_dataset # 數(shù)據(jù)集根目錄 train: images/train # 訓(xùn)練集相對(duì)路徑 val: images/val # 驗(yàn)證集相對(duì)路徑 test: images/test # 測(cè)試集相對(duì)路徑?jīng)]有就刪掉這行 nc: 1 # 類別數(shù)果園成熟果實(shí)通常只檢測(cè)一類 names: [ripe_fruit] # 類別名稱順序要和標(biāo)注里的 class_id 對(duì)應(yīng)nc是類別數(shù)量如果只檢測(cè)成熟果實(shí)就是 1。names列表的順序很重要標(biāo)注文件里的 class_id 是 0 就對(duì)應(yīng)列表第一個(gè)名字。如果數(shù)據(jù)集里還有未成熟果實(shí)或其他類別nc和names都要相應(yīng)增加。路徑可以用相對(duì)路徑也可以用絕對(duì)路徑相對(duì)路徑是相對(duì)于你執(zhí)行訓(xùn)練命令時(shí)所在的目錄不是相對(duì)于 data.yaml 文件本身這一點(diǎn)容易搞混。3.2 標(biāo)注格式轉(zhuǎn)換Labelme 轉(zhuǎn) YOLO 的腳本與邊界處理如果數(shù)據(jù)集里的標(biāo)注是 Labelme 生成的 JSON 格式需要轉(zhuǎn)成 YOLO 的 txt 格式。轉(zhuǎn)換的核心是把多邊形或矩形坐標(biāo)歸一化到 0 到 1 之間格式是class_id x_center y_center width height。下面是一個(gè)可直接用的轉(zhuǎn)換腳本。import json import os from pathlib import Path def labelme_to_yolo(json_dir, output_dir, class_map): json_dir: Labelme JSON 文件目錄 output_dir: 輸出 YOLO txt 的目錄 class_map: 類別名到 id 的映射如 {ripe_fruit: 0} json_dir Path(json_dir) output_dir Path(output_dir) output_dir.mkdir(parentsTrue, exist_okTrue) for json_file in json_dir.glob(*.json): with open(json_file, r, encodingutf-8) as f: data json.load(f) img_w data[imageWidth] img_h data[imageHeight] lines [] for shape in data[shapes]: label shape[label] if label not in class_map: continue # 跳過未定義類別避免訓(xùn)練時(shí)報(bào)錯(cuò) class_id class_map[label] points shape[points] # 取多邊形或矩形的外接框 xs [p[0] for p in points] ys [p[1] for p in points] x_min, x_max min(xs), max(xs) y_min, y_max min(ys), max(ys) # 歸一化并計(jì)算中心點(diǎn)和寬高 x_center (x_min x_max) / 2.0 / img_w y_center (y_min y_max) / 2.0 / img_h width (x_max - x_min) / img_w height (y_max - y_min) / img_h # 邊界裁剪防止坐標(biāo)超出 0-1 范圍 x_center min(max(x_center, 0.0), 1.0) y_center min(max(y_center, 0.0), 1.0) width min(max(width, 0.0), 1.0) height min(max(height, 0.0), 1.0) lines.append(f{class_id} {x_center:.6f} {y_center:.6f} {width:.6f} {height:.6f}) # 寫入同名 txt txt_path output_dir / (json_file.stem .txt) with open(txt_path, w, encodingutf-8) as f: f.write(\n.join(lines)) if __name__ __main__: labelme_to_yolo( json_dir./raw_annotations, output_dir./fruit_dataset/labels/train, class_map{ripe_fruit: 0} )這個(gè)腳本做了三件事讀取 Labelme JSON、把多邊形轉(zhuǎn)成外接矩形并歸一化、寫入 YOLO 格式 txt。class_map參數(shù)控制類別映射數(shù)據(jù)集里有什么類別就加什么沒在 map 里的標(biāo)注會(huì)被跳過避免訓(xùn)練時(shí)出現(xiàn)未知 class_id 導(dǎo)致報(bào)錯(cuò)。歸一化后的坐標(biāo)做了 0 到 1 的裁剪防止標(biāo)注時(shí)點(diǎn)超出圖片邊界導(dǎo)致訓(xùn)練異常。轉(zhuǎn)換完記得抽查幾個(gè) txt 文件確認(rèn)坐標(biāo)數(shù)值在合理范圍內(nèi)不要出現(xiàn)大于 1 或負(fù)數(shù)的情況。注意圖片和標(biāo)注文件名必須一一對(duì)應(yīng)除了擴(kuò)展名不同。如果圖片是img_001.jpg標(biāo)注必須是img_001.txt放在 labels 對(duì)應(yīng)目錄下。名字對(duì)不上訓(xùn)練時(shí)會(huì)被當(dāng)成無(wú)標(biāo)注圖片跳過。4. 模型訓(xùn)練與參數(shù)調(diào)優(yōu)從默認(rèn)配置到果園場(chǎng)景適配4.1 訓(xùn)練命令與關(guān)鍵參數(shù)含義YOLOv8 的訓(xùn)練入口很簡(jiǎn)潔一條命令就能啟動(dòng)。但默認(rèn)參數(shù)不一定適合果園果實(shí)這種密集小目標(biāo)場(chǎng)景需要根據(jù)實(shí)際情況調(diào)整。# 基礎(chǔ)訓(xùn)練命令 yolo detect train \ data./fruit_dataset/data.yaml \ modelyolov8n.pt \ epochs100 \ imgsz640 \ batch16 \ lr00.01 \ patience20 \ project./runs/train \ namefruit_expmodel參數(shù)決定用哪個(gè)預(yù)訓(xùn)練權(quán)重。yolov8n.pt是最小的 nano 版本速度快但精度低如果果實(shí)目標(biāo)小且密集建議換成yolov8s.pt或yolov8m.pt。epochs是訓(xùn)練輪數(shù)100 輪起步數(shù)據(jù)集小的話可以加到 200。imgsz是輸入圖片尺寸640 是默認(rèn)值果實(shí)占畫面比例小的話可以提到 1280但顯存占用會(huì)明顯增加。batch是批大小顯存不夠就往下調(diào)從 16 降到 8 再到 4。lr0是初始學(xué)習(xí)率默認(rèn) 0.01數(shù)據(jù)集小可以降到 0.001 防止過擬合。patience是早停輪數(shù)20 輪內(nèi)驗(yàn)證指標(biāo)沒提升就自動(dòng)停省時(shí)間。訓(xùn)練過程中會(huì)在runs/train/fruit_exp下生成權(quán)重文件、損失曲線和驗(yàn)證結(jié)果。重點(diǎn)關(guān)注results.csv里的metrics/mAP50和metrics/mAP50-95前者是 IoU 0.5 時(shí)的平均精度后者是 0.5 到 0.95 的平均值。果園計(jì)數(shù)場(chǎng)景下 mAP50 到 0.85 以上基本可用低于 0.7 就要檢查數(shù)據(jù)集標(biāo)注質(zhì)量或增加數(shù)據(jù)量。4.2 小目標(biāo)密集場(chǎng)景的參數(shù)調(diào)整策略果園果實(shí)往往在畫面里占比較小而且成熟果實(shí)可能成簇出現(xiàn)默認(rèn)的 640 輸入尺寸和 anchor 配置不一定最優(yōu)。幾個(gè)實(shí)際有效的調(diào)整方向參數(shù)默認(rèn)值果園場(chǎng)景建議原因imgsz640960 或 1280提高小目標(biāo)分辨率modelyolov8nyolov8s 或 yolov8m更大模型對(duì)小目標(biāo)更敏感batch168 或 4大輸入尺寸下顯存不夠lr00.010.005 或 0.001小數(shù)據(jù)集防過擬合mosaic1.00.5 或關(guān)閉果實(shí)密集時(shí) mosaic 可能引入干擾close_mosaic1020 或 30最后階段關(guān)閉增強(qiáng)穩(wěn)定收斂mosaic是 YOLOv8 默認(rèn)開啟的數(shù)據(jù)增強(qiáng)把四張圖拼成一張訓(xùn)練。果實(shí)計(jì)數(shù)場(chǎng)景下如果圖片本身果實(shí)就很密集mosaic 可能讓模型學(xué)到錯(cuò)誤的上下文關(guān)系適當(dāng)降低比例或最后幾十輪關(guān)掉。close_mosaic控制最后多少輪關(guān)閉 mosaic設(shè)大一點(diǎn)讓模型在真實(shí)分布上多收斂幾輪。訓(xùn)練完之后用驗(yàn)證集跑一遍評(píng)估命令是yolo detect val model./runs/train/fruit_exp/weights/best.pt data./fruit_dataset/data.yaml。看輸出的混淆矩陣和各類別 AP如果只有一類重點(diǎn)看漏檢和誤檢的比例。漏檢多說(shuō)明模型太保守可以降低置信度閾值誤檢多說(shuō)明模型把背景當(dāng)成了果實(shí)需要增加負(fù)樣本或提高置信度閾值。5. 可視化界面聯(lián)調(diào)與計(jì)數(shù)邏輯讓檢測(cè)框變成數(shù)字5.1 界面調(diào)用推理的代碼結(jié)構(gòu)與參數(shù)傳遞可視化界面通常是一個(gè)獨(dú)立的 Python 腳本通過按鈕觸發(fā)圖片選擇、推理和結(jié)果顯示。核心邏輯是加載訓(xùn)練好的權(quán)重對(duì)選中圖片做推理把檢測(cè)框畫在圖上同時(shí)統(tǒng)計(jì)框的數(shù)量作為計(jì)數(shù)結(jié)果。下面是一個(gè)典型的界面推理函數(shù)。from ultralytics import YOLO import cv2 class FruitCounter: def __init__(self, model_path, conf_threshold0.5): self.model YOLO(model_path) self.conf_threshold conf_threshold def detect_and_count(self, image_path): # 執(zhí)行推理conf 控制置信度閾值 results self.model(image_path, confself.conf_threshold) # 獲取檢測(cè)框數(shù)量 boxes results[0].boxes count len(boxes) if boxes is not None else 0 # 繪制結(jié)果圖 annotated results[0].plot() return annotated, count # 界面里調(diào)用 counter FruitCounter(./runs/train/fruit_exp/weights/best.pt, conf_threshold0.5) img, num counter.detect_and_count(./test_images/orchard_01.jpg) cv2.imwrite(./output/result_01.jpg, img) print(f檢測(cè)到成熟果實(shí)數(shù)量{num})conf_threshold是置信度閾值默認(rèn) 0.5。這個(gè)參數(shù)直接決定計(jì)數(shù)結(jié)果調(diào)高會(huì)減少誤檢但可能漏檢調(diào)低會(huì)檢出更多但可能把背景算進(jìn)去。果園場(chǎng)景下建議先在驗(yàn)證集上試幾個(gè)值看哪個(gè)閾值下計(jì)數(shù)誤差最小。results[0].boxes是檢測(cè)框?qū)ο髄en()就是數(shù)量。results[0].plot()返回畫好框的圖片可以直接顯示在界面上或保存。界面部分如果是 PyQt5把detect_and_count綁定到按鈕的點(diǎn)擊事件上圖片顯示用 QLabel 的 setPixmap。如果是 tkinter用 Canvas 或 Label 顯示。關(guān)鍵是把推理放在子線程里不要在主線程跑否則界面會(huì)卡死。這一點(diǎn)在演示的時(shí)候特別明顯老師或評(píng)委看到界面無(wú)響應(yīng)會(huì)直接扣分。5.2 計(jì)數(shù)邏輯的邊界處理與結(jié)果校驗(yàn)檢測(cè)框數(shù)量不等于果實(shí)數(shù)量這是最容易翻車的地方。兩個(gè)常見問題一是同一個(gè)果實(shí)被檢測(cè)出多個(gè)框二是相鄰果實(shí)被合并成一個(gè)框。前者需要加非極大值抑制NMSYOLOv8 默認(rèn)已經(jīng)做了但如果 IoU 閾值設(shè)得太高重疊框不會(huì)被抑制。后者需要看訓(xùn)練數(shù)據(jù)里果實(shí)間距如果標(biāo)注時(shí)就把兩個(gè)果實(shí)標(biāo)成一個(gè)框模型學(xué)到的就是合并檢測(cè)。# 調(diào)整 NMS 的 IoU 閾值 results self.model(image_path, conf0.5, iou0.45)iou參數(shù)控制 NMS 的閾值默認(rèn) 0.7。調(diào)低到 0.45 會(huì)抑制更多重疊框適合果實(shí)密集且相互遮擋的場(chǎng)景。但調(diào)太低也可能把相鄰果實(shí)的一個(gè)框誤刪需要根據(jù)實(shí)際圖片試。另一個(gè)校驗(yàn)手段是設(shè)置面積過濾太小的框可能是噪聲太大的框可能是誤檢。# 按面積過濾異常框 boxes results[0].boxes valid_count 0 for box in boxes: x1, y1, x2, y2 box.xyxy[0].tolist() area (x2 - x1) * (y2 - y1) if 100 area 50000: # 根據(jù)實(shí)際圖片分辨率調(diào)整 valid_count 1面積閾值要根據(jù)圖片分辨率和果實(shí)實(shí)際像素大小來(lái)定??梢韵扰軒讖垐D打印出所有框的面積分布再定上下限。這一步?jīng)]有固定公式靠實(shí)際數(shù)據(jù)調(diào)。注意界面顯示計(jì)數(shù)結(jié)果時(shí)建議同時(shí)顯示置信度分布或檢測(cè)框可視化方便演示時(shí)解釋為什么是這個(gè)數(shù)字。只給一個(gè)數(shù)字評(píng)委問起來(lái)不好回答。6. 避坑與常見問題排查那些讓我重跑訓(xùn)練的血淚教訓(xùn)6.1 訓(xùn)練 loss 不下降或震蕩嚴(yán)重現(xiàn)象訓(xùn)練開始后 box_loss 和 cls_loss 一直在高位震蕩mAP 不漲。原因通常是學(xué)習(xí)率太大或數(shù)據(jù)標(biāo)注有問題。先檢查標(biāo)注文件里有沒有坐標(biāo)超出 0 到 1 范圍的再檢查類別 id 是否從 0 開始連續(xù)。如果標(biāo)注沒問題把lr0降到 0.001 再跑。還有一種情況是預(yù)訓(xùn)練權(quán)重和模型結(jié)構(gòu)不匹配比如用yolov8n.pt加載到y(tǒng)olov8m的配置上這時(shí)候會(huì)報(bào)錯(cuò)或靜默失敗確認(rèn) model 參數(shù)和權(quán)重文件對(duì)應(yīng)。6.2 推理時(shí)檢測(cè)框數(shù)量明顯偏多或偏少現(xiàn)象同一張圖界面顯示的計(jì)數(shù)和肉眼數(shù)的差很多。原因可能是置信度閾值不合適或者 NMS 的 IoU 閾值需要調(diào)整。先固定一張測(cè)試圖把conf從 0.1 到 0.9 逐個(gè)試看計(jì)數(shù)變化曲線選一個(gè)穩(wěn)定區(qū)間。如果框大量重疊把iou從 0.7 降到 0.45 再試。另外檢查輸入圖片的尺寸如果推理時(shí) resize 到 640 但原圖是 4000 像素寬小果實(shí)會(huì)縮到幾個(gè)像素檢測(cè)不到很正常。6.3 界面啟動(dòng)報(bào)缺少 DLL 或模塊找不到現(xiàn)象在 Windows 上雙擊運(yùn)行界面腳本報(bào)ImportError或缺少Q(mào)t platform plugin。原因是 PyQt5 的環(huán)境變量沒配好或者虛擬環(huán)境沒激活。解決方法是確保在激活的虛擬環(huán)境里運(yùn)行不要直接雙擊 py 文件。如果還報(bào) Qt 插件錯(cuò)誤設(shè)置環(huán)境變量QT_QPA_PLATFORM_PLUGIN_PATH指向 PyQt5 的 plugins 目錄或者重裝 PyQt5pip install --force-reinstall pyqt5。6.4 訓(xùn)練完的權(quán)重在界面里加載失敗現(xiàn)象訓(xùn)練時(shí)一切正常界面加載best.pt時(shí)報(bào)錯(cuò)或檢測(cè)結(jié)果全空。原因是界面腳本里的模型路徑寫錯(cuò)了或者用了last.pt而不是best.pt。last.pt是最后一輪的權(quán)重可能過擬合best.pt是驗(yàn)證集上最好的權(quán)重優(yōu)先用這個(gè)。另外確認(rèn)界面腳本和訓(xùn)練用的 ultralytics 版本一致版本不同可能導(dǎo)致權(quán)重加載兼容性問題。6.5 數(shù)據(jù)集劃分不合理導(dǎo)致驗(yàn)證指標(biāo)虛高現(xiàn)象mAP 很高但實(shí)際用的時(shí)候效果差。原因是訓(xùn)練集和驗(yàn)證集里有重復(fù)圖片或相似度極高的圖片模型相當(dāng)于在“背答案”。劃分?jǐn)?shù)據(jù)集時(shí)確保同一棵樹的圖片不要同時(shí)出現(xiàn)在訓(xùn)練集和驗(yàn)證集里最好按拍攝時(shí)間或地點(diǎn)劃分。如果數(shù)據(jù)集本身不大用 8:1:1 的比例驗(yàn)證集至少留幾十張有代表性的圖。7. 進(jìn)階技巧用置信度分布和面積過濾把計(jì)數(shù)誤差壓到最低訓(xùn)練和界面都跑通之后真正決定這套系統(tǒng)好不好用的是計(jì)數(shù)誤差。我自己的習(xí)慣是做一個(gè)簡(jiǎn)單的后處理校準(zhǔn)先在一批測(cè)試圖上跑推理把每個(gè)檢測(cè)框的置信度和面積都導(dǎo)出來(lái)然后畫散點(diǎn)圖看分布。通常會(huì)發(fā)現(xiàn)置信度在 0.3 到 0.5 之間有一批模棱兩可的框這些就是誤差的主要來(lái)源。具體做法是分兩步過濾。第一步按置信度卡一個(gè)下限比如 0.4低于這個(gè)值的框直接丟掉。第二步按面積卡上下限太小的框面積小于圖片總面積的 0.1%大概率是噪聲太大的框面積大于 5%大概率是誤檢。兩個(gè)條件同時(shí)滿足才計(jì)入最終數(shù)量。def calibrated_count(results, img_w, img_h, conf_min0.4, area_min_ratio0.001, area_max_ratio0.05): boxes results[0].boxes if boxes is None: return 0 img_area img_w * img_h count 0 for box in boxes: conf box.conf[0].item() x1, y1, x2, y2 box.xyxy[0].tolist() area (x2 - x1) * (y2 - y1) if conf conf_min and area_min_ratio * img_area area area_max_ratio * img_area: count 1 return count這個(gè)函數(shù)比直接len(boxes)多了一層校準(zhǔn)參數(shù)需要根據(jù)實(shí)際圖片調(diào)。conf_min從 0.4 開始試area_min_ratio和area_max_ratio根據(jù)果實(shí)占畫面比例定。調(diào)好之后同一批測(cè)試圖的計(jì)數(shù)誤差通常能從 ±20% 壓到 ±5% 以內(nèi)。還有一個(gè)技巧是保存每次推理的原始結(jié)果包括框坐標(biāo)、置信度和面積存成 CSV。這樣后期如果發(fā)現(xiàn)某張圖計(jì)數(shù)不對(duì)可以回溯是哪個(gè)框被誤算或漏算了不用重新跑推理。我一般會(huì)在界面里加一個(gè)“導(dǎo)出詳細(xì)結(jié)果”的按鈕演示的時(shí)候如果評(píng)委問某個(gè)數(shù)字怎么來(lái)的直接打開 CSV 指給他看比口頭解釋有說(shuō)服力。從那以后我每次做完檢測(cè)類項(xiàng)目都會(huì)強(qiáng)制走一遍“置信度分布 面積過濾 結(jié)果導(dǎo)出”這三步不管界面看起來(lái)多正常。希望幫到你。本文還有配套的精品資源點(diǎn)擊獲取