Markdownで表示

パノプティックセグメンテーション

パノプティックセグメンテーションは、数えられる物体インスタンスと不定形の背景領域を統合し、各ピクセルを重なりのない1つのセグメントへ割り当てます。タスクキーはpanopticです。

定義

パノプティックセグメンテーションは他の2つのセグメンテーションタスクを統合したものです。各ピクセルは正確に1つのセグメントへ割り当てられ、セグメントは重なりません。セグメントはthing(数えられる物体インスタンス)か、stuff(空や道路などの不定形領域)のどちらかです。そのため、背景ピクセルを未割り当てのままにし、マスクの重なりを許すインスタンスセグメンテーションより厳密です。また、各ピクセルにラベルを付けるものの、同じクラスの接するインスタンスを統合するセマンティックセグメンテーションよりも厳密です。

panopticが標準タスクキーで、チェックポイントのファイル名にある-panoptic接尾辞が選択します。そのため、公開済みの重みを読み込むときにtask=は不要です。

predict()result.panopticを設定します。.dataは元画像のキャンバス上の(H, W)整数セグメントIDマップです。.segments_infoはセグメントごとの辞書リストで、各辞書には少なくとも{"id", "category_id"}が含まれます。idはマップ内の値と一致し、category_idresult.namesを参照します。.segment_idsは存在するIDを並べ替えたリスト、.segment_mask(id)は1つのセグメントを選択するブール値の(H, W)配列です。セグメントID0はvoid値です。ラベルのないピクセルとして指標から除外され、.segment_idsにも含まれません。

thingとstuffの区別は個々のセグメントではなくカテゴリーの属性です。ラベル集合のカテゴリーメタデータに保持され、推論ペイロードが便宜上各セグメントへ"isthing"としてコピーする場合もありますが、正式な情報源はカテゴリーメタデータです。

モデル

EoMTLibreYOLO()を通してこのタスクに対応するファミリーです。基本パッケージで実行でき、COCOで学習したs、b、lの3サイズのパノプティックチェックポイントを提供します。

SenseNova-Visionもパノプティックマップを出力します。固有のファクトリLibreVLMと固有の追加パッケージを持つプロンプト生成モデルです。ボキャブラリーを設定しない場合は、ファインチューニングに使ったCOCO panopticカテゴリーへフォールバックします。重みは非商用です。推論ごとに拡散デコードを実行するため、画像ごとのレイテンシは専用セグメンターよりはるかに長くなります。

推論

重みは初回使用時にHugging Faceからダウンロードされ、ローカルにキャッシュされます。

Python
from libreyolo import LibreYOLO, SAMPLE_IMAGE # ファイル名の-panoptic接尾辞がタスクを選択するためtask引数は不要model = LibreYOLO("LibreEoMTl-panoptic.pt")result = model(SAMPLE_IMAGE, save=True) pan = result.panopticprint(pan.data.shape)       # (H, W) セグメントIDprint(pan.segments_info)    # [{"id": ..., "category_id": ...}, ...]
CLI
libreyolo predict model=LibreEoMTl-panoptic.pt save=True \  source=https://raw.githubusercontent.com/LibreYOLO/libreyolo/release/libreyolo/assets/parkour.jpg
セグメントごとに処理
from libreyolo import LibreYOLO, SAMPLE_IMAGE result = LibreYOLO("LibreEoMTl-panoptic.pt")(SAMPLE_IMAGE)pan = result.panoptic for segment in pan.segments_info:    pixels = pan.segment_mask(segment["id"])   # boolean (H, W)    print(result.names[segment["category_id"]], int(pixels.sum()))
小型チェックポイント
from libreyolo import LibreYOLO, SAMPLE_IMAGE model = LibreYOLO("LibreEoMTs-panoptic.pt")result = model(SAMPLE_IMAGE) print(len(result.panoptic.segment_ids))

confはクエリ選択を絞り込みます。入力ソース、ストリーミング、結果の処理については推論を参照してください。

データセット形式

LibreYOLOはKirillovら(CVPR 2019)のCOCO-panoptic形式をそのまま採用しています。LibreYOLO固有のパノプティック配置はありません。

dataset/
  data.yaml
  images/
    val/000000000139.jpg
  annotations/
    panoptic_val.json
    panoptic_val/000000000139.png

