Ultralytics YOLO27: ウェイトリストに登録する。
Get Started
レッスン中級

セマンティックセグメンテーション:すべてのピクセルにラベルを付ける

yolo26n-sem.pt でピクセル単位のクラスマップを予測し、カバー率の数値に変換してPNGクラスマップのデータセットを構築し、ピクセル精度に惑わされずにmIoUを読み取ります。

数える対象となるオブジェクトがない質問もあります。歩道のどのくらいが塞がれているか、畑のどのくらいが雑草か、走行可能な道路がどこで終わるか、といった質問です。セマンティックセグメンテーションは、ピクセルごとに1つのクラスIDを割り当ててこれらに答えます。ただし、主要な指標は誤解しやすいものです。このレッスンで学習するモデルは、人物を1人も検出できないにもかかわらず、ピクセル精度が91%になります。

成果

yolo26n-sem.pt のクラスマップを使ってフレーム内の領域のカバー率を算出し、Cityscapes8で学習して、mIoU、ピクセル精度、およびモデルが見逃すクラスを報告します。

短期集中コース
すでに使い方をご存じの方は、こちらをご覧ください。
  1. yolo26n-sem.pt で予測し、result.semantic_mask.data を読み取ります。これは元のサイズのクラスIDを格納した H × W テンソルで、255は無視を意味します。

  2. result.names のクラスIDとクラスマップを比較して、カバー率に関する質問に答えます。

  3. masks/ 以下にラベルを可逆PNGクラスマップとして保存し、images/ と同じ構成を反映させ、YAMLには masks_dir: masks を指定します。

  4. リリースの判定にはmIoUとクラスごとのIoUを使い、ピクセル精度だけで判定しないでください。

実践的

インスタンスですか、それともセマンティックですか?#

各ピクセルが道路、歩道、自動車、人物、自転車、植生、建物、空のクラス別に色分けされた、街路のセマンティックセグメンテーション

インスタンスセグメンテーション(segment)セマンティックセグメンテーション(semantic)
出力オブジェクトごとに1つのマスクとバウンディングボックスピクセルごとに1つのクラスID
オブジェクトをカウントするはいいいえ — 接触している2台の車は1つの「車」領域です
「もの」(道路、空、草)を扱う不得意 — 自然なインスタンスがありませんはい
ラベルポリゴンPNGクラスマップ、またはポリゴン
ゲート指標マスクmAP50-95mIoU
事前学習済み重みyolo26n-seg.pt(COCO、80クラス)yolo26n-sem.pt(Cityscapes、19クラス)
数を知りたいのか、量を知りたいのか?

下流の質問に「いくつ」が含まれる場合は、インスタンスセグメンテーションを使ってください。「どれくらい」や「どこ」が問われる場合は、セマンティックセグメンテーションのほうがラベル付けも読み取りも簡単です。セマンティックセグメンテーションのタスクページにモデル一覧があります。

クラスマップを予測する#

result.semantic_mask.data は元の画像サイズの H × W テンソルです。各値はクラスIDで、255は無視を意味します。result.summary() を使うと、クラスごとのピクセル比率を算出できます。

from ultralytics import YOLO

model = YOLO("yolo26n-sem.pt")  # Cityscapes, 19 classes
result = model("https://ultralytics.com/images/bus.jpg")[0]

class_map = result.semantic_mask.data  # H x W tensor of class ids, 255 = ignore
print("class map:", tuple(class_map.shape), class_map.dtype)
for row in result.summary():
    if row["pixel_ratio"] >= 0.02:
        print(f"{row['name']:12s} {row['pixel_ratio']:.1%}")
class map: (1080, 810) torch.uint8
road         27.5%
sidewalk     2.0%
building     19.3%
vegetation   4.5%
person       14.6%
train        30.9%

最後の行を確認してください。Cityscapesには bus クラスがありますが、モデルはバスを train と判定します。主にドイツの道路を車載カメラで撮影した映像から学習しているため、歩道から近距離で撮影されたバスはその分布の範囲外です。セマンティックモデルは、検出モデルよりも学習データの撮影視点やクラス定義、つまりデータセットバイアスを強く引き継ぎます。そのため、マップを信頼する前に、自分のカメラでファインチューニングしてください。

クラスマップから答えを導き出す#

クラスマップは、単純なテンソル比較で製品上の数値に変換できます。ここでは、「歩行者が進む領域のうち、道路または歩道が占める割合と、人が占める割合はどれくらいか」を求めます。

from ultralytics import YOLO

result = YOLO("yolo26n-sem.pt")("https://ultralytics.com/images/bus.jpg", verbose=False)[0]
class_map = result.semantic_mask.data  # H x W class ids at the original size, 255 = ignore
ids = {name: i for i, name in result.names.items()}

