Kaggle Grandmasterになったのでこれまでの参加コンペを振り返る

はじめに

機械学習コンペティションプラットフォームKaggleのコンペ「G2Net Detecting Continuous Gravitational Waves」にて、5枚目の金メダルを取得し、Kaggle Competitions Grandmaster (GM) となることができたので、振り返りです。

最後の1年は時間の限られるパパKagglerとしてある程度打算的にGMを目指していたので、まずその辺りの参加スタイルを紹介します。

最近のKaggle参加スタイル

  • 子供が寝た後21時過ぎからが主戦場。週の半分は自分が寝かしつけるのでそのまま寝てしまう確率が高い。その場合、夜中に起きて深夜まで頑張る
  • 短期チャレンジ・複数コンペ同時参加はしない
    • ちゃんと金を狙う、取れなかったときの言い訳を作らない
  • 本格的な参加タイミングは開催後1ヶ月くらい経ってから
    • EDAやdiscussionが充実して自身のベースライン検討に必要な情報が出揃い、ドキュメントやメトリックの不備がある場合も指摘・修正されていることが多い
      • 正直フリーライド的なスタイルなので今後恩返ししたい
  • 序盤
    • Discussion/code/データを眺めながらコンペの雰囲気を把握しつつアプローチを妄想する
      • アプローチを妄想するのはPC前じゃなくて良いのでお風呂とか、寝かしつけしながら想いを馳せたりする。だが考えている間に一緒に寝てしまう
    • 最初は自分でEDAはせず、voteの多いEDA notebookを中心に見る。Discussionもvoteの多いものから読む(重要そうな情報はメモしておく)
    • 何となく雰囲気がつかめてきたら自分のベースライン手法構築のための仮説検証を目的としたEDAを行う
  • 中盤
    • なるべくシンプルなベースラインからスタートして1つずつ改善を入れてCVスコアを上げていく
    • ある程度CVで自信のあるモデルができてからsub。これは個人的なこだわりで、最初のベースラインができたタイミングでsubするほうが効率は良さそう
    • やる気が出ないときや学習結果待ちのときに未読のdiscussionは全部読む。追加でコメントがされたものも全部読む。voteの少ないものでも重要なdiscussionがあったりする
        - 終了1ヶ月前くらいまでになるべくLBを上げて、チームマージを検討する
  • 終盤
    • これまでの延長上で大きなモデルを長時間学習しつつ、別のアプローチの検討も続ける
    • チームの場合は他のメンバーのアプローチと相補的なアプローチを重視
  • コンペ後
    • 終了前にsolutionを予め準備しておいて、コンペ終了後すぐ投稿する
      • 最近は金とかじゃなくてもちゃんと書くようにしている。コンペ終了直後に投稿するチームは少ない&まだ熱が残っているので読んでもらえる
    • 上位解法との差分を再現検証すべきだができていない。理想的にはなるべくシンプルなsingle modelでどこまでスコアを出せるかを考えるのが一番意味がありそう

それらしいことを書きましたが、なんだかんだソロのこだわりみたいなのがあり、ガンガンチームマージするのは苦手でそこまで打算的にはできませんでした。本記事のこれ以降は、初めてKaggleに参加してからGMになるまで、自分が真面目にやったコンペの思い出ポエムです。長文注意。

 

初コンペ参加

全く記憶がないのですが、Kaggleのアカウント作成自体は2016年の10月に行っていました。当時の所属はKDDIで、育休から復帰して事業部から研究所に帰任、2016年9月に博士号を取得した直後のタイミングなので、何か新しいことをやりたくなったのでしょうか。その後DeNAに転職しています。

初のコンペ参加は2018年5月、GLRの略称でシリーズ化されている、Google Landmark Recognition Challenge / Google Landmark Retrieval Challengeでした。ちょうど2018年4月にその時の所属であったDeNAでKaggle制度が導入されています。私自身はデータサイエンティスト職ではなかったので制度の対象外ですが、Kaggle自体には興味を持っていて、前職で画像検索の研究をしていたこともあり、@Seed57_cash さんに誘われて、@nardtree さんとともに参加しました。

