📢 公告:OpenCV 系列文章重構完成(75%)。專案實作篇仍在製作中,完成時間未定,敬請期待!→ 查看文章索引

Like Share Discussion Bookmark Smile

J.J. Huang   2026-04-09   Python OpenCV 07.物件偵測與辨識篇   瀏覽次數:次   DMCA.com Protection Status

Python | OpenCV YOLOv8 模型訓練

📚 前言

在上一篇 YOLOv8 預標籤(Pre-Label) 中,我們用預訓練模型自動產生標籤草稿,再透過 LabelImg 人工修正,完成了標記工作。
這一篇進入最核心的環節:YOLOv8 模型訓練

YOLOv8 的訓練指令非常簡潔,但背後有許多重要參數影響訓練效果。
這一篇說明每個關鍵參數的意義,以及 GPU 加速與中斷恢復的設定方式。

🔎 開始訓練前的確認

在開始訓練之前,請確認前幾篇的工作都已完成,你手上應該有以下結構:

1
2
3
4
5
6
7
8
9
10
11
12
project/
├── raw_images/ ← 原始圖片(20260407 收集)
├── raw_labels/ ← 預標籤 + 人工修正後的 .txt(20260408 完成)
├── dataset/
│ ├── images/
│ │ ├── train/ ← 訓練集圖片
│ │ └── val/ ← 驗證集圖片
│ └── labels/
│ ├── train/ ← 訓練集標籤
│ └── val/ ← 驗證集標籤
├── data.yaml ← 訓練用設定檔(20260407 建立)
└── train.py ← 本篇將撰寫此檔案

💻 基本訓練指令

🔹 指令列方式

1
2
3
4
5
6
7
yolo detect train \
model=yolov8n.pt \
data=data.yaml \
epochs=100 \
imgsz=640 \
batch=16 \
device=0 # 無 GPU 請改為 device=cpu

🔹 Python API 方式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
# train.py
import time
import torch
from ultralytics import YOLO

model = YOLO("yolov8n.pt") # 以預訓練模型為起點(第一次執行會自動下載)

start = time.time()

results = model.train(
data="data.yaml", # 資料集設定檔路徑(由 20260407 的 create_yaml.py 產生)
epochs=100, # 訓練總輪數,初次建議先設 3~5 確認流程
imgsz=640, # 輸入圖片尺寸,越大越準確但越慢、越吃記憶體
batch=16, # 每批次圖片數,GPU 記憶體不足時調小(8、4)
device=0 if torch.cuda.is_available() else "cpu", # 自動偵測 GPU,無 GPU 退回 CPU
workers=0, # 資料載入執行緒數,Windows 必須設 0
name="my_model", # 訓練結果子目錄,結果存在 runs/detect/my_model/
save_period=10, # 每 10 個 epoch 儲存一次 checkpoint
plots=True, # 自動產生訓練曲線圖表
verbose=True, # 顯示每個 epoch 的詳細訓練資訊
)

elapsed = time.time() - start
print(f"訓練完成,總耗時:{elapsed // 3600:.0f}{elapsed % 3600 // 60:.0f}{elapsed % 60:.0f} 秒")
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
D:\PythonWorkspace\yolov8-tutorial\.venv\Scripts\python.exe D:\PythonWorkspace\yolov8-tutorial\train.py 
Ultralytics 8.4.37 Python-3.10.11 torch-2.11.0+cu130 CUDA:0 (NVIDIA GeForce RTX 2060 SUPER, 8192MiB)
engine\trainer: agnostic_nms=False, amp=True, angle=1.0, augment=False, auto_augment=randaugment, batch=16,
bgr=0.0, box=7.5, cache=False, cfg=None, classes=None, close_mosaic=10, cls=0.5, cls_pw=0.0, compile=False,
conf=None, copy_paste=0.0, copy_paste_mode=flip, cos_lr=False, cutmix=0.0, data=data.yaml, degrees=0.0,
deterministic=True, device=0, dfl=1.5, dnn=False, dropout=0.0, dynamic=False, embed=None, end2end=None,
epochs=100, erasing=0.4, exist_ok=False, fliplr=0.5, flipud=0.0, format=torchscript, fraction=1.0,
freeze=None, half=False, hsv_h=0.015, hsv_s=0.7, hsv_v=0.4, imgsz=640, int8=False, iou=0.7, keras=False,
kobj=1.0, line_width=None, lr0=0.01, lrf=0.01, mask_ratio=4, max_det=300, mixup=0.0, mode=train,
model=yolov8n.pt, momentum=0.937, mosaic=1.0, multi_scale=0.0, name=my_model, nbs=64, nms=False,
opset=None, optimize=False, optimizer=auto, overlap_mask=True, patience=100, perspective=0.0, plots=True,
pose=12.0, pretrained=True, profile=False, project=None, rect=False, resume=False, retina_masks=False,
rle=1.0, save=True, save_conf=False, save_crop=False, save_dir=D:\PythonWorkspace\yolov8-tutorial\runs\detect\my_model,
save_frames=False, save_json=False, save_period=10, save_txt=False, scale=0.5, seed=0, shear=0.0, show=False,
show_boxes=True, show_conf=True, show_labels=True, simplify=True, single_cls=False, source=None, split=val,
stream_buffer=False, task=detect, time=None, tracker=botsort.yaml, translate=0.1, val=True, verbose=True,
vid_stride=1, visualize=False, warmup_bias_lr=0.1, warmup_epochs=3.0, warmup_momentum=0.8, weight_decay=0.0005,
workers=0, workspace=None
Overriding model.yaml nc=80 with nc=2

