壺コンペ振り返り
kaggleのiMet Collection 2019 - FGVC6コンペに参戦したので、振り返ります。
コンペの概要
FGVC6 のコンペで、美術品のラベル付けの精度を競う
ラベルは1103種類存在する
その中でも398種類がcultureに関するラベル(どの文化の美術品なのか)
残りの705種類がtagに関するラベル(どういう美術品なのか)
一つの美術品に対するラベルは当然複数存在しうる(いわゆるマルチラベル)
評価指標は F2 score
データ
学習用の画像(/trainフォルダ)
学習用の画像に対応するラベル(train.csv)
推論用の画像(/testフォルダ)
ラベルのidとnameを対応させた表(labels.csv)
コンペを始めるにあたって
このコンペを始めようと思ったきっかけはPyTorchを書けるようになりたいなと思ったからです。一応PyTorchの本を読んではいましたが、コーディングは全然していなかったので実践するのに丁度いいコンペが来てくれました。
以下はコンペ初期のPyTorch何もわかっていない時の僕です。懐かしい。
PyTorchようやく少し理解できてきた
— Y.Nakama (@NmaViv) April 14, 2019
PyTorchのこと何も理解できていなかった(やっとおかしなとこ直せた)
— Y.Nakama (@NmaViv) April 18, 2019
また今回のコンペはマルチラベルのタスクで、僕はFashionMNISTでマルチクラス分類をやったことはありますが、マルチラベルの場合どうすればいいのか当時よくわかっていませんでした。
同じような方がDiscussionにもいて、ここでようやくマルチラベルのタスクに対するアプローチを理解しました。
コンペ初期
自分でベースラインを実装する実力は当然なかったので、コンペ初期は以下のカーネルを参考にさせていただきました。
このカーネルはpretrainedモデルを使って特徴抽出を行い、得られたtensorをinputとしてMultiLayerPerceptronで学習させるようなカーネルで、PyTorch初心者にも理解しやすい内容になっています。
このカーネルがあったおかげでスムーズにPyTorchに入門できたと思うのでとても感謝しています。
コンペ中期
上記のカーネルをもとに自分用のベースラインを作成したものの、まだ書き方が冗長でepochを全然回すことができていませんでした(カーネルのGPUは9時間まで)。
そんなとき、fastaiでモデルを作成していたカーネルが自分のベースラインよりも高速にepochを回していることに気づき、ここでfastaiに移行しました。
fastaiがその名の通り簡単にモデルを組むことができることは聞いたことがありましたが、このカーネルを見ても分かる通り、本当にお手軽にモデルが組めました。
fastaiで色々試行錯誤したところ、結局上記のカーネルのようにモデルを学習させて、ResNet50のモデルをアンサンブルしてようやく公開カーネルを超えるスコアが出せました。
久しぶりに壺
— Y.Nakama (@NmaViv) May 17, 2019
公開カーネルは超えたので画像コンペ初メダル取りたいな pic.twitter.com/k7DUu3muZT
チーム mhiro2 & Y.Nakama
当時LBで0.63台につけていたmhiro2さんがチームメイトを募集していて、スコアがそこまで近くない身分でお声がけしたところ、とても丁寧なDMをいただきチームマージする運びとなりました。
ぼくのスコアが近くなったら...🙏(0.620)
— Y.Nakama (@NmaViv) May 21, 2019
mhiro2さんは以下のカーネルを参考にしていました。
このカーネルは初期の頃からありましたが、僕は何をやっているか詳しく見ずにスルーしていました。
このカーネルが何をしているかと言うと、.pyファイルのソースコードをbase64を使ってエンコードしたものをカーネル環境でデコードして、カーネルでそれぞれの.pyファイルを実行するというようなことをやっています。
これ、詳しく見てみたらソースコードとかめちゃくちゃ参考になるもので、作者さんには感謝しかないです。
しかもこのカーネルは僕が参考にしていたfastaiよりも多くepochを回せるようだったので、チームマージ後はこのカーネルとmhiro2さんによる追加実装を参考に作業を進めていきました。
チームマージしてから具体的にやったことは以下になります。
-
モデルの検討
- Discussionにもあった通りSEResNeXt101_32x4dが一番良かった
- アンサンブル時に多様性を出すために、ResNet101、SEResNet101、SEResNet152、DenseNet161なども用意した
- pretrainedが出たEfficientNet-b3も試したが、精度があまり出なかったので不採用
-
2nd-trainの検討
- GPUは9時間までしか回せないので、9時間だけでは十分にモデルを学習させることができないモデルもあります
- そこで9時間学習させたモデル(1st-train)のweightを引き継いで、lrを調整して2nd-trainさせることで十分に学習させました
-
lossの検討
- BCELoss、FocalLoss、F2Lossから検討
- 上記の組み合わせを試したものの、最終的にはBCELossを使用
-
schedulerの検討
- CosineAnnealingLRも試したが、ReduceLROnPlateau方式を採用
-
batch sizeの検討
- batch sizeは基本的に大きい方が精度が出るイメージがありますが、32と64で比較してみたところ、32の方が精度が良かったので32を採用しました
-
transformの検討
- 縦長の画像もあれば横長の画像もあったので、transformを色々検討しました
- 90度回転させてみたりもしましたが、結局以下に落ち着きました
# size == 320
RandomResizedCrop(320, scale=(0.6, 1.0), ratio=(9/16, 16/9)),
RandomHorizontalFlip()
# size == 288
RandomCrop(288), RandomHorizontalFlip()
- size=320のときのtransformの方がCVが高く出ましたが、LBではsize=288のときのtransformとほとんど変わらなかったので、もともと学習を回していたsize=288に追加する形で、size=320でtransformを変えてまたいくつかモデルを作ったという感じです
- TTAのときにもこれらを採用しました(TTA 4)
-
post-processの検討
- 予測結果も合わせてEDAしてみて、手元のvalidationでもスコアが改善されて根拠としても十分な以下を導入しました
壺の小話、ラベルにmen, women, actors, actressesがあったけど、men, womenのラベルが学習データにいっぱいあってそれら精度良く学習してくれるので、例えばmenが予測されてないのにactorsが予測されていた場合、予測ミスしている確率が高いのでそのあたり修正するとCV0.0000xくらい改善する(誤差)
— Y.Nakama (@NmaViv) June 6, 2019
-
アンサンブル
反省点
-
閾値の検討
- cultureラベルとtagラベルでの閾値はそれぞれで検討すべきだった
- コンペ序盤では、閾値を一つに決めるのではなくclass-wiseな閾値も検討したが、精度が下がったので閾値は一つでいいかと思ったまま最後を迎えてしまった
-
stacking
終わりに
壺コンペはカーネルも充実していて本当に勉強になりました。
CVとLBで大きな差が出ることもなかったので良コンペだったと思います。
X5?知らない子ですね・・・
Discussionで公開されている解法も時間がある時に追いたいです。
最後に、mhiro2さんとチーム組ませていただいたおかげで様々な取り組みが出来るようになったので本当に感謝しています!ありがとうございました!
壺無難に銀メダル取れてました!画像コンペ初メダル嬉しい...!
— Y.Nakama (@NmaViv) June 11, 2019
チームマージで圧倒的成長が得られたのでチーム組んでくださったmhiro2さんにはあらためて感謝です🙏 pic.twitter.com/VqG46Zj2py
また何かあれば追記します