セマンティックセグメンテーション
セマンティックセグメンテーションは画像の各ピクセルにクラスを割り当て、同じクラスのインスタンス同士を区別しません。タスクキーはsemanticです。
定義
セマンティックセグメンテーションは物体ではなくピクセルにラベルを付けます。各ピクセルに1つのクラスIDを割り当てるため、画像内で2台の車が接していると、境界のない1つの車クラス領域になります。インスタンスを数えるのはインスタンスセグメンテーション、すべてのピクセルへラベルを付けながらインスタンスも分離するのはパノプティックセグメンテーションです。
semanticが標準タスクキーで、チェックポイントのファイル名にある-sem接尾辞が選択します。そのため、公開済みの重みを読み込むときにtask=は不要です。
predict()はresult.semantic_maskを設定します。.dataは元画像のキャンバス上の(H, W)整数クラスマップ、.classesは存在するIDを並べ替えたリスト、.class_mask(id)は1クラスを選択するブール値の(H, W)配列です。値255は無視ラベルです。クラスとして扱われず、損失と指標から除外され、.classesにも含まれません。
モデル
学習と推論の両方に対応するファミリーは3つです。SegFormer、LingBot-Vision、DINOv2です。SegFormerとLingBot-Visionは基本パッケージで実行でき、公開済みの重みがあります。DINOv2にはpip install "libreyolo[rfdetr]"が必要で、LibreYOLOがホストするチェックポイントはありません。アップストリームのバックボーンを読み込み、密なヘッドはランダム初期化から始まるため、すぐに使える推論器ではなく学習の出発点です。
さらに4つのファミリーが推論、検証、エクスポートに対応しますが、train()はNotImplementedErrorを送出します。FCN、DeepLabv3、PIDNet、EoMTです。
クラス集合はファミリーではなくチェックポイントごとに異なります。公開済みの重みは、ADE20Kの150クラスやCityscapesの19クラスなど、ほとんど共通点のないラベル空間を持つデータセットから得られています。何にラベルを付けられるかはチェックポイントのnamesで確認し、2つのチェックポイントを比較できるのは同じデータセットで学習した場合だけです。
推論
重みは初回使用時にHugging Faceからダウンロードされ、ローカルにキャッシュされます。
from libreyolo import LibreYOLO, SAMPLE_IMAGE # ファイル名の-sem接尾辞がタスクを選択するためtask引数は不要model = LibreYOLO("LibreSegformerb0-sem.pt")result = model(SAMPLE_IMAGE, save=True) mask = result.semantic_maskprint(mask.data.shape) # 元キャンバス上の(H, W)クラスIDprint(mask.classes) # 255を除く存在クラスIDを並べ替えたものlibreyolo predict model=LibreSegformerb0-sem.pt save=True \ source=https://raw.githubusercontent.com/LibreYOLO/libreyolo/release/libreyolo/assets/parkour.jpgfrom libreyolo import LibreYOLO, SAMPLE_IMAGE result = LibreYOLO("LibreSegformerb0-sem.pt")(SAMPLE_IMAGE)mask = result.semantic_mask for class_id in mask.classes: pixels = mask.class_mask(class_id) # boolean (H, W) print(result.names[class_id], int(pixels.sum()))from libreyolo import LibreYOLO, SAMPLE_IMAGE model = LibreYOLO("LibrePIDNets-sem.pt")result = model(SAMPLE_IMAGE) print(result.semantic_mask.data.shape)マップはピクセルごとのargmaxなのでNMS処理がなく、iouは効果を持ちません。SegFormer、PIDNet、その他の密な予測器では、confとmax_detをAPI互換性のため受け付けますが何もしません。EoMTは例外で、confがクエリ選択を絞り込みます。入力ソース、ストリーミング、結果の処理については推論を参照してください。
データセット形式
各画像は.txtラベルファイルではなく、密な単一チャンネルマスクと対応付けます。画像パス内のimagesをマスクディレクトリへ置き換えて検索します。
dataset/
data.yaml
images/
train/000001.jpg
val/000101.jpg
masks/
train/000001.png
val/000101.pngマスクは通常PNGの可逆圧縮単一チャンネル画像です。パレットモードのPNGはパレットインデックスとして読み込まれます。各ピクセル値は0..nc-1範囲のクラスID、値255は無視を意味します。マスク解像度は対応する画像と一致する必要があります。
YAMLでは共通契約に加えて2つのキーを使用します。
path: dataset
train: images/train
val: images/val
masks_dir: masks
nc: 19
names:
0: road
1: sidewalkmasks_dirはimagesの代わりに使うディレクトリ名で、デフォルトはmasksです。label_mappingは任意の{source_id: train_id}マッピングで、読み込み時にマスクのピクセル値へ適用されます。1から150の番号を使うデータセットを0から149へ変換する場合などに使用します。マッピングされていないソース値はすべて無視になり、各学習IDは0..nc-1範囲でなければなりません。
masks_dirを省略すると、ローダーはフォールバックへ切り替わります。通常のimagesからlabelsへの規約で解決したポリゴンラベルを読み込み時にラスタライズし、物体クラスの後にbackgroundクラスを追加するため、ncが1増えます。
標準ローダーはlibreyolo.data.SemanticDatasetです。
学習
from libreyolo import LibreYOLO model = LibreYOLO("LibreSegformerb0-sem.pt")model.train(data="my-dataset.yaml", epochs=160, imgsz=512, batch=8)libreyolo train model=LibreSegformerb0-sem.pt data=my-dataset.yaml \ epochs=160 imgsz=512 batch=8# ade20k.yamlには約1 GBのアーカイブ用ダウンロードスクリプトが# 埋め込まれているためデータがローカルになければ明示的な許可が必要libreyolo train model=LibreSegformerb0-sem.pt data=ade20k.yaml \ epochs=160 imgsz=512 batch=8 allow_download_scripts=Trueここでのimgszには検出器にはない制約があります。各ファミリーはパッチグリッドまたは出力ストライドに基づく除数を宣言し、imgszが割り切れない場合は、学習と検証の両方で実行前にValueErrorを送出します。除数はSegFormerで32、LingBot-VisionとEoMTで16、DINOv2で14、FCNとPIDNetで8です。データセット、データ拡張、マルチGPU、ロガーについては学習を参照してください。
検証
val()は、データセットYAMLのvalで指定した分割に対して計算したmetrics/キーを持つ通常の辞書を返します。
from libreyolo import LibreYOLO model = LibreYOLO("LibreSegformerb0-sem.pt") # val()はオブジェクトではなく通常のdictを返すmetrics = model.val(data="my-dataset.yaml") print(metrics["metrics/mIoU"])print(metrics["metrics/pixel_accuracy"])libreyolo val model=LibreSegformerb0-sem.pt data=my-dataset.yamlmetrics/mIoUは平均Intersection over Unionです。各クラスについて予測ピクセルと正解ピクセルの共通部分を和集合で割り、クラス間で平均します。主要な数値であり、学習中の最良エポック選択にも使用されます。metrics/pixel_accuracyは正しいクラスを割り当てたピクセルの割合ですが、大きな背景クラスによって高く見える場合があるため、比較にはmIoUを使用してください。255と記されたピクセルはどちらの指標にも含まれません。辞書にはmIoU値のコピーであるfitnessも含まれます。
エクスポート
from libreyolo import LibreYOLO model = LibreYOLO("LibreSegformerb0-sem.pt")model.export(format="onnx", imgsz=512)libreyolo export model=LibreSegformerb0-sem.pt format=onnx imgsz=512from libreyolo import LibreYOLO, SAMPLE_IMAGE # ファクトリはファイルの拡張子に応じて振り分けるためエクスポートした# アーティファクトもチェックポイントと同様に読み込まれ同じResultsオブジェクトを返すmodel = LibreYOLO("LibreSegformerb0-sem.onnx")result = model(SAMPLE_IMAGE) print(result.semantic_mask.data.shape)エクスポートしたアーティファクトはファイルの拡張子に基づいてLibreYOLO()で再読み込みできるため、.onnxや.engineファイルもチェックポイントと同様に動作し、同じResultsを返します。対応形式はファミリーごとに異なり、各モデルページのマトリックスは手入力ではなく検証済みの集合から生成されます。形式、追加パッケージ、制約についてはエクスポートとデプロイを参照してください。