Darknet YOLO 入坑手冊

Darknet YOLO 入坑手冊

電腦視覺物件偵測實戰課程

Oliver's Tech Workshop 2025


今日議程

  • 🎯 電腦視覺與物件偵測簡介
  • 🧠 機器學習與神經網路基礎
  • 🚀 YOLO 技術原理與最新發展
  • 💻 開發環境建置 (CUDA/Docker)
  • 🔧 實戰訓練流程 (PyTorch & Darknet)
  • 📱 部署到邊緣設備 (Ameba Pro2)
  • 🛠️ 故障排除與最佳化技巧

第一章:電腦視覺基礎


什麼是物件偵測?

YOLO架構圖

核心任務

  • 🔍 定位 (Localization) - 找出物體在哪裡
  • 🏷️ 分類 (Classification) - 判斷物體是什麼
  • 📦 邊界框 (Bounding Box) - 框出物體範圍
  • 📊 置信度 (Confidence) - 預測的可信度

YOLO 家族演進 (2025更新)

版本 特點 年份 mAP 速度
YOLOv1 開創性的實時檢測 2016 63.4% 45 FPS
YOLOv3 Darknet-53, 多尺度預測 2018 55.3% 20 FPS
YOLOv4 CSPDarknet53, Mish激活 2020 65.7% 65 FPS
YOLOv5 PyTorch實現, 輕量化 2020 68.9% 140 FPS
YOLOv7 可訓練的包袋式自注意力 2022 69.7% 161 FPS
YOLOv8 統一框架, 多任務 2023 68.2% 280 FPS
YOLOv9 PGI + GELAN架構 2024 70.4% 104 FPS
YOLOv10 實時檢測最佳化 2024 71.2% 300+ FPS

為什麼選擇 YOLO?

🚀 速度優勢

  • 實時處理: 30+ FPS
  • 端到端: 單一神經網路
  • 推理快速: 適合邊緣計算

🎯 精度提升

  • 多尺度特徵: 檢測大小物體
  • 豐富的增強: 資料增強策略
  • 損失函數: 針對檢測任務優化

🛠️ 易用性

  • 生態成熟: 大量預訓練模型
  • 文檔完善: 豐富的學習資源
  • 社群活躍: 持續更新維護

第二章:前置準備


學習路線圖

[mermaid 圖表 — 原始 HackMD 版本可正常渲染]

graph TD A[YOLO前置準備] --> B[硬體準備] A --> C[軟體環境] A --> D[知識基礎]

B --> E[GPU/NPU]
B --> F[CUDA/cuDNN]

C --> G[Linux/Docker]
C --> H[Python/PyTorch]

D --> I[神經網路]
D --> J[深度學習]</div>

硬體需求

基本配置

  • CPU: i5 以上
  • RAM: 16GB+
  • GPU: NVIDIA GTX 1060+

推薦配置

  • CPU: i7/i9 或 AMD Ryzen 7/9
  • RAM: 32GB+
  • GPU: RTX 3060+ (12GB VRAM)

GPU vs NPU

類型 優點 缺點
GPU 通用性強、生態完整 功耗高、成本高
NPU 專為AI優化、低功耗 生態受限、彈性較低

💡 沒有GPU也能學習!可使用:

  • Google Colab (免費GPU)
  • Kaggle Kernel
  • 雲端服務 (AWS, GCP)

第三章:機器學習基礎


什麼是機器學習?

定義

讓電腦從數據中自動學習規律,而無需明確編程

三大類型

  1. 監督式學習 - 有標註數據 (分類、回歸)
  2. 非監督式學習 - 無標註數據 (聚類、降維)
  3. 強化學習 - 透過獎懲機制學習 (遊戲、機器人)

物件偵測屬於監督式學習

  • 需要標註的邊界框
  • 需要物體類別標籤
  • 使用損失函數優化

神經網路 (NN)

神經網路架構

基本概念

  • 神經元: 最基本的計算單元
  • 權重: 控制輸入的重要性
  • 激活函數: 增加非線性能力
  • 反向傳播: 調整權重的方法

卷積神經網路 (CNN)

為什麼要用 CNN?

  • 🖼️ 空間不變性: 位置改變不影響識別
  • 🔍 局部感受野: 關注局部特徵
  • 📉 參數共享: 減少參數數量
  • 🎯 平移不變性: 特徵可以出現在任何位置

CNN 核心組件

# CNN 基本結構
Input Image (224x224x3)
    ↓
Conv2D (32 filters, 3x3) → ReLU → MaxPool (2x2)
    ↓
Conv2D (64 filters, 3x3) → ReLU → MaxPool (2x2)
    ↓
Conv2D (128 filters, 3x3) → ReLU → MaxPool (2x2)
    ↓
Flatten → Dense (512) → ReLU → Dropout
    ↓
Dense (num_classes) → Softmax

CNN 層級特徵學習

低層特徵 (前幾層)

  • 邊緣檢測: 水平線、垂直線、對角線
  • 紋理識別: 點狀、條紋、格子
  • 色彩梯度: 顏色變化、亮度變化

中層特徵 (中間層)

  • 形狀組合: 圓形、矩形、三角形
  • 物體局部: 眼睛、耳朵、輪廓
  • 複雜紋理: 毛髮、皮膚、表面材質

高層特徵 (最後幾層)

  • 完整物體: 人臉、汽車、動物
  • 場景理解: 室內、戶外、街道
  • 語義概念: 抽象的物體類別

從分類到檢測

圖像分類 vs 物件偵測

任務 輸入 輸出 難度
分類 整張圖片 類別標籤 較簡單
檢測 整張圖片 位置+類別 較複雜

檢測的挑戰

  • 🔍 多尺度: 大小物體都要檢測
  • 📍 精確定位: 邊界框要準確
  • 🚀 實時性: 速度要夠快
  • 🎯 多物體: 同時檢測多個物體

YOLO 的解決方案

  • 單一網路: 端到端訓練
  • 網格劃分: 全圖同時預測
  • 多尺度: 不同層級特徵融合

第四章:Dataset 資料集


為什麼需要 Dataset?

  • 🎯 訓練模型的"教材"
  • 📊 評估模型性能
  • 🔄 持續改進的基礎

