Markdownで表示

インスタンスセグメンテーション

インスタンスセグメンテーションは各物体インスタンスの位置を特定し、検出器が返すボックス、クラス、スコアに加えて、物体ごとにピクセル単位のマスクを返します。タスクキーはsegmentです。

定義

インスタンスセグメンテーションは検出に形状を加えたものです。各物体インスタンスには引き続きボックス、クラス、スコアがあり、さらにその物体に属するピクセルを覆う二値マスクが追加されます。マスクは重なることができ、どの物体にも属さないピクセルは未割り当てのままです。この点がセマンティックセグメンテーションパノプティックセグメンテーションとの違いです。

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

predict()result.boxesとともにresult.masksを設定します。.dataは元画像のキャンバス上の(N, H, W)スタックで、ボックスと行が対応します。そのためマスクiはボックスiに属します。.xyは各マスクを最大の外輪郭であるピクセル単位の(P, 2)配列へ変換し、.xynは同じ輪郭を正規化して返します。

モデル

マスクの学習と推論の両方に対応するファミリーは4つです。RF-DETREdgeCrafterD-FINERTMDetです。RF-DETRには専用の追加パッケージpip install "libreyolo[rfdetr]"が必要で、他の3つは基本パッケージで実行できます。

Mask R-CNNはマスクの推論、検証、エクスポートに対応しますが、train()NotImplementedErrorを送出します。

EoMTはマスクの推論と検証に対応しますが、学習はできません。エクスポートの範囲はさらに狭く、export()が受け付けるのはsemanticタスクだけです。segmentpanopticに必要なクエリマスクのランタイム契約が定義されていないため、これらではNotImplementedErrorを送出します。EoMTのインスタンスマスクはエクスポート済みグラフではなくPythonで使用してください。

別のグループはクラスリストではなくプロンプトからセグメンテーションします。クリック、ボックス、フレーズで物体を選び、モデルがそのマスクを返します。SAMSAM 2SAM 3MobileSAMEdgeTAMPicoSAM3がこの方法を使います。SenseNova-Visionも同様ですが、そのセグメンテーションは参照式で、1つの物体を指すフレーズを受け取ります。これらは固有のファクトリと追加パッケージを通して読み込まれ、正確な呼び出しは各モデルページに記載されています。

推論

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

Python
from libreyolo import LibreYOLO, SAMPLE_IMAGE # ファイル名の-seg接尾辞がマスクヘッドを選択するためtask引数は不要model = LibreYOLO("LibreDFINEn-seg.pt")result = model(SAMPLE_IMAGE, save=True) print(result.masks.data.shape)   # (N, H, W) 検出ごとに1つのマスクprint(result.boxes.xyxy.shape)   # (N, 4) 同じN行
CLI
libreyolo predict model=LibreDFINEn-seg.pt save=True \  source=https://raw.githubusercontent.com/LibreYOLO/libreyolo/release/libreyolo/assets/parkour.jpg
マスクの輪郭
from libreyolo import LibreYOLO, SAMPLE_IMAGE model = LibreYOLO("LibreDFINEn-seg.pt")result = model(SAMPLE_IMAGE) # .xyはピクセル単位の(P, 2)輪郭リスト .xynは正規化した同じ輪郭for name, contour in zip(result.boxes.cls, result.masks.xy):    print(result.names[int(name)], contour.shape)
別ファミリーでも同じ呼び出し
from libreyolo import LibreYOLO, SAMPLE_IMAGE model = LibreYOLO("LibreRTMDets-seg.pt")result = model(SAMPLE_IMAGE) print(result.masks.data.shape)

confmax_detは検出と同じように出力を絞り込み、マスクも対応するボックスとともにフィルタリングされます。入力ソース、ストリーミング、結果の処理については推論を参照してください。

データセット形式

配置は検出と同じです。画像ごとに1つの.txtラベルファイルを使用し、画像パス内のimageslabelsへ置き換えて拡張子を変更し、ファイルを検索します。

dataset/
  data.yaml
  images/
    train/000001.jpg
    val/000101.jpg
  labels/
    train/000001.txt
    val/000101.txt

異なるのは行の内容です。セグメントはクラスインデックスの後に平坦化したポリゴンを記述します。

<class_id> <x1> <y1> ... <xN> <yN>

点は3つ以上必要なので、クラスインデックス後の座標数は6以上の偶数となり、ポリゴンは退化していない必要があります。座標は元画像の幅と高さに対する[0, 1]範囲の浮動小数点数です。5フィールドの検出行もセグメンテーションデータセット内で受け付け、長方形のセグメントとして読み取ります。そのため、ボックスだけのデータセットも変換処理なしで読み込めます。