初subの様子

結果ですが、Recognitionが27位、Retrievalが39位でした。1ヶ月弱の参加だったことを差し引いても、仮にも自分の専門分野だったこともあり悔しい思いをしました。他方、みんな元々専門家じゃないのにコンペ期間だけで一気にキャッチアップしてくるヤバい場所なんだな、と驚きました。ということで、これを機にKaggle依存が始まったようです。

なお、@nardtree さんに大規模処理のhelpをお願いしたら、簡易大規模システムみたいなのを構築して一晩でやってくれましたみたいなのが発生したのが衝撃的でした。

 

Quick, Draw! Doodle Recognition Challenge(2018年12月)

落書きコンペ。AIに自分が書いた落書きを認識させるゲーム、Quick, Draw!のデータセットを使った落書きのクラス分類を行うタスク。ラスタ画像ではなく、ベクタのストローク情報が与えられており、単に白黒のラスタ画像に変換する、筆順やストロークの方向を色情報に落とし込む等の色々なアプローチが考えられる面白いコンペです。

最初のコンペで短期決戦で脳汁出るのが楽しかったらしく、2週間くらいの短期参加でソロ銅の結果でした。業務でもコンペでもKerasを使ってきたのですが、そろそろKeras辛いみたいな感じになって、このコンペ以降はPyTorchに移行しました。

 

Humpback Whale Identification(2019年3月)

いわゆるクジラコンペ。クジラの尻尾画像が与えられ、そのクジラの個体識別を行う、顔認証ならぬ尻尾認証コンペです。

知人とやろうと話をしていたのですが、私自身はチームマージ期限ギリギリに独自モデルを初subしてミジンコのようなスコアを出しながらチームマージしてたようです。
ちょうどその頃、新卒採用の面接で顔認証をやっていた方とお会いして、顔認証では最近ArcFaceというのが良いらしいという話を聞き、早速クジラコンペで試してみたらうまくいったという思い出深い話があります。

チームメイトのほうはpublic notebookの手法をベースにしており、全くアプローチが違うのでアンサンブルでかなり伸び、なんと17位でフィニッシュでした。今から思うと非常にもったいない参加の仕方をしているのですが、この頃は短期でそこそこ良い結果を出すのが楽しいと思っていたようで、それじゃ勝てないなと言う感じです。


VSB Power Line Fault Detection(2019年3月)

電線コンペ。三相交流の電圧波形から、送電線の部分放電を検出するタスク。同僚の @Kenmatsu4 さんと参加。電圧波形から色々特徴抽出してCNNやLSTMでコネコネしていたけど、CV/LBが全く連動せず、メダル圏外。電線何も分からん。@Kenmatsu4 さんの選択しなかったラストサブが銀圏だったので申し訳ない気持ちでいっぱいでした。終了直前、鼻中隔湾曲症の手術で入院していたのですが、夜な夜な休憩スペースでずっとKaggleしていました。


Recursion Cellular Image Classification(2019年9月)

細胞コンペ。様々な低分子干渉RNA (siRNA) を利用してRNA干渉を行った細胞の分類を行うタスク。画像コンペに飢えていたのか、初期から参加していたようです。ベースラインモデルがハマったのと、RNA干渉実験を行ったプレート毎に277クラスが多くとも1回しか現れないというリークを使って割当問題を解いてラベルを最適化すると序盤に金圏に浮上することができました。

このコンペは何故か通常1週間前に設定されるチームマージ期限がコンペ開始後1ヶ月に設定されており、そのタイミングで更に上位のチームからチームマージの誘いがありました。悩んだ挙げ句、まだまだ先も長いしチームマージして頑張ることにしました。

終了半月前くらいにリーク情報が運営から公開されスコアが詰まりましたが、最終的に4位でフィニッシュし、Kaggle Masterになることができました。最終的な解法は、チームメンバーが学習した大量のモデルを使って、割当問題でラベルを最適化してpseudo labelで学習するのを繰り返すという力技でした。

 

Open Images 2019 - Instance Segmentation(2019年10月)

