Kaggle Google QUEST Q&Aコンペに参加した記録
Kaggle Google QUEST Q&Aコンペに参加して61位(1571チーム中)でソロ銀メダルを取れました。
以下ではその記録についてまとめます。
本記事の概要
- コンペ概要
- 私の取り組み
- 興味深かった上位ソリューション
- 感想
コンペ概要
Google QUEST Q&A Labeling | Kaggle
タスク概要
- QAサイトの質問・回答に対して人が主観的にどう感じたかを予測するタスク。後述の入力データから予測対象データを予測する。
- QAサイトの質問・回答に対して人が主観的にどう感じたかを予測するタスク。後述の入力データから予測対象データを予測する。
データ
- 入力データ:stackoverflowなどのQAサイトの質問タイトル、質問文、回答文、カテゴリ、等
- 予測対象データ:質問・回答に関する人の主観的な30個の項目について、0~1の得点が与えられる。例えば、answer_helpfulという項目は回答がhelpfulであるかどうかを表しており、得点0に近ければhelpfulではなく、1に近ければhelpfulである。得点はアノテータが付けたものらしい。
- 入力データ:stackoverflowなどのQAサイトの質問タイトル、質問文、回答文、カテゴリ、等
予測性能の評価方法
スタンダードな解法
- 予測モデル:Deep learningベースの自然言語処理モデル(Bertなど)を学習させ、入力(質問タイトル、質問文、回答文)から30項目の予測対象を回帰で推定。
- 後処理:評価指標値を上げるために、予測モデルの出力を離散値とするような後処理を実施。正解値は0~1の範囲の離散値(例:0, 0.333, 0.666, ...,1.0)をとっていたため、予測値も離散値とすることでスピアマン順位相関係数が高くなる。
- 予測モデル:Deep learningベースの自然言語処理モデル(Bertなど)を学習させ、入力(質問タイトル、質問文、回答文)から30項目の予測対象を回帰で推定。
こちらのブログでわかりやすくまとめてありました。
Kaggle Google QUEST Q&A コンペ 振り返り - 機械学習 Memo φ(・ω・ )
私の解法
私の解法は以下のとおりです。流れは上記のスタンダードな解法と同じです。
コード
github.com概要
使ったライブラリ
- pytorch:kerasから乗り換えました。モデル構造や学習スキームをいじりたい凝り性の人にはpytorchおすすめ!自由度高くて使いやすい。あとgradient accumulate使いやすいのほんと良い。
- hugging face:DL系の自然言語処理ライブラリ。初めて使ったけど、かなり使いやすい。
- pytorch:kerasから乗り換えました。モデル構造や学習スキームをいじりたい凝り性の人にはpytorchおすすめ!自由度高くて使いやすい。あとgradient accumulate使いやすいのほんと良い。
モデル構造
データ前処理
- 入力:特に特別な処理をしていない。
- 出力:予測対象の値の偏りが大きかったので、ランク値にして最大ランクで割ることでスケーリングした。
- 入力:特に特別な処理をしていない。
モデルの学習
- 3epoch(最初の1epochはwarmup)。
- 学習率は1e-4。Bertは5e-5~2e-5が推奨されているらしいですが、1e-4でうまくいった。
- 損失関数は、回帰ではBinary cross entropy、分類ではcategorical cross entropy。label smoothingも使った。
- 3epoch(最初の1epochはwarmup)。
後処理
うまくいかなかったこと
- pair wiseのランク学習やってみたけど効果なかった。list wiseのランク学習であるListNetをやりたかったけど、メモリが足りなくて断念。バッチサイズをある程度大きくとれないと厳しい。ただ、ランク学習自体は面白い分野だと思うので今後活用していきたい。ランク学習に関して知りたい人は以下のサイトがおすすめ。かなり参考になりました。
ランク学習(Learning to Rank) Advent Calendar 2018 - Adventar - 初手でAlbertを試したけどまったく精度でなかった。精度出なさ過ぎて自分のコードのどこかにバグがあるのか探し回ってしまったぐらい精度が出なかった。
- Stochastic Weight Averagingは効果がなかった。でもいつか使いどころが出てくる気がする。
- pair wiseのランク学習やってみたけど効果なかった。list wiseのランク学習であるListNetをやりたかったけど、メモリが足りなくて断念。バッチサイズをある程度大きくとれないと厳しい。ただ、ランク学習自体は面白い分野だと思うので今後活用していきたい。ランク学習に関して知りたい人は以下のサイトがおすすめ。かなり参考になりました。
興味深かった上位のソリューション
入力の工夫
モデル構造の工夫
- 最期の全結合層の入力として、Bertの最終層の出力だけでなく、中間層の出力も使っていた。具体的には、中間層Aの出力([CLS])、中間層Bの出力([CLS])、…、最終層([CLS])の出力を重み付き平均し、それを全結合層の入力としていた。重み付き平均の重みは学習パラメータとし、合計が1になるようにしていた。この発想めっちゃよさげ。どこかで使いたい。
- 全結合層を2つ重ねていた。僕はBertは全結合層1つでいいものだという思い込みがあって、そこの工夫をまったくしていなかった。。
- 最期の全結合層の入力として、Bertの最終層の出力だけでなく、中間層の出力も使っていた。具体的には、中間層Aの出力([CLS])、中間層Bの出力([CLS])、…、最終層([CLS])の出力を重み付き平均し、それを全結合層の入力としていた。重み付き平均の重みは学習パラメータとし、合計が1になるようにしていた。この発想めっちゃよさげ。どこかで使いたい。
学習の工夫
- Bertの部分と全結合層で学習率を変えていた。
- Bertの部分と全結合層で学習率を変えていた。