Detection Head
検出ヘッドは物体検出器の最終段であり、バックボーンとネックの特徴を、各グリッド位置におけるバウンディングボックスとクラスのスコアに変換します。
検出ヘッドは物体検出ネットワークの最終層群です。前段の層が生成した特徴マップを受け取り、各候補位置についてバウンディングボックスとクラスごとのスコアを出力します。その設計によって、ボックスをアンカーボックスからのオフセットとして符号化するか、点からの距離として符号化するか、モデルが生成する候補ボックスの数、さらに非最大値抑制 (NMS)などの後処理で重複を除去する必要があるかが決まります。
ヘッドの配置#
現代の検出器は3つの段階で構成されます。バックボーンは、通常畳み込みネットワークまたはビジョントランスフォーマーであり、ピクセルを特徴マップに変換します。深くなるにつれて解像度は下がり、意味的な情報は増加します。特徴ピラミッドネットワーク (FPN)などのネックは、深い層と浅い層のマップを統合し、各出力スケールに細部とコンテキストの両方を持たせます。次にヘッドが通常ストライド8、16、32の各ピラミッドレベルで小規模な畳み込みブランチを実行し、細かなマップで小さな物体を、粗いマップで大きな物体を検出します。
1段階検出器は、すべてのグリッドセルで予測する単一の高密度ヘッドを備えています。Faster R-CNNなどの2段階検出器は2つのヘッドを備えています。1つはすべての位置でアンカーを評価する領域提案ネットワークで、もう1つは提案された数百個の領域を分類・調整する関心領域ヘッドです。
ヘッドがボックスとクラスを予測する仕組み#
高密度ヘッドは各グリッドセルで3種類の値を予測します。
- クラススコア: クラスごとに1つのスコアを出力し、それぞれにシグモイドを適用するため、位置ごとに各クラスを独立して評価できます。
- ボックス回帰: ボックスを配置する4つの数値です。アンカーボックスを移動・サイズ変更するオフセット、またはセルの中心からボックスの4辺までの距離を使います。
- 品質スコアとタスク出力: ボックスをランク付けするオブジェクトネススコア (YOLOv1からYOLOv5) または中心性スコア (FCOS) に加え、インスタンスセグメンテーション用のマスク係数や姿勢推定用のキーポイントなど、タスク固有の値です。
ボックスの符号化方式が、アンカーベース検出器とアンカーフリー検出器を区別します。各ブランチは数層の畳み込みで構成され、最後に予測値ごとに1つの出力チャンネルを持つ1 × 1畳み込みを適用します。RetinaNetとFCOSはすでに分類ブランチと回帰ブランチを分離しており、YOLOXは2021年にこの分離型ヘッドをYOLOに導入し、YOLOv3の単一共有出力層と比べて学習の収束が大幅に速いと報告しました。以下のスケッチでは、640 × 640画像の3つのピラミッドレベルに対する最終的な1 × 1層を構築し、その出力を1つの候補リストに平坦化します。
import torch
from torch import nn
# Neck outputs for a 640x640 image at strides 8, 16, and 32 (80x80, 40x40, and 20x20 grids)
channels = (64, 128, 256)
features = [torch.randn(1, c, 640 // s, 640 // s) for c, s in zip(channels, (8, 16, 32))]
# Decoupled head: a box branch (4 values) and a class branch (80 scores) for every pyramid level
box_branches = nn.ModuleList(nn.Conv2d(c, 4, 1) for c in channels)
cls_branches = nn.ModuleList(nn.Conv2d(c, 80, 1) for c in channels)
# Flatten each level's grid and concatenate, giving one candidate per grid cell
boxes = torch.cat([branch(f).flatten(2) for branch, f in zip(box_branches, features)], dim=2)
scores = torch.cat([branch(f).flatten(2) for branch, f in zip(cls_branches, features)], dim=2).sigmoid()
print(f"boxes {tuple(boxes.shape)}, class scores {tuple(scores.shape)}")boxes (1, 4, 8400), class scores (1, 80, 8400)が出力されます。6,400 + 1,600 + 400個のグリッドセルが、それぞれ80個のクラススコア付きボックスを1つずつ提案します。
生の出力から検出結果へ#
学習時に、各物体に対する予測数を決定します。1対多割り当てでは、各物体の近くにある複数のセルを正例とするため、ヘッドがより多くの学習シグナルを得られます。推論時には物体ごとに重複したボックスが複数残るため、NMSで最良のボックスを選びます。DETRとYOLOv10の推論ヘッドが採用する1対1割り当てでは、物体ごとに予測を1つだけ学習するため、出力にNMSは不要です。
YOLO26のヘッドは4辺までの距離を直接予測します。これにより、YOLOv8とYOLO11が使用していた、辺ごとの16ビンのDistribution Focal Loss出力を廃止しています。また、ボックスとクラスの各ブランチを1対多用と1対1用にそれぞれ学習します。YOLO26はデフォルトで1対多出力にNMSを適用しますが、nms=Falseを渡すと1対1ブランチに切り替わり、画像ごとに最大300個のボックスをNMSなしで返します。
実際のヘッド設計#
- 新しいクラスへのファインチューニング: クラスブランチの最終層はクラスごとに1つの出力チャンネルを持つため、クラス数が異なるデータセットで学習するには、新しい分類層が必要です。事前学習済みのバックボーンとネックの重みは引き継げます。
- デプロイ: ヘッド内のすべての演算はターゲットデバイス上で実行されるため、シンプルなボックスデコードとNMS不要の出力によってエクスポートが容易になり、後処理時間も短縮できます。
- 小さな物体: ストライド4のピラミッドレベルを追加すると、追加の計算コストと引き換えに、小さな物体向けのより細かなグリッドがヘッドに与えられます。640 × 640の入力では160 × 160 = 25,600個のセルが追加され、ストライド8のレベルの4倍に相当します。










