W&Bの高度な可視化機能その① (イメージオーバーレイ編)
Created on January 8|Last edited on September 2
Comment
こんにちは。Weights & Biases Japanの山本です。コンピュータビジョンは機械学習における主要な領域の一つですが、皆様は画像データを普段どのように保存してどのように分析されているでしょうか?一番良くないのは、ストレージの画像フォルダに画像がごちゃっと入っていてただそれだけという状態で、これでは分析を行うことが困難です。
もう少しマシな状態としては、その画像IDやファイルパスなどでその他の各種メタデータを含む構造化データと紐づけられているというもので、例えばそれらをカラムとして含むDataFrameに対してグルーピングやフィルタリグを適用しつつNotebook上で可視化することで様々な切り口からの分析が可能となり、深いインサイトを得ることができる用になります。しかし、分析コードと可視化コードを毎回書いていては効率面ではあまり良いとは言えず、また手元で可視化していたのでは得られたインサイトをチームに波及させることも困難です。

よくある画像データの分析例で、ここでは元画像とマスクを並べて可視化している
そこで、本稿ではこうした非構造化データを含む分析に非常に有効なW&B Tableのマルチメディアサポートについてご紹介したいと思います。W&B Tableは通常の静止画以外にマスクやバウンディングボックスとセットで保存してクラスごとにON/OFFなども可能なイメージオーバーレイ、3Dポイントクラウド、分子構造やタンパク質の立体構造、MatplotlibやPlotlyなどのプロットや動画、音声など幅広くサポートしています。

多様なマルチメディアデータをサポートするW&B Table機能
まずはマスクあり画像のイメージオーバーレイの例をご紹介します。基本的なロギングの仕方は以下の通りで、通常の画像のロギングに加えてmasksの設定を追加するだけです。この例では"predictions"のマスクのみを与えていますが、"ground_truths"も追加して予実差を様々な角度から分析するということももちろん可能です。
import wandbimport numpy as npfrom 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) スコアが入っています。
Run set
37
まず、スコアを見ると、"background", "road", "vehicle"の3大マジョリティクラスについてはある程度捉えられていそうですが、"traffic light", "person", "bicycle"はゼロが並んでいるのがわかります。実際に現物を確認してみましょう。Image欄をクリックすると、クリックした画像を拡大して確認することができます。また、その際に予測と実測のマスクに対してそれぞれのクラスごとの表示のON/OFFの切り替えも可能です。やはり、小さなオブジェクトは捉えられていないことがわかります。
正解データ
Run set
37
ベースラインモデルの予測結果
Run set
37
まずはマイノリティクラスの中でも"bicycle"を見てみましょう。まずは"bicycle"がNaNでない行を抽出します。直接抽出しても良いのですが、ここではW&B Tableのメニューから"Insert 1 right"を選んでカラムを挿入し、"Column settings"で"bicycle"が含まれているかのブーリアン列を用意した上でGroupByしてみました。Imageカラムには"bicycle"を含むサンプルと含まないサンプルがそれぞれ3枚ずつ例示されています。
"bicycle"の有無でグルーピングした例
Run set
37
以下はそのうちの1枚について"bicycle"のマスクだけONにした状態のなのですが、人間の目で見てもどれが自転車なのかさっぱりわかりません。"bicycle"は数ピクセルしかないように見え、検出できなかったのも無理からぬことがわかります。
Run set
37
さて、気を取り直して、今度はマジョリティクラスを掘り下げてみましょう。テーブル右下のReset Tableをクリックして初期状態に一旦戻します。次に右上の歯車のアイコンをクリックして、表示をCombined TableからCombined Plotを選択します。X Dimはrow["road IoU"]、Y Dimはrow["vehicle IoU"]として、道路と自動車のスコアをそれぞれ縦軸横軸に取って散布図を表示することができます。道路も自動車も大きいオブジェクトで出現頻度も高いからか先ほどの自転車よりはだいぶ良く検出できていますが、プロットの左下原点付近にいずれもうまく検出できていないサンプルが2つあることがわかります。
Run set
37
なぜ、こんなにもスコアが低いのかみてみましょう。右上の歯車アイコンからCombined Tableに戻って、これらの両クラスに対する低スコアサンプルを抽出します。左上の▼アイコンをクリックして、以下のように条件を指定します。すると簡単に先ほどの2サンプルを抽出することができます。1枚目の写真はかなり特殊で、写っている自動車はルーフ部分のみでかつ写り込みが激しいことがわかります。さらに、正解ラベルは画像の全面が"background"となっており、これでは良いスコアが出るわけがないことがわかります。せっかくですので、もう一枚も見てみましょう。こちらは一見問題がなさそうにも見えるのですが、与えられているground_truthをよく確認すると、前面の"road"のはずの領域が"vehicle"に誤ってラベル付けされていることがわかります。
row["road IoU"] < 0.1 and row["vehicle IoU"] < 0.1
Run set
37
以上のように、マルチメディア対応のW&B Tableを活用することで非構造化データと構造化データを上手に組み合わせて様々な角度からデータや予測結果を簡単に分析することができ、得られたインサイトはモデルの精度改善にも非常に有用です。
なお、本レポートの内容はW&B Courses EffectiveのMLOps: Model Developmentの冒頭部分を題材にしています。こちらの無料のコースをご受講頂くことでリファクタリングやモデルの改善と最適化などの続きを楽しめますので是非ご受講ください。日本語版コース「効果的なMLOps:モデル開発」もあります。
Add a comment