測驗:YOLO 部署與優化
共 5 題,點選答案後會立即顯示結果
1. 為什麼訓練完成的 PyTorch 模型(.pt 檔案)不適合直接部署到生產環境?
2. 如果要在 NVIDIA GPU 上獲得最佳推論速度,應該匯出為哪種格式?
3. 量化技術中,FP16 半精度相較於 FP32 全精度,主要的特性是什麼?
4. 在即時影片偵測中,如果 FPS 不足,以下哪個方法最有效?
5. 在 Raspberry Pi(無 GPU)上部署 YOLO 模型,應該優先選擇哪種匯出格式?
前言
經過前四篇的學習,你已經能夠訓練出自己的 YOLO 模型。但訓練完成只是第一步——如何將模型部署到實際應用中,才是真正的挑戰。
本篇將帶你了解:
- 如何將 PyTorch 模型匯出為不同格式
- 各種部署平台的選擇與考量
- 如何優化模型以獲得更好的推論速度
- 建立即時偵測應用的完整流程
模型匯出:從 .pt 到部署格式
為什麼需要匯出?
YOLO 訓練完成後,你會得到一個 .pt 檔案(PyTorch 格式)。這個格式在開發時很方便,但在實際部署時有幾個問題:
- 需要完整的 PyTorch 環境:部署環境需要安裝 PyTorch,佔用大量空間
- 推論速度較慢:PyTorch 格式未針對推論優化
- 跨平台支援有限:不是所有平台都能直接使用 PyTorch
因此,我們需要將模型「匯出」為更適合部署的格式。
基本匯出指令
# 匯出為 ONNX 格式(最通用)
yolo export model=best.pt format=onnx
# 匯出為 TensorRT 格式(NVIDIA GPU 最佳化)
yolo export model=best.pt format=engine
# 匯出為 CoreML 格式(Apple 裝置)
yolo export model=best.pt format=coreml
# 匯出為 TFLite 格式(行動裝置、邊緣運算)
yolo export model=best.pt format=tflite
Code language: PHP (php)執行後,你會在同一目錄下看到對應格式的檔案:
runs/detect/train/weights/
├── best.pt # 原始 PyTorch 模型
├── best.onnx # ONNX 格式
├── best.engine # TensorRT 格式
└── best.mlmodel # CoreML 格式
Code language: PHP (php)匯出參數詳解
yolo export model=best.pt format=onnx imgsz=640 half=True simplify=True
Code language: PHP (php)讓我們看看這些參數的意義:
| 參數 | 說明 | 常用值 |
|---|---|---|
model |
模型路徑 | best.pt 或 yolov8n.pt |
format |
匯出格式 | onnx, engine, coreml, tflite |
imgsz |
輸入圖片尺寸 | 640, 320, 1280 |
half |
使用 FP16 半精度 | True, False |
simplify |
簡化 ONNX 模型 | True, False |
dynamic |
動態輸入尺寸 | True, False |
batch |
批次大小 | 1, 8, 16 |
各格式比較
格式比較表
┌─────────────┬──────────────┬──────────────┬─────────────┐
│ 格式 │ 適用場景 │ 優點 │ 缺點 │
├─────────────┼──────────────┼──────────────┼─────────────┤
│ PyTorch │ 開發測試 │ 最靈活 │ 部署不便 │
│ ONNX │ 跨平台部署 │ 通用性最高 │ 速度中等 │
│ TensorRT │ NVIDIA GPU │ 速度最快 │ 僅限 NVIDIA │
│ CoreML │ Apple 裝置 │ 整合度高 │ 僅限 Apple │
│ TFLite │ 行動/邊緣 │ 檔案小 │ 精度可能降 │
└─────────────┴──────────────┴──────────────┴─────────────┘
量化技術:讓模型更小更快
什麼是量化?
量化(Quantization)是將模型的權重從高精度(FP32)轉換為低精度(FP16 或 INT8)的技術。想像一下:
- FP32:用 32 位元儲存一個數字,精度高但佔空間
- FP16:用 16 位元儲存,精度稍低但大小減半
- INT8:用 8 位元儲存,大小再減半但精度損失更多
精度與大小關係
┌──────────┬──────────┬──────────┬────────────┐
│ 精度 │ 模型大小 │ 推論速度 │ 精度損失 │
├──────────┼──────────┼──────────┼────────────┤
│ FP32 │ 100% │ 基準 │ 無 │
│ FP16 │ 50% │ 1.5-2x │ 極小 │
│ INT8 │ 25% │ 2-4x │ 可接受 │
└──────────┴──────────┴──────────┴────────────┘
Code language: CSS (css)FP16 半精度量化
最簡單的量化方式,幾乎不損失精度:
# 匯出時啟用 FP16
yolo export model=best.pt format=onnx half=True
Code language: PHP (php)在 Python 中使用:
from ultralytics import YOLO
# 載入模型時指定半精度
model = YOLO('best.pt')
results = model.predict('image.jpg', half=True)
Code language: PHP (php)INT8 量化
需要校準資料集來確保精度:
# TensorRT INT8 量化
yolo export model=best.pt format=engine int8=True data=coco.yaml
Code language: PHP (php)這裡 data=coco.yaml 提供校準資料,讓模型知道如何最佳化數值範圍。
量化效果實測
以 YOLOv8n 為例,在 RTX 3080 上的表現:
實測數據(輸入 640x640)
┌──────────┬──────────┬──────────┬──────────┐
│ 模式 │ 模型大小 │ FPS │ mAP │
├──────────┼──────────┼──────────┼──────────┤
│ FP32 │ 6.3 MB │ 180 │ 37.3% │
│ FP16 │ 3.2 MB │ 280 │ 37.2% │
│ INT8 │ 1.6 MB │ 420 │ 36.8% │
└──────────┴──────────┴──────────┴──────────┘
Code language: CSS (css)FP16 幾乎不損失精度,但速度提升明顯,是最推薦的選擇。
部署場景與平台選擇
伺服器部署:最大效能
適合需要處理大量請求的場景,如雲端 API 服務。
# server_deploy.py - 使用 FastAPI 建立偵測 API
from fastapi import FastAPI, UploadFile
from ultralytics import YOLO
import cv2
import numpy as np
app = FastAPI()
model = YOLO('best.engine') # 使用 TensorRT 格式
@app.post("/detect")
async def detect(file: UploadFile):
# 讀取上傳的圖片
contents = await file.read()
nparr = np.frombuffer(contents, np.uint8)
img = cv2.imdecode(nparr, cv2.IMREAD_COLOR)
# 執行偵測
results = model(img)
# 整理結果
detections = []
for r in results:
for box in r.boxes:
detections.append({
'class': model.names[int(box.cls)],
'confidence': float(box.conf),
'bbox': box.xyxy[0].tolist()
})
return {'detections': detections}
Code language: PHP (php)啟動伺服器:
uvicorn server_deploy:app --host 0.0.0.0 --port 8000
Code language: CSS (css)邊緣裝置部署:Jetson 系列
NVIDIA Jetson(如 Jetson Nano、Orin)是邊緣 AI 的熱門選擇。
環境準備:
# 在 Jetson 上安裝 ultralytics
pip install ultralytics
# 確認 CUDA 可用
python -c "import torch; print(torch.cuda.is_available())"
Code language: PHP (php)匯出 TensorRT 模型:
# 直接在 Jetson 上匯出,確保相容性
yolo export model=best.pt format=engine device=0
Code language: PHP (php)注意事項:
- 在目標裝置上匯出 TensorRT 模型,避免相容性問題
- Jetson Nano 建議使用 YOLOv8n(最小模型)
- 適當降低輸入尺寸(如 320×320)可大幅提升 FPS
邊緣裝置部署:Raspberry Pi
Raspberry Pi 沒有 GPU,需要使用 CPU 優化的格式。
# 匯出為 NCNN 格式(ARM CPU 優化)
yolo export model=best.pt format=ncnn
# 或使用 TFLite
yolo export model=best.pt format=tflite
Code language: PHP (php)效能期望(Pi 4B):
- YOLOv8n + NCNN:約 5-10 FPS
- YOLOv8n + TFLite:約 3-5 FPS
如果需要更高 FPS,考慮使用 Coral USB Accelerator。
即時影片偵測應用
基本架構
# realtime_detect.py - 即時攝影機偵測
import cv2
from ultralytics import YOLO
import time
def main():
# 載入模型
model = YOLO('best.pt') # 或 best.onnx, best.engine
# 開啟攝影機
cap = cv2.VideoCapture(0) # 0 = 預設攝影機
cap.set(cv2.CAP_PROP_FRAME_WIDTH, 640)
cap.set(cv2.CAP_PROP_FRAME_HEIGHT, 480)
# FPS 計算
prev_time = time.time()
while True:
ret, frame = cap.read()
if not ret:
break
# 執行偵測
results = model(frame, verbose=False)
# 在畫面上繪製結果
annotated_frame = results[0].plot()
# 計算並顯示 FPS
curr_time = time.time()
fps = 1 / (curr_time - prev_time)
prev_time = curr_time
cv2.putText(annotated_frame, f'FPS: {fps:.1f}', (10, 30),
cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 255, 0), 2)
# 顯示結果
cv2.imshow('YOLO Detection', annotated_frame)
# 按 'q' 退出
if cv2.waitKey(1) & 0xFF == ord('q'):
break
cap.release()
cv2.destroyAllWindows()
if __name__ == '__main__':
main()
Code language: PHP (php)優化即時偵測效能
1. 降低輸入解析度
# 使用較小的輸入尺寸
results = model(frame, imgsz=320) # 預設是 640
Code language: PHP (php)效果:FPS 可提升 2-4 倍,但小物件偵測效果會下降。
2. 跳幀處理
不需要每一幀都偵測:
frame_count = 0
skip_frames = 2 # 每 3 幀偵測 1 次
while True:
ret, frame = cap.read()
frame_count += 1
if frame_count % (skip_frames + 1) == 0:
results = model(frame)
last_results = results
# 使用上次的結果繪製
if last_results:
annotated_frame = last_results[0].plot()
Code language: PHP (php)3. 使用多執行緒
將讀取影像和推論分開:
import threading
from queue import Queue
class VideoStream:
def __init__(self, src=0):
self.cap = cv2.VideoCapture(src)
self.queue = Queue(maxsize=2)
self.stopped = False
def start(self):
threading.Thread(target=self._update, daemon=True).start()
return self
def _update(self):
while not self.stopped:
ret, frame = self.cap.read()
if not self.queue.full():
self.queue.put(frame)
def read(self):
return self.queue.get()
def stop(self):
self.stopped = True
# 使用方式
stream = VideoStream(0).start()
while True:
frame = stream.read()
results = model(frame)
效能評估與監控
關鍵指標
部署後需要監控這些指標:
| 指標 | 說明 | 理想值 |
|---|---|---|
| FPS | 每秒處理幀數 | 依應用需求,通常 >15 |
| Latency | 單幀處理延遲 | <100ms |
| GPU 使用率 | GPU 負載 | 60-80%(有餘裕) |
| 記憶體使用 | 顯存/記憶體佔用 | 低於上限 |
效能測試腳本
# benchmark.py - 效能測試
from ultralytics import YOLO
import time
import numpy as np
def benchmark(model_path, num_iterations=100):
model = YOLO(model_path)
# 使用假圖片測試
dummy_input = np.random.randint(0, 255, (640, 640, 3), dtype=np.uint8)
# 暖機(讓 GPU 進入工作狀態)
for _ in range(10):
model(dummy_input, verbose=False)
# 正式測試
times = []
for _ in range(num_iterations):
start = time.time()
model(dummy_input, verbose=False)
times.append(time.time() - start)
times = np.array(times) * 1000 # 轉換為毫秒
print(f"模型: {model_path}")
print(f"平均延遲: {times.mean():.2f} ms")
print(f"標準差: {times.std():.2f} ms")
print(f"FPS: {1000 / times.mean():.1f}")
print(f"最快: {times.min():.2f} ms")
print(f"最慢: {times.max():.2f} ms")
# 比較不同格式
benchmark('best.pt')
benchmark('best.onnx')
benchmark('best.engine') # 需要 TensorRT
Code language: PHP (php)典型輸出
模型: best.pt
平均延遲: 12.45 ms
標準差: 1.23 ms
FPS: 80.3
最快: 10.21 ms
最慢: 18.67 ms
模型: best.engine
平均延遲: 4.32 ms
標準差: 0.45 ms
FPS: 231.5
最快: 3.89 ms
最慢: 5.67 ms
Code language: CSS (css)常見問題與解決方案
Q1: TensorRT 匯出失敗
錯誤訊息: TensorRT export requires TensorRT>=7.0.0
Code language: JavaScript (javascript)解決方案:
# 安裝 TensorRT
pip install tensorrt
# 或者在 Jetson 上使用系統自帶的 TensorRT
Code language: PHP (php)Q2: ONNX 模型推論結果不同
可能原因: opset 版本不相容
解決方案:
# 指定 opset 版本
yolo export model=best.pt format=onnx opset=12
Code language: PHP (php)Q3: 記憶體不足
解決方案:
- 使用較小的模型(n < s < m < l < x)
- 降低輸入解析度
- 減少 batch size
- 使用 FP16 或 INT8 量化
Q4: 邊緣裝置 FPS 太低
優化順序:
- 確認使用正確的匯出格式(TensorRT for Jetson)
- 降低輸入尺寸(640 -> 320)
- 使用較小的模型
- 實作跳幀處理
部署檢查清單
在正式上線前,確認以下項目:
部署前檢查
[ ] 模型已匯出為目標格式
[ ] 在目標硬體上測試過效能
[ ] FPS 符合應用需求
[ ] 記憶體使用在合理範圍
[ ] 錯誤處理機制已實作
[ ] 有監控和日誌機制
[ ] 已準備回滾方案
Code language: CSS (css)系列總結
恭喜你完成了 YOLO 物件偵測的完整學習旅程!讓我們回顧一下:
| 篇章 | 主題 | 你學會了 |
|---|---|---|
| #01 | 基礎概念 | YOLO 的原理與架構 |
| #02 | 環境與快速開始 | 安裝環境與執行推論 |
| #03 | 資料集準備 | 標註與格式轉換 |
| #04 | 訓練與評估 | 訓練模型與分析指標 |
| #05 | 部署與優化 | 匯出、量化與即時應用 |
下一步建議
- 嘗試不同的部署場景:從本地應用到雲端 API
- 探索進階功能:追蹤、分割、姿態估計
- 優化模型架構:針對特定場景客製化
- 學習 MLOps:模型版本控制、持續訓練
參考資源
進階測驗:YOLO 部署與優化 進階
共 5 題情境應用題,測試你對部署與優化的深入理解
1. 根據文章中的實測數據,哪種配置最符合需求?
2. 根據文章建議,TensorRT 模型的匯出應該在哪裡進行?為什麼?
3. 根據文章的優化建議,下一步應該優先嘗試什麼?
data 參數。
4. 這個 data=coco.yaml 參數的作用是什麼?
VideoStream 類別實作。