7.12. 後処理

検出ネットワークはボックスを出力しません。出力するのは、モデルが学習されたアーキテクチャに応じてレイアウトが異なる1つ以上のテンソルです。YOLO系の検出器では候補予測の2次元テンソル、MediaPipe検出器では (boxes, scores) のテンソルのペア、ポーズネットワークではキーポイント座標のフラットなリストといった具合です。アプリケーションはこれらを直接読み取ることはできません。アプリケーションが求めるもの(ボックスのリスト、キーポイントのリスト、クラスごとの内訳)は、生のテンソルから デコード する必要があります。

そのデコーダが 後処理 です。ml.postprocessing モジュールはそれらをソースのエコシステムごとにまとめています。

7.12.1. Darknet

ml.postprocessing.darknet は初期のYOLO時代のモデルをデコードします。YOLO v2は、その後の多くの検出器が何らかの形で継承した グリッドアンカー の考え方を導入したため、v2のレイアウトが最もわかりやすい出発点です。

YOLO v2は、まず入力画像を粗いグリッドに分割します。標準的な416ピクセルの入力では13×13のレイアウト、小さいモデルではより小さくなります。そして、各グリッドセルが、その中心が含まれるあらゆる物体の検出を担当するようにネットワークを学習させます。出力テンソルの空間的レイアウトは入力のレイアウトを反映しており、画像内の各セルにつき出力に1つの位置が対応します。

各グリッドセルにおいて、ネットワークは何もないところからボックスを予測するわけではありません。アンカー と呼ばれる、あらかじめ選ばれたいくつかの参照形状から選択します。これは固定の (width, height) のペアで、モデルが見ると予想される典型的な物体をカバーするように、学習セット内のボックスサイズをクラスタリングしてオフラインで導出されます。各セルでのネットワークの役割は、各アンカーについて、セル内のボックス中心への小さなオフセット、アンカーの幅と高さに対するスケール、objectness スコア(何かが存在する尤度)、そしてクラスごとの確率ベクトルを予測することです。したがって、デフォルトの5つのアンカーと20クラスを持つ13×13グリッドは、推論ごとに 13 * 13 * 5 * (4 + 1 + 20) = 21,125 個の数値を出力します。

YoloV2 はそのレイアウトをデコードします。セルをたどり、各アンカーのオフセットとスケールを適用して絶対的なボックス座標を復元し、objectnessとクラス確率を組み合わせてクラスごとのスコアを求め、しきい値処理を行い、生き残ったものをNMSに渡します。このクラスは、モデルがカスタムアンカーテーブルで学習された場合に anchors= コンストラクタ引数を取り、そうでない場合は組み込みのデフォルトにフォールバックします。特定のクラスセット向けに調整されたバリアントが同じサブモジュールに含まれています。

7.12.2. Ultralytics

ml.postprocessing.ultralytics はより新しい世代のYOLOをデコードします。YoloV8 は列優先の出力を読み取ります。各列は1つのアンカー予測で、ボックス座標とクラスごとのスコアベクトルを保持します。以前のYOLO出力が持っていたobjectnessチャンネルはv8で削除され、クラススコアが単独で立っています。YOLOv8ウォークスルー ではデコードをテンソルごとに段階的に説明します。古いUltralytics時代のバージョンも、それらのレイアウトで学習されたモデル向けに同じサブモジュールに含まれています。

7.12.3. MediaPipe

ml.postprocessing.mediapipe はGoogleの軽量なオンデバイスファミリーをデコードします。BlazeFacehello-blazeface で扱った顔検出器です。高速なアンカーベースの検出器で、顔ごとにボックスと6つのランドマーク座標を出力し、ランドマークが別の出力リストとしてではなく各ボックスに付随した (box, score, keypoints) のタプルとして返されます。同じファミリーの手検出、ランドマーク、ポーズのモデルも一緒に含まれており、同じキーポイント付随型の戻り値の形状に従います。

7.12.4. 選択する

適切な後処理は、アプリケーションが求めるものではなく、モデルが学習されたアーキテクチャによって決まります。YOLOv8の .tfliteYoloV8 を通してのみ正しくデコードされ、BlazeFaceの .tfliteBlazeFace を通してのみ正しくデコードされます。後処理を選ぶことはモデルを選ぶことの一部です。モデルのアーキテクチャが出荷される後処理で表現されていない場合は、独自に記述する のは簡単です。

分類ネットワークは例外です。その単一の出力テンソルは、すでにアプリケーションが求めるもの(クラスごとのスコアのリスト)そのものであり、後処理は不要です。テンソルI/O で扱ったように、postprocess= なしでモデルをロードし、予測結果をフラットなndarrayとして読み取るのが適切な方法です。