各画像は同じ解像度の1枚のRGB PNGと対応付けられ、各ピクセルの色が所属するセグメントのIDをエンコードします。

segment_id = R + 256 * G + 256 * 256 * B

セグメントID0、つまりRGBの黒はvoidです。ラベルのないピクセルであり、推論結果への加点も減点もありません。それ以外の各ピクセルは正確に1つのセグメントへ属します。

JSONには画像ごとにセグメントID PNGと、その中のセグメントを記述します。

json
{
  "images":      [{"id": 139, "file_name": "000000000139.jpg"}],
  "annotations": [{"image_id": 139, "file_name": "000000000139.png",
                   "segments_info": [
                     {"id": 3226956, "category_id": 1, "area": 2840,
                      "bbox": [413, 158, 53, 138], "iscrowd": 0}]}],
  "categories":  [{"id": 1, "name": "person", "isthing": 1}]
}

annotations[].file_nameはパノプティックディレクトリ内のPNG名で、segments_info[].idはそのPNG内の値と一致します。iscrowdはグループ領域を示します。偽陰性として数えられることはなく、領域の大半を覆う推論も偽陽性になりません。isthingcategoriesにあり、個々のセグメントにはありません。

YAMLは両方を参照します。

yaml
path: dataset
val: images/val
annotations:
  val: annotations/panoptic_val.json
panoptic_dir:
  val: annotations/panoptic_val
names:
  0: person
  1: bicycle

annotationspanoptic_dirはそれぞれ単一パスまたは分割ごとのマッピングを受け付けます。生のCOCOカテゴリーIDは通常連続していませんが、モデルは連続する0..nc-1を予測するため、カテゴリー名に基づいてnamesを通してIDを再マッピングします。namesにないJSONカテゴリーは暗黙に破棄せずエラーになります。破棄すると恒常的な偽陰性として採点されるためです。

標準ローダーはlibreyolo.data.PanopticDatasetです。

学習

現在、LibreYOLO内でパノプティックセグメンテーションを学習できるファミリーはありません。EoMTのtrain()NotImplementedErrorを送出するため、パノプティックチェックポイントは公開済みの状態で使用します。

検証

val()はデータセットYAMLのvalで指定した分割に対して、正解解像度で計算したmetrics/キーを持つ通常の辞書を返します。同じカテゴリーの予測セグメントと正解セグメントはIoUが0.5を超えると一致し、その対応は一意です。

Python
from libreyolo import LibreYOLO model = LibreYOLO("LibreEoMTl-panoptic.pt") # val()はオブジェクトではなく通常のdictを返すmetrics = model.val(data="my-dataset.yaml") print(metrics["metrics/PQ"])print(metrics["metrics/SQ"], metrics["metrics/RQ"])print(metrics["metrics/PQ_things"], metrics["metrics/PQ_stuff"])
CLI
libreyolo val model=LibreEoMTl-panoptic.pt data=my-dataset.yaml

metrics/PQはPanoptic Qualityであり、主要な数値です。1つのカテゴリー内では2つの要素の積です。Segmentation Qualityは一致したセグメント間の平均IoUで、対応した形状がどれだけ揃っているかを示します。Recognition QualityはTP / (TP + 0.5 FP + 0.5 FN)で、対応自体のF1値です。見つけられたセグメント数を示します。この3つの数値は出現したカテゴリー間で平均され、metrics/PQmetrics/SQmetrics/RQとして報告されます。そのため、報告されるPQはカテゴリーごとの積の平均であり、報告された2つの平均値の積ではありません。

metrics/PQ_thingsmetrics/PQ_stuffは同じカテゴリーごとのPQをthingカテゴリーとstuffカテゴリーで別々に平均します。metrics/categoriesは出現し、平均対象になったカテゴリー数です。辞書にはPQ値のコピーであるfitnessも含まれます。

エクスポート

パノプティックチェックポイントはエクスポートできません。このタスクのクエリマスク出力にはランタイムのエクスポート契約がまだないため、export()NotImplementedErrorを送出します。EoMTのセマンティックタスクはエクスポートできます。セマンティックセグメンテーションエクスポートとデプロイを参照してください。

LibreYOLO v1.5.0で検証済みです。