クソデカOpen Imagesデータセットを用いたコンペ。Object detection, instance segmentation, visual relationship detectionのタスクのコンペが3つ同時開催されました。Instance segmentation trackでmaskrcnn-benchmarkを動かすだけみたいな解法でソロ銀でした。

この同時3コンペで、同僚の @Schwert さんが金1銀2を取得して一夜にしてKaggle Masterになってました。そこまで潤沢な計算資源があるわけではない中、初期からコツコツ実験を重ねてのソロ金で本当に凄かった。5人+チームとGMばっかりの恐ろしいobject detection trackのLBを見て欲しいです。Instance segmentationも11位の銀で惜しかった。


Lyft 3D Object Detection for Autonomous Vehicles(2019年11月)

Lyftコンペ。自動運転のための物体検出タスクで、LiDARとカメラ画像のデータが与えられるが、6DoFを求めないといけないので基本的にLiDARメインとなる。LiDARデータを2.5D化してsegmentationタスクで解くという公開notebook的なアプローチでソロ銀。上位はpoint cloudからの物体検出手法をちゃんと使っていて、完全に負け。

なお、当時インターンに来てもらっていたpoint cloudからの物体検出のプロ @_yukke42_ さんにまだ参加しないんですかーとか煽っていたら一瞬で抜かれて3位入賞されてて凄すぎた。


RSNA Intracranial Hemorrhage Detection(2019年11月)

CT画像から頭蓋内出血のタイプを分類するコンペ。@Appian さんが終盤にめちゃくちゃ整った金圏出るレベルのrepoを公開されて、これのモデルでっかくしてアンサンブルしたら簡単にメダル取れるじゃんぐへへみたいな邪な気持ちで手を付けた記憶があります。中途半端にコンペ掛け持ちするのは駄目です。

最終的には、隣接するCTのスライス情報をうまく統合することが必要で、いっぱいshake downして銅で終了だったのはさておき、このときのAppianさんのrepoを参考に、自前のPyTorchテンプレートみたいなものが確立できたのがとても良かった。


Peking University/Baidu - Autonomous Driving(2020年1月)

車載カメラ画像から、写っている車両の位置・姿勢(6DoF)を推定するタスク。ちゃんと初期から取り組んで、初のソロ金を取得することができた思い出深いコンペです。年末年始に実家に帰っているときも、ド深夜に家族を起こさないようにトイレにこもってバグ取りしていた記憶があります。

車両の角度を精度良く求めるために、GTのカメラ座標系での角度ではなく対象の車両をカメラ中心に持ってきたときの角度とするようなことをしていたのですが、推論結果はカメラ座標系に戻さないといけなかったりして無駄にパイプラインが複雑になり、座標系のバグでひたすら辛かった時期がありました。ちなみに、scipy.spatial.transform.Rotation が、オイラー角、クォータニオン、回転行列が全て簡単に扱えてめちゃくちゃ便利です。最後のアプローチとして終了5日前に突貫で投入した、難しい奥行き推定だけをモデルを分けるというアプローチがうまくいったのがドラマチックでした。

最終的な解法はこちら


Bengali.AI Handwritten Grapheme Classification(2020年3月)

ベンガルコンペ。手書きのベンガル語の文字画像を分類するタスク。各文字は、grapheme root, vowel diacritics, consonant diacriticsという3種類のパーツから構成されており、それぞれのパーツのクラスを推定する必要があります。3種類のパーツのクラス分類をそれぞれ行ってもよいのですが、組み合わせである文字自体のクラス分類として解いたほうがLBが良かったので、そのアプローチで突き進みました。その結果、チーム組んで頂いた fnakamura さんと、sukekiyo さんを巻き込んでshake downしてしまった苦い思い出、教訓です。

Testにはtrainに存在しない組み合わせの文字も存在すると明記されていましたが、public/privateでそんなあからさまなsplitはしないだろうと思っていました。愚か。上位陣はちゃんとtrainに存在するかどうかを距離学習ベースで認識して処理を変える等をしていました。なお、反省会で飲みに行ったのはめちゃくちゃ楽しかったです。


ALASKA2 Image Steganalysis(2020年7月)

