壺コンペ振り返り

kaggleのiMet Collection 2019 - FGVC6コンペに参戦したので、振り返ります。

www.kaggle.com

コンペの概要

FGVC6 のコンペで、美術品のラベル付けの精度を競う

ラベルは1103種類存在する

その中でも398種類がcultureに関するラベル(どの文化の美術品なのか)

残りの705種類がtagに関するラベル(どういう美術品なのか)

一つの美術品に対するラベルは当然複数存在しうる(いわゆるマルチラベル

評価指標は F2 score

データ

学習用の画像(/trainフォルダ)

学習用の画像に対応するラベル(train.csv

推論用の画像(/testフォルダ)

ラベルのidとnameを対応させた表(labels.csv

コンペを始めるにあたって

このコンペを始めようと思ったきっかけはPyTorchを書けるようになりたいなと思ったからです。一応PyTorchの本を読んではいましたが、コーディングは全然していなかったので実践するのに丁度いいコンペが来てくれました。

以下はコンペ初期のPyTorch何もわかっていない時の僕です。懐かしい。

 

また今回のコンペはマルチラベルのタスクで、僕はFashionMNISTでマルチクラス分類をやったことはありますが、マルチラベルの場合どうすればいいのか当時よくわかっていませんでした。

同じような方がDiscussionにもいて、ここでようやくマルチラベルのタスクに対するアプローチを理解しました。

www.kaggle.com

コンペ初期

自分でベースラインを実装する実力は当然なかったので、コンペ初期は以下のカーネルを参考にさせていただきました。

www.kaggle.com

このカーネルはpretrainedモデルを使って特徴抽出を行い、得られたtensorをinputとしてMultiLayerPerceptronで学習させるようなカーネルで、PyTorch初心者にも理解しやすい内容になっています。

このカーネルがあったおかげでスムーズにPyTorchに入門できたと思うのでとても感謝しています。

コンペ中期

上記のカーネルをもとに自分用のベースラインを作成したものの、まだ書き方が冗長でepochを全然回すことができていませんでした(カーネルGPUは9時間まで)。

そんなとき、fastaiでモデルを作成していたカーネルが自分のベースラインよりも高速にepochを回していることに気づき、ここでfastaiに移行しました。

www.kaggle.com

fastaiがその名の通り簡単にモデルを組むことができることは聞いたことがありましたが、このカーネルを見ても分かる通り、本当にお手軽にモデルが組めました。

fastaiで色々試行錯誤したところ、結局上記のカーネルのようにモデルを学習させて、ResNet50のモデルをアンサンブルしてようやく公開カーネルを超えるスコアが出せました。

チーム mhiro2 & Y.Nakama 

当時LBで0.63台につけていたmhiro2さんがチームメイトを募集していて、スコアがそこまで近くない身分でお声がけしたところ、とても丁寧なDMをいただきチームマージする運びとなりました。

mhiro2さんは以下のカーネルを参考にしていました。

www.kaggle.com

このカーネルは初期の頃からありましたが、僕は何をやっているか詳しく見ずにスルーしていました。

このカーネルが何をしているかと言うと、.pyファイルのソースコードbase64を使ってエンコードしたものをカーネル環境でデコードして、カーネルでそれぞれの.pyファイルを実行するというようなことをやっています。

これ、詳しく見てみたらソースコードとかめちゃくちゃ参考になるもので、作者さんには感謝しかないです。

しかもこのカーネルは僕が参考にしていたfastaiよりも多くepochを回せるようだったので、チームマージ後はこのカーネルとmhiro2さんによる追加実装を参考に作業を進めていきました。

チームマージしてから具体的にやったことは以下になります。

  • モデルの検討
  1. Discussionにもあった通りSEResNeXt101_32x4dが一番良かった
  2. アンサンブル時に多様性を出すために、ResNet101、SEResNet101、SEResNet152、DenseNet161なども用意した
  3. pretrainedが出たEfficientNet-b3も試したが、精度があまり出なかったので不採用
  • 2nd-trainの検討
  1. GPUは9時間までしか回せないので、9時間だけでは十分にモデルを学習させることができないモデルもあります
  2. そこで9時間学習させたモデル(1st-train)のweightを引き継いで、lrを調整して2nd-trainさせることで十分に学習させました
  • lossの検討
  1. BCELoss、FocalLoss、F2Lossから検討
  2. 上記の組み合わせを試したものの、最終的にはBCELossを使用
  • schedulerの検討
  1. CosineAnnealingLRも試したが、ReduceLROnPlateau方式を採用
  • batch sizeの検討
  1. batch sizeは基本的に大きい方が精度が出るイメージがありますが、32と64で比較してみたところ、32の方が精度が良かったので32を採用しました
  • transformの検討
  1. 縦長の画像もあれば横長の画像もあったので、transformを色々検討しました
  2. 90度回転させてみたりもしましたが、結局以下に落ち着きました
    # size == 320
    RandomResizedCrop(320, scale=(0.6, 1.0), ratio=(9/16, 16/9)),
    RandomHorizontalFlip()
    # size == 288
    RandomCrop(288),
    RandomHorizontalFlip()
  3. size=320のときのtransformの方がCVが高く出ましたが、LBではsize=288のときのtransformとほとんど変わらなかったので、もともと学習を回していたsize=288に追加する形で、size=320でtransformを変えてまたいくつかモデルを作ったという感じです
  4. TTAのときにもこれらを採用しました(TTA 4)
  • post-processの検討
  1. 予測結果も合わせてEDAしてみて、手元のvalidationでもスコアが改善されて根拠としても十分な以下を導入しました

 

  • アンサンブル
  1. 各モデルの予測値を等weightでブレンディング
  2. 閾値も各モデルでのベストな閾値を等weightでブレンディング

反省点

  1. cultureラベルとtagラベルでの閾値はそれぞれで検討すべきだった
  2. コンペ序盤では、閾値を一つに決めるのではなくclass-wiseな閾値も検討したが、精度が下がったので閾値は一つでいいかと思ったまま最後を迎えてしまった
  • stacking

終わりに

壺コンペはカーネルも充実していて本当に勉強になりました。

CVとLBで大きな差が出ることもなかったので良コンペだったと思います。

X5?知らない子ですね・・・

Discussionで公開されている解法も時間がある時に追いたいです。

最後に、mhiro2さんとチーム組ませていただいたおかげで様々な取り組みが出来るようになったので本当に感謝しています!ありがとうございました!

 

また何かあれば追記します