7/22まで行われていた「#11 [初心者歓迎! / 画像編] atmaCup」に参加してました。 それに取り組む中で勉強した事を備忘として記録していきたいと思います。
これは何?
短期間のコンペに初めて取り組んだので、せっかくなので学んだことを記録に残しておくものです。
どんなコンペ?
チュートリアルは下記のようになっています。
超ざっくり書くと、画像と少しの参考情報から画像の年代を当てるのが目的です。
ほーん。で、何位だったの?
- Public LB
- RMSE=0.7433
- Private LB
- RMSE=0.7330, 61位
まあ、こんなもんでしょう。 特段良くもなく、悪すぎることもなく、これくらいが丁度いいんすよ…割と真面目にやったのに…(涙目)
コンペに取り組む上で勉強したこと
ディスカッションを読む上で、必要になったものを書き下していきたいと思います。
SSL (自己教師あり学習, Self Supervised Learning)
多分Discussionのなかで一番話題になっていたのはSSLってやつだと思います。
今回のコンペでは、学習済みモデルを使用することができませんでした。 言い換えると、与えられた画像だけを使用してモデルを学習させる必要があるのですが、それに対してpureにtrainに使用できるラベル付きデータが少ないという点が厄介かと思います。
そこで、BERTにおける事前学習のように、ラベルなしのテストデータを含めて使用した自己教師あり学習が有効そうに思われます。 今回のコンペではSimSiamがDiscussionで取り上げられるなどしていましたし、これを上手に使えると結構上の方まで行けるのかもしれません。
自己教師あり学習の新しいアプローチ / SimSiam: Exploring Simple Siamese Representation Learning - Speaker Deck
実際に試したこと
実際に試したことをかいつまんで書き出していきます。
classification -> regression
まず最初にスコアをあげるために、classificationで解いていたものをregressionに置き換えました。 こちらはDiscussionでも議論に上っていました。
最終的な評価がRMSEだったので連続値で提出しても問題ないことから、regressionとして計算したものをそのまま提出しました。
モデルの選定
初手ではEfficientNetを使ってやってましたが、なかなかスコアが上がりませんでした。 このへんでDiscussionを参考にして、規模の小さいNNモデルが有効そうだと判断し、Resnet18dを使用したところこれもスコアが上がりました。
ただ、最後の方でEfficientNet-b0でLBで0.75までは手元で出たので、うまいことやればEfficientNetでも戦えたのかもしれません。 この辺はほんとナニモワカラナイ…
Early stopping
割と最初の方は基本的なことすらできてなかったコードだったのでこの辺からやってみました。 モチベーションとしてはlossの低下とは対象的にCVの値がなかなか安定していませんでした。
学習のepoch数を適当に決めるのではなく、CVの値がある程度下がりきったのを確認し、その段階で学習を止めるように切り替えたところ、かなりスコアが改善しました。
この辺、pytorch lightningとか使っているとやってて当たり前のようでした。 なので、このあたりまでやってようやく普通の人が言うベースラインといったところでしょうか。
StratifiedKFold -> StratifiedGroupKFold
こちらもDiscussionで取り上げられていました。 CVを分けていくときに、よくやるやり方としてはStratifiedKFoldを使うことがあります。
この辺のtrain/validation がどのように分けられているかはscikit-learnのドキュメントがわかりやすいです。
今回の場合だと、シリーズ物の作品が一部含まれているようで、それをグループとしてStratifiedGroupKFoldするのが効いている印象でした。
image sizeの変更 (224x224 -> 256x256 -> 300x300)
こちらは半信半疑でやってみました。 一部の方が画像を大きく扱っていたので、それをやってみました。
これは意外と効果があって、LBで0.01 ~ 0.02くらいはスコアが上がったのでおそらく画像を大きく捉えることは重要そうです。
試したけどあんまりダメだったこと
pseudo labeling
画像サイズを変更したあたりでLBの上がりが頭打ちになってしまったので、半信半疑でpseudo labelingを試してみることにしました。 試してみるとCVは大きく向上したのですが、LBがあまり上がらなかったのでちょっとだけテコ入れをしました。 CVは向上した(0.6後半〜0.7くらい)んですが、LBとの相関が取れなくなってしまい、LB上では全く良くなっていなかったです。
SSL
上にも書いたように、話題になっていたのでやってみはしたんですが、あまりうまくいきませんでした。 SSLで事前学習したモデルから学習するとCVは多少下がるんですが、LB上では特に変化がなかったので、なんかやり方ミスっていただんだと思います。
上位解法のメモ
所感としては、下記のあたりが効きそうでした。
- epoch数を増やすことが結構重要
- 普段imageNetの学習済みモデルを使っている感覚でやるよりかなり増やすとうまくいく
- 画像は大きめにリサイズしたほうが精度が上がる傾向がありそう
- 画像の強引なresizeではなく、paddingで縦横比を保つと良い
- Vision Transformerは効く
- ただし手元で試した感じ、自分はライブラリの選定でミスってたっぽい
- 上位はtimmを使ってるみたい
- SimSiamは効く人と効かない人で半々のイメージ、多分うまいこと事前学習するためには結構頑張らないといけない
- Stackingが効く
- classificationとregressionのどちらでも解いて、最後にStakingする感じ
参考文献
Discussionに加えてSSLに関しては下記のブログを参考にしました。
振り返り会でもありますが、1位解法はこちらのようでした。
感想
過去のも出たいとは思ってたんですがなかなか都合がつかず、今回がatmaCup初参加でした。
参加者・運営の方々、お疲れさまでした。 大変楽しい&勉強になるコンペでした。 ありがとうございました。
まず、コンペ自体とはちょっと違いますが、コンペのサイトの挙動とかがすごく可愛いですね。 サイトがよく出来てるなーと素直に感心してしまったのは自分だけではないはず…たぶん。
個人的な反省としては、ディスカッションの内容を再現できなかったことでしょうか。 強い人はディスカッションの内容は基本的にすべて試して(あるいは経験則で取捨選択して)いて、その上でなんらかのアレンジを加えていくというのがセオリーかと思っているので、とにかく一通り試してみてました。 全部できたわけではなかったですが、ディスカッションに上がっている内容を試すと結構な確率でスコアは上がったので、やっぱりディスカッションを読み込むことは重要なんだと思いました。
ただし、記載の内容を再現できたかは別問題です。 多くの場合で、スコアが記載されているものを大きく下回っていたので何かがおかしいとはわかったんですが、その原因は最後まで分からず終いでした。 個人的には、途中から勝ち負けはどうでも良いから、SSLでモデル作ってサブミットすることだけ考えてやってましたが、CVは良くなるのにLBに変化せず、というような感じでした。
何はともあれ、めったに参加することがない画像コンペに真面目に取り組んで色々学びもあり、大変勉強になりました。