画像にこっそり埋め込まれた情報であるsteganographyが存在するかどうかを判定するタスク。学部の頃に画像に対する電子透かしの研究をしていたのと、前職で深層学習モデルに電子透かし埋め込むという一発芸研究をしたので、ドメイン知識はあるだろうということで参加。

同僚の @kzykmyzw さんと一緒にやりつつ、最後はひたすらチームマージの誘いを送りまくって勝った!と思ったら、6位→21位にshake downしてしまいました。完全にtrust CVゲーでした。Trust CVを心で理解しました。

オーバーフィットして喜んでいる姿をご覧ください。


Lyft Motion Prediction for Autonomous Vehicles(2020年11月)

Lyftコンペ。自動運転車両が、認識した周囲の車両が今後どう動くかという軌跡を予測するタスク。ドメインがモビリティということで、同僚5人でチームを組んで参加しました。データ量が膨大で、またデータフォーマット等をちゃんと把握するのが大変でした。それぞれの車両に、3つまで確信度付きで軌跡を予測できるのですが、この順不同の出力をどうするかとか色々考えていたのですが、全く本質ではなかったです。ちゃんと大量のデータを使い切るところがスタートラインだったようで、後半その辺りを頑張り始めたが間に合わずという感じで銀メダル。

チームメンバーとワイガヤしてできたのは楽しかった一方、私はほとんど貢献できず申し訳なかったり、チーム内でのモチベーションやコミットが偏るところが、最初からチームを組んでやる際の難しいところだなと実感したコンペでもありました。

この辺りまでが私のKaggleの前半という感じです。2020年〜2021年は組織が別会社に承継されたり、下の子が生まれたりで上記のコンペも含めあまり参加できなかった時期です。


NFL 1st and Future - Impact Detection(2021年1月)

NFLコンペ。ナショナル・フットボール・リーグのプレイ映像において、プレイヤーのヘルメット同士がぶつかったタイミングを予測するタスク。年末年始の短期チャレンジで参加。久しぶりにガッツリ手を動かせて楽しかった。


Sartorius - Cell Instance Segmentation(2021年12月)

細胞コンペ。3種類の細胞のインスタンスセグメンテーションタスク。大晦日が最終日という非人道的コンペ。検出しなければならない細胞が小さく大量に存在し、mmdetのデフォルトconfigだとこの状況に対応できないので、通常あまりいじらない部分のパラメータを変更する必要があるのが特徴でした。逆にその辺りをちゃんと設定して、細胞の種類毎のモデルを作って適切にconfのしきい値を調整すると、モデル自体はmask_rcnn_r50_fpnとかで銀圏上位に行ける感じでした。

Pseudo labelから後処理まで色々やることがあり、ソロだと辛いと感じていたので終了1ヶ月前くらいに、@Ocha_Cocoa さん、@tnkcoder さん、@tereka114 さんのチームにマージしてもらいました。そこで主力で使われてたmmdetを直接魔改造したCBNetV2が単体で強かったので、segmentationモデルでrerankするアプローチを試したり、GTのマスクがぶっ壊れているのを投稿時にも再現する後処理をやったり、terekaさんが作られてたtwo-stageモデルをアンサンブルする部分のバグ取りとかをしていました。これまでのチーム戦で一番スコアへの貢献度が低かった気がしますが、賞金圏内かどうかぐらいの貢献はあったかなという感じです。大作の解法はこちら

1年ぶりくらいに真面目にKaggleやって金が取れたことで、今年は継続して頑張ってみようかなと思った瞬間でした。

 

TensorFlow - Help Protect the Great Barrier Reef(2022年2月)

ヒトデコンペ、あるいはGBRコンペ。珊瑚礁の海底映像から、珊瑚を捕食してしまうオニヒトデを検出するタスク。ちゃんとtime-series APIのコンペになっているのが良い。YOLOv5モデルで推論画像サイズを大きくしていくとどんどん精度が上がるという謎現象があったり、上位が何かしらmagicがあるようなLBスコアを出していたりしていたので、GBR何も分からんと言われていた。

