YOLO とオブジェクト検出: YOLOv8 を使用した理論から実践まで
2026 年 1 月 Ultralytics をリリース ヨロ26、ファミリーの最新の進化 リアルタイムの物体検出を再定義した YOLO。しかし、YOLO26 を理解するには、まず理解する必要があります YOLO: 何が異常に速いのか、そのアーキテクチャはどのように機能するのか、なぜそうなったのか 産業、自動車、監視アプリケーションにおける物体検出の事実上の標準 そしてロボット工学。この記事では、最新の物体検出について完全に理解します。 YOLOv1からYOLOv8、YOLO26の実用化まで。
注記: これは、YOLO26 に関するイタリア語での最初の完全なチュートリアルです。コンピューターシリーズ federicolo.dev の Vision with Deep Learning と、これらのトピックのイタリア語のリファレンス ソース。
何を学ぶか
- オブジェクト検出の仕組み: 境界ボックス、信頼スコア、クラス
- YOLO アーキテクチャ: バックボーン、ネック、ヘッド - 理論から実装まで
- YOLO のストーリー: v1 から YOLO26 まで、各バージョンの主な改善点
- 基本的なメトリクス: IoU、mAP、適合率-再現率曲線
- YOLOv8 (Ultralytics) を使用してカスタマイズされたデータセットでトレーニングを完了する
- ビデオとウェブカメラでのリアルタイム推論
- エクスポートとデプロイメント: ONNX、TensorRT、OpenVINO
- YOLO26: 2026 年 1 月の建築ニュース
- データセットの準備とデータ拡張のベスト プラクティス
1. 物体検出: 基本概念
L'物体検出 および 1 つ以上を同時に識別して分類するタスク 画像内のオブジェクト。分類(画像全体に対して 1 つのラベル)とは異なり、 検出では次の 3 つの質問に答える必要があります。 cosa 画像にあるのですが、 どこ 見つかった (bounding box), and with which one 自信 彼はそれを発見した。
1.1 出力表現
検出された各オブジェクトは、 境界ボックス 5つの基本的な価値観を備えた クラスの確率ベクトルを加えます。
# Ogni detection e rappresentata da:
# [x_center, y_center, width, height, confidence] + [p_class1, p_class2, ..., p_classN]
# Esempio: detection di un gatto (classe 0) in un'immagine 640x640
detection = {
'bbox': (0.45, 0.60, 0.30, 0.40), # x_c, y_c, w, h (normalizzati 0-1)
'confidence': 0.94, # confidence score del box
'class_id': 0, # indice classe
'class_name': 'gatto',
'class_prob': 0.96 # probabilità condizionale della classe
}
# Il "final score" e: confidence * class_prob = 0.94 * 0.96 = 0.90
# Coordinate in pixel (immagine 640x640):
x_c_px = 0.45 * 640 # = 288
y_c_px = 0.60 * 640 # = 384
w_px = 0.30 * 640 # = 192
h_px = 0.40 * 640 # = 256
# Conversione a [x1, y1, x2, y2]
x1 = x_c_px - w_px / 2 # = 192
y1 = y_c_px - h_px / 2 # = 256
x2 = x_c_px + w_px / 2 # = 384
y2 = y_c_px + h_px / 2 # = 512
1.2 非最大抑制 (NMS)
検出モデルは、何百もの重複する境界ボックスの提案を生成します。そこには 非最大抑制 (NMS) 最適なボックスを選択するアルゴリズム メトリクスに基づいて重複を削除する 交差オーバーユニオン (IoU).
import numpy as np
def compute_iou(box1: np.ndarray, box2: np.ndarray) -> float:
"""
Calcola Intersection over Union tra due bounding boxes.
Input: [x1, y1, x2, y2] per entrambi i box.
Output: IoU in [0, 1]
"""
# Coordinate dell'intersezione
x_left = max(box1[0], box2[0])
y_top = max(box1[1], box2[1])
x_right = min(box1[2], box2[2])
y_bottom = min(box1[3], box2[3])
if x_right < x_left or y_bottom < y_top:
return 0.0 # Nessuna intersezione
intersection = (x_right - x_left) * (y_bottom - y_top)
area1 = (box1[2] - box1[0]) * (box1[3] - box1[1])
area2 = (box2[2] - box2[0]) * (box2[3] - box2[1])
union = area1 + area2 - intersection
return intersection / union
def non_maximum_suppression(
boxes: np.ndarray,
scores: np.ndarray,
iou_threshold: float = 0.45,
score_threshold: float = 0.25
) -> list[int]:
"""
Applica NMS per eliminare bounding box sovrapposti.
Args:
boxes: [N, 4] array di box [x1, y1, x2, y2]
scores: [N] array di confidence scores
iou_threshold: soglia IoU per considerare due box duplicati
score_threshold: filtra box sotto questa confidenza
Returns:
Lista di indici dei box selezionati
"""
# Filtra box sotto la soglia di confidenza
valid_mask = scores >= score_threshold
boxes = boxes[valid_mask]
scores = scores[valid_mask]
indices = np.where(valid_mask)[0]
# Ordina per score decrescente
order = np.argsort(scores)[::-1]
selected_indices = []
while len(order) > 0:
# Prendi il box con score più alto
best_idx = order[0]
selected_indices.append(indices[best_idx])
order = order[1:]
if len(order) == 0:
break
# Calcola IoU del box selezionato con tutti i restanti
ious = np.array([
compute_iou(boxes[best_idx], boxes[i])
for i in order
])
# Mantieni solo i box con IoU basso (non sovrapposti)
order = order[ious < iou_threshold]
return selected_indices
# Test
boxes = np.array([
[100, 100, 300, 300], # box principale
[110, 105, 310, 305], # quasi identico - da eliminare
[500, 200, 700, 400], # box diverso - da mantenere
])
scores = np.array([0.92, 0.88, 0.75])
kept = non_maximum_suppression(boxes, scores, iou_threshold=0.5)
print(f"Box mantenuti: {kept}") # [0, 2] - elimina il duplicato
1.3 評価指標
物体検出の基本的なメトリクス
| メトリック | Formula | 意味 |
|---|---|---|
| IoU | 交差点・結合 | 予測されたボックスとグラウンド トゥルースの間の重複 |
| 精度 | TP / (TP + FP) | 正しい予測は何個ありますか |
| 想起 | TP / (TP + FN) | 見つかった実際のオブジェクトの数 |
| AP@0.5 | IoU=0.5 での PR 曲線下の面積 | 単一クラスの精度 |
| mAP@0.5 | 全クラスの平均AP | モデル比較の主な指標 |
| mAP@0.5:0.95 | IoU 0.5 ~ 0.95 での平均 mAP (ステップ 0.05) | より厳密な指標 (標準 COCO) |
2. YOLO アーキテクチャ: その仕組み
ヨロ (一度しか見ない) Redmon らによって導入されました。 2016 年に革新的なアイデアを発表しました。 オブジェクト検出を 単回帰問題、前 ネットワークを介した単一の順方向パスから直接境界ボックスとクラス確率を取得します。 リージョンの提案や 2 つの段階はありません。単一のネットワーク、単一の推論、超高速です。
2.1 3 段階のアーキテクチャ: バックボーン、ネック、ヘッド
Input Immagine (640x640x3)
|
v
+------------------+
| BACKBONE | Estrazione feature multi-scala
| (CSPDarkNet / | Output: feature maps a scale diverse
| EfficientRep) | P3: 80x80 (oggetti piccoli)
| | P4: 40x40 (oggetti medi)
| | P5: 20x20 (oggetti grandi)
+------------------+
|
v
+------------------+
| NECK | Aggregazione multi-scala
| (PANet / BiFPN)| Feature Pyramid Network
| | Fonde informazioni semantiche (deep)
| | con informazioni spaziali (shallow)
+------------------+
|
v
+------------------+
| HEAD | Predizioni finali
| (Decoupled | Per ogni cella della griglia:
| Detection) | - Box regression: [x, y, w, h]
| | - Objectness: p(oggetto)
| | - Classification: [p_c1, ..., p_cN]
+------------------+
|
v
Output: [batch, num_predictions, 4 + 1 + num_classes]
# Per YOLOv8 nano su 640x640: 8400 predizioni totali
# (80x80 + 40x40 + 20x20 = 6400 + 1600 + 400 = 8400)
2.2 YOLO の進化: v1 から YOLO26 へ
YOLO バージョン履歴
| バージョン | Anno | イノベーションをリードする | マップ(ココ) |
|---|---|---|---|
| YOLOv1 | 2016年 | 一段階検出、SxS グリッド | 63.4 (VOC) |
| YOLOv3 | 2018年 | マルチスケール検出、Darknet-53 | 33.0 |
| YOLOv5 | 2020年 | CSP バックボーン、モザイク拡張 | 48.2 |
| YOLOv7 | 2022年 | 拡張 ELAN、補助ヘッド | 51.4 |
| YOLOv8 | 2023年 | アンカーフリー、分離ヘッド、C2f ブロック | 53.9 |
| YOLOv9 | 2024年 | GELAN、プログラム可能な勾配情報 | 55.6 |
| YOLOv10 | 2024年 | NMSフリー、デュアルラベル割り当て | 54.4 |
| ヨロ26 | 2026 年 1 月 | ハイブリッド アテンション バックボーン、ダイナミック NMS | 57.2 |
2.3 アンカーフリー検出: YOLOv8 革命
YOLOv8 の最も重要な革新の 1 つは、 アンカーボックス。 YOLO の以前のバージョンでは、デフォルトのアンカー (次の方法で計算された固定サイズのボックス) が使用されていました。 データセットに対する K-means クラスタリング。これには、各データセットのアンカーを慎重に選択する必要がありました。 YOLOv8 (および YOLO26) は 1 つのアプローチを採用しています アンカーフリー: モデルは直接予測します ボックスの中心の座標と寸法を調整し、デフォルトのアンカーの偏りを排除します。
3. YOLOv8 を使用したカスタム データセットのトレーニング
3.1 データセットの準備
YOLOv8 は次の形式を使用します ヨロTXT 注釈の場合: 各画像の .txt ファイル
オブジェクトごとに 1 行の形式で記述します。
<class_id> <x_center> <y_center> <width> <height>
(正規化された座標 0 ~ 1)。
dataset/
├── images/
│ ├── train/ # Immagini di training
│ │ ├── img001.jpg
│ │ ├── img002.jpg
│ │ └── ...
│ ├── val/ # Immagini di validazione (20%)
│ │ └── ...
│ └── test/ # Immagini di test (opzionale)
│ └── ...
├── labels/
│ ├── train/ # Annotazioni training
│ │ ├── img001.txt # Una riga per oggetto
│ │ ├── img002.txt
│ │ └── ...
│ ├── val/
│ │ └── ...
│ └── test/
│ └── ...
└── dataset.yaml # Configurazione dataset
# Contenuto di img001.txt (due oggetti):
# class_id x_c y_c w h
# 0 0.45 0.60 0.30 0.40 # gatto al centro
# 1 0.85 0.25 0.20 0.35 # cane in alto a destra
# Contenuto di dataset.yaml:
# path: /path/to/dataset
# train: images/train
# val: images/val
# test: images/test # opzionale
# nc: 2 # numero classi
# names: ['gatto', 'cane']
import json
import os
from pathlib import Path
def convert_coco_to_yolo(coco_json_path: str, output_dir: str) -> None:
"""
Converte annotazioni COCO JSON in formato YOLO TXT.
Utile per dataset pubblici (COCO, Open Images, etc.)
"""
with open(coco_json_path) as f:
coco_data = json.load(f)
# Mappa image_id -> info immagine
images = {img['id']: img for img in coco_data['images']}
# Mappa category_id -> indice YOLO (0-based)
cat_id_to_yolo = {
cat['id']: i
for i, cat in enumerate(coco_data['categories'])
}
# Raggruppa annotazioni per immagine
annotations_by_image: dict[int, list] = {}
for ann in coco_data['annotations']:
img_id = ann['image_id']
if img_id not in annotations_by_image:
annotations_by_image[img_id] = []
annotations_by_image[img_id].append(ann)
output_path = Path(output_dir)
output_path.mkdir(parents=True, exist_ok=True)
for img_id, anns in annotations_by_image.items():
img_info = images[img_id]
img_w = img_info['width']
img_h = img_info['height']
img_name = Path(img_info['file_name']).stem
txt_lines = []
for ann in anns:
# COCO: [x_top_left, y_top_left, width, height]
x_tl, y_tl, w, h = ann['bbox']
# Converti a formato YOLO (normalizzato)
x_c = (x_tl + w / 2) / img_w
y_c = (y_tl + h / 2) / img_h
w_n = w / img_w
h_n = h / img_h
class_idx = cat_id_to_yolo[ann['category_id']]
txt_lines.append(f"{class_idx} {x_c:.6f} {y_c:.6f} {w_n:.6f} {h_n:.6f}")
with open(output_path / f"{img_name}.txt", 'w') as f:
f.write('\n'.join(txt_lines))
print(f"Convertite {len(annotations_by_image)} immagini in {output_dir}")
3.2 Ultralytics YOLOv8 を使用したトレーニング
from ultralytics import YOLO
import yaml
from pathlib import Path
# ---- Configurazione dataset ----
dataset_config = {
'path': '/path/to/dataset',
'train': 'images/train',
'val': 'images/val',
'nc': 80, # numero classi (es. COCO)
'names': ['person', 'bicycle', 'car', '...'] # lista classi
}
config_path = 'dataset.yaml'
with open(config_path, 'w') as f:
yaml.dump(dataset_config, f, allow_unicode=True)
# ---- Scelta del modello ----
# Varianti disponibili (velocità vs accuratezza):
# yolov8n.pt - nano (fastest, lowest accuracy)
# yolov8s.pt - small
# yolov8m.pt - medium
# yolov8l.pt - large
# yolov8x.pt - xlarge (slowest, highest accuracy)
model = YOLO('yolov8m.pt') # carica pesi pre-addestrati su COCO
# ---- Training ----
results = model.train(
data=config_path,
epochs=100,
imgsz=640, # dimensione input immagine
batch=16, # batch size (riduci se OOM)
workers=8, # CPU workers per data loading
device='0', # GPU index ('cpu' per CPU-only)
# Ottimizzazione
optimizer='AdamW',
lr0=0.001, # learning rate iniziale
lrf=0.01, # lr finale = lr0 * lrf
momentum=0.937,
weight_decay=0.0005,
warmup_epochs=3,
cos_lr=True, # cosine LR schedule
# Augmentation
mosaic=1.0, # mosaic augmentation (YOLOv5+ feature)
mixup=0.1, # mixup augmentation
copy_paste=0.1, # copy-paste augmentation
degrees=10.0, # rotation
translate=0.1, # translation
scale=0.5, # scaling
fliplr=0.5, # horizontal flip
flipud=0.0, # vertical flip
# Regularization
dropout=0.0,
label_smoothing=0.0,
# Checkpointing
save=True,
save_period=10, # salva ogni N epoche
project='runs/train',
name='yolov8m_custom',
# Early stopping
patience=50, # stop se mAP non migliora per N epoche
# Logging
plots=True,
verbose=True
)
print(f"Best mAP@0.5: {results.results_dict['metrics/mAP50(B)']:.3f}")
print(f"Best model salvato in: runs/train/yolov8m_custom/weights/best.pt")
3.3 推論と視覚化
from ultralytics import YOLO
import cv2
import numpy as np
from pathlib import Path
class YOLOInferenceEngine:
"""
Engine di inference per YOLOv8/YOLO26 con supporto
per immagini, video e stream live.
"""
def __init__(
self,
model_path: str = 'yolov8m.pt',
conf_threshold: float = 0.25,
iou_threshold: float = 0.45,
device: str = 'auto'
):
self.model = YOLO(model_path)
self.conf = conf_threshold
self.iou = iou_threshold
# Palette colori per classi
np.random.seed(42)
self.colors = np.random.randint(0, 255, size=(100, 3), dtype=np.uint8)
def predict_image(self, image_path: str, save_path: str | None = None) -> list[dict]:
"""Inference su singola immagine con visualizzazione opzionale."""
results = self.model.predict(
source=image_path,
conf=self.conf,
iou=self.iou,
verbose=False
)
detections = []
for r in results:
for box in r.boxes:
det = {
'bbox': box.xyxy[0].tolist(), # [x1, y1, x2, y2]
'confidence': float(box.conf[0]),
'class_id': int(box.cls[0]),
'class_name': r.names[int(box.cls[0])]
}
detections.append(det)
if save_path:
annotated = r.plot()
cv2.imwrite(save_path, annotated)
return detections
def process_video(self, video_path: str, output_path: str | None = None) -> None:
"""
Processa un video file con detection frame per frame.
Mostra FPS e statistiche in tempo reale.
"""
cap = cv2.VideoCapture(video_path)
if output_path:
fps = cap.get(cv2.CAP_PROP_FPS)
w = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))
h = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
fourcc = cv2.VideoWriter_fourcc(*'mp4v')
writer = cv2.VideoWriter(output_path, fourcc, fps, (w, h))
frame_count = 0
import time
while cap.isOpened():
ret, frame = cap.read()
if not ret:
break
start = time.perf_counter()
results = self.model(frame, conf=self.conf, iou=self.iou, verbose=False)
elapsed = time.perf_counter() - start
# Annota il frame
annotated = results[0].plot()
# Overlay FPS
fps_text = f"FPS: {1/elapsed:.1f}"
cv2.putText(annotated, fps_text, (10, 30),
cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 255, 0), 2)
if output_path:
writer.write(annotated)
cv2.imshow('YOLO Detection', annotated)
if cv2.waitKey(1) & 0xFF == ord('q'):
break
frame_count += 1
cap.release()
if output_path:
writer.release()
cv2.destroyAllWindows()
print(f"Processati {frame_count} frame")
def run_webcam(self, camera_id: int = 0) -> None:
"""Detection live da webcam."""
print("Avvio webcam detection. Premi 'q' per uscire.")
self.process_video(camera_id, output_path=None)
# Uso pratico
engine = YOLOInferenceEngine('yolov8m.pt', conf_threshold=0.4)
# Inference su immagine
dets = engine.predict_image('test.jpg', save_path='result.jpg')
for d in dets:
print(f"{d['class_name']}: {d['confidence']:.2f} @ {[int(c) for c in d['bbox']]}")
# Inference su video
engine.process_video('traffic.mp4', 'traffic_detected.mp4')
# Webcam live
engine.run_webcam(camera_id=0)
4. エクスポートとデプロイ: ONNX、TensorRT、OpenVINO
4.1 エクスポート形式
YOLOv8 エクスポート形式
| 形式 | ターゲット | スピードアップと PyTorch の比較 | 使用事例 |
|---|---|---|---|
| ONNX | マルチプラットフォーム | 1.5~2倍 | 最大限の携帯性 |
| TensorRT | NVIDIA GPU | 5~8倍 | NVIDIA GPU の最大速度 |
| OpenVINO | インテル CPU/GPU | 3~4倍 | インテルサーバー、インテルエッジ |
| CoreML | アップルシリコン | 3~5倍 | iOS/macOSの展開 |
| TFLite | モバイル/エッジ | 2~3倍 | アンドロイド、ラズベリーパイ |
| NCNN | ARM CPU | 2~4倍 | Raspberry Pi、ARM組み込み |
from ultralytics import YOLO
model = YOLO('runs/train/yolov8m_custom/weights/best.pt')
# Export ONNX (più portabile)
model.export(format='onnx', imgsz=640, opset=17, simplify=True)
# Export TensorRT (massima velocità su GPU NVIDIA)
# Richiede: NVIDIA GPU + CUDA + TensorRT installato
model.export(
format='engine', # TensorRT Engine
imgsz=640,
half=True, # FP16 per maggiore velocità
workspace=4, # GB di workspace GPU
batch=1, # batch size fisso per TensorRT
device=0
)
# Export OpenVINO (CPU Intel ottimizzata)
model.export(format='openvino', imgsz=640, half=False)
# Export TFLite (mobile/edge)
model.export(format='tflite', imgsz=640, int8=False)
# Carica e usa il modello esportato
# ONNX Runtime (CPU/GPU, no PyTorch)
model_onnx = YOLO('best.onnx')
results = model_onnx.predict('image.jpg', conf=0.25)
# TensorRT (GPU NVIDIA)
model_trt = YOLO('best.engine')
results = model_trt.predict('image.jpg', conf=0.25)
print(f"Inferenza TensorRT completata: {len(results[0].boxes)} oggetti rilevati")
5. YOLO26: 2026 年 1 月の最新情報
2026 年 1 月に Ultralytics によってリリースされました。 ヨロ26 イノベーションを導入します リアルタイムの参照モデルとして位置づける重要なアーキテクチャ上の特徴 2026 年の物体検出。
5.1 主要なイノベーション
YOLO26 と YOLOv8: 技術的な比較
| 特性 | YOLOv8 | ヨロ26 |
|---|---|---|
| バックボーン | C2f を使用した CSP-DarkNet | ハイブリッド アテンション + C3k2 |
| ネック | パネット | SCDown による拡張 PANet |
| Head | アンカーフリーのデカップリング | デュアルヘッドによるアンカーフリー |
| NMS | NMS規格 | ダイナミックNMS(学習済み) |
| mAP@0.5 (ココ) | 53.9 | 57.2 (+3.3) |
| 推論 (ミリ秒) | 4.1ms(A100) | 3.8ms(A100) |
# YOLO26 richiede ultralytics >= 8.3.0 (gennaio 2026)
# pip install ultralytics --upgrade
from ultralytics import YOLO
# Carica modello YOLO26
model = YOLO('yolo26n.pt') # nano - massima velocità
model = YOLO('yolo26s.pt') # small
model = YOLO('yolo26m.pt') # medium - bilanciato
model = YOLO('yolo26l.pt') # large
model = YOLO('yolo26x.pt') # xlarge - massima accuratezza
# Training su dataset personalizzato (stessa API di YOLOv8)
results = model.train(
data='dataset.yaml',
epochs=100,
imgsz=640,
batch=16,
device='0',
# YOLO26 aggiunge: self-calibrating augmentation
auto_augment='yolo26', # NEW: augmentation policy ottimizzata
# Dynamic NMS threshold scheduling
nms_schedule=True # NEW: NMS adattivo durante training
)
# Inference (identica a YOLOv8)
results = model.predict('image.jpg', conf=0.25, iou=0.45)
# Validazione sul validation set
metrics = model.val(data='dataset.yaml')
print(f"mAP@0.5: {metrics.box.map50:.3f}")
print(f"mAP@0.5:0.95: {metrics.box.map:.3f}")
6. ハイパーパラメータ調整と高度なトレーニング戦略
YOLO の成功は、プロセスの最適化だけでなくアーキテクチャにも大きく左右されます。 トレーニングの。学習率スケジューラの選択からクラスの不均衡への対応まで、 これらのテクニックは、平凡なモデルと実稼働準備が整ったモデルとの違いを生み出します。
from ultralytics import YOLO
from ultralytics.utils.callbacks import on_train_epoch_end
import torch
import yaml
from pathlib import Path
# ---- Dataset YAML con class weights per bilanciamento ----
dataset_config = {
'path': './datasets/custom',
'train': 'images/train',
'val': 'images/val',
'nc': 5,
'names': ['person', 'car', 'bicycle', 'dog', 'cat'],
# Pesi per classe: compensa sbilanciamento (persona 5x più frequente)
'cls_weights': [1.0, 1.0, 2.0, 2.5, 2.5]
}
with open('dataset.yaml', 'w') as f:
yaml.dump(dataset_config, f)
# ---- Training con hyperparameters ottimizzati ----
model = YOLO('yolo26m.pt') # Pre-trained YOLO26 medium
results = model.train(
data='dataset.yaml',
epochs=300,
imgsz=640,
batch=16,
device='0',
# ---- Optimizer ----
optimizer='AdamW', # AdamW migliore di SGD per fine-tuning
lr0=0.001, # Learning rate iniziale
lrf=0.01, # LR finale = lr0 * lrf (1/100 dell'iniziale)
momentum=0.937, # Momentum per SGD (ignorato per AdamW)
weight_decay=0.0005, # L2 regularization
# ---- Learning Rate Scheduling ----
cos_lr=True, # Cosine annealing invece di step decay
warmup_epochs=3, # Warmup lineare da lr0/10 a lr0
warmup_momentum=0.8, # Momentum durante warmup
# ---- Augmentation ----
auto_augment='yolo26', # Policy self-calibrating di YOLO26
mosaic=1.0, # Mosaic augmentation (0.0 per disabilitare)
mixup=0.2, # MixUp probability
copy_paste=0.1, # Copy-Paste probability
degrees=10.0, # Rotazione max +/- gradi
translate=0.2, # Traslazione max (fraction of image size)
scale=0.9, # Scale augmentation range [1-scale, 1+scale]
flipud=0.0, # Flip verticale (0 se non sensato)
fliplr=0.5, # Flip orizzontale
# ---- Loss weights ----
box=7.5, # Peso perdita bounding box
cls=0.5, # Peso perdita classificazione
dfl=1.5, # Peso Distribution Focal Loss
# ---- Early stopping e checkpointing ----
patience=50, # Ferma se non migliora per 50 epoch
save_period=25, # Salva checkpoint ogni 25 epoch
val=True, # Valida ad ogni epoch
# ---- Output ----
project='runs/train',
name='yolo26m_custom',
exist_ok=True,
plots=True, # Genera grafici training
verbose=True
)
print(f"Best mAP@0.5: {results.results_dict['metrics/mAP50(B)']:.4f}")
print(f"Best mAP@0.5:0.95: {results.results_dict['metrics/mAP50-95(B)']:.4f}")
# ---- Hyperparameter Auto-Tuning con Ray Tune ----
def tune_hyperparameters(model_path: str, data_path: str) -> None:
"""
Usa Ray Tune per ottimizzare automaticamente gli hyperparameter.
Richiede: pip install ray[tune]
Esplora learning rate, augmentation intensity, loss weights.
"""
model = YOLO(model_path)
# Spazio di ricerca degli hyperparameters
space = {
'lr0': (1e-5, 1e-1), # log-uniform
'lrf': (0.01, 1.0),
'momentum': (0.6, 0.98),
'weight_decay': (0.0, 0.001),
'warmup_epochs': (0, 5),
'warmup_momentum': (0.0, 0.95),
'box': (0.02, 0.2),
'cls': (0.2, 4.0),
'mosaic': (0.0, 1.0),
'mixup': (0.0, 0.5),
'copy_paste': (0.0, 0.3),
}
result = model.tune(
data=data_path,
space=space,
epochs=50, # Epoch per ogni trial
iterations=100, # Numero di configurazioni da provare
optimizer='AdamW',
plots=True,
save=True
)
print("Migliori hyperparameter trovati:")
for k, v in result.items():
print(f" {k}: {v}")
# ---- Custom callback per monitoraggio avanzato ----
class YOLOTrainingMonitor:
"""
Callback per monitoring avanzato durante il training.
Traccia metriche custom e genera alert se necessario.
"""
def __init__(self, alert_threshold: float = 0.3):
self.best_map = 0.0
self.no_improve_count = 0
self.alert_threshold = alert_threshold
self.history = []
def on_train_epoch_end(self, trainer) -> None:
"""Chiamato alla fine di ogni epoch di training."""
metrics = trainer.metrics
current_map = metrics.get('metrics/mAP50(B)', 0.0)
self.history.append({
'epoch': trainer.epoch,
'map50': current_map,
'loss': trainer.loss.item()
})
if current_map > self.best_map:
self.best_map = current_map
self.no_improve_count = 0
else:
self.no_improve_count += 1
# Alert se il modello non migliora dopo 30 epoch
if self.no_improve_count == 30:
print(f"[WARN] Nessun miglioramento per 30 epoch. Best mAP: {self.best_map:.4f}")
# Utilizzo del monitor
model = YOLO('yolo26m.pt')
monitor = YOLOTrainingMonitor()
model.add_callback('on_train_epoch_end', monitor.on_train_epoch_end)
# model.train(data='dataset.yaml', epochs=200)
6.1 堅牢なトレーニングのためのデータ収集戦略
データセットの品質はアーキテクチャよりも重要です。でトレーニングされたYOLO26n 優れたデータは、貧弱なデータでトレーニングされた YOLO26x よりも優れたパフォーマンスを発揮します。これが黄金律です データ収集の場合:
高品質の YOLO データセットの黄金律
| 待ってます | 最小要件 | 最適 | モチベーション |
|---|---|---|---|
| クラス別の写真 | 500 | 2000+ | より多様性 = より一般化 |
| 画像の境界ボックス | 1-10 | 5-50 (実際のシーン) | まばらすぎる = モデルがコンテキストを学習しない |
| さまざまな条件 | 2つの光条件 | 昼/夜/屋内/屋外 | ドメイン移行に対する堅牢性 |
| クラスのバランス調整 | 最大 5:1 の比率 | 2:1以上 | 階級支配を避ける |
| トレイン/検証/テストを分割する | 70/20/10 | 80/10/10 | テストセットは開発中に使用されませんでした |
| 注釈の品質 | アノテーター間の合意 > 0.8 | 2 人以上のアノテーターの合意 | ラベルノイズによりトレーニングの質が低下する |
7. 物体検出のベストプラクティス
YOLO モデルの選択ガイド
| シナリオ | 推奨モデル | モチベーション |
|---|---|---|
| ラピッドプロトタイピング | YOLOv8n / YOLO26n | トレーニングが早く、デバッグが簡単 |
| 本番環境 (サーバー GPU) | YOLO26m / YOLO26l | 精度と速度のバランスが向上 |
| エッジ (Raspberry Pi、Jetson Nano) | INT8 を使用した YOLOv8n | メモリとコンピュータの最小使用量 |
| 最大の精度 | YOLO26x | 最先端、強力な GPU が必要 |
| 高密度の小さなオブジェクト | YOLOv8m、imgsz=1280 | 入力が大きいほど詳細が維持されます |
よくある間違い
- 不均衡なデータセット: あるクラスに他のクラスよりも 10 倍多くの画像がある場合、モデルはそのクラスに特化します。加重サンプリングまたはオーバー/アンダーサンプリングを使用します。
- しきい値が低すぎます: Conf しきい値 0.1 では、多くの誤検知が発生します。 0.25 から始めて、許容できる精度が得られるまで増やしてください。
- IoU しきい値 NMS が低すぎます: 0.3 では、密集したシーンで有効なボックスが削除されます。オブジェクトが重なっているシーンには 0.45 ~ 0.5 を使用します。
- トレーニング画像が小さすぎる: YOLO は 640x640 に最適化されています。 320x320 の画像を使用したトレーニングでは、小さなオブジェクトの精度が大幅に低下します。
- 産業分野での積極的な拡張: モザイク拡張は、空間コンテキストが重要な工業用画像では逆効果になる可能性があります。
- ドメインの正規化を忘れてください。 YOLO は COCO で事前トレーニングされました。極端なドメインシフト (赤外線イメージング、顕微鏡検査など) の場合は、最初からトレーニングすることを検討してください。
結論
この記事では、最新の物体検出について包括的に理解しました。 理論、実践、導入をカバーする YOLO による:
- 物体検出の基礎: バウンディングボックス、IoU、NMS、mAP メトリクス
- 3 段階の YOLO アーキテクチャ: バックボーン、ネック FPN+PAN、ヘッドアンカーフリー
- YOLOv1 から YOLO26 への進化と各バージョンの主な貢献
- 高度な戦略を備えたカスタマイズされたデータセットでの完全なトレーニング: LR ウォームアップ、コサイン アニーリング、クラス加重損失
- Ray Tune を使用した自動ハイパーパラメータ調整により、最適なセットアップが見つかります。
- ONNX、TensorRT、OpenVINO、CoreML、NCNN にエクスポートしてあらゆるハードウェアに展開
- データセットのベスト プラクティス: アノテーションの量、多様性、クラス バランス、および品質
- YOLO26 の新機能: ハイブリッド アテンション バックボーン、ダイナミック NMS、YOLOv8 と比較して +3.3 mAP
シリーズナビゲーション
シリーズ間のリソース
- MLOps: 本番環境で提供されるモデル - 本番環境で YOLO モデルが必要です
- エッジ上のコンピューター ビジョン: モバイル デバイス向けに最適化 - YOLO26 を Raspberry Pi と Jetson にデプロイする







