W&Bの高度な可視化機能その① (イメージオーバーレイ編)
こんにちは。Weights & Biases Japanの山本です。コンピュータビジョンは機械学習における主要な領域の一つですが、皆様は画像データを普段どのように保存してどのように分析されているでしょうか?一番良くないのは、ストレージの画像フォルダに画像がごちゃっと入っていてただそれだけという状態で、これでは分析を行うことが困難です。
もう少し改善された状況としては、その画像IDやファイルパスなどでその他の各種メタデータを含む構造化データと紐づけられているというもので、例えばそれらをカラムとして含むDataFrameに対してグルーピングやフィルタリグを適用しつつNotebook上で可視化することで様々な切り口からの分析が可能となり、深いインサイトを得ることができるようになります。しかし、分析コードと可視化コードを毎回書いていては効率面ではあまり良いとは言えず、また手元で可視化していたのでは得られたインサイトをチームに波及させることも困難です。
そこで、本稿ではこうした非構造化データを含む分析に非常に有効なW&B Tableのマルチメディアサポートについてご紹介したいと思います。W&B Tableは通常の静止画以外にマスクやバウンディングボックスとセットで保存してクラスごとにON/OFFなども可能なイメージオーバーレイ、3Dポイントクラウド、分子構造やタンパク質の立体構造、MatplotlibやPlotlyなどのプロットや動画、音声など幅広くサポートしています。
まずはマスクあり画像のイメージオーバーレイの例をご紹介します。基本的なロギングの仕方は以下の通りで、通常の画像のロギングに加えてmasksの設定を追加するだけです。この例では"predictions"のマスクのみを与えていますが、"ground_truths"も追加して予実差を様々な角度から分析するということももちろん可能です。
import wandb
import numpy as np
from PIL import Image
# クラスラベルを定義します。
class_labels = {
1: "tree",
2: "car",
3: "road"
}
# マスクデータを定義します。
mask_data = np.array([
[1, 2, 2, 2, 2, 1],
[1, 3, 3, 3, 3, 1]
])
# イメージをロードします。
image = Image.open("sample_image.png")
# wandbイメージオブジェクトを作成します。
mask_img = wandb.Image(
image,
masks={
"predictions": {
"mask_data": mask_data,
"class_labels": class_labels
}
}
)
# wandbにログします。これは画像単独でログする例
wandb.log({"image": mask_img})
# 画像をTableに格納してログする場合のイメージ
table = wandb.Table(columns=["id", "image", "data"])
# wandb.Tableにデータを追加していく
for idx, (mask_img, data) in enumerate(zip(mask_imgs, data_list)):
table.add_data(idx, mask_img, data)
# wandb.Tableをログする
run.log({"my_table": table})
では、実際に得られたW&B Tableを用いて簡単な分析をしてみましょう。今回用いたコードとプロジェクトはこちらです(Colab, W&B Project)。得られたTableを見ると、Imageカラムに元画像と正解および推論結果のマスクが格納されていることがわかります。また、それ以外のカラムは各クラスに対応するIoU (Intersection over Union) スコアが入っています。
まず、スコアを見ると、"background", "road", "vehicle"の3大マジョリティクラスについてはある程度捉えられていそうですが、"traffic light", "person", "bicycle"はゼロが並んでいるのがわかります。実際に現物を確認してみましょう。Image欄をクリックすると、クリックした画像を拡大して確認することができます。また、その際に予測と実測のマスクに対してそれぞれのクラスごとの表示のON/OFFの切り替えも可能です。やはり、小さなオブジェクトは捉えられていないことがわかります。
まずはマイノリティクラスの中でも"bicycle"を見てみましょう。まずは"bicycle"がNaNでない行を抽出します。直接抽出しても良いのですが、ここではW&B Tableのメニューから"Insert 1 right"を選んでカラムを挿入し、"Column settings"で"bicycle"が含まれているかのブーリアン列を用意した上でGroupByしてみました。Imageカラムには"bicycle"を含むサンプルと含まないサンプルがそれぞれ3枚ずつ例示されています。
以下はそのうちの1枚について"bicycle"のマスクだけONにした状態のなのですが、人間の目で見てもどれが自転車なのかさっぱりわかりません。"bicycle"は数ピクセルしかないように見え、検出できなかったのも無理からぬことがわかります。
さて、気を取り直して、今度はマジョリティクラスを掘り下げてみましょう。テーブル右下のReset Tableをクリックして初期状態に一旦戻します。次に右上の歯車のアイコンをクリックして、表示をCombined TableからCombined Plotを選択します。X Dimはrow["road IoU"]、Y Dimはrow["vehicle IoU"]として、道路と自動車のスコアをそれぞれ縦軸横軸に取って散布図を表示することができます。道路も自動車も大きいオブジェクトで出現頻度も高いからか先ほどの自転車よりはだいぶ良く検出できていますが、プロットの左下原点付近にいずれもうまく検出できていないサンプルが2つあることがわかります。
なぜ、こんなにもスコアが低いのかみてみましょう。右上の歯車アイコンからCombined Tableに戻って、これらの両クラスに対する低スコアサンプルを抽出します。左上の▼アイコンをクリックして、以下のように条件を指定します。すると簡単に先ほどの2サンプルを抽出することができます。
row["road IoU"] < 0.1 and row["vehicle IoU"] < 0.1
1枚目の写真はかなり特殊で、写っている自動車はルーフ部分のみでかつ写り込みが激しいことがわかります。さらに、正解ラベルは画像の全面が"background"となっており、これでは良いスコアが出るわけがないことがわかります。
せっかくですので、もう一枚も見てみましょう。こちらは一見問題がなさそうにも見えるのですが、与えられているground_truthをよく確認すると、前面の"road"のはずの領域が"vehicle"に誤ってラベル付けされていることがわかります。
さらに、W&B Tableも当然W&B Reportに埋め込むことができますので、例えば本ブログの内容も簡単にレポートとしてチームで共有することができます。W&B Reportではスクリーンショットを貼り付けた単なるドキュメントとは異なり、ロギング結果や可視化結果を含むW&Bダッシュボード機能をそのまま共有できますので、チームメンバー全員がシェアされた結果をインタラクティブに確認することができます。これはインサイトを個人に留めることなくチームに波及させる上で大変重要です。
以上のように、マルチメディア対応のW&B Tableを活用することで非構造化データと構造化データを上手に組み合わせて様々な角度からデータや予測結果を簡単に分析することができ、得られたインサイトはモデルの精度改善にも非常に有用です。
なお、本レポートの内容はW&B Courses Effective MLOps: Model Development(日本語版コース名「効果的なMLOps:モデル開発」もあります。)の冒頭部分を題材にしています。こちらの無料のコースをご受講頂くことでリファクタリングやモデルの改善と最適化などの続きを楽しめますので是非ご受講ください。
この記事が気に入ったらサポートをしてみませんか?