そのmagicは結局、public testのデータセットのbounding boxが訓練データと比較してtightにつけられており、推論結果のbounding boxを小さくして投稿するとpublic LBが上がるということだったらしい。ひどい話だと思うのが、テストデータは5つのvideoから構成されており、public testは3番目と4番目のvideoのそれぞれ一部から構成されていることがprobingにより分かっていたので、private testも前述のtight bounding boxの傾向があるはず(少なくとも3番めと4番目のvideoのprivate testは)と予測されるのだが、どうやらpublic test部分だけこの傾向があったらしく、大きくshakeする結果となっていた。

私の取り組みとしては、評価指標がrecall重視のメトリックだったので、訓練動画を逆再生してトラッキングして、遠方の漏れているBBOXを自動で付加してアノテーションを増やすみたいなのをやったりしつつ、YOLOv5とmmdetのモデルを混ぜたりしていましたが、LBが全然上がらず、モヤモヤしたまま終わりました。ソロ銀。面白かったけど。

 

Happywhale - Whale and Dolphin Identification(2022年4月)

クジラコンペ第二弾。今回は対象にイルカも加わり、様々な種類のクジラ・イルカの個体識別を行うタスク。距離学習系のコンペは、最後は画像サイズとモデルを大きくして殴るみたいなところがあり、一度TPUをちゃんと使ってみようというモチベーションで参加。

結果的に、GPUデスクトップやGCPインスタンスはほぼ使わず、Colab Pro+のTPUだけで戦い切ることができました。現在はColabはポイント制になってコスパが悪くなっていますが、V100やA100といったGPUと比較してTPUは性能に対して消費ポイントは低いので、TPUを使うのであればまだColab環境は選択肢に上がると思います。
ひたすらクジラとイルカのBBOXをアノテーションしてcropの精度を上げて、TPUで効率的に大きなモデルを学習するという正攻法で1ヶ月前くらいまでに銀圏上位に到達し、また @tereka114 さんチームに入れて頂きました。

今回はちゃんとモデルでも貢献しつつ、捨てられそうになっていたSiamese Networkモデルを救い出す等の貢献ができました。最後はどんどん周りのスコアが上がって来てドキドキしましたがなんとか金圏に残り、4つ目の金を取ることができました。解法はこちら

 

Image Matching Challenge 2022(2022年6月)

IMCコンペ。2枚の画像が与えられ、それらの間の基礎行列を推定するタスク。Twitterでやるぜー!みたいな機運を感じたので入れて頂きました with @fam_taro さん、@mlaass1 さん、@arutema47 さん、@s_shohey さん!

スタート時点から社外の方とチーム組んでやるのは初めてでしたが、ゆるふわと言いつつみんなガンガンコミットするので、乗り遅れないように頑張ってました。

チームの方針としては、タスク自体は2枚の画像毎に処理をすることが想定されているのですが、データ上は同じsceneに所属する画像群が特定できるので、それら全ての画像集合をSfMで三次元再構築してしまうというものでした。決まれば一撃必殺なのではというワクワク手法でしたが、中々LoFTRベースの手法から精度が上げられず終了でした。めっちゃ楽しかったけど、悔しいのでリベンジしたい。@s_shohey さんがめちゃくちゃprobingしていたのが凄かった。

 

UW-Madison GI Tract Image Segmentation(2022年7月)

UWMGIコンペ。MRI画像から大腸、小腸、胃の部位をセグメンテーションするタスク。Public notebookでスコアが出てたのが2.5Dアプローチだったので、どこかでチームマージすることも考え、3Dモデルに注力していました。ちょうど渾身のモデルをsubするぞ!という凄いタイミングで、@inoichan さんから誘って頂いてチームマージしました。@inoichan さんがちょうどつよつよ2.5Dモデルだったので、計算通りです。

終了ギリギリまで計画的に2人でそれぞれモデルを強化していき、最後はちょっとshake upしての15位でした。最後の3subにprivate 8位相当のsubがあり、それまでのprobingで最後に選んだsubはpublicにoverfitしているのは実は分かっていたはずで、終了後はちょっとしょんぼりしていました。終了直前までLBがそこまで上がらず、半ば心で負けてしまっていたと反省。

