Ultralytics におけるエンドツーエンド検出の理解
はじめに
以前のモデル(例: YOLOv8 や YOLO11からYOLO26へアップグレードする場合、最も大きな変更点の一つとしてNon-Maximum Suppression(NMS)が削除されたことが挙げられます。YOLO 数千もの重複する予測結果を生成するため、最終的な検出結果に絞り込むにはNMS が必要でした。これにより遅延が生じ、エクスポートグラフが複雑化し、ハードウェアプラットフォームによって動作が不安定になる可能性がありました。
YOLO26は異なるアプローチを採用しています。このモデルでは、外部でのフィルタリングを必要とせず、モデルから直接最終的な検出結果を出力します。これは「エンドツーエンドの物体検出」として知られており、すべてのYOLO26モデルでデフォルトで有効になっています。その結果、デプロイメントのパイプラインが簡素化され、レイテンシが低減され、CPU上での推論速度が最大43%向上します。
このガイドでは、変更点、コードの更新が必要かどうか、どのエクスポート形式がエンドツーエンド推論に対応しているか、そして従来のYOLO からスムーズに移行する方法について解説します。
このアーキテクチャの変更の背景にある理由について詳しく知りたい方は、YOLO26NMS削除された理由についてUltralytics 記事をご覧ください。
概要
- Ultralytics またはCLI をお使いですか? 変更は必要ありません。モデル名を次のように置き換えるだけです。
yolo26n.pt. - カスタム推論コード(ONNX 、TensorRT)を使用していますか? 後処理を更新してください — 検出結果の出力が変更されました
(N, 300, 6)でxyxyフォーマットのため、NMS 。その他のタスクでは、追加データ(マスク係数、キーポイント、または角度)が追加されます。 - エクスポートしますか? ほとんどのフォーマットは、ネイティブでエンドツーエンド出力をサポートしています。ただし、一部のフォーマット(NCNN、RKNN、PaddlePaddle、ExecuTorch、IMX、EdgeTPU)では、オペレータの制約がサポートされていないため(例:
torch.topk)。
エンドツーエンド検出の仕組み
YOLO26は、学習時にデュアル ヘッドアーキテクチャを採用しています。両方のヘッドは同じバックボーンとネックを共有していますが、出力の生成方法は異なります:
| 頭 | 目的 | 検出出力 | 後処理 |
|---|---|---|---|
| 1対1(デフォルト) | エンドツーエンド推論 | (N, 300, 6) | 信頼区間のみ |
| 一対多 | 従来のYOLO | (N, nc + 4, 8400) | NMSが必要です |
上記の形状は検出用です。その他のタスクでは、検出ごとに追加データを付加して、1対1の出力を拡張します:
| タスク | エンドツーエンドの出力 | 追加データ |
|---|---|---|
| 検出 | (N, 300, 6) | — |
| セグメンテーション | (N, 300, 6 + nm) + プロト (N, nm, H, W) | nm マスク係数(デフォルトは32) |
| ポーズ | (N, 300, 57) | 17のキーポイント × 3(x、y、可視性) |
| OBB | (N, 300, 7) | 回転角度 |
学習中、両方のヘッドが同時に動作します。1対多のヘッドはより豊富な学習信号を提供し、一方、1対1のヘッドは、明確で重複のない予測を生成することを学習します。学習中、 推論 および エクスポート、ただ マンツーマン指導 デフォルトで有効になっており、1画像あたり最大300件の検出結果を以下の形式で出力します [x1, y1, x2, y2, confidence, class_id].
電話をかける際 model.fuse()また、推論を高速化するためにConv層とBatchNorm層を折りたたみ、エンドツーエンドモデルでは1対多のヘッドも削除することで、モデルサイズとFLOPsを削減します。デュアルヘッドアーキテクチャの詳細については、 YOLO26のモデルページ.
コードを変更する必要がありますか?
Ultralytics Python またはCLIの使用
変更の必要はありません。標準Ultralytics Python を使用する場合、または CLIを使用すれば、予測、検証、エクスポートなど、すべての処理が自動的に行われ、モデルを最初から最後までシームレスに扱えます。
Ultralytics ではコードの変更は不要です
from ultralytics import YOLO
# Load a YOLO26 model
model = YOLO("yolo26n.pt")
# Predict — no NMS step, no code changes
results = model.predict("image.jpg")
yolo predict model=yolo26n.pt source=image.jpg
カスタム推論コードの使用
はい、出力形式は異なります。もし YOLOv8 または YOLO11 用にカスタム後処理ロジックを実装した場合(例えば、ONNX や TensorRT)を使用する場合、新しい出力形状に対応するために更新する必要があります:
| YOLOv8 YOLO11 | YOLO26(エンドツーエンド) | |
|---|---|---|
| 検出出力 | (N, nc + 4, 8400) | (N, 300, 6) |
| ボックス形式 | xywh (中心x座標, 中心y座標, 幅, 高さ) | xyxy (左上 x, 左上 y, 右下 x, 右下 y) |
| レイアウト | アンカーごとのボックス座標とクラススコア | [x1, y1, x2, y2, conf, class_id] |
| NMS | はい | いいえ |
| 後処理 | NMS 信頼度フィルター | 信頼度フィルターのみ |
セグメンテーション、ポーズ推定、およびOBBタスクでは、YOLO26は各検出結果にタスク固有のデータを付加します。詳細は上記の出力形状表を参照してください。
どこ N は バッチサイズ および nc はクラスの数です(例:80は COCO)。
エンドツーエンドのモデルを使用すると、後処理がはるかに簡単になります。たとえば、ONNX を使用する場合:
import onnxruntime as ort
# Load and run the exported end-to-end model
session = ort.InferenceSession("yolo26n.onnx")
output = session.run(None, {session.get_inputs()[0].name: input_tensor})
# End-to-end output: (batch, 300, 6) → [x1, y1, x2, y2, confidence, class_id]
detections = output[0][0] # first image in batch
detections = detections[detections[:, 4] > conf_threshold] # confidence filter — that's it!
「1対多」ヘッドへの切り替え
YOLO が必要な場合(例えば、NMSの後処理コードを再利用する場合など)、以下の設定を行うことで、いつでも1対多のヘッドに切り替えることができます。 end2end=False:
従来のNMSの出力に「1対多」のヘッダーを使用する
from ultralytics import YOLO
model = YOLO("yolo26n.pt")
# Prediction with NMS (traditional behavior)
results = model.predict("image.jpg", end2end=False)
# Validation with NMS
metrics = model.val(data="coco.yaml", end2end=False)
# Export without end-to-end
model.export(format="onnx", end2end=False)
yolo predict model=yolo26n.pt source=image.jpg end2end=False
yolo val model=yolo26n.pt data=coco.yaml end2end=False
yolo export model=yolo26n.pt format=onnx end2end=False
エクスポート形式の互換性
ほとんどのエクスポート形式は、デフォルトでエンドツーエンド推論に対応しています。これには以下が含まれます。 ONNX、 TensorRT、 CoreML、 OpenVINO、 TFLite、TF.js、およびMNN。
以下の形式はエンドツーエンドに対応しておらず、自動的に1対多のヘッドにフォールバックします: NCNN、RKNN、 PaddlePaddle、ExecuTorch、IMX、およびEdgeTPU。
エンドツーエンドがサポートされていない場合、どうなるのでしょうか
これらの形式のいずれかにエクスポートすると、Ultralytics 「1対多」のヘッドに切り替わり、警告を記録します。手動での操作は不要です。つまり、これらの形式 NMS 、 YOLOv8 や YOLO11と同様に、推論パイプラインにNMSが必要になるということです。
TensorRT INT8
TensorRT エンドツーエンドに対応していますが、それは 自動的に無効化される でエクスポートする際 int8=True TensorRT .3.0 以前のバージョンで
精度と速度のトレードオフ
エンドツーエンド検出は、精度への影響を最小限に抑えつつ、導入において大きなメリットをもたらします:
| メトリック | エンドツーエンド(デフォルト) | 1対多 +NMSend2end=False) |
|---|---|---|
| CPU 速度 | 最大43%高速化 | ベースライン |
| mAP | 約0.5mAP | YOLO1YOLO11と同等か、それ以上の性能 |
| 後処理 | 信頼度フィルターのみ | NMS 全体 |
| 展開の複雑性 | ミニマル | NMS が必要 |
実世界のほとんどのアプリケーションでは、約0.5 mAP この差はごくわずかであり、特に処理速度と簡便性の向上を考慮すればなおさらです。もし最高精度を最優先とするのであれば、いつでも end2end=False.
すべてのモデルサイズ(n、s、m、l、x)にわたる詳細なベンチマークについては、YOLO26の性能指標をご覧ください。
YOLOv8 YOLO11からの移行
既存のプロジェクトをYOLO26にアップグレードする場合、スムーズに移行するための簡単なチェックリストを以下に示します:
- Ultralytics /CLI : 変更は必要ありません。モデル名を次のように更新するだけです。
yolo26n.pt(またはyolo26n-seg.pt,yolo26n-pose.pt,yolo26n-obb.pt) - カスタム後処理コード: 新しい出力形式に対応するための更新 —
(N, 300, 6)検出用、およびタスク固有のデータ セグメンテーション, ポーズ、および OBBまた、ボックス形式がxywh宛先xyxy - エクスポートパイプライン:対象の形式については、上記の「形式の互換性」のセクションをご確認ください
- TensorRT INT8:エンドツーエンドのサポートを利用するには、TensorRT のTensorRT 10.3.0以上であることを確認してください
- FP16形式でのエクスポート: すべての出力をFP16で出力する必要がある場合は、以下のコマンドでエクスポートしてください
end2end=False— 参照 なぜoutput0がFP32のままなのか - iOS CoreML: エンドツーエンドのサポートが完全に提供されています。Xcode Previewのサポートが必要な場合は、
end2end=Falsewithnms=True - エッジデバイス(NCNN、RKNN):これらの形式は自動的に「1対多」モードに切り替わるため、デバイス上のNMS を含めてください
よくある質問
end2end=True と nms=True を同時に使用することはできますか?
いいえ。これらのオプションは互いに排他的です。もし nms=True エンドツーエンドモデルにおいて エクスポート、自動的に強制的に nms=False ただし、注意点があります。エンドツーエンドのヘッドは内部ですでに重複フィルタリングを処理しているため、外部のNMS 不要NMS 。
しかしながら、 end2end=False と組み合わせて nms=True これは有効な設定です。従来のNMS エクスポートNMS 組み込んでいます。これは、 CoreML エクスポートする理由は、Xcodeのプレビュー機能を検出モデルと直接連携して使用できるためです。
エンドツーエンドモデルにおいて、max_detパラメータは何を制御するのでしょうか?
The max_det パラメータ(デフォルト:300)は、1対1ヘッドが1枚の画像につき出力できる検出結果の最大数を設定します。これは推論時またはエクスポート時に調整できます:
model.predict("image.jpg", max_det=100) # fewer detections, slightly faster
model.export(format="onnx", max_det=500) # more detections for dense scenes
なお、デフォルトのYOLO26チェックポイントは、以下の設定で学習されています max_det=300この値を大きくすることも可能ですが、1対1のヘッドはトレーニング時に最大300個の正確な検出結果を出力するように最適化されているため、その上限を超えた検出結果は精度が低下する可能性があります。画像あたり300個以上の検出が必要な場合は、より高い値で再トレーニングすることを検討してください。 max_det 値。
ONNX (1, 300, 6) ですが、これで合っていますか?
はい、それが検出における想定されるエンドツーエンドの出力形式です: バッチサイズ 1つにつき、最大300件の検出、それぞれに6つの値 [x1, y1, x2, y2, confidence, class_id]信頼度閾値でフィルタリングするだけで完了です。NMS 。
その他のタスクでは、出力の形状が異なります:
| タスク | 出力形状 | 説明 |
|---|---|---|
| 検出 | (1, 300, 6) | [x1, y1, x2, y2, conf, class_id] |
| セグメンテーション | (1, 300, 38) + (1, 32, 160, 160) | 6つのボックス値と32個のマスク係数、およびプロトタイプマスクtensor |
| ポーズ | (1, 300, 57) | 6つのボックス値 + 17のキーポイント × 3(x、y、可視性) |
| OBB | (1, 300, 7) | 6つのボックス値 + 1つの回転角度 |
エクスポートしたモデルがエンドツーエンドかどうかを確認するにはどうすればよいですか?
Python を使用するか、ONNX 直接確認することで、確認できます:
モデルがエンドツーエンドであるか確認する
from ultralytics import YOLO
model = YOLO("yolo26n.onnx")
model.predict(verbose=False) # run predict to setup predictor first
print(model.predictor.model.end2end) # True if end-to-end is enabled
import onnxruntime as ort
session = ort.InferenceSession("yolo26n.onnx")
metadata = session.get_modelmeta().custom_metadata_map
print(metadata.get("end2end")) # 'True' if end-to-end is enabled
あるいは、出力形状を確認してください。エンドツーエンド検出モデルは (1, 300, 6)一方、従来のモデルは (1, nc + 4, 8400)その他のタスク形状については、 出力形状に関するよくある質問.
セグメンテーション、ポーズ推定、およびOBBタスクにおいて、エンドツーエンドの処理はサポートされていますか?
はい。YOLO26のすべてのタスクバリエーション―― 検出, セグメンテーション, 姿勢推定、および 指向物体検出 (obb) — デフォルトでエンドツーエンドの推論をサポートします。 end2end=False フォールバックは、すべてのタスクでも利用可能です。
各タスクは、基本の検出結果にタスク固有のデータを追加します:
| タスク | モデル | エンドツーエンドの出力 |
|---|---|---|
| 検出 | yolo26n.pt | (N, 300, 6) |
| セグメンテーション | yolo26n-seg.pt | (N, 300, 38) + プロト (N, 32, 160, 160) |
| ポーズ | yolo26n-pose.pt | (N, 300, 57) |
| OBB | yolo26n-obb.pt | (N, 300, 7) |