資料集三要素

  1. 訓練集 (Train) - 70%
  2. 驗證集 (Valid) - 20%
  3. 測試集 (Test) - 10%

YOLOv7 資料集結構

dataset/
├── train/
│   ├── images/
│   └── labels/
├── valid/
│   ├── images/
│   └── labels/
├── test/
│   ├── images/
│   └── labels/
└── data.yaml

YOLOv7 資料集結構範例

資料集結構

分別有測試、訓練、驗證三個部分

資料集分割

data.yaml 訓練時會使用到


常用資料集資源

公開資料集平台

Roboflow 資料集下載範例

Roboflow 水族館資料集

使用 Yolo v7 PyTorch 格式下載

下載格式選擇

標註工具

  • LabelImg
  • CVAT
  • Roboflow Annotate

第五章:環境建置


GPU 設備檢查

1. 確認 GPU 支援

# 檢查 GPU 資訊
nvidia-smi

# 檢查 CUDA 版本
nvcc --version

# 檢查 GPU 計算能力
nvidia-smi --query-gpu=compute_cap --format=csv

2. 推薦 GPU 配置

GPU 型號 VRAM 適用場景
RTX 4060 16GB 學習/小規模訓練
RTX 4070 12GB 中等規模訓練
RTX 4080+ 16GB+ 大規模訓練

CUDA & cuDNN 完整安裝

Ubuntu 20.04/22.04 安裝步驟

# 1. 移除舊版本
sudo apt-get --purge remove "*nvidia*" "*cuda*" "*cudnn*"

# 2. 安裝 NVIDIA 驅動
sudo apt update
sudo apt install nvidia-driver-535

# 3. 重開機
sudo reboot

# 4. 安裝 CUDA 11.8
wget https://developer.download.nvidia.com/compute/cuda/11.8.0/local_installers/cuda_11.8.0_520.61.05_linux.run
sudo sh cuda_11.8.0_520.61.05_linux.run

# 5. 設定環境變數
echo 'export PATH=/usr/local/cuda-11.8/bin:$PATH' >> <sub>/.bashrc
echo 'export LD_LIBRARY_PATH=/usr/local/cuda-11.8/lib64:$LD_LIBRARY_PATH' >> </sub>/.bashrc
source <sub>/.bashrc

cuDNN 安裝

# 1. 下載 cuDNN 8.7.0 (需要 NVIDIA 帳號)
# 從 https://developer.nvidia.com/cudnn 下載 tar 檔案

# 2. 解壓縮並複製檔案
tar -xvf cudnn-linux-x86_64-8.7.0.84_cuda11-archive.tar.xz

# 3. 複製標頭檔
sudo cp cudnn-*/include/cudnn*.h /usr/local/cuda/include 

# 4. 複製函式庫
sudo cp -P cudnn-*/lib64/libcudnn* /usr/local/cuda/lib64 

# 5. 設定權限
sudo chmod a+r /usr/local/cuda/include/cudnn*.h 
sudo chmod a+r /usr/local/cuda/lib64/libcudnn*

# 6. 驗證安裝
nvidia-smi
nvcc --version

Python 環境設置

Conda 完整設置

# 1. 下載 Miniconda
wget https://repo.anaconda.com/miniconda/Miniconda3-latest-Linux-x86_64.sh
bash Miniconda3-latest-Linux-x86_64.sh

# 2. 建立專用環境
conda create -n yolo python=3.8 -y
conda activate yolo

# 3. 安裝 PyTorch (CUDA 11.8)
pip install torch<mark>2.0.1 torchvision</mark>0.15.2 torchaudio==2.0.2 --index-url https://download.pytorch.org/whl/cu118

# 4. 驗證 PyTorch CUDA 支援
python -c "import torch; print(torch.cuda.is_available())"
python -c "import torch; print(torch.cuda.get_device_name(0))"

必要套件安裝

# 基本套件
pip install numpy opencv-python pillow matplotlib seaborn
pip install pandas scikit-learn tqdm

# 深度學習相關
pip install ultralytics  # YOLOv8
pip install roboflow     # 資料集管理
pip install wandb        # 訓練監控

# 圖像處理
pip install albumentations  # 資料增強
pip install imgaug         # 圖像增強

# 視覺化
pip install tensorboard
pip install plotly

# 驗證安裝
python -c "import cv2; print(cv2.__version__)"
python -c "import ultralytics; print('YOLOv8 安裝成功')"

Docker 環境 (推薦)

Docker 工作流程

優點

  • 環境隔離: 不會影響主系統
  • 可重現性: 團隊環境一致
  • 快速部署: 一鍵啟動完整環境
  • 版本控制: 不同專案用不同版本

Docker 完整設置

1. 安裝 Docker

# Ubuntu 安裝 Docker
curl -fsSL https://get.docker.com -o get-docker.sh
sudo sh get-docker.sh

# 安裝 NVIDIA Docker
distribution=$(. /etc/os-release;echo $ID$VERSION_ID)
curl -s -L https://nvidia.github.io/nvidia-docker/gpgkey | sudo apt-key add -
curl -s -L https://nvidia.github.io/nvidia-docker/$distribution/nvidia-docker.list | sudo tee /etc/apt/sources.list.d/nvidia-docker.list

sudo apt-get update && sudo apt-get install -y nvidia-docker2
sudo systemctl restart docker

2. 使用預建映像

# 方式1: 使用官方映像
docker pull nvcr.io/nvidia/pytorch:22.12-py3

# 方式2: 使用自定義映像
docker pull oliver0804/darknet-opencv:latest

# 運行容器
docker run --gpus all -it --rm \
  -v $PWD:/workspace \
  -p 8888:8888 \
  nvcr.io/nvidia/pytorch:22.12-py3

自建 Docker 映像

Dockerfile 範例

FROM nvidia/cuda:11.8-devel-ubuntu20.04