from n params module arguments
0 -1 1 464 ultralytics.nn.modules.conv.Conv [3, 16, 3, 2]
1 -1 1 4672 ultralytics.nn.modules.conv.Conv [16, 32, 3, 2]
2 -1 1 7360 ultralytics.nn.modules.block.C2f [32, 32, 1, True]
3 -1 1 18560 ultralytics.nn.modules.conv.Conv [32, 64, 3, 2]
4 -1 2 49664 ultralytics.nn.modules.block.C2f [64, 64, 2, True]
5 -1 1 73984 ultralytics.nn.modules.conv.Conv [64, 128, 3, 2]
6 -1 2 197632 ultralytics.nn.modules.block.C2f [128, 128, 2, True]
7 -1 1 295424 ultralytics.nn.modules.conv.Conv [128, 256, 3, 2]
8 -1 1 460288 ultralytics.nn.modules.block.C2f [256, 256, 1, True]
9 -1 1 164608 ultralytics.nn.modules.block.SPPF [256, 256, 5]
10 -1 1 0 torch.nn.modules.upsampling.Upsample [None, 2, 'nearest']
11 [-1, 6] 1 0 ultralytics.nn.modules.conv.Concat [1]
12 -1 1 148224 ultralytics.nn.modules.block.C2f [384, 128, 1]
13 -1 1 0 torch.nn.modules.upsampling.Upsample [None, 2, 'nearest']
14 [-1, 4] 1 0 ultralytics.nn.modules.conv.Concat [1]
15 -1 1 37248 ultralytics.nn.modules.block.C2f [192, 64, 1]
16 -1 1 36992 ultralytics.nn.modules.conv.Conv [64, 64, 3, 2]
17 [-1, 12] 1 0 ultralytics.nn.modules.conv.Concat [1]
18 -1 1 123648 ultralytics.nn.modules.block.C2f [192, 128, 1]
19 -1 1 147712 ultralytics.nn.modules.conv.Conv [128, 128, 3, 2]
20 [-1, 9] 1 0 ultralytics.nn.modules.conv.Concat [1]
21 -1 1 493056 ultralytics.nn.modules.block.C2f [384, 256, 1]
22 [15, 18, 21] 1 751702 ultralytics.nn.modules.head.Detect [2, 16, None, [64, 128, 256]]
Model summary: 130 layers, 3,011,238 parameters, 3,011,222 gradients, 8.2 GFLOPs

Transferred 319/355 items from pretrained weights
Freezing layer 'model.22.dfl.conv.weight'
AMP: running Automatic Mixed Precision (AMP) checks...
AMP: checks passed
train: Fast image access (ping: 0.00.0 ms, read: 1838.31089.4 MB/s, size: 174.8 KB)
train: Scanning D:\PythonWorkspace\yolov8-tutorial\dataset\labels\train.cache... 98 images, 15 backgrounds, 0 corrupt: 100% ━━━━━━━━━━━━ 98/98 0.0s
val: Fast image access (ping: 0.00.0 ms, read: 2107.01291.3 MB/s, size: 131.0 KB)
val: Scanning D:\PythonWorkspace\yolov8-tutorial\dataset\labels\val.cache... 24 images, 1 backgrounds, 0 corrupt: 100% ━━━━━━━━━━━━ 24/24 0.0s
optimizer: 'optimizer=auto' found, ignoring 'lr0=0.01' and 'momentum=0.937' and determining best 'optimizer', 'lr0' and 'momentum' automatically...
optimizer: AdamW(lr=0.001667, momentum=0.9) with parameter groups 57 weight(decay=0.0), 64 weight(decay=0.0005), 63 bias(decay=0.0)
Plotting labels to D:\PythonWorkspace\yolov8-tutorial\runs\detect\my_model\labels.jpg...
Image sizes 640 train, 640 val
Using 0 dataloader workers
Logging results to D:\PythonWorkspace\yolov8-tutorial\runs\detect\my_model
Starting training for 100 epochs...

