はじめに
2021年3月5日(金)〜3月13日(土)に開催されたatmaCup#10に参加してました.
毎回,参加者同士のディスカッションなどが活発であり,学びがとても多いので今回も参加させていただきました.
他の方のsolutionを確認したところ,異なるアプローチでスコアを伸ばすことができたので,簡潔にまとめておきたいなと思い記事作成に至りました.
今回はチームを組んで参加したいと思っていましたが,最終的にソロ参加で終わってしまったので,この記事では思っていたことなども含めて,コンペを振り返れたらと思います.
また,いろいろなことを学んでいる最中なので,間違った記述などもあると思いますので,そっと教えてもらえたら幸いです.
開会式
開会式は3月5日の夕方でした.
印象的だったのは,コンペ開催前からディスカッションが投稿されていたことでした.
ちゃかぶ さん(@cha_kabu)
TabNetを使えるようになりたい【追記①lgbmとstacking(ちょっと上がる)】
しんちろ さん(@sinchir0)
特に,ちゃかぶさんのディスカッションはとても詳細に記述がされており感動しました.
atmaCup開催期間は一週間と限られていたので,今回は実装することができませんでしたが,ゆっくりと理論や実装を学んでいきたいと思います.
序盤
初日submitを普段は目標にしていたのですが,今回はチームを組んでみたいと思っていたことから,無駄なsubmitを極力避けるために慎重にスタートを切りました.
特に今回は,データが複数テーブルにまたがっており,とりあえずの特徴量作りも一苦労でした.
コンペ課題は,美術作品の属性情報から,その作品がどのぐらい人々に評価されるのかを予測するものでしたが,使用することができるデータには,テキスト情報や色情報も含まれており,非常に自由度の高いコンペでした.
自身は,画像系の特徴量の取り扱い方がわからなかったので,まずは複数テーブルをひとつのテーブルにまとめることにしました.
作品の材料情報や作品制作者の生まれた場所など,様々なデータがあったのでOneHot表現にしたり,作品の制作開始日の欠損はほとんどなかったので,その値を利用することで,製作者の生まれた日や亡くなった日の欠損を回帰で補完したりなどしました.
CVの切り方は,trainとtestで'art_series_id'(シリーズものの作品ID)が被っていなかったので,CVはtrainとvalidに同じ'art_series_id'がないようにしました.
やっとの思いでテーブルデータをまとめることができたので,lightGBMで作成した特徴量を全部投入して学習を開始!(この時点ではテキストや色の特徴量は使用せず)
CV: 1.0418となかなか良さげな結果となって,3月7日にfirst submit.
しかし,結果は過学習しておりLB: 1.6027でした...
正直,かなり丁寧に特徴量を作ったつもりでしたが,LB悪くて絶望していました.
頑張って作成した特徴量を丁寧に取り除いていくことで,何とかLB: 1.0513にすることはできました.
しかし,特徴量を加えてはCVは下がるが,過学習によりLBは悪くなってしまいどうすればいいか何もわからなくなってしまいました.
当初は3月8日あたりでチームマージをしたいと思っていたのですが,CVとLBの関係も安定せず,LBスコアもあまり良い結果でなかったため,誰にも声をかけることができませんでした.
中盤
テキスト情報のembedding,何歳で作成した作品か(制作開始日 - 制作者の生年月日),亡くなる間際の作品か(製作者の命日 - 制作開始日),制作期間(制作終了日 - 制作開始日)などの特徴量を追加したり,製作者と材料情報をクロス集計し,主成分分析を利用した特徴量を作るなどいろいろ試したが,効果が出ず...
3月10日までに13 submitしましたが,LBスコア1.0を切ることができませんでした.
ドメイン知識もないので,どういった特徴量が効くのかも検討がまったくつきませんでした.
このままでは何もできないで終わってしまうと思い,「でぃ~ぷら~にんぐ」に全部お任せすることにしました.
実はこの部分が他の参加者と大きく手法が異なる部分であり,自身のスコアを大幅に改善する要因となったので,少し細かく紹介できたらと思います.
何をしたのか
先に結論ですが,やったことはテキストデータとカテゴリカルデータにTagを追加しながら連結することで,ひとつのsentenceにしました. このsentenceを入力とすることで,Self Attention Based BiLSTM Modelを学習させました.
Step1: sentenceの作成
まずは入力データを作成します.
全データの詳細な連結は細かくなるので省いて,メインの部分について説明できたらと思います.
例えば,以下のようなデータを連結させることを考えます.
- 'material': oil print print canvas
- 'maker_1': jan hackaert
- 'birth': amsterdam
- 'death': amsterdam
- 'roles': painter
- 'title': the avenue of 'UNK'
- 'long_title': the avenue of 'UNK' jan hackaert 'No_4'
- 'description': 'None'
- 'acquisition_method': purchase
- 'acquisition_credit_line': 'None'
これらのデータを連結して以下のようなsentenceを作成します.
'material' oil print print canvas 'maker_1' jan hackaert 'birth' amsterdam 'death' amsterdam 'roles' painter 'title' the avenue of 'UNK' 'long_title' the avenue of 'UNK' jan hackaert 'No_4' 'description' 'None' 'acquisition_method' purchase 'acquisition_credit_line' 'None'
まず,データが欠損していた場合には'None'で埋める.
出現頻度が低い文字列(自身は10以下のもの)は'UNK'で置き換える.
数字は,桁数で対応するタグに置き換える(例: 1994 → 'No_4').
今思えば,4桁の数字は年代によって特徴を持つ可能性があったので,以下のディスカッションを参考に少し工夫の余地があるかもしれないなと思います.
Kien Y. Knot さん(@0_u0)
上記に挙げたデータ以外も同様の方法で連結していきました.
連結のポイントは,関係のありそうなものを近くに連結するのが大事だと思います(この次のword2vecの学習時に多少影響が出るため).
例えば,材料と製作者名を近くに連結することで,ある製作者は特定の材料を使いやすいかどうかなどを学習させることができる(はず).
Step2: 分散表現の学習
付近に出現する文字列同士から,文字列の分散表現を学習させる.
分散表現の学習には,word2vecを用いた.
word2vecはSkip-gramを採用し,200次元の分散表現をwindow幅10で学習を行った.
Skip-gramの詳細な説明は省略するが,簡潔にまとめると,ある単語の付近に出現する単語を予測することで,単語の分散表現を獲得するモデルである.
Hidehisa Arai さん(@kaggle_araisan)がコンペ開催中に以下のようなディスカッションを投稿してくれていました.
Word2Vecを使ってmaterial, technique, object_collectionなどを特徴ベクトル化する
かえるるる さん(@kaeru_nantoka)もsolution読むと似たようなことをやっており,「めちゃくちゃ効きました」とのこと.
[Private 12th / Public 16th] Solution Summary
word2vecに関して,ハイパーパラメータをいじって確認したわけではありませんが,一般的にwindow幅を狭くすると文法を,window幅を広くするとトピックを学習させることができると言われているので,今回のような場合は,window幅を大きめに設定するのが有効である可能性が高いです.
Step3: Self Attention Based BiLSTM Modelの学習
自身のsolutionで,他の参加者と大きく異なるのは,この部分かと思います.
sentenceのどの部分が,目的変数の予測に有効かを自動で学習させるのに最適なモデルだと思い採用しました.
実装したモデルは,LSTMが双方向でattention layerを複数使用しましたが,説明のために単方向LSTM&single attentionの簡潔なモデルを以下に示します.
隠れ層を用いてattention(隠れ層の加重平均をとるための重み)を計算することで,入力の重要な部分と不要な部分を特定することが可能となっています.
これにより,'None'などの影響を小さくすることができるだけでなく,例えば,'description'の記述がなく'None'になっているデータの場合には,代わりに'long_title'などにattentionが多く集まったりするような効果が期待できます.
attention layerを複数実装することで,様々な加重平均を取ることが可能になり,モデルの柔軟性が向上が期待できると考え,attention layer×10で加重平均を計算しました. (あるattention layerは'material'を重視し,あるattention layerは制作者を重視したりしてくれたらいいなと)
細かい工夫としては,LSTMの出力に正規分布に従うノイズを付与したり,dropout層などを追加しています.
結果と考察
CVは序盤同様,Group K-Fold(K=10)で試したところCV: 1.0469でイマイチかなと思いましたが,ダメ元で提出したらLB: 0.9847でした.
これまでのコンペでも,NNは学習データやエポック数によるばらつきが大きいためか,CVよりも複数の学習器の結果を平均しているLBの結果が安定するためよくなるので,CVとLBの乖離はそれが原因かなと思います.
また,この予測にはyearや色情報を特徴量に加えていないので,それらの特徴量と掛け合わせることでより結果が良くなると考え,lightGBMに深層学習モデルの出力を入力として加えyearの特徴量と学習させたところ,LB: 0.9524を出すことができました.
lightGBMの入力に,NNの出力を加えるとよくなることが多いイメージでしたが,ここまで劇的によくなると思っていませんでした.
コンペ終了後に以下のようなtweetを拝見し,自身のモデルは'description'が欠損していた場合,他の'title'や'more_title'にattentionが集まることで,欠損をこれらで補完したときと同じような効果が期待できているのも効果が強かった要因なのかなとも思いました.(ちゃんと分析したい…)
descriptionの欠損をtitleやmore_titleで埋めたのが自分の中ではよかったのだが、みなさんが欠損をどのように処理していたかを知りたい。#atmaCup
— rotto (@rotto55791838) March 14, 2021
終盤
この時点で,LBではかなり上位につけることができました.
しかし,このあたりから新生活の準備で思うように時間がとれないことがわかり,チームマージしたくてもあまりコミットできないため,消極的に募集を待つ形になってしまいました.
submitがまだ30とたくさん残っているが、チームマージするか、アンサンブルとかで浪費するか迷いどころ(´・ω・)
— たかいと (@takaito0423) March 12, 2021
Nice Hard Work ✒ 現在の順位は 4位です。 https://t.co/ndLLcBtEnh #atmaCup
また,確かにLB上の結果は良かったのですが,CVとLBの乖離からshake downの可能性もあり積極的になれませんでした.
Attentionの重みから,どのinputが結果に影響を与えるのか分析もできたのですが,こちらも時間がとれず分析できませんでした(未だ分析できてない…).
時間もとれなかったことから,申し訳程度に色特徴量や,製作者の何番目くらいの作品かなどの特徴量を加えたり,Catboost試してみたり,presude labelingなどを試して多少スコアを伸ばしましたが,大幅な改善は見られず…
最後は,深層学習,lightGBM,Catboostの出力をアンサンブルしたものを提出しました.
予定もあったためコンペ終了ぎりぎりまでコミットできず,submitを19ほど残して後は神に祈ることにしました.
結果
帰宅後,自身の順位を確認したところ,LB: 0.9443でLB順位は12位でした.
そして,最終順位はshake downして17位でした.
感想
今回はいろいろなことができたがゆえに,まだまだできることはたくさんあったなと思います.
また,課題である根本的な特徴量を作る能力が足りておらず,モデルに救われただけでもあるので,他の方のsolutionからいろいろ学んでいけたらと思います.
ただ,テキストデータやカテゴリカルデータに対して,使用したモデルが有効である可能性があることを知れた経験はとても有意義なものでした.
この結果を得られただけでも意義があったと思いますし,今後のコンペでも活用していけたらと思います.
また,今回のコンペはチームマージしてみたいという意気込みがあったのですが,なかなか思うようにチームマージはできず,温存していたsubmit数も無駄になってしまったのも反省点です.
個人的に,参加し始めてからのチームマージは,タイミングが難しいと感じているので,コンペ参加前から組んで参加するところから始めてみたいなと思いました.
特に今回は,自身の方法が少し特殊だったので他の方とうまくチームを組んで,attentionの分析や色特徴や他のモデルの結果とstackingすることでもう少し上の順位が狙えたのかなと思いますし,行き詰っていた特徴量作りのアイデアが出ていたかも...と思いました.
このあたりまでが反省ですが,一時的にですが上位に付けることができていたり,ディスカッションが活発だったりと,とても楽しむことができました!
社会人になって,どこまで参加できるかわかりませんが,今後も自分のペースで参加していけたらと思いますので,同じコンペ参加することがあれば,よろしくお願いいたします!
他の参加者の公開solutionや参加記録
記事投稿するの遅くなってしまったので,可能な範囲で見つけたものを共有できたらと思います.
[Public 3rd/Private 1st] solution copasta さん(@copasta_)&HOKAGE さん(@HOKAGE149)&朱眠子 さん(@akaneko6922)
feature importanceを見ると,やはりword2vecが効いているようです.
[Public 2nd/Private 2nd] LGBM single model solution もーぐり さん(@tellmoogry)
テキストを翻訳して使用していたり,色のデータから丁寧に様々な温かみのある手作り特徴量を作成していて,にじみ出る強者感.
feature importanceは,テキスト情報を除くと,groupby特徴量がかなり上位に多い印象(このあたり参考にして次に活かしたい).
3rd place solution CALPIS10000 さん(@CALPIS10000)
CALPIS10000 さんは,Music×Analytics Meetupの発表が印象に残っています.
こちらもword2vecが,テキストや1対多のテーブルで効果が絶大だったようです.
Lab色空間などを特徴量に使用しているのが印象的でした.
上位三名の方は,テキストと色の情報をきっちり使いこなしている印象を受けました.
4th Place Solution (チームマージはいいぞ) ころんびあ さん(@yurucamp_i)&tubo さん(@213tubo)
チームであることを最大限に活かし,モデルの多様性を意識して,様々なモデルを用いて予測した結果をstackingしていました(羨ましい!).
コメントにて,チームマージに関する質問にも答えていただきました.
自身はあまり,複数のモデルを実装したことがないので,使用しているモデルに関しては,実装できるようにしたいと思いました.
ここまでが物理メダル獲得者のsolutionでした.
おめでとうございます!
5th place solution suk1yak1 さん(@suk1yak1)
全特徴量(約2,000個)で学習させ,そのfeature importance上位に絞って学習するという方法が効いたとのことで,自身もこれくらい特徴量を作れるようになりたい.
6th place solution(yukiモデル+コメント欄にsqrt4kaidoモデルもあるよ) yuki さん(@yuki93753711)&rt4kaido さん(@sqrt4kaido)
yuki さんの単独モデルはPublic33rd/Private18thとのことなので,チームマージにより,異なる特徴量を用いたモデルを組み合わせることが有効であるいい例だと思いました.
チームで参加するときは,ディスカッションも大切だけど,各々で特徴量考えてモデル作成するのも大事なんだろうなと思いました.
7th place solution takoi さん(@TaTakoihirokazu)
palette系をkmeansでclusteringしている部分がこれまでの解法とは異なる部分なのかなと思いました.
clusteringによる特徴量作りは試したことないので,試してみたいなと思いました.
[Public 1st/Private 8th] Solution hiroshun さん(@h1r0shun)
rolesがpainterのmakerが関わっているか,materialがoil paintか,が効いた特徴量とのことで,油絵かどうかが予測に有効だったとのこと.
接戦の最終盤の中,Public 1stも本当にすごいなと思いました.
9th place solution masato8823 さん(@mst_8823)
4th Place Solution同様,stackingをしっかり行っています.