YAMLは検出用YAMLと同じです。

yaml
path: dataset
train: images/train
val: images/val
names:
  0: person
  1: bicycle

ネイティブのCOCO JSONも使用できます。分割名とJSONファイルのannotationsマッピングを追加すると、分割パスが画像ルートになります。

学習

Python
from libreyolo import LibreYOLO # マスクヘッドを含む公開済みセグメンテーション重みから続ける# dataはポリゴンを持つラベルのデータセットを指す必要があるmodel = LibreYOLO("LibreDFINEn-seg.pt")model.train(data="my-dataset.yaml", epochs=50, imgsz=640, batch=8, lr0=2e-4)
CLI
libreyolo train model=LibreDFINEn-seg.pt data=my-dataset.yaml \  epochs=50 imgsz=640 batch=8 lr0=2e-4
検出用重みから開始
# 検出用重みにはマスクヘッドがないため明示的な転移となり# ヘッドは未学習状態から始まる task=segmentの指定がこれを許可するlibreyolo train model=LibreDFINEn.pt data=my-dataset.yaml \  task=segment epochs=50 imgsz=640

学習はデフォルトで公開済みの-segチェックポイントから続行します。検出用重みから始めることもできますが、意図的な転移として扱われます。その重みにはマスクヘッドがないため未学習状態から始まり、task=segmentを渡すことで入れ替えを許可します。データセット、データ拡張、マルチGPU、ロガーについては学習を参照してください。

検証

val()metrics/キーを持つ通常の辞書を返します。ボックスとマスクはどちらもCOCO評価で別々に採点され、マスクの数値が主要な結果です。

Python
from libreyolo import LibreYOLO model = LibreYOLO("LibreDFINEn-seg.pt")metrics = model.val(data="my-dataset.yaml") print(metrics["metrics/mAP50-95"])       # マスクprint(metrics["metrics/mAP50-95(M)"])    # 明示的なマスクprint(metrics["metrics/mAP50-95(B)"])    # ボックス
CLI
libreyolo val model=LibreDFINEn-seg.pt data=my-dataset.yaml

接尾辞なしのキーにはマスクの結果が格納されます。metrics/mAP50-95metrics/mAP50metrics/mAP75、物体面積別のmetrics/mAP_smallmetrics/mAP_mediummetrics/mAP_large、平均再現率のmetrics/AR1metrics/AR10metrics/AR100metrics/AR_smallmetrics/AR_mediummetrics/AR_largeです。metrics/AR_max_detmetrics/max_detには実行時に使った検出上限が記録されます。

どの数値をファミリーが主要としたかに依存せず比較できるよう、4つの数値はマスクを表す(M)とボックスを表す(B)の明示的な接尾辞付きでも公開されます。metrics/mAP50-95(M)metrics/mAP50-95(B)metrics/mAP50(M)metrics/mAP50(B)metrics/precision(M)metrics/precision(B)metrics/recall(M)metrics/recall(B)です。このタスクには接尾辞なしのmetrics/precisionmetrics/recallはありません。

適合率と再現率のキーは注意して解釈してください。後方互換性のために維持された別名であり、ある運用点の値ではありません。metrics/precision(M)metrics/mAP50-95(M)と同じ値を、metrics/recall(M)は検出数100でのマスク平均再現率と同じ値を保持します。(B)もボックスについて同様です。この2つをペアとして描画すると同じ数値を二重に報告することになります。

エクスポート

Python
from libreyolo import LibreYOLO model = LibreYOLO("LibreDFINEn-seg.pt")model.export(format="onnx", imgsz=640)
CLI
libreyolo export model=LibreDFINEn-seg.pt format=onnx imgsz=640
エクスポートしたファイルを使用
from libreyolo import LibreYOLO, SAMPLE_IMAGE # ファクトリはファイルの拡張子に応じて振り分けるためエクスポートした# アーティファクトもチェックポイントと同様に読み込まれ同じResultsオブジェクトを返すmodel = LibreYOLO("LibreDFINEn-seg.onnx")result = model(SAMPLE_IMAGE) print(result.masks.data.shape)

エクスポートしたアーティファクトはファイルの拡張子に基づいてLibreYOLO()で再読み込みできるため、.onnx.engineファイルもチェックポイントと同様に動作し、同じResultsを返します。同じファミリーでもセグメンテーションの対応形式は検出より狭くなります。各モデルページのマトリックスは検証済みの集合から生成され、利用できない理由も示します。形式、追加パッケージ、制約についてはエクスポートとデプロイを参照してください。

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