このコンペ、MRIスキャンのボクセルの下部でアノテーションが良く分からない場所から途切れているという事象があり、全く現実の問題には貢献しないですが、この途切れを気にせずに全部セグメンテーションするモデルでセグメンテーションしつつ、別のモデルでこの途切れる位置を推定するという部分がキーポイントだったと思います。解法はこちら

 

RSNA 2022 Cervical Spine Fracture Detection(2022年10月)

頸椎のCT画像から頚椎のC1-C7部位それぞれおよび全体の骨折の有無の判定を行うタスク。骨折のラベル情報だけではなく、頚椎領域の3Dセグメンテーションや、骨折領域のbounding boxも与えられており、解法のパイプラインとして様々な可能性が考えられるという観点で非常に面白いコンペだと思いました。

私の解法は、頚椎部分を3Dモデルでセグメンテーションし、C1-C7の部位にそれぞれ2.5Dモデル+Attentionを適用するというものでした。先ほど色々な可能性が考えられると書きましたが、結果的には上位解法は大体こんなソリューションに落ち着いていました。UWMGIコンペリベンジとしてもかなり本気で取り組んでいたのと、パイプラインとしてはほぼ1st Place Solutionと同じだったので、精度を上げきれてないのが悔しかったコンペでした。

 

G2Net Detecting Continuous Gravitational Waves(2023年1月)

G2Netコンペ。レーザー干渉計 (detector) によって観測される信号から、中性子星が高速回転する際に発生する未観測の重力波の1種であるContinuous Gravitational Waves (CW) を検出するコンペ。まだ観測されたことがない信号なので、detectorの観測および人工的に作成されたノイズに、シミュレーションで生成されたCW信号を合成することで作成されたデータセットが提供されていました。

Testデータのノイズをなるべく模倣するデータを生成することに注力し、CNNベースの手法で中盤くらいにLB3位まで上がったのですが、そこからほとんど本質的な改善ができずに終了してしまいました。最終的な解法はこちら。なんとか金圏には残ることができ、Grandmasterになることができました。

上位陣は、matched filter的なアプローチで、signalのパラメータから決定される波形から、そこにsignalがあった場合のスコアを算出するというのを大量のテンプレートに対して行っていました。この大量の試行をどう効率的に行うかがチームごとに違って面白かったです。競プロというか、Heuristic Contest的な趣ですね。なお、コンペのトップページには最初から下記のように書いてあったのですよね!

Traditional approaches to detecting these weak and hard-to-find continuous signals are based on matched-filtering variants. 

 

終わりに

今後ですが、これまで、Kaggle Masterになってもソロ金ないしなぁと思い、ソロ金とってもGMではないしなぁと思いながらやってきて、ついにGMになることができましたが、悔いがない、やりきった、あるいは完全に勝ったぞと思えるコンペが正直ないので、まだまだやっていきたいと思います。後は、もう少しdiscussionやnotebookでも貢献していきたいです!一緒にやろうぜも募集しています!

おめでとうコメントを頂いた方々、ありがとうございました。中でも、昔書いた記事を参考にして頂いたという話が聞けたのがとても嬉しかったです。

 

参考文献

GMの方の記事ってあるのかなと思って検索して見つけた記事です。どれも面白いですね。他にもあれば教えて下さい!

 

@smly さん

ho.lc

 

@tereka114 さん

nonbiri-tereka.hatenablog.com

 

@hirune924 さん

zenn.dev

 

@NmaViv さん

nmaviv.hatenablog.com

 

@colun さん

zenn.dev

 

@aryyyyy221 さん

aryyyyy.hatenablog.com

 

@s_shohey さん

zenn.dev

 

@tnkcoder さん

tnkcoder.hatenablog.com

 

@junkoda さん

medium.com

 

@knshnb さん

blog.knshnb.com

 

@jy_msc さん

www.wantedly.com

 

@tattaka_sun さん

tattakaaqua.hatenablog.com

 

@monnu0621 さん

monnu621.hatenablog.com

 

 

 

zenn.dev