クルトンのプログラミング教室

Pythonの使い方やPythonを使った競技プログラミングの解法などを解説しています。

atmaCup参戦記(#11)

 こんにちは、クルトンです!

 この記事は僕が参加したatmaCup#11の参戦記になります。

 この記事ではコンペ中に僕がどのようなことを考え、何をしていたのかということをメインに書こうと思っています。

 なので、良いスコアが出る解法を知りたいという方にはツヨツヨの人たちの解法記事を見ることをお勧めします。

コンペが始まる前

 サムネイルの画像から、今回のコンペも絵画がテーマになるということが分かっていたので、絵画から文章を作成して、特徴量にするコードを書いていました。

 ネットから拾ってきたのを少し変えただけですが、割とうまく行っていたのでワクワクしながらコンペが始まるのを待っていました。

f:id:kuruton456:20210805230816p:plain
今回のatmaCupのサムネイルに使われている”The Threatened Swan”を文章化したもの。
かなり正確に絵画の内容を説明できていることが分かる。

 結局、事前学習済みのモデルが使えないということだったのでこれは使えませんでしたが、楽しかったし割といい勉強にもなりました。

コンペ開始(7/9)

 いよいよコンペが始まりました。

 次の日に開催されるnyk_gotoさんの初心者講座でベンチマークとなるコードがもらえるのは分かっていたのですが、とりあえず自力で1subできるように頑張ってみようと思いました。

 このときは、スコアは気にせず1subすることを目的としていたので大分特殊な解法で解いていました。

 (SimSiamによる自己教師あり学習チュートリアルhttps://www.guruguru.science/competitions/17/discussions/a39d588e-aff2-4728-8323-b07f15563552/)によって得た情報を、16次元に落とし、そこからLGBMを使って回帰予想するというもの)


 このときのスコアは、(CV:0.9377, LB: 0.9340)とかなり悪いものでしたが、スコアが出るコードを自分で書けたというのが初めてのことだったのでとても嬉しかったことを覚えています。

BERTを使う(7/10)

 ほぼ一日かけて

  1. Trainデータのmaterial, techniquesをBERTの2次元ベクトルに直す
  2. 16次元に落とした画像情報からtrainデータのBERTベクトルを学習させ、テストデータのBERTベクトルを予測する。
  3. 16次元に落とした画像情報と予想したBERTベクトルから年代を予測する。

ということをしました。

 結果は(CV: 0.8463, LB: 0.9607)でCVがめちゃくちゃ改善したので期待しましたが、LBではむしろスコアが悪化してしまいました(絶対上がると思ったので結構ショックでした)。


 そしてなぜこのような結果になったか考えて

  1. material, techniques のBERTは効く
  2. このやり方ではテストデータのBERTを正確に予測することができない

という結論に至りました。


 とりあえずこの日はこの作業で終わって、次の日から大人しくnyk_gotoさんのコードを使って取り組むことにしました。

nyk_gotoさんのコードをイジり始める(7/11)

 nyk_gotoさんのコードを使って

  • epoch=30
  • StratifiedGroupKFold(n = 5)

で学習させました(以下、この実験をpart1とする)。

 結果は(CV: 0.8928, LB: 0.8902)でした。

 0.8台にのったことは嬉しかったのですが、この時点で上位陣は軒並み0.7台だったので、単純なことを見落としているんだろうな~と思っていました。


 そこで、絵画の場合は色彩が重要なのではないかと思い、data augmentationでの色や明度彩度の変換をなくすことにしました(以下、この実験をpart2とする)。

 これによって(CV: 0.8694, LB: 0.8591)まで上がりました。


 ただ、これでも0.7台には程遠いので、単純にepoch数が足りないのではないかと考えました。

 そこで、part2のepochを100まで増やしたところ、スコアが(CV: 0.8200, LB: 0.8370)まで改善しました。

sorting_dateをtargetに変換する(7/12)

 どうせ回帰分析をするなら、sorting_dateを回帰したほうが精度が上がるのではないかと思い、sorting_dateをtargetに変換して回帰を行いました。

 その際、part2のtargetをsorting_dateにしたもの(part3)とpart1のtargetをsorting_dateにしたもの(part4)で実験を行いました。以下はその結果です。

  • part1, epoch = 300: (CV: 0.7794)
  • part1, epoch = 400: (CV: 0.7654, LB: 0.7543)
  • part3, epoch = 200: (CV: 0.7777)
  • part4, epoch = 100: (CV: 0.8429)

ttaを試してみる(7/13)

 part3がうまく行きそうだったのでそのまま学習を進めました。

  • part3, epoch = 400: (CV: 0.7456, LB: 0.7386)


 学習を回している間が暇だったので、part3にttaを試してみることにしました。

  • part3, epoch = 400, tta: (CV: 0.8534, LB: 0.7355)

 このときにCVが謎の下がり方をしてメチャクチャ焦りました…(未だに原因が分かっていないとは言えない)

他のモデルを試してみる(7/14)

 part3がうまく行っていることは分かったので、ディスカッションで話題になっているモデルを試してみる事にしました。

 ひとまず、part3のモデルだけをEfficientNet0Bに変えたpart5を作って学習を回すことにしました。

  • part5, epoch = 400: (CV: 0.7390, LB: 0.7105)
  • part5, epoch = 500: (CV: 0.7355, LB: 0.6950)

 このときは、最終的には0.67当たりの勝負になると思っていたのでかなり喜んでいました。

 今から思うと、これぐらいのスコアでも充分勝負になるだろうと思い、ほかの手法に積極的に手を出さなかったのが良くなかったのだと思います。

f:id:kuruton456:20210805232351p:plain
これはスコアが0.6台に乗り、分かりやすく調子に乗っている僕

ひたすら学習を回す(7/16~7/20)

 part3のモデルをresnet-18に変えたpart6を作りました。

 この期間は脳死でpart5とpart6の学習を延々と回していました。

 今から考えると、完全にこの期間何もしていなかったのが敗因だったんだな~と思います…

 この時点でのスコアは以下の通りでした。

  • part5, epoch = 700, tta = 100: (CV: 0.7076, LB: 0.6947)
  • part6, epoch = 1500, tta = 100: (CV: 0.7101, LB: 0.7094)
f:id:kuruton456:20210805234724p:plain
スコアが上がらないイライラで、nyk_gotoさんを怖がらせる僕

part5とpart6をアンサンブルする(7/21)

  • part6とpart7のアンサンブル, tta = 100: (CV: 0.6846, LB: 0.6938)
f:id:kuruton456:20210805233359p:plain
アンサンブルをした際のCVにおけるスコアの変化。明確に改善していることが分かる。

 このときは、アンサンブルがかなり効いたのが嬉しかったのと同時に、「もしかしてSimSiamの方も回してればアンサンブルでワンチャンあった?」と思いかなりへこみました。

 最終日になって途中まで回していたSimSiamの学習を再開したのですが、当然間に合いませんでした…

結果

f:id:kuruton456:20210805233748p:plain

 614チーム中22位という結果に終わりました。
 実力以上の結果を出せたとは思いますが、内容としてはかなり反省点が多いコンペだったので次に活かそうと思います。