🛩️

kaggle飛行機雲コンペ 上位解法まとめ

2023/08/15に公開

はじめに

衛星画像から飛行機雲のセグメンテーションを行うGoogle Research - Identify Contrails to Reduce Global Warmingというkaggleコンペが2023/8/10まで開催されていました。
コンペ終了後に公開された上位解法からたくさん学びがあったので、備忘録も兼ねてまとめていきたいと思います。

コンペ概要

  • 衛星画像から、飛行機雲のピクセル領域を予測するモデルの精度を競うコンペでした。
  • 画像データとしてはband8〜band16の9つのマルチスペクトル画像が提供されています。画像は10分間隔の連続7フレームが各サンプルごとに提供されていますが、推論対象となるのは4フレーム目のみであり、GTも4フレーム目に対してのみ提供されています。
  • 各画像は4人以上のアノテータによってラベリングされており、50%以上のアノテータが飛行機雲と判断したピクセルが最終的にGround Truthとみなされます。コンペデータとしては、各アノテータごとのマスク(individual_mask)と、それを集約した最終的なマスク(human_pixel_mask)が与えられています。
  • 詳細が知りたい方はコンペのデータタブを確認してください。

上位チーム解法まとめ

1. Data

色空間

  • 多くのチームはfalseRGB(AshColor)画像を使用していました。実際のアノテータもこの色空間に変換したスペクトル画像でアノテーションをしていたため、上位に限らず公開ノートブックのほとんどもこの色空間画像を使った学習を行なっていました。
