RTX3090x1でKaggle LLMコンペは戦えるのか?
はじめに
この記事は2024/12/13まで開催されていたKaggle Eedi - Mining Misconceptions in Mathematicsコンペを題材に、限られたリソースでどこまでスコアを上げることができるのかLateサブで検証してみた内容をまとめたものです。
Eediコンペは数学の質問テキストと不正解のペアに対して、その不正解の背景にある誤解(Misconception)を予測するNLPタスクで、ソリューションにはLLMが多く活用されたコンペでした。
本記事では割愛しますがタスク詳細や上位ソリューションについては、kutoさんの「Eediコンペ上位解法まとめ」がとても分かりやすいので、ぜひそちらを参照ください。
モチベーション
RTX3090x1で金圏スコアを再現し、潤沢な計算リソースが無くても昨今のNLPコンペで金メダルを取れる可能性があることを証明したいというのが今回の検証のモチベーションになります。
少し昔話になりますが、2022~2023年頃のNLPコンペは7b~14bのLLMが若干台頭しつつもDeBERTaが覇権を握っており、少なくとも計算リソースに関してはRTX3090(24GB)があれば十分トップ争いが可能な環境でした。
ここ1年ほどNLPコンペから遠ざかっていたのですが、昨年末に軽い気持ちでNLPコンペに参加してみたところ、DeBERTaは見る影もなく淘汰され、上位勢は当たり前のようにA100やH100で32b以上のモデルを学習させているなど、想像していた以上に環境が激変していて衝撃を受けました。
最近は安価なGPUレンタルサービスがあるとはいえ、それでも長時間レンタルするには躊躇う費用がかかるのが現状です。そんな中、計算リソースを準備しないとトップ争いの参加権すら無いというのはあまりにも無情なので、手元のRTX3090でどこまで行けるのか(あわよくば金メダルを取れる可能性を見出すべく)復習がてら実験をしてみようというのが本検証のいきさつになります。
検証
0. 縛り条件
本検証では以下のローカル環境でどの程度のスコアが出せるのか検証します。
- 計算リソース
- GPU:24GB(RTX3090x1)
- RAM:64GB
- ただし、ChatGPTなどの有料APIの使用はOKとします
- 上位チームが公開してくれているSyntheticデータをそのまま使いたかったので、外部APIの使用はOKとしています
- 学習用に大容量GPUをレンタルするのに比べれば良心的な費用なので、このくらいは大目に見るということで...
1. ベースライン
- 今回は5thチームの公開ソースコードをベースに検証を行います。
- ソリューション詳細については本家のDiscussionを読んでもらえればと思いますが、大まかな概要は以下の通りです。
- RetrieverとRerankerを組み合わせた2stageアプローチ
- Retrieverにはdunzhang/stella_en_1.5B_v5を使用
- RerankerにはQwen/Qwen2.5-32B-Instructでlistwise方式で並べ替えを行う
- gemini-1.5-proでtrainに含まれないMisconceptionに対応する質問-誤答ペアデータを生成してSyntheticデータとして追加
- Qwen/Qwen2.5-32B-Instruct(ファインチューニングなし)で各質問-誤答ペアのMisconceptionを推定させたテキストを生成し、Retriever/Rerankerの学習/推論時に使用することで知識蒸留を行う
- RetrieverとRerankerを組み合わせた2stageアプローチ
- オリジナルのソリューションではRerankerにQwen2.5-32B-Instructを採用していますが、今回のリソースでは学習できないのでQwen2.5-7B-Instructで代用します。
スコア
CV - Recall@100 | CV - MAP@25 | Public LB | Private LB | |
---|---|---|---|---|
Retriever only (fold4) | 0.94406 | 0.40785 | 0.39100 | 0.34815 |
Retriever + Reranker (fold4) | - | 0.53684 | 0.53747 | 0.50403 |
このスコアはPrivate58位(銀下位)に相当します。銀メダルという意味ではまぁまぁな感じもしますが、5位ソリューションをベースにしていることを考慮するとだいぶスコアが落ちてしまっている印象です。
ここをベースに、いくつかの工夫を加えることでどこまで改善できるか検証していきます。
2. データによる改善
2.1 Syntheticデータの追加
-
1stチームの公開Syntheticデータを追加することでどの程度スコア改善するか検証してみます。
- Claude 3.5 Sonnetで生成したものをGPT-4oでキュレーションしたSyntheticデータで、件数は約10.6k(コンペデータは1.8k)、コンペ用に与えられたMisconceptionに含まれれない新規のMisconceptionも約4800件ほど追加されています。
- Misconceptionをクラスタリングして生成時にfew shot exampleとして与えていたり、新規のMisconceptionがノイズにならないようにEmbedding modelで既存のMisconceptionと極端に類似したサンプルは除外するなど、非常に高品質なデータセットとなっています。
-
ハイパーパラメータやモデルアーキテクチャなどはベースラインから変更していません。
スコア
CV - Recall@100 | CV - MAP@25 | Public LB | Private LB | |
---|---|---|---|---|
Retriever only | 0.97254 | 0.44009 | 0.41292 | 0.38055 |
Retriever + Reranker | - | 0.54229 | 0.54259 | 0.51969 |
Retriever、Reranker両者とも性能向上しており、Publicで約0.005ポイント、Privateで約0.015ポイントほどスコアアップしています。これはPrivate35位(銀中位)に相当するスコアなので、シンプルながら大きな改善です。
特に今回に関しては、冒頭で述べた通りキュレーションがしっかりされていて高品質であったことがスコア改善のキーになったのかなと思います。
2.2 Misconception Augmentation
- 2ndソリューションで提案されていた手法で、LLMでMisconceptionに対する説明を生成し、それを学習に適用することでRetrieverの精度を向上させるアプローチです。
- 説明生成に使用するモデルはllama3.1-70b-Instructとqwen2.5-72b-Instructが良い性能を発揮したとDiscussionで言及されていたので、今回はqwen2.5-72b-Instructを使用してみます。ちなみに72bモデルもvllmでcpu_offload_gbを指定すればRTX3090で推論可能です。
- 1stチームのSyntheticデータを追加した状態でRetrieverのみ学習を行い、Rerankerは前述の2.1で学習させたweightを使用します。
スコア
CV - Recall@100 | CV - MAP@25 | Public LB | Private LB | |
---|---|---|---|---|
Retriever only | 0.97254 | 0.45544 | 0.43857 | 0.40644 |
Retriever + Reranker | - | 0.54444 | 0.55847 | 0.52777 |
期待通りRetriever単独のMAPに関してはそれなりに性能向上しましたが、Rerankerは微改善(Private 約0.008ポイント向上)という結果でした。ですが、RetrieverのCV-Recall@100がほぼ変わらなかったことを考慮すると、妥当な結果と言えるでしょう。
CV-Recallは既に0.97以上であることからRetrieverの性能(候補抽出性能)は現時点で十分で、大幅なスコアアップにはReranker側の改善がより重要と考えられます。
2.3 全データ学習
- データ周りの最後の検証として、全データ学習に切り替えることでどの程度の性能改善が見られるか確認してみます。
- 今回はCV検証時に学習完了時点でオーバーフィットしている様子は特に見られなかったので、同じハイパーパラメータで学習してlast_ckptを使用しています。
スコア
Public LB | Private LB | |
---|---|---|
Retriever(fold4) + Reranker (fold4) | 0.55847 | 0.52777 |
Retriever(all_data) + Reranker (fold4) | 0.56378 | 0.53449 |
Retriever(fold4) + Reranker (all_data) | 0.55845 | 0.53158 |
Retriever(all_data) + Reranker (all_data) | 0.56498 | 0.53569 |
期待通り、全データ学習に切り替えることでRetriever/Rerankerともに性能向上しました。
ただRerankerの改善はかなり限定的で、ほぼRetrieverが改善割合のほとんどを占めています。ここについては深く考察できていませんが、タスクや学習時のハイパラに依存しているのかもしれません。
ということで、Rerankerについては全データ学習にしてもあまり大きな差が見られなかったので以降の検証ではRetrieverのみ全データ学習、Rerankerは5fold分割で学習したweightを使用します。
(全データ学習しても良いのですが、単純に時間がかかるので...)
3. モデル変更による改善
3.1 14bモデルの使用
- ベースラインでは7bモデルをLoRAでファインチューニングしていましたが、QLoRAであれば14bモデルもRTX3090で十分扱えるので、RerankerモデルをQwen2.5-14B-Instructに変更してみます。
- Retrieverは2.3で使用したモデルから変更していません。(cv計算時は対応するfoldで学習したモデルを使用)
スコア
CV - MAP@25 | Public LB | Private LB | |
---|---|---|---|
Qwen2.5-7B-Instruct (fold4) | 0.54444 | 0.56378 | 0.53449 |
Qwen2.5-14B-Instruct (fold4) | 0.58419 | 0.58201 | 0.54985 |
Rerankerを14bに変更するだけでPublic/Privateともに約0.015~0.018ポイントという大幅な改善が得られました。このスコアはPrivate19位(銀上位)に相当しています。
おそらくパラメータ数が大きいモデルほど思考能力が高く、未知のMisconceptionへの対応力が優れているため大幅なスコア改善に繋がったのではないかと思います。
また、オリジナルソリューションが32bモデルを使用することで5位を達成していることを踏まえると、もっと大きいモデルを使えば更にスコア改善できると予想されます。(残念ながら、今回のリソースではこれ以上大きいモデルはファインチューニングできないのですが...)
3.2 Rerankerのアンサンブル
- 小さいサイズのモデルを使用している副次効果で処理時間にだいぶ余裕があるので、2.1で学習した7bモデルと3.1で学習した14bモデルをアンサンブルしてみます。
- アンサンブルは各モデルの出力logitの重み付き平均で行います。
- weightはCVをもとに手動で調整して、7b:14b=0.35:0.65としました。
スコア
CV - MAP@25 | Public LB | Private LB | |
---|---|---|---|
Qwen2.5-7B-Instruct | 0.54444 | 0.56378 | 0.53449 |
Qwen2.5-14B-Instruct | 0.58419 | 0.58201 | 0.54985 |
Ensemble 7b+14b | 0.58641 | 0.58447 | 0.55619 |
かなり微々たるレベルですが、それでもPrivateで0.006ポイントほど改善できており、Private15位相当のスコアを達成できました。12位(0.56429)から金メダルなのでやっとボーダーが見えてきた感じです。
なお、改善幅が小さかったのはアンサンブルに使用したモデルの多様性があまり無かったことが原因と思われます。恐らく別なモデルアーキテクチャを採用したり、学習設定を変えたモデルを使えばもっと改善が見込める気がしますが、時間がかかるので今回の検証では一旦ここまでとします。
4. 後処理の追加
- 最後に3rd、4thソリューションなどで採用されていたtrainに含まれない未知misconceptionのスコア補正をする後処理を試してみます。
- これはtestデータはtrainに登場しない未知のmisconeptionが多いことを利用した本コンペ特有のテクニックで、未知misconceptionのスコアを上方補正 or 既知misconceptionのスコアを下方補正する処理を最後に加えることでスコアを伸ばします。
- 今回は4thソリューションを参考に、既知misconceptionに対するスコアをC倍(C=0.2~0.4)してみます。
- なお、ベースは最もスコアの良い3.2のアンサンブル時点のサブを使用します。
スコア
Public LB | Private LB | |
---|---|---|
C=1.0 (ベースライン) | 0.58447 | 0.55619 |
C=0.4 | 0.61269 | 0.56675 |
C=0.3 | 0.61465 | 0.57030 |
C=0.2 | 0.61461 | 0.56677 |
期待通り後処理を追加することでPublic/Privateともにスコアが大幅に改善しました。
C=0.3のベストパラメータで、ついにPrivate10位相当(金圏)を達成できました。
結論
RTX3090x1でもLLMコンペで金メダルは取れる
最終的にPrivate10位相当のスコアを達成できたため、RTX3090でも最近のLLMコンペで金メダルを取ることは可能であることを証明することができました。
LLMの台頭でインフレが進むNLP界隈において、少メモリGPUでも十分に戦えるという希望のある検証結果に終われて非常に良かったです。
本当に取れるのか?
...と希望に溢れた結論で締めましたが、現実にはかなり厳しいだろうなぁというのが個人的な感想です。
本検証では確かに金圏相当のスコアを出せたのは事実なので、リソースが限られていても金メダルが取れる可能性があるというのは真実なのですが、あくまでLateサブの検証結果であることは無視できません。
Lateサブ検証と異なり、実際のコンペ中はPrivateスコアも見えず、ライバルが最終的にどこまでスコアを伸ばすのかも分かりません。本気で上位を目指して少しでも差を付けるためにスコアを伸ばしたいという心理状態の中、限られたリソースで勝てるという強い信念を持ってやり遂げるのは正直かなり難しいのではないかと思います。
また、検証を通して"大きいモデルを使う"というのは改善アイデア1~2個に相当するように感じました。
個人的な感覚として金メダルを取るには他参加者が思いつかないようなタスクに刺さる工夫を1~2個は見つける必要があると考えているのですが、リソースに縛りがあるとそのビハインドを補うため追加で更に1~2個のアイデアを見つけなければなりません。経験上そのようなアイデアは1個見つけるだけでもかなりしんどいのに、それを追加で1~2個探し当てなければならないというのはコンペ的にはかなり厳しい戦いを強いられることが容易に予想されます。
ということで、もし上位を目指すなら手元のリソースで扱えるモデルで実験を行い、コンペ終盤で大容量GPUをレンタルしてベストセッティングで大規模モデルを学習するのが現実的な戦略かなと思います。(ちなみに1位の方もDiscussionで同じようなことを言及されていました。)
さいごに
久々のNLPコンペで色んな衝撃は受けたものの、Lateサブ検証を通して最新のLLM周りの知見を得られたのは間違いなく大きな収穫でした。特にunslothやvllmなど1年前には見かけなかった技術が今やどのソリューションでも採用されるほどメジャーになっているくらいLLM周りの技術は日進月歩で発展しているので、これからも定期的にコンペに参加して知識をアップデートしていきたいなと強く感じました。
希望があるのか無いのか分からない結論になってしまいましたが、少なくとも工夫次第で金メダルを狙うのが不可能ではないことが分かったので、いつの日かRTX3090ユーザーがスマートなソリューションでかっこよくLLMコンペで優勝する日が来ることを期待しています。
Discussion