Epoch GPU_mem box_loss cls_loss dfl_loss Instances Size
1/100 2.02G 0.6719 2.927 1.129 5 640: 100% ━━━━━━━━━━━━ 7/7 2.2it/s 3.3s
Class Images Instances Box(P R mAP50 mAP50-95): 100% ━━━━━━━━━━━━ 1/1 2.2it/s 0.4s
all 24 30 0.0041 1 0.557 0.489

... 中間省略 ...

Epoch GPU_mem box_loss cls_loss dfl_loss Instances Size
90/100 2.18G 0.448 0.5201 0.9692 8 640: 100% ━━━━━━━━━━━━ 7/7 4.3it/s 1.6s
Class Images Instances Box(P R mAP50 mAP50-95): 100% ━━━━━━━━━━━━ 1/1 3.1it/s 0.3s
all 24 30 0.936 0.938 0.979 0.758
Closing dataloader mosaic

... 中間省略 ...

Epoch GPU_mem box_loss cls_loss dfl_loss Instances Size
100/100 2.18G 0.3441 0.5115 0.8918 3 640: 100% ━━━━━━━━━━━━ 7/7 4.5it/s 1.6s
Class Images Instances Box(P R mAP50 mAP50-95): 100% ━━━━━━━━━━━━ 1/1 3.1it/s 0.3s
all 24 30 0.851 0.9 0.941 0.69

100 epochs completed in 0.065 hours.
Optimizer stripped from D:\PythonWorkspace\yolov8-tutorial\runs\detect\my_model\weights\last.pt, 6.3MB
Optimizer stripped from D:\PythonWorkspace\yolov8-tutorial\runs\detect\my_model\weights\best.pt, 6.3MB

Validating D:\PythonWorkspace\yolov8-tutorial\runs\detect\my_model\weights\best.pt...
Ultralytics 8.4.37 Python-3.10.11 torch-2.11.0+cu130 CUDA:0 (NVIDIA GeForce RTX 2060 SUPER, 8192MiB)
Model summary (fused): 73 layers, 3,006,038 parameters, 0 gradients, 8.1 GFLOPs
Class Images Instances Box(P R mAP50 mAP50-95): 100% ━━━━━━━━━━━━ 1/1 2.9it/s 0.3s
all 24 30 0.95 0.933 0.979 0.76
cat 18 25 0.899 0.92 0.964 0.57
dog 5 5 1 0.945 0.995 0.95
Speed: 0.2ms preprocess, 1.6ms inference, 0.0ms loss, 1.0ms postprocess per image
Results saved to D:\PythonWorkspace\yolov8-tutorial\runs\detect\my_model
訓練完成,總耗時:0 時 4 分 1 秒

Process finished with exit code 0

💡 訓練完成後,結果會自動儲存在 runs/detect/my_model/ 目錄下。


圖:YOLOv8 訓練 Log 重點解析 ─ 環境資訊、模型規格、訓練參數與過程總覽


圖:YOLOv8 train.cache 與 val.cache 說明 ─ 加速訓練與注意事項

🧠 重要訓練參數說明


圖:YOLOv8 train 完整參數表 ─ 16 個常用參數與預設值說明

💡 模型選擇建議


圖:YOLOv8 三種起點模型選擇 ─ 從預訓練權重微調、從頭訓練到繼續中斷的 checkpoint

① 從預訓練權重微調(一般情況,推薦)
載入 Ultralytics 在 COCO 資料集上訓練好的權重,再用自己的資料繼續訓練。模型已具備基本的影像辨識能力,收斂快、所需資料量少,是最常見的做法。

1
2
3
# demo_pretrained.py
from ultralytics import YOLO
model = YOLO("yolov8n.pt") # 第一次執行會自動下載,約 6MB

② 從頭訓練(特殊情況)
只載入網路架構定義,權重全部隨機初始化,需要大量資料(通常數千張以上)才能訓練出好的模型。若你的類別與 COCO 差異極大(例如醫療影像、衛星圖)才考慮。

1
2
3
# demo_from_scratch.py
from ultralytics import YOLO
model = YOLO("yolov8n.yaml") # 只有架構,無預訓練權重