h = class_map.shape[0]
lower = class_map[h // 2 :]  # the half of the frame a pedestrian would walk into
walkable = (lower == ids["road"]) | (lower == ids["sidewalk"])
people = lower == ids["person"]
print(f"lower half: {walkable.float().mean():.0%} road or sidewalk, {people.float().mean():.0%} person")
result.save("semantic_overlay.jpg")  # colored class map over the photo, for a visual check
lower half: 59% road or sidewalk, 23% person

これらの数値を信頼できるものにするには、次の3つの習慣が重要です。

  • IDは名前から検索します。 result.names から検索し、番号をハードコードしないでください。独自のクラスで学習したモデルでは、クラス番号が異なります。
  • 重要な領域に限定します。 フレーム全体の比率には空や建物も含まれます。最初にクラスマップをスライスするか、領域マスクを乗算します。
  • オーバーレイを開きます。 semantic_overlay.jpg を見れば、数値の算出に使われた「道路」が本当に道路かどうかをすぐに確認できます。

データセット形式#

セマンティックデータセットでは、各画像に、ピクセル値がクラスIDであるシングルチャンネルのマスク画像を組み合わせます。セマンティックデータセットガイドがリファレンスです。ディレクトリ構成は images/ をファイル単位で反映しています。

cityscapes8/
├── images/
│   ├── train/aachen_000000_000019.png
│   └── val/aachen_000004_000019.png
└── masks/
    ├── train/aachen_000000_000019.png
    └── val/aachen_000004_000019.png

YAMLには masks_dir が追加されます。また、マスクに格納されたIDが学習時のIDと異なる場合は、label_mapping ブロックも追加されます。

path: cityscapes8
train: images/train
val: images/val
masks_dir: masks # semantic mask directory

names:
  0: road
  1: sidewalk
  # ... 19 classes in total

label_mapping: # raw mask value -> training id
  0: ignore_label
  7: 0 # road
  8: 1 # sidewalk
  # ...

Cityscapesのマスクには、-1から33までの生のラベルIDが格納されています。マッピングではそのうち19個を維持し、残りは ignore_label に割り当てられ、255として保存されます。255に設定されたピクセルは、損失と指標の両方から除外されます。アノテーターが判断できなかった領域にも、同じ値を使用してください。

すでにポリゴンラベルがあり、masks_dir がない場合、ローダーがポリゴンをラスタライズし、未カバーのピクセルに background クラスを追加します。

マスクをJPEGで保存しない

非可逆圧縮では隣接するピクセル値が混ざり、クラス7とクラス8の境界が、7、8、および存在しないIDの混ざった状態になります。マスクはすべてPNGまたはTIFFで保存してください。

学習してmIoUを読み取る#

Cityscapes8には都市シーンの画像が8枚あり、学習用が4枚、検証用が4枚です。CPUでのスモークテストには十分です。

from ultralytics import YOLO

model = YOLO("yolo26n-sem.pt")
model.train(data="cityscapes8.yaml", epochs=1, imgsz=320, device="cpu")
metrics = model.val()
print(f"mIoU: {metrics.miou:.3f}  pixel accuracy: {metrics.pixel_accuracy:.3f}")
                 Class     Images     Pixels       mIoU     PixAcc
                   all          4     192315      0.415      0.906
                  road          4      78529      0.974      0.996
            vegetation          4      37602      0.844      0.936
                person          3        722          0          0
                 rider          1         21          0          0
mIoU: 0.415  pixel accuracy: 0.906

(クラスごとの行は省略しています。)ピクセル精度は91%ですが、mIoUは42%です。クラスごとの行を見ると、モデルは人物を1人も検出していません。これらはすべて正しい結果です。道路、建物、植生がピクセルの大部分を占めています。道路だけでも192,315ピクセル中78,529ピクセルです。そのため、これらのクラスをうまく塗り分けるモデルは、小さなクラスをすべて見逃しても高いピクセル精度を得られます。mIoUはクラスごとのIoUを等しい重みで平均するため、クラスを見逃すたびに値が下がります。

鳥を使ったIoU(Intersection over Union)の図:バウンディングボックスとマスクの両方について、予測領域と正解領域の重なりをそれらの和集合で割った値

判断基準

mIoU と、製品が処理に使うクラスのIoUを基準にしてください。人物IoUが0の歩行者安全機能は、ピクセル精度がどのような値でも不合格です。

試してみる

自分で撮影した街路写真に対して semantic.py を実行し、面積が大きいクラスを3つ列挙します。walkable.py を調整して、写真のカバー率に関する質問を1つ解決します。たとえば、下半分に道路が占める割合を求めます。次に、cityscapes8.yaml で1エポック学習し、mIoU、ピクセル精度、およびIoUが0のすべてのクラスを記録します。

完了条件
以下のすべてを満たすと、レッスンは完了です。
  • 自分の画像についてクラスごとのピクセル比率と領域のカバー率を1つ算出し、保存したオーバーレイと照合しています。

  • 学習実行時のmIoUとピクセル精度を記録し、IoUが0のクラスを列挙しています。

  • この実行でピクセル精度がmIoUより高い理由を、1文で説明できます。

解答を表示

今回の実行では、mIoUは0.415、ピクセル精度は0.906でした。wall、person、rider、motorcycle、bicycleのIoUは0で、4枚の検証画像にピクセルが存在しないクラスもすべてIoUが0でした。

ピクセル精度が高いのは、ピクセル数を基準に数えるためです。Cityscapesの各フレームの大部分は、道路、建物、植生、空で占められています。mIoUは各クラスを等しい重みで評価するため、見逃した5つの小さなクラスは、数百ピクセルしか占めていなくても平均値を下げます。人物を対象に動作する製品では、personのIoUだけでこのモデルは判定基準を満たしません。

次のステップ

次に、領域ではなく点を扱い、ポーズモデルにラベルを付けて学習します。