falseRGB = [band15-band14, band14-band11, band14]
  • ただし、いくつかのチームは全てのバンド画像を用いたデータで学習を行なうことで精度改善を実現することができたようです。
    • 11ch(band15-band14, band14-band11, band8~band16)画像で、約100epoch学習させることでfalse RGBよりも精度が改善した。(引用:6th solution
    • スペクトルを直交化した独自の色空間画像を使用することで、0.007~0.008程度のスコア向上が見られた。(引用:7th solution

マスクの0.5ピクセルズレ

  • 今回提供されたデータは実は画像とマスクの位置が微妙に合っておらず、マスクが右下に0.5pixズレていました。今回のコンペではこの現象に気づくことができるかどうかが大きなキーとなっていました。

    • 要因としては、本コンペの座標系とopencvの座標系の定義が一致しておらず、ポリゴンをマスクに変換する際に0.5pixのズレが発生したものと考えられます。詳細はこちらのディスカッションがとても分かりやすかったです。
    • 通常であればほぼ誤差で(おそらく)無視できるレベルですが、今回のコンペの検出対象は非常に小さく細長く、数ピクセルの差でも大きな影響を及ぼしてしまうため対策が非常に重要でした。
    • この位置ズレを補正しないとflipやrot90などのaugmentationが機能しなくなってしまい、過学習を抑制できず精度を上げることが困難になってしまいます。
  • 画像またはラベルのどちらかをシフトさせることで位置を合わせて対応することができるようになります。

    • 1stソリューションはF.grid_sample()でマスクをシフトさせながら拡大させて学習することで対応を行なっていました。こちらの場合、推論時にも予測したマスクを補正する必要があるので、Unetの後に補正用のconv層を追加することで対応をしていました。Unetはシフトしたマスク(y_sym)で学習を行い、追加したconv層は元のマスク(y)で学習させています。(引用:1st solution
    • 9thソリューションは画像の方をアフィン変換でシフトしながら拡大させることで対応を行なっていました。こちらの場合、推論時は同様の方法で画像を変換して予測を行うだけで良く、非常にシンプルな対策となっています。(引用:9th solution
  • 実際やってみると、目視確認だけで0.5pixのズレと原因に気づくことはかなり難易度が高いのですが、この現象に気づいた方は「flipやrot90をするとなぜか精度が下がる」という明らかに不可解な現象から、flipなしで学習させたモデルでflip画像を推論して誤差の傾向を掴むことで発見できたとのことです。

2. Model

アーキテクチャ

  • decoder部分はほぼ全てのチームがUnetを使用していましたが、組み合わせるencoderは各チーム様々なモデルを採用していました。
    • MaxViTが割と多くのチームでベストモデルとして採用されていた印象ですが、efficientNetV2やresnest、convnextなどを採用しているチームもいたので、ハイパーパラメータなどに依存するのかもしれません。
  • 2ndチームの見解として、このコンペでは(1)contrailがかなり細長いので大局的な特徴を捉えられること、(2)contrailの厚さが数ピクセルしかないので、ピクセルレベルでの予測精度が求められること、が特徴として挙げられ、(1)はTransformer、(2)は畳み込みネットワークやlocal attentionで対応ができるため、どちらの側面も持つCoaTやNeXtViTのような階層構造を持つTransformerが効果的だったのではないかと考察していました。(引用:2nd solution
  • 8thチームでは、OneFormerが強力なモデルとして紹介されていました。このモデルを用いることで、時系列を考慮しないシングルフレームモデルにも関わらず、単独で銀上位の精度を達成することができたそうです。(引用:8th solution

時系列モデル

  • 今回のコンペでは、連続フレーム画像を上手く活用して時系列情報を反映させるモデリングが有効であり、多くのチームが2.5Dセグメンテーションモデルを活用することで実現していました。(引用:2nd solution, 3rd solution, 5th solution, 6th solution

    • 基本的には、バッチ次元にフレーム次元を統合してencoderに通し、スキップ接続に3Dconvを連結することで2Dに戻してマスクを出力するアーキテクチャを採用していましたが、使用するフレーム数や3Dconvを接続する解像度などで各チーム若干モデリングの違いがありました。
  • 少し変わった手法として、1stチームはt=1,2,3,4の画像(512x512)を4つ並べた1024x1024画像を生成し、MaxViTのself-attentionで時間情報を反映させる方法を採用していました。本来は3DResNetやconvLSTMを組み込んだモデルを採用したかったが、上手く学習できなかったので空間的に時系列画像を並べてself-attentionが上手く時系列情報を反映してくれることを期待したとのことです。(引用:1st solution

3. Train

Soft Label

  • 多くのチームが各アノテータごとのアノテーション結果(individual_mask)の平均をSoftLabelとして使用する方法を採用していました。
  • 実際にindividual_maskを確認するとアノテータごとにマスクに結構差があり、ラベルがノイジーだったためSoftLabelが有効だったのではないかと考えられます。
  • 5thチームはindividual_maskをaux lossのように扱って精度向上を行なっていました。(引用:5th solution

Pseudo Label

  • 推論対象以外のフレーム画像に対して、擬似ラベルを付与して学習に回すことで精度を上げているチームもいくつかいました。(引用:3rd solution, 8th solution
  • ただ、fold平均を取るとPseudoLabelの利得がかなり小さくなるという結果のチームもいたようなので、モデルや学習スキームに依存する部分があるのかもしれません。(引用:1st solution

4. Predict

分類モデルを組み合わせたスクリーニング

  • 6thチームは、classificationモデルと2.5D segmentationモデルを組み合わせて、最初に画像中にcontrailが含まれるかどうかを分類して画像をスクリーニングしていました。スクリーニングの結果、contrailが含まれると判断された画像に対してのみ2Dセグメンテーションモデルやposデータのみで学習させた2.5Dセグメンテーションモデルを適用してアンサンブルすることで精度向上ができたようです。(引用:6th solution
  • この方法を採用することで推論時間に余裕ができて、重要な(contrailが含まれると予想される)画像に対して多くのセグメンテーションモデルを割り当てることが可能になるとのことです。

まとめ

実際に参加してみた所感とソリューションを読んだ私見になりますが、今回のコンペでキーになったのは「マスクのピクセルズレを発見できたかどうか」と「時系列を反映させるモデリング」だったように思います。
直感と反する結果が出た時に「よく分からない」と無視せずに、仮説を立てて結果を確認して原因を特定することや、タスクに対して有用な情報を上手くモデリングすることが、当たり前ですが非常に重要であることを再認識しました。
特に後者の方については、思いついた時にすぐに実験を回せるようにソースコードや基本的なアイデアを日頃からストックしておくことが大事なように思いました。このコンペでも多くの人がソースコードを公開してくれているので、もう少し自分なりに噛み砕いて理解しつつ、今後のコンペや業務での手数を増やしていきたいと思います。

Discussion