0. 模型訓練小知識
自從深度學習火了以後,大家就把傳統視覺算法看低了。
因為模型的訓練需要GPU或者CPU飛速運轉好久才能完成,而訓練出來的模型又每次都非常意外,所以大家又把模型訓練戲稱為煉丹,真是充滿了玄學意味。
深度學習時代,什麼最重要?數據!像我們這次的任務,需要準備100~500張圖片,確保包含不同角度、光照和模糊程度。如果想做的很好,業界推薦是幾千張幾萬張圖片。可想而知,準備這些樣本就會付出很多成本。尤其是機器視覺領域,工業中的瑕疵檢測,就需要大量的瑕疵樣本,而這些樣本不是那麼容易收集的。所以就會出現一個職業,賣樣本。
好了,現在樣本也有了,可以開始煉丹了嗎?別急,只有樣本還不夠,需要告訴計算機這次我們要煉什麼。那就是標註。我們藉助標註工具,在圖片中選出目標並做一個分類標記,這個過程就是標註。工具有挺多種,我們常用的是X-AnyLabeling-CPU。只不過它的自動化標註有問題,暫時我沒有解決。
手動標註300張圖片,我們三人分工,搞了幾個小時。好了,現在都準備好了。那就將標註後的圖片進行一個分類。調用YOLO工具,進行訓練。CPU速度慢很多,與GPU不是一個量級。如果只是做個試驗,筆記本CPU也是可以的。
1. 樣本準備
自己拍攝照片話,就需要在不同的時間,不同的距離,不同的光照,不同的角度,不同的物體進行採樣拍照。多多益善。
2. 標註
X-AnyLabeling是一個開源項目,維護的非常健康。我們直接下載exe,雙擊就可以運行。標註是非常簡單而且枯燥的。下面截圖中,我們是要給圓圈中有十字的做標註。採用矩形框的方式,快捷鍵R配合鼠標左鍵就可以做一個框,將目標選中,並填寫好的它的類別。如果圖片不多,人工去標註也還好。
全部標註完成,導出YOLO水平框標籤OK了。 導出的Labels文件夾中有圖片和txt文件,txt格式為:
<class_id> <center_x> <center_y> <width> <height>
比如:
0 0.899370 0.356576 0.098531 0.115827
標註導出
3. 訓練前準備
我們現在已經有了數據了,那麼需要將數據分為三部分:訓練集(80%)、驗證集(10%)和測試集(10%)。 數據集結構類似:
custom_dataset/
├── images/
│ ├── train/ # 訓練圖片
│ |── val/ # 驗證圖片
| |── test/ # 測試圖片
└── labels/
├── train/ # 訓練標籤
|── val/ # 驗證標籤
└── test/ # 測試標籤
接下來我們創建數據集配置文件dataset.yaml
# Datasets
path: D:/datasets/ # 數據集文件夾所在路徑
train: train.txt # 數據集路徑下的 train.txt
val: val.txt # 數據集路徑下的 val.txt
test: test.txt # 數據集路徑下的 test.txt
# Number of Classes
nc: 1
# Classes Name List
names:
0: cross
4. 訓練開始
from ultralytics import YOLO
# 加載預訓練模型
model = YOLO('yolov8n.pt') # 基礎模型
def train():
# 開始訓練
model.train(
data='dataset.yaml',
epochs=100, # 訓練輪數
batch=16, # 批大小
imgsz=640, # 圖像尺寸
device='0', # 使用GPU
name='None', # 保存模型訓練結果的項目目錄名稱
patience=20, # 早停機制
lr0=0.01, # 初始學習率
augment=True, # 自動增強
hsv_h=0.015, # 色調增強
copy_paste=0.2 # 複製粘貼增強
plots=True, # 生成並保存訓練和驗證指標圖和預測示例圖,可視化模型性能和訓練進度
)
if __name__ == '__main__':
train()
5060Ti果然很厲害:100 epochs completed in 0.026 hours.
5. 推理與轉換為onnx格式
訓練完成後會生成兩個pt模型文件,best.pt和last.pt。我們直接用它進行推理:
yolo predict model=C:\runs\detect\train\weights\best.pt, source=D:\yolo\cross6.jpg
效果還補錯,那接下來我們將其改為onnx格式,讓應用面更廣。比如我就準備在C#中使用這個模型推理。 可以很簡單的:
from ultralytics import YOLO
# 加載一個模型,路徑為 YOLO 模型的 .pt 文件
model = YOLO(r"C:\runs\detect\train\weights\best.pt")
# 導出模型,格式為 ONNX
model.export(format="onnx")
也可以很複雜:
from ultralytics import YOLO
# 加載一個模型,路徑為 YOLO 模型的 .pt 文件
model = YOLO(r"runs/detect/train3/weights/best.pt")
# 導出模型,設置多種參數
model.export(
format="onnx", # 導出格式為 ONNX
imgsz=(640, 640), # 設置輸入圖像的尺寸
keras=False, # 不導出為 Keras 格式
optimize=False, # 不進行優化 False, 移動設備優化的參數,用於在導出為TorchScript 格式時進行模型優化
half=False, # 不啓用 FP16 量化
int8=False, # 不啓用 INT8 量化
dynamic=False, # 不啓用動態輸入尺寸
simplify=True, # 簡化 ONNX 模型
opset=None, # 使用最新的 opset 版本
workspace=4.0, # 為 TensorRT 優化設置最大工作區大小(GiB)
nms=False, # 不添加 NMS(非極大值抑制)
batch=1, # 指定批處理大小
device="cpu" # 指定導出設備為CPU或GPU,對應參數為"cpu" , "0"
)
使用onnx做個簡單推理:
yolo predict model=C:\runs\detect\train\weights\best.onnx, source=D:\yolo\cross6.jpg
6. 評估指標解讀
今天的任務算是完成了,最後我想説一下訓練的指標。請參考本次訓練結果圖(result.png):
可以發現左側有三種loss(損失函數),右側有四個指標:precision(精確率)、recall(召回率)、mAP50和mAP50-95.
6.1 損失函數
損失函數(Loss Function)是衡量模型“預測錯誤程度”的工具:
box_loss(邊界框損失):衡量模型預測的“框位置”與真實位置的差距。cls_loss(分類損失):衡量模型判斷“是不是目標”的錯誤程度,比如圖中明明是目標狗,模型卻認為“有30%概率是老鼠”,cls_loss 就會變大;如果模型100%確定是狗,cls_loss 就接近0。
dfi_loss(分佈焦點損失):專門優化“模糊/邊緣不清晰”的檢測,讓模型更關注難分辨的目標。對於邊緣模糊的目標狗,dfi_loss 會“強迫”模型多學習這類樣本,減少漏檢。
在圖中,我們可以看到: train/box_loss、train/cls_loss、train/dfi_loss:這三條訓練損失曲線均從高位快速下降並趨於平穩(最終接近0),無反彈或波動,説明模型學習過程正常,未出現過擬合或欠擬合。 val/box_loss、val/cls_loss、val/dfi_loss:驗證集損失與訓練集損失趨勢一致且差距較小,表明模型泛化能力良好,沒有過擬合訓練數據。
6.2 精確率
- 公式:Precision = 正確檢測的目標數模型檢測出的所有目標數
它表示檢測結果中有多少是真實的目標(避免誤檢)。 比如:Precisinotallow=0.9 表示模型標註的10個目標中,9個是真的,1個是誤檢。 穩定在1.0附近,説明模型對訓練數據中的檢測幾乎沒有誤檢。
6.3 召回率
- 公式:Recall = 正確檢測的目標數數據中實際的目標總數
它表示有多少真實目標被檢測出來(避免漏檢)。 比如:Recall=0.8 表示數據中有10個印章,模型找到了其中8個。 穩定在1.0附近,説明模型對訓練數據中的檢測幾乎沒有漏檢。
6.4 mAP50和mAP50-95
首先我們還要温習下之前看過的概念:
- IoU(交併比):衡量模型預測框與真實框的重疊程度(0~1,值越大越準)。比如預測框與真實框重疊50% → IoU=0.5。
- AP(平均精度):針對單個類別(如“圓圈”),計算不同置信度下的“精確率-召回率”曲線下面積(值越大,模型對該類別的檢測能力越強)。
6.4.1 mAP50(B)
先來逐字拆解:mAP:mean Average Precision(所有類別的AP平均值)。50:IoU閾值=0.5(即預測框與真實框重疊≥50%就算“檢測正確”)。(B):B代表“Box”(檢測框任務,區別於分割或關鍵點)。
我們來通俗解釋下:假設測試集中有100張圖片,每張都有1個目標(共100個真實印章)。模型對這100個目標的預測結果中,只要預測框與真實框重疊≥50%,就視為“找對了”。mAP50(B)=0.9 表示在IoU=50%的寬鬆標準下,模型對印章的平均檢測準確率為90%。這是檢測任務的 “基礎及格線”,值≥0.8即達到實用標準(我們的訓練結果中 mAP50=1.0,十分優秀)。這個指標適合快速判斷模型是否“能用”(不及格就別用了)。
6.4.2 mAP50-95
這個指標表示IoU閾值從0.5到0.95,每隔0.05取一個值(共10個閾值:0.5、0.55、0.6、...、0.95),對每個IoU閾值計算一次 mAP,再取這10個 mAP 的平均值。 也即是説,IoU=0.5是個寬鬆的指標,預測框只要蓋住真實框一半以上就算對(哪怕位置偏一點)。而IoU=0.95是嚴格的指標,預測框必須幾乎完美覆蓋真實框(位置、大小都要極準,邊緣模糊的很難達標)。 mAP50-95(B)=0.85 表示:在從“寬鬆”到“嚴格”的10個標準下,模型的平均準確率為85%。 我們圖表中mAP50-95(B)的值最終穩定在0.85~0.9,説明即使在嚴格的IoU閾值(50%~95%)下,模型仍保持較高精度,對邊緣模糊、形變等情況有較強魯棒性。
6.4.3 總結
看這個表格,我們可以優先看 mAP@0.5,這樣可以綜合判斷模型好壞。而結合Precision/Recall,能夠明確模型是誤檢多還是漏檢多。