③ 繼續訓練中斷的 checkpoint
訓練途中若因斷電、關機等原因中斷,可從上次儲存的 last.pt 繼續,不需要從頭跑。詳細用法見本篇 [中斷後繼續訓練] 章節。

1
2
3
# demo_resume.py
from ultralytics import YOLO
model = YOLO("runs/detect/my_model/weights/last.pt")

💻 多張 GPU 訓練

device 參數的常用值:0(第一張 GPU)、"0,1"(雙 GPU)、"cpu"(強制使用 CPU)。
有多張 GPU 時,可用以下方式自動偵測並全部啟用:

1
2
3
4
5
6
7
8
9
10
# setup_gpu.py
import torch
from ultralytics import YOLO

gpu_count = torch.cuda.device_count()
device = ",".join(str(i) for i in range(gpu_count)) if gpu_count >= 2 else 0
print(f"偵測到 {gpu_count} 張 GPU,使用 device={device!r}")

model = YOLO("yolov8n.pt")
model.train(data="data.yaml", epochs=100, device=device)

⛃ GPU 記憶體不足(OOM)


圖:GPU 記憶體使用原理 ─ batch 和 imgsz 是最吃記憶體的兩個參數

訓練時 GPU 需要把圖片、模型權重、梯度全部同時放進記憶體計算。
batch(每次丟幾張圖)和 imgsz(每張圖的解析度)是最吃記憶體的兩個設定:

  • batch=16 表示每次同時處理 16 張圖,16 張的資料都要同時放進 GPU
  • imgsz=640 表示每張圖縮放到 640×640,解析度越高,每張圖佔的記憶體越大

兩個值相乘就是每次計算的「記憶體負擔」。以 8GB 顯卡為例:

  • batch=16, imgsz=640 → 可能剛好 OOM
  • batch=8, imgsz=640 → 記憶體砍半,通常能跑
  • batch=8, imgsz=416 → 更小,適合記憶體非常有限的環境

訓練啟動後若出現以下錯誤,就是記憶體不夠:

1
RuntimeError: CUDA out of memory.

依序嘗試以下調整,直到不再 OOM:

1
2
3
4
5
6
7
8
9
10
11
12
13
# fix_oom.py
import torch
from ultralytics import YOLO

model = YOLO("yolov8n.pt")

# 方法一:先縮小 batch(優先嘗試,對準確度影響較小)
model.train(data="data.yaml", epochs=100, imgsz=640, batch=8,
device=0 if torch.cuda.is_available() else "cpu")

# 方法二:batch 和 imgsz 同時縮小(記憶體非常有限時)
# model.train(data="data.yaml", epochs=100, imgsz=416, batch=8,
# device=0 if torch.cuda.is_available() else "cpu")

💻 中斷後繼續訓練

YOLOv8 每個 epoch 都會儲存 last.pt,可隨時從中斷點繼續:

1
2
3
4
5
6
7
8
9
# resume_training.py
from ultralytics import YOLO

# 方法一:Python API
model = YOLO("runs/detect/my_model/weights/last.pt")
model.train(resume=True)

# 方法二:指令列
# yolo detect train resume model=runs/detect/my_model/weights/last.pt

⚠️ 注意事項

  • CPU 訓練速度非常慢:無 GPU 環境下,100 epochs 可能需要數小時甚至更長。第一次執行建議先將 epochs 設為 3~5,確認資料集路徑、格式、流程都正確後,再調回正式輪數。若需要完整訓練,強烈建議使用有 CUDA 的環境或 Google Colab(免費 GPU)。
  • Windows 上 workers 需設為 0:設成其他數值可能造成 DataLoader 死鎖,訓練無法啟動。
  • batch=-1 自動計算:可設定 batch=-1 讓 YOLOv8 根據 GPU 記憶體自動計算最大 batch size,但不夠穩定,建議手動設定。
  • 訓練過程中不要刪除 runs/ 目錄:中斷恢復需要依賴其中的 last.ptargs.yaml

🎯 結語

YOLOv8 的基本訓練流程相當精簡,幾行程式碼就能啟動,並內建快取、自動儲存與斷點恢復等機制。
下一步是 YOLOv8 訓練進階設定,介紹資料增強與防止過擬合的進階參數調整。

📖 如在學習過程中遇到疑問,或是想了解更多相關主題,建議回顧一下 Python | OpenCV 系列導讀,掌握完整的章節目錄,方便快速找到你需要的內容。

註:以上參考了
Ultralytics YOLOv8 官方文件 — Train
Ultralytics YOLOv8 官方文件 — Configuration