# 安裝基本套件
RUN apt-get update && apt-get install -y \
    python3 python3-pip git wget \
    libopencv-dev python3-opencv \
    && rm -rf /var/lib/apt/lists/*

# 安裝 Python 套件
RUN pip3 install torch torchvision torchaudio \
    opencv-python ultralytics

# 設定工作目錄
WORKDIR /workspace

# 複製專案檔案
COPY . .

# 暴露端口
EXPOSE 8888

# 啟動命令
CMD ["bash"]

建置與使用

# 建置映像
docker build -t my-yolo-env .

# 運行容器
docker run --gpus all -it --rm \
  -v $PWD:/workspace \
  my-yolo-env

第六章:YOLO 訓練實戰


訓練前準備檢查清單

📋 硬體需求確認

  • ✅ GPU 記憶體 > 8GB
  • ✅ 系統記憶體 > 16GB
  • ✅ 儲存空間 > 50GB
  • ✅ CUDA 版本相容

📋 軟體環境確認

# 檢查清單
python --version         # Python 3.8+
pip list | grep torch    # PyTorch 1.12+
nvidia-smi              # GPU 狀態
nvcc --version          # CUDA 版本

YOLOv8 完整訓練流程

1. 環境設置

# 安裝 Ultralytics YOLOv8
pip install ultralytics

# 驗證安裝
yolo version

2. 準備資料集

# 資料集結構
dataset/
├── images/
│   ├── train/
│   ├── val/
│   └── test/
├── labels/
│   ├── train/
│   ├── val/
│   └── test/
└── data.yaml

資料集配置檔案

data.yaml 範例

# 資料集路徑
path: ./dataset
train: images/train
val: images/val
test: images/test

# 類別數量
nc: 3

# 類別名稱
names:
  0: person
  1: bicycle
  2: car

標註格式 (YOLO)

# 每行一個物體: class_id x_center y_center width height
# 座標為相對值 (0-1)
0 0.5 0.5 0.3 0.4
1 0.2 0.3 0.1 0.2

訓練腳本詳解

資料集配置範例

data.yaml 配置

此檔案經過修改,將 Path 改為絕對路徑

模型配置選擇

YOLOv7 配置檔案

路徑中包含 v7-tiny 版本選項

基本訓練

from ultralytics import YOLO

# 載入模型
model = YOLO('yolov8n.pt')  # nano 版本

# 開始訓練
results = model.train(
    data='data.yaml',
    epochs=100,
    imgsz=640,
    batch=16,
    name='my_experiment'
)

進階訓練設定

# 進階參數設定
results = model.train(
    data='data.yaml',
    epochs=300,
    imgsz=640,
    batch=32,
    lr0=0.01,           # 初始學習率
    lrf=0.01,           # 最終學習率
    momentum=0.937,     # 動量
    weight_decay=0.0005,# 權重衰減
    warmup_epochs=3,    # 預熱期
    warmup_momentum=0.8,# 預熱動量
    box=7.5,            # 邊界框損失權重
    cls=0.5,            # 分類損失權重
    dfl=1.5,            # 分布焦點損失權重
    patience=50,        # 早停耐心值
    save_period=10,     # 保存週期
    name='advanced_training'
)

訓練監控與視覺化

1. TensorBoard 監控

# 啟動 TensorBoard
import tensorboard
%load_ext tensorboard
%tensorboard --logdir runs/train

2. Weights & Biases 整合

# 安裝 wandb
pip install wandb

# 登入 wandb
wandb login

# 訓練時自動記錄
results = model.train(
    data='data.yaml',
    epochs=100,
    project='yolo-training',  # W&B 專案名稱
    name='experiment-1'
)

訓練過程監控

即時監控腳本

import psutil
import GPUtil
import time

def monitor_training():
    while True:
        # CPU 使用率
        cpu_percent = psutil.cpu_percent()
        
        # 記憶體使用率
        memory = psutil.virtual_memory()
        
        # GPU 使用率
        gpus = GPUtil.getGPUs()
        
        print(f"CPU: {cpu_percent}%")
        print(f"RAM: {memory.percent}%")
        
        for gpu in gpus:
            print(f"GPU {gpu.id}: {gpu.load*100:.1f}%")
            print(f"VRAM: {gpu.memoryUsed}MB/{gpu.memoryTotal}MB")
        
        time.sleep(5)

# 背景執行監控
import threading
monitor_thread = threading.Thread(target=monitor_training, daemon=True)
monitor_thread.start()

訓練過程展示

訓練開始

訓練開始截圖

GPU 資源監控

nvtop GPU 監控

可以使用 nvtop 進行 GPU 使用資源檢視


超參數調整策略

學習率調整

# 學習率調度策略
schedulers = {
    'cosine': 'cos',      # 餘弦退火
    'linear': 'linear',   # 線性衰減
    'constant': 'constant' # 常數
}

# 自動學習率尋找
model.tune(
    data='data.yaml',
    epochs=30,
    iterations=300,
    optimizer='AdamW',
    plots=True,
    save=True
)

批次大小優化

# 自動批次大小調整
def find_optimal_batch_size(model, data_yaml):
    batch_sizes = [8, 16, 32, 64, 128]
    best_batch = 8
    
    for batch in batch_sizes:
        try:
            results = model.train(
                data=data_yaml,
                epochs=5,
                batch=batch,
                verbose=False
            )
            best_batch = batch
            print(f"Batch {batch}: 成功")
        except RuntimeError as e:
            if "out of memory" in str(e):
                print(f"Batch {batch}: 記憶體不足")
                break
    
    return best_batch

模型驗證與測試

驗證腳本

# 驗證模型性能
metrics = model.val(
    data='data.yaml',
    imgsz=640,
    batch=32,
    conf=0.001,
    iou=0.6,
    save_json=True,
    save_hybrid=True
)

# 輸出指標
print(f"mAP50: {metrics.box.map50:.3f}")
print(f"mAP50-95: {metrics.box.map:.3f}")
print(f"Precision: {metrics.box.mp:.3f}")
print(f"Recall: {metrics.box.mr:.3f}")

測試腳本

# 單張圖片測試
results = model.predict(
    source='test.jpg',
    conf=0.25,
    save=True,
    show_labels=True,
    show_conf=True
)

# 批次圖片測試
results = model.predict(
    source='test_images/',
    conf=0.25,
    save=True,
    save_txt=True,  # 保存標註
    save_crop=True  # 保存裁切圖片
)

# 即時攝影機測試
results = model.predict(
    source=0,       # 攝影機ID
    conf=0.25,
    show=True,
    save=True
)

模型匯出與部署

多格式匯出

# 匯出為不同格式
model.export(
    format='onnx',      # ONNX 格式
    imgsz=640,
    dynamic=True,       # 動態輸入尺寸
    half=True,          # FP16 精度
    int8=True,          # INT8 量化
    optimize=True       # 優化
)

# 其他格式
formats = [
    'torchscript',  # PyTorch Script
    'tflite',       # TensorFlow Lite
    'edgetpu',      # Edge TPU
    'tfjs',         # TensorFlow.js
    'coreml'        # Core ML
]

for fmt in formats:
    model.export(format=fmt)

性能基準測試

# 推理速度測試
import time
import numpy as np

def benchmark_model(model, input_size=(640, 640), iterations=100):
    model.eval()
    dummy_input = np.random.randn(1, 3, *input_size).astype(np.float32)
    
    # 預熱
    for _ in range(10):
        model.predict(dummy_input, verbose=False)
    
    # 測試
    times = []
    for _ in range(iterations):
        start = time.time()
        model.predict(dummy_input, verbose=False)
        end = time.time()
        times.append(end - start)
    
    avg_time = np.mean(times)
    fps = 1.0 / avg_time
    
    print(f"平均推理時間: {avg_time*1000:.2f}ms")
    print(f"FPS: {fps:.2f}")
    
    return avg_time, fps

訓練成果展示

魚類偵測範例

偵測結果

魚類偵測結果

好多好多魚魚 <>< <3

最終魚類偵測

訓練指標

測試集結果

測試集結果

訓練集結果

訓練集結果

混淆矩陣

混淆矩陣

攝影機即時檢測

攝影機檢測


常見問題解決

記憶體不足

# 解決方案
strategies = {
    '降低批次大小': 'batch=8',
    '使用混合精度': 'amp=True',
    '減少輸入尺寸': 'imgsz=320',
    '梯度累積': 'accumulate=2'
}

# 梯度累積範例
model.train(
    data='data.yaml',
    epochs=100,
    batch=8,
    accumulate=4,  # 等效批次大小 = 8*4 = 32
    amp=True       # 自動混合精度
)

訓練不收斂

# 診斷與解決
diagnostic_steps = [
    "檢查學習率是否過高",
    "確認資料集標註正確性",
    "檢查類別平衡性",
    "調整損失函數權重",
    "增加資料增強"
]

# 學習率調整
model.train(
    data='data.yaml',
    lr0=0.001,      # 降低初始學習率
    warmup_epochs=5, # 增加預熱期
    patience=100     # 增加早停耐心
)

第七章:Darknet 框架


Darknet 簡介

特點

  • C/CUDA 原生實現 - 極致性能
  • 🚀 輕量級框架 - 無複雜依賴
  • 📦 易於修改 - 源碼清晰
  • 🔧 原生支援 - YOLO 官方框架

作者

Joseph Redmon (YOLO v1-v3 原作者)
Alexey Bochkovskiy (YOLOv4 維護者)

與 PyTorch 比較

特性 Darknet PyTorch
速度 極快
易用性 中等
生態系統 有限 豐富
自定義 需要 C 代碼 Python 即可

Darknet 完整安裝

1. 系統依賴安裝

# Ubuntu/Debian
sudo apt-get update
sudo apt-get install -y build-essential cmake git

# 編譯工具
sudo apt-get install -y gcc g++ make

# 可選:OpenCV 支援
sudo apt-get install -y libopencv-dev

# 可選:OpenMP 支援
sudo apt-get install -y libomp-dev

2. 克隆與編譯

# 克隆改良版 Darknet (推薦)
git clone https://github.com/AlexeyAB/darknet.git
cd darknet

# 編輯 Makefile
nano Makefile

Makefile 配置

# GPU 支援
GPU=1
CUDNN=1
CUDNN_HALF=1

# OpenCV 支援
OPENCV=1

# OpenMP 支援
OPENMP=1

# 偵錯模式
DEBUG=0

# 其他選項
LIBSO=1  # 建立 .so 檔案
ZED_CAMERA=0  # ZED 攝影機支援

編譯指令

# 清理舊檔案
make clean

# 編譯 (使用多核心)
make -j$(nproc)

# 驗證編譯結果
./darknet version

OpenCV 安裝過程截圖

OpenCV 3.4.19 版本確認

OpenCV 版本

編譯過程

編譯進度1 編譯進度2 編譯完成


基本測試

1. 下載預訓練模型

# YOLOv4 權重
wget https://github.com/AlexeyAB/darknet/releases/download/darknet_yolo_v3_optimal/yolov4.weights

# YOLOv4-tiny 權重
wget https://github.com/AlexeyAB/darknet/releases/download/yolov4/yolov4-tiny.weights

# YOLOv7-tiny 權重
wget https://github.com/AlexeyAB/darknet/releases/download/yolov4/yolov7-tiny.weights

2. 測試圖片檢測

# YOLOv4 檢測
./darknet detect cfg/yolov4.cfg yolov4.weights data/dog.jpg

# YOLOv4-tiny 檢測
./darknet detect cfg/yolov4-tiny.cfg yolov4-tiny.weights data/dog.jpg

# 自訂閾值
./darknet detect cfg/yolov4.cfg yolov4.weights data/dog.jpg -thresh 0.5

測試結果展示

YOLOv3 檢測結果

YOLOv3 狗狗檢測

YOLOv7-tiny 檢測結果

YOLOv7-tiny 結果


影片與攝影機檢測

影片檢測

# 檢測影片
./darknet detector demo cfg/coco.data cfg/yolov4.cfg yolov4.weights test.mp4

# 儲存結果
./darknet detector demo cfg/coco.data cfg/yolov4.cfg yolov4.weights test.mp4 -out_filename result.avi

攝影機檢測

# 使用 webcam
./darknet detector demo cfg/coco.data cfg/yolov4.cfg yolov4.weights -c 0

# 使用外接攝影機
./darknet detector demo cfg/coco.data cfg/yolov4.cfg yolov4.weights -c 1

# 設定參數
./darknet detector demo cfg/coco.data cfg/yolov4.cfg yolov4.weights -c 0 -thresh 0.25 -here

自定義訓練準備

1. 建立專案資料夾

mkdir my_yolo_project
cd my_yolo_project

# 建立目錄結構
mkdir -p {data,cfg,weights,results}
mkdir -p data/{images,labels}
mkdir -p data/images/{train,valid,test}
mkdir -p data/labels/{train,valid,test}

2. 準備資料集

# 資料集結構
my_yolo_project/
├── data/
│   ├── images/
│   │   ├── train/
│   │   ├── valid/
│   │   └── test/
│   ├── labels/
│   │   ├── train/
│   │   ├── valid/
│   │   └── test/
│   ├── train.txt
│   ├── valid.txt
│   └── test.txt
├── cfg/
│   ├── my_dataset.data
│   ├── my_yolov4.cfg
│   └── my_classes.names
└── weights/

配置檔案設定

1. 建立 .data 檔案

# my_dataset.data
classes = 3
train = data/train.txt
valid = data/valid.txt
names = cfg/my_classes.names
backup = weights/

2. 建立 .names 檔案

# my_classes.names
person
car
bicycle

3. 建立圖片列表

# 產生訓練列表
find $(pwd)/data/images/train -name "*.jpg" > data/train.txt

# 產生驗證列表
find $(pwd)/data/images/valid -name "*.jpg" > data/valid.txt

# 檢查列表
head -5 data/train.txt

模型配置調整

1. 複製基礎配置

# 複製 YOLOv4-tiny 配置
cp ../darknet/cfg/yolov4-tiny.cfg cfg/my_yolov4.cfg

2. 修改配置檔案

# 編輯配置
nano cfg/my_yolov4.cfg

# 關鍵修改點:
# 1. 修改 classes 數量
# 2. 修改 filters 數量
# 3. 調整學習率
# 4. 設定批次大小

重要參數說明

[net]
batch=64          # 批次大小
subdivisions=8    # 子批次
width=416         # 輸入寬度
height=416        # 輸入高度
channels=3        # 通道數
momentum=0.9      # 動量
decay=0.0005      # 權重衰減
angle=0           # 隨機旋轉角度
saturation=1.5    # 飽和度變化
exposure=1.5      # 曝光變化
hue=.1            # 色調變化

learning_rate=0.001  # 學習率
max_batches=6000     # 最大批次 (classes * 2000)
policy=steps         # 學習率策略
steps=4800,5400      # 降低學習率的步驟
scales=.1,.1         # 學習率縮放

預訓練權重準備

1. 下載預訓練權重

# YOLOv4-tiny 預訓練權重
wget https://github.com/AlexeyAB/darknet/releases/download/darknet_yolo_v4_pre/yolov4-tiny.conv.29

# YOLOv4 預訓練權重
wget https://github.com/AlexeyAB/darknet/releases/download/darknet_yolo_v3_optimal/yolov4.conv.137

2. 驗證權重檔案

# 檢查檔案大小
ls -lh weights/

# 測試權重載入
./darknet detector test cfg/my_dataset.data cfg/my_yolov4.cfg weights/yolov4-tiny.conv.29

開始訓練

自定義資料集範例

手語識別資料集

手語資料集

自定義設定資料夾

自定義設定

基本訓練指令

# 單 GPU 訓練
./darknet detector train cfg/my_dataset.data cfg/my_yolov4.cfg weights/yolov4-tiny.conv.29

# 多 GPU 訓練
./darknet detector train cfg/my_dataset.data cfg/my_yolov4.cfg weights/yolov4-tiny.conv.29 -gpus 0,1

# 從檢查點繼續訓練
./darknet detector train cfg/my_dataset.data cfg/my_yolov4.cfg weights/my_yolov4_last.weights

# 計算 mAP
./darknet detector train cfg/my_dataset.data cfg/my_yolov4.cfg weights/yolov4-tiny.conv.29 -map

訓練過程監控

訓練進行中


訓練監控

1. 查看訓練日誌

# 即時查看訓練進度
tail -f training.log

# 提取損失值
grep "avg" training.log | tail -10

2. 損失函數分析

# 訓練輸出範例
Region xx: cfg: (anchors) ...
1000: 2.950644, 2.950644 avg, 0.000010 rate, 3.456 seconds, 64000 images

參數說明

  • 1000: 當前迭代次數
  • 2.950644: 當前損失值
  • 2.950644 avg: 平均損失值
  • 0.000010 rate: 當前學習率
  • 3.456 seconds: 此批次訓練時間
  • 64000 images: 已處理圖片數

訓練結果評估

1. 計算 mAP

# 計算驗證集 mAP
./darknet detector map cfg/my_dataset.data cfg/my_yolov4.cfg weights/my_yolov4_best.weights

2. 測試個別圖片

# 測試單張圖片
./darknet detector test cfg/my_dataset.data cfg/my_yolov4.cfg weights/my_yolov4_best.weights data/test.jpg

# 批次測試
./darknet detector test cfg/my_dataset.data cfg/my_yolov4.cfg weights/my_yolov4_best.weights < data/test.txt

3. 調整檢測閾值

# 不同閾值測試
for thresh in 0.1 0.25 0.5 0.75; do
    echo "Testing with threshold: $thresh"
    ./darknet detector test cfg/my_dataset.data cfg/my_yolov4.cfg weights/my_yolov4_best.weights data/test.jpg -thresh $thresh
done

高級功能

1. 資料增強

# 在 [net] 部分加入
mosaic=1          # 馬賽克增強
cutmix=1          # CutMix 增強
mixup=1           # MixUp 增強

2. 多尺度訓練

# 隨機尺度訓練
random=1

# 多尺度設定
width=416
height=416

3. 學習率調度

# 學習率策略
policy=steps
steps=4800,5400
scales=.1,.1

# 或使用多項式衰減
policy=poly
power=4

疑難排解

常見錯誤解決

# 1. CUDA 記憶體不足
# 解決:降低 batch size 或 subdivisions

# 2. 找不到圖片
# 解決:檢查 .txt 檔案中的路徑

# 3. 標註格式錯誤
# 解決:檢查 YOLO 格式是否正確

# 4. 類別數量不匹配
# 解決:確認 classes 和 filters 設定正確

優化建議

  1. 記憶體優化: 調整 subdivisions
  2. 速度優化: 使用 -dont_show 參數
  3. 精度優化: 增加 max_batches
  4. 穩定訓練: 使用 -map 監控 mAP

Docker 部署 (完整版)

1. 使用現成映像

Docker 工作流程示意

Docker 工作流程

# 拉取映像
docker pull oliver0804/darknet-opencv:latest

# 運行容器
docker run --gpus all -it --rm \
    -v $(pwd):/workspace \
    -v $(pwd)/data:/darknet/data \
    -v $(pwd)/cfg:/darknet/cfg \
    -v $(pwd)/weights:/darknet/weights \
    oliver0804/darknet-opencv:latest

Docker 執行結果

Docker 執行結果

最終檢測結果

Docker 檢測結果

2. 在容器中訓練

# 進入容器
docker exec -it <container_id> bash

# 開始訓練
./darknet detector train cfg/my_dataset.data cfg/my_yolov4.cfg weights/yolov4-tiny.conv.29 -dont_show -map

3. 自動化腳本

#!/bin/bash
# auto_train.sh

# 設定參數
DATA_FILE="cfg/my_dataset.data"
CFG_FILE="cfg/my_yolov4.cfg"
WEIGHTS_FILE="weights/yolov4-tiny.conv.29"

# 執行訓練
docker run --gpus all -it --rm \
    -v $(pwd):/workspace \
    oliver0804/darknet-opencv:latest \
    ./darknet detector train $DATA_FILE $CFG_FILE $WEIGHTS_FILE -dont_show -map

第八章:邊緣設備部署


Ameba Pro2 簡介

硬體規格

  • 處理器: ARM Cortex-M55 @ 500MHz
  • AI 加速器: 0.4 TOPS NPU
  • 記憶體: 768KB SRAM + 16MB PSRAM
  • 攝像頭: 2MP 感光元件
  • 連接: Wi-Fi 6 + BLE 5.0
  • 尺寸: 35mm x 28mm

為什麼選擇邊緣 AI?

  • 🔒 隱私保護: 資料不上雲
  • 低延遲: 即時推理
  • 💰 成本效益: 無雲端費用
  • 🔋 低功耗: 適合 IoT 應用

重要注意事項

支援時程

注意: ameba pro2 對 yolo 的支援時間會比較晚

當前限制

  • 模型轉換需要線上工具
  • 暫無離線版本工具
  • 如果在意模型保密需要考慮

適用場景

  • 🏠 智慧家居監控
  • 🏭 工業品質檢測
  • 🚗 車內駕駛行為分析
  • 📱 IoT 邊緣計算

模型轉換詳解

1. 準備轉換檔案

檔案要求

# 打包內容
yolo_model.zip
├── yolov4-tiny.weights    # 訓練好的權重檔
└── yolov4-tiny.cfg        # 對應的配置檔

# 重要限制
❌ 不能包含中文字符
❌ cfg 檔案註解也不能有中文
❌ 檔案路徑不能有中文

配置檔案清理

# 移除中文註解
sed -i '/[\u4e00-\u9fff]/d' yolov4-tiny.cfg

# 檢查檔案編碼
file yolov4-tiny.cfg

# 確保 UTF-8 編碼
iconv -f GB2312 -t UTF-8 yolov4-tiny.cfg > yolov4-tiny_clean.cfg

線上轉換流程

1. 上傳模型

模型轉換上傳

網址: https://www.amebaiot.com/en/amebapro2-ai-convert-model/

2. 轉換過程

  • ⏱️ 等待時間: 10-20 分鐘
  • 📧 結果通知: 轉換完成會發送郵件
  • 📦 輸出格式: .nb 檔案 (Neural Network Binary)

3. 轉換參數

參數 說明 建議值
Input Size 輸入圖片尺寸 416x416
Quantization 量化位元數 INT8
Optimization 優化等級 High

Arduino IDE 環境設置

1. 安裝 Arduino IDE

# 下載 Arduino IDE 2.0+
wget https://downloads.arduino.cc/arduino-ide/arduino-ide_2.2.1_Linux_64bit.zip

# 或使用套件管理器
sudo apt install arduino

2. 添加開發板支援

開發板管理員 URL

https://github.com/ambiot/ambpro2_arduino/raw/main/Arduino_package/package_realtek.com_amebapro2_index.json

開發板管理員設定

安裝步驟

  1. 開啟 Arduino IDE
  2. 檔案 → 偏好設定 → 額外的開發板管理員網址
  3. 貼上上述 URL
  4. 工具 → 開發板 → 開發板管理員
  5. 搜尋 "Realtek Ameba"
  6. 安裝 "Realtek Ameba Pro2 Boards"

選擇開發板

開發板設定

選擇 Ameba Pro2

設定路徑: 工具 → 開發板 → Realtek Ameba Pro2 → "Ameba Pro2"

編譯選項

Board: "Ameba Pro2"
CPU Speed: "500MHz"
Optimization: "Smallest (-Os)"
Upload Speed: "115200"

神經網路範例程式

1. 開啟範例

NN 範例

路徑: 檔案 → 範例 → AmebaNN → YOLO

2. 基本程式結構

#include "NeuralNetwork.h"
#include "VideoStream.h"
#include "RTSP.h"

// 物件類別定義
#define YOLO_CLASSES 26  // 自定義類別數

// 類別名稱陣列
String objectList[YOLO_CLASSES] = {
    "A", "B", "C", "D", "E", "F", "G", "H", "I", "J",
    "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", 
    "U", "V", "W", "X", "Y", "Z"
};

void setup() {
    Serial.begin(115200);
    
    // 初始化攝像頭
    Camera.configVideoChannel(VIDEO_CHN, 416, 416, 30, VIDEO_H264_JPEG);
    Camera.videoInit();
    
    // 初始化神經網路
    NNObjectDetection.configVideo(VIDEO_CHN);
    NNObjectDetection.modelSelect(OBJECT_DETECTION, YOLO_CLASSES, DEFAULT_YOLO, NA_MODEL);
    NNObjectDetection.begin();
    
    // 初始化 RTSP
    RTSP.configVideo(VIDEO_CHN);
    RTSP.begin();
}

void loop() {
    // 執行物件偵測
    if (NNObjectDetection.available()) {
        ObjectDetectionResult result = NNObjectDetection.getResult();
        
        // 處理偵測結果
        for (int i = 0; i < result.count(); i++) {
            int obj_type = result.type(i);
            int score = result.score(i);
            
            if (score > 50) {  // 信心度閾值
                Serial.printf("偵測到: %s (信心度: %d%%)\n", 
                             objectList[obj_type].c_str(), score);
            }
        }
    }
    delay(100);
}

模型替換詳解

1. 找到模型檔案位置

模型檔案路徑

典型路徑:

<sub>/Arduino/libraries/AmebaNN/src/
├── models/
│   ├── yolov4_tiny.nb      # 原始模型
│   └── yolov4_tiny_new.nb  # 你的新模型

2. 備份原始模型

# 進入模型目錄
cd </sub>/Arduino/libraries/AmebaNN/src/models/

# 備份原始模型
cp yolov4_tiny.nb yolov4_tiny_original.nb

# 替換新模型
cp /path/to/your/model.nb yolov4_tiny.nb

3. 修改類別設定

更新類別數量

// 原始 COCO dataset (80 類)
#define YOLO_CLASSES 80

// 改為你的類別數 (例如: 26 類手語)
#define YOLO_CLASSES 26

更新類別名稱

// 原始 COCO 類別
String objectList[YOLO_CLASSES] = {
    "person", "bicycle", "car", ... // 80 個類別
};

// 改為手語字母 (26 類)
String objectList[YOLO_CLASSES] = {
    "A", "B", "C", "D", "E", "F", "G", "H", "I", "J",
    "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", 
    "U", "V", "W", "X", "Y", "Z"
};

程式碼修改詳解

1. 修改 OSD 標籤顯示

原始標籤清單

OSD 標籤修改

修改後的手語標籤

手語標籤清單

原始代碼:

// 舊版本 (可能已修正)
printf("%s", item.name());

修正後:

// 新版本
printf("%s", objectList[obj_type].c_str());

2. 物件類型處理

物件類型修正

修改位置: 約第 114 行

// 修改前
item.name()

// 修改後  
objectList[obj_type].objectName

測試與除錯

1. 序列埠監控

void printDetectionInfo(ObjectDetectionResult result) {
    Serial.printf("偵測到 %d 個物件\n", result.count());
    
    for (int i = 0; i < result.count(); i++) {
        int obj_type = result.type(i);
        int score = result.score(i);
        int x = result.xMin(i);
        int y = result.yMin(i);
        int w = result.width(i);
        int h = result.height(i);
        
        Serial.printf("物件 %d: %s\n", i+1, objectList[obj_type].c_str());
        Serial.printf("  信心度: %d%%\n", score);
        Serial.printf("  位置: (%d, %d) 大小: %dx%d\n", x, y, w, h);
    }
}

2. 性能監控

unsigned long prev_time = 0;
int frame_count = 0;

void loop() {
    if (NNObjectDetection.available()) {
        frame_count++;
        unsigned long curr_time = millis();
        
        if (curr_time - prev_time >= 1000) {  // 每秒統計
            Serial.printf("FPS: %d\n", frame_count);
            frame_count = 0;
            prev_time = curr_time;
        }
        
        // 處理偵測結果...
    }
}

實際展示效果

1. 手語識別展示

YouTube 影片: Ameba pro2 yolo展示

功能展示

  • ✅ 即時手語字母識別
  • ✅ 邊界框繪製
  • ✅ 信心度顯示
  • ✅ RTSP 串流輸出

2. 性能表現

指標 數值
推理速度 10 FPS
延遲 <100ms
功耗 <500mW
精確度 85%+

模型快速替換工具

1. 問題描述

  • 🔍 路徑深層: Arduino 目錄結構複雜
  • 🔄 頻繁更換: 需要測試不同模型
  • 💾 備份需求: 保存之前的模型版本

2. 自動化腳本

YouTube 教學: Ameba pro2 快速替換模型腳本

Windows 批次檔 (model_swap.bat)

@echo off
setlocal enabledelayedexpansion

echo Ameba Pro2 模型快速替換工具
echo ================================

set ARDUINO_PATH=%USERPROFILE%\Documents\Arduino
set MODEL_PATH=%ARDUINO_PATH%\libraries\AmebaNN\src\models
set BACKUP_PATH=%MODEL_PATH%\backup

REM 建立備份目錄
if not exist "%BACKUP_PATH%" mkdir "%BACKUP_PATH%"

REM 顯示當前模型
echo 當前模型檔案:
dir "%MODEL_PATH%\*.nb" /b

echo.
echo 選擇操作:
echo 1. 替換模型
echo 2. 還原備份
echo 3. 建立備份
set /p choice="請輸入選項 (1-3): "

if "%choice%"=="1" goto REPLACE_MODEL
if "%choice%"=="2" goto RESTORE_BACKUP  
if "%choice%"=="3" goto CREATE_BACKUP
goto END

:REPLACE_MODEL
set /p new_model="請輸入新模型檔案路徑: "
if not exist "%new_model%" (
    echo 錯誤: 找不到指定的模型檔案
    goto END
)

REM 備份當前模型
copy "%MODEL_PATH%\yolov4_tiny.nb" "%BACKUP_PATH%\yolov4_tiny_%date:</sub>0,4%%date:<sub>5,2%%date:</sub>8,2%.nb"

REM 替換模型
copy "%new_model%" "%MODEL_PATH%\yolov4_tiny.nb"
echo 模型替換完成!
goto END

:RESTORE_BACKUP
echo 可用的備份檔案:
dir "%BACKUP_PATH%\*.nb" /b
set /p backup_file="請輸入要還原的備份檔案名: "
copy "%BACKUP_PATH%\%backup_file%" "%MODEL_PATH%\yolov4_tiny.nb"
echo 模型還原完成!
goto END

:CREATE_BACKUP
copy "%MODEL_PATH%\yolov4_tiny.nb" "%BACKUP_PATH%\yolov4_tiny_%date:<sub>0,4%%date:</sub>5,2%%date:~8,2%.nb"
echo 備份建立完成!
goto END

:END
pause

3. Linux/Mac 腳本 (model_swap.sh)

#!/bin/bash

ARDUINO_PATH="$HOME/Arduino"
MODEL_PATH="$ARDUINO_PATH/libraries/AmebaNN/src/models"
BACKUP_PATH="$MODEL_PATH/backup"

# 建立備份目錄
mkdir -p "$BACKUP_PATH"

echo "Ameba Pro2 模型快速替換工具"
echo "================================"

echo "當前模型檔案:"
ls -la "$MODEL_PATH"/*.nb 2>/dev/null || echo "找不到模型檔案"

echo ""
echo "選擇操作:"
echo "1. 替換模型"
echo "2. 還原備份"
echo "3. 建立備份"
read -p "請輸入選項 (1-3): " choice

case $choice in
    1)
        read -p "請輸入新模型檔案路徑: " new_model
        if [ ! -f "$new_model" ]; then
            echo "錯誤: 找不到指定的模型檔案"
            exit 1
        fi
        
        # 備份當前模型
        cp "$MODEL_PATH/yolov4_tiny.nb" "$BACKUP_PATH/yolov4_tiny_$(date +%Y%m%d_%H%M%S).nb"
        
        # 替換模型
        cp "$new_model" "$MODEL_PATH/yolov4_tiny.nb"
        echo "模型替換完成!"
        ;;
    2)
        echo "可用的備份檔案:"
        ls -1 "$BACKUP_PATH"/*.nb 2>/dev/null || echo "沒有備份檔案"
        read -p "請輸入要還原的備份檔案名: " backup_file
        cp "$BACKUP_PATH/$backup_file" "$MODEL_PATH/yolov4_tiny.nb"
        echo "模型還原完成!"
        ;;
    3)
        cp "$MODEL_PATH/yolov4_tiny.nb" "$BACKUP_PATH/yolov4_tiny_$(date +%Y%m%d_%H%M%S).nb"
        echo "備份建立完成!"
        ;;
    *)
        echo "無效的選項"
        ;;
esac

疑難排解

常見問題

  1. 模型轉換失敗

    • 檢查檔案是否包含中文
    • 確認 cfg 和 weights 對應
    • 重新清理配置檔案
  2. 編譯錯誤

    • 確認開發板選擇正確
    • 檢查類別數量設定
    • 更新 Arduino 核心
  3. 推理速度慢

    • 降低輸入解析度
    • 使用 INT8 量化
    • 優化模型架構

效能優化建議

  • 🎯 模型選擇: 使用 YOLOv4-tiny 而非完整版
  • 📏 輸入尺寸: 建議 320x320 或 416x416
  • 量化: 使用 INT8 量化減少記憶體用量
  • 🔄 批次處理: 避免頻繁的模型切換

第九章:實用技巧


OpenCV 應用

電腦視覺基礎操作

OpenCV 基本操作

OpenCV 可以處理顏色、物件邊緣、光流等,是代碼版本的 Photoshop

影像前處理

import cv2

# 讀取圖片
img = cv2.imread('image.jpg')

# 轉換顏色空間
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

# 邊緣檢測
edges = cv2.Canny(gray, 50, 150)

# 影像增強
enhanced = cv2.equalizeHist(gray)

進階應用範例

人臉識別應用

OpenCV 人臉識別

透過 OpenCV contrib 實現人臉偵測

OCR 文字識別

OpenCV OCR

使用 Tesseract 進行光學字符識別


資料增強技巧

常用方法

  1. 旋轉 - 增加角度變化
  2. 翻轉 - 水平/垂直鏡像
  3. 縮放 - 尺度不變性
  4. 色彩調整 - 光照變化
  5. 加噪 - 提升魯棒性
# Albumentations 範例
transform = A.Compose([
    A.RandomRotate90(),
    A.Flip(),
    A.RandomBrightnessContrast(p=0.2),
])

第十章:常見問題


GPU 記憶體不足

解決方案

  1. 降低 batch size
  2. 使用混合精度訓練
  3. 減少輸入圖片尺寸
  4. 使用梯度累積
# 梯度累積範例
accumulation_steps = 4
for i, (imgs, targets) in enumerate(dataloader):
    loss = model(imgs, targets)
    loss = loss / accumulation_steps
    loss.backward()
    
    if (i + 1) % accumulation_steps == 0:
        optimizer.step()
        optimizer.zero_grad()

訓練不收斂

檢查清單

  • ✅ 學習率是否合適
  • ✅ 資料集是否平衡
  • ✅ 標註是否正確
  • ✅ 增強是否過度

調試技巧

# 學習率調度
scheduler = torch.optim.lr_scheduler.CosineAnnealingLR(
    optimizer, T_max=epochs
)

總結與展望


學習要點回顧

技術堆疊

  • ✅ 深度學習基礎
  • ✅ YOLO 架構原理
  • ✅ 訓練流程實作
  • ✅ 模型優化技巧
  • ✅ 邊緣設備部署

實戰經驗

  • 💡 資料集準備的重要性
  • 🔧 超參數調整的藝術
  • 📊 性能指標的理解
  • 🚀 部署優化的考量

未來發展方向

技術趨勢

  1. Vision Transformer - 新架構崛起
  2. 自監督學習 - 減少標註需求
  3. 邊緣 AI - 更強大的端側推理
  4. 多模態融合 - 結合語言理解

應用場景

  • 🏭 智慧製造
  • 🚗 自動駕駛
  • 🏥 醫療影像
  • 🛡️ 安防監控

參考資源

官方資源

社群資源

  • GitHub: AlexeyAB/darknet
  • GitHub: WongKinYiu/yolov7
  • Roboflow Blog
  • PyImageSearch

Q&A 時間

聯絡方式

感謝聆聽!🎉


附錄:快速參考

常用指令

# PyTorch 訓練
python train.py --batch 16 --epochs 100

# Darknet 訓練
./darknet detector train cfg/data.data cfg/yolo.cfg weights.conv

# 模型測試
python detect.py --weights best.pt --source test.jpg

# Docker 運行
docker run --gpus all -it darknet:latest

本文最初發布於 HackMD @BASHCAT

留言

這個網誌中的熱門文章

Arduino 課本可能沒教的事(1)

SI4432 搭配Arduino

燒錄 Arduino mini Pro 燒錄