松尾研LLMサマースクールのコンペ
https://gyazo.com/b0631db7cfa8ad1bf6d02dc707fc34c6 (thanks TaroNakasendoさん)
https://gyazo.com/8c1a991f9f156c0aef595175c7ab22b1
最終スコア
10/10締め切り
3種類のタスクが混ざって提供される
うち2つの機械的に定量評価できるタスク(五択クイズ、長文要約)でリーダーボードが作られる
その上位入賞者で残りの生成タスクの質を相互評価する
参加者はSlack上で質問したり議論したりしながら同じ課題に取り組む
これがすごく参考になる、自分の試行錯誤の回数が数倍に拡張されているようなもの
松尾研の演習環境omnicampusでは24GBのGPUが8つまで使える
最初に50クレジットもらってて8つ使うと1時間で8クレジット消費する
10/2の段階でベースライン以上のスコアを出してる313人はGPUクレジットが75GPU時間追加してもらえた
ダイジェスト
選択肢問題と自由記述問題に"TheBloke/StableBeluga2-70B-GPTQ"、要約問題に'lightblue/openorca_stx'を切り替えて使った
選択肢問題
知識は全結合層に保存されるという仮説があるが、確かに'stabilityai/StableBeluga-13B'から'TheBloke/StableBeluga2-70B-GPTQ'への変更で格段に正解率が上がった。
文章の生成をせず選択肢の出現確率を直接参照することで爆速になり、正解率も上がった。
要約問題
期待する出力のスタイルを言語的に指示するのが困難で、入力が長いのでFew shotをするコストも高いので、ファインチューニング向きのタスク
演習環境でL4のGPUを4つ使って学習させた、1000データで2時間ちょい
データを増やすにつれて性能が上がっていくことを確認した。データは7000ちょい用意してあるが、与えられたGPUクレジットに限界があって試せなさそう
似たデータでファインチューニングされてる'lightblue/openorca_stx'を使うことにした
当初のプロンプトでは要約出力に関してrepetition penaltyを増やした方がスコアが上がったのだが、後から知ったファインチューニング時のプロンプトに揃えた場合はpenaltyを増やさない方がスコアが高いので戻した
自由記述問題
二つのそれぞれでの出力を見てStableBeluga2-70Bの方が良さそうだったのでそれを選択
コンペ中の思考
コンペ中に書いたメモを振り返りながら終了後に書いている
自分が「当たり前」と思うこともあえて書く
自分自身も「慣れてる人が当たり前だと思ってること」をわかってなかったから
例: 考えていることを記録する
後から何を考えていたか振り返れるように
開始前
コンペは多分9/25の月曜日に始まったのだと思うけど、僕は24日から旅行(熊野古道2023)に行ってたので遅れて29日金曜日から参加した 金曜日は会議が多いので合間に最終の講義を聞いてSlackを見て「いっぱい書き込みがあるなぁ」と思ってた
30日土曜日は溜まってたSlackのログを全部読んで非公開のScrapboxに入れた
これは後々エラーメッセージで検索して便利に使えた
9/29に、10/1迄にSubmitしている人を対象としてGPU利用時間を追加付与するアナウンスがあった
9/31
とりあえずスターターを走らせてサブミットまでやる
いじる前にまず確認する、先にいじると問題が発生した時に切り分けが困難になるから
追加GPU利用時間ももらいたいしね
終了時にbeepを鳴らす(thanks chocopanさん)
code:python
!pip install Jupyter-Beeper
import jupyter_beeper
b = jupyter_beeper.Beeper()
...
b.beep(frequency=392, secs=3, blocking=True)
エラー時にも別の音を鳴らせるといいなと思ったんだけどそれは結局実装してない
device_map='auto'の設定ではGPUにモデルが乗り切らなかった場合に自動でRAMかdiskに、モデルや推論途中のテンソルを載せるので、推論が遅くなる(thanks shitsutyoさん) モデルの各レイヤーがどのGPUに割り当てられているかはhf_device_mapで確認できる(thanks chocopanさん) 後から気づいたけどGoogle Colabならリソースの消費状況がグラフで表示されるので状況を理解しやすい
この辺りの話を先にSlackで読んでいたので問題の原因に気づくことができた
スターターは無事動いた: score: 2.0
出力されたファイルはbaseline.jsonと名付けて保存しておいた
これはその後何十回も活用されることになった
進捗表示が必要だと考えて実装した
何タスク中の何番目なのかを表示するようにした
後にタスクの開始時刻とタスクごとの所要時間を表示するようにした
「今どれくらい進んでいるのか、あとどれくらいの時間が掛かるのか」を理解するため
この辺で100問目から要約問題が始まることに気づいた
これの入力がとても長い
Slack上で「途中まで走ってからメモリ不足で死んだ」という報告がチラホラあったのはこれが原因だなーと思った
「テスト対象を1/10に間引くフラグ」「要約問題を1問だけ解くフラグ」「選択肢問題(最初の100問)をスキップするフラグ」などをつけた
フルで走らせる前にこれらの方法で死なないことを確認した
1/10データで推論にかかった秒数 {'generation': 8.499536145999855, 'summarization': 41.61696943300012, 'multiple_choice': 36.508038440000064}
20問しかない要約タスクが100問ある選択タスクより時間を使っている
要約が途切れるのでmax_lengthを増やしたいという話と、増やしてかえって悪化したという話をSlackで見た
要約タスクの入力サイズを確認して2048を超えているものがあることに気づいた
max_lengthを2048トークンにすると2GPUでも溢れる
4GPU, 1/10データで推論にかかった秒数 {'generation': 2.6214422240000204, 'summarization': 58.79387292899992, 'multiple_choice': 0}
4096トークンだとさらにコストが掛かる
入力の全体を見ないで捨てるか、分割して読むかのどちらかにしようと考えた
Google Colabで動かす実験
10/1
Colabで実験
(A) とりあえずプロンプト変更: 下がった
ChatGPTで使い慣れたフォーマットが良いかと思ったらそんなことはなかった
賢くないLLMはその賢くないLLMにとって理解しやすいフォーマットで情報を与えることが重要なのだなぁ
(B) stabilityai/StableBeluga-13Bにした: 2.67003
Beluga-13B + summarizationとgenerationのmax_tokenを1024にした: 2.79775
(A)で下がったので(B)からプロンプトをオリジナルに戻す
2.72885
(B)の2.67003からの比較なので改善している
この辺りの実験はColabで並行して行っている
受講生が課金しなくても実験できるようにしていることは良いことだと思うが、それは僕が課金してはいけないということではない
ずっとコンペだけしてられるわけではないので僕の可処分時間がボトルネックであり、GPU時間は金で買えるので相対的に貴重ではない
Colab Pro+を契約して実験を走らせて、結果待ちの間に新しい実験を実装して走らせていた
https://gyazo.com/23dd95763cb4e2168c476b7dddcc13a9
後どれくらい残ってるのか表示してくれるので親切
分割してそれぞれ要約して結合するコードを書いたが、正解データを眺めて、要求される要約文が想像以上に短いのでいいスコアにならないと判断してやめた
プロンプトの工夫だけで4点台
XLSUMでファインチューニングしている
multiple_choice:
baseline: 35問正解
TheBloke/StableBeluga2-70B-GPTQ: 90問正解
lightblue/openorca_stx : 80問正解
summarization:
baseline: 4.044292964896873
TheBloke/StableBeluga2-70B-GPTQ: 4.705614584018149
lightblue/openorca_stx : 6.788956451595625
思考
これを使えば手軽に性能は上がるだろう
が、僕にとって「コンペのスコアを上げること」より「経験したことを増やすこと」が重要な戦略目標
なのでネクストアクションはXLSUMでのファインチューニング
タスクごとにモデルとの相性がこんなに異なるのなら、タスクごとに実験して結果を出せるようにするべき
きっと最終的にタスクごとにモデルを切り替えて出力する形になるな、と予想
選択肢問題をTheBloke/StableBeluga2-70B-GPTQで解くのを試すべき
10/4
model00: スターターでファインチューニング
気づき: そもそもスターターでは長い要約の入力は学習データからスキップされてる(Slackでシェアした)
xlsumを見てて気づき: この「要約タスク」と呼ばれてるタスクって、実際のところ要約をしていないと思った(Slackでシェアした)
{
"id": 19,
"task_type": "summarization",
"text": "ムーサ・ウカビル容疑者 スペインのカタルーニャ警察によると、バルセロナ事件に関与した疑いのムーサ・ウカビル容疑者は、バルセロナ襲撃の約8時間後にカンブリスで警察に射殺された一人だったという。容疑者はカタルーニャ北部ジロナ出身のスペイン国籍で、17歳だったとみられる。警察は後に、バルセロナ襲撃に運転手は逃亡中だと発表。地元メディアは、これはすでに指名手配されているユネス・アブーヤクーブ容疑者(22)と伝えている。 ウカビル容疑者らはカンブリスでもワゴン車で歩行者をはね、女性一人を死亡させたほか、6人にけがをさせた疑い。 調べによると、歩行者をはねた後に横転した車から出た容疑者らを、一人の警官が射殺した。容疑者の一人はナイフを手にしていたとされる。自爆ベルトのようなものを身に着けていたが、後にこれは偽物だと判明したという。 警察がウカビル容疑者と共に指名手配したサイード・アーラア容疑者(18)、モハメド・ハイチャミ容疑者(24)も、カンブリスで死亡した4人に含まれるという。指名手配した中では、ユネス・アブーヤクーブ容疑者(22)のみ、行方が分かっていない。ウカビル容疑者以外は、モロッコ出身という。 左から、ウカビル容疑者、アーラア容疑者、ハイチャミ容疑者、アブーヤクーブ容疑者。左3人は死亡。アブーヤクーブ容疑者は行方不明 ウカビル容疑者は、兄の身分証明書を使い複数の車両を借り出したとみられる。バルセロナ襲撃で使用されたワゴン車に、兄の身分証が残されていた。また逃走用に用意したとみられる別のワゴン車が、バルセロナ北約80キロにあるビック市で発見された。 捜査当局は、バルセロナとカンブリスの襲撃を、カンブリスから西南約90キロのアルカナルで16日夜に起きた民家爆発と結びつけている。民家爆発では一人が死亡した。当局は容疑者らが爆発物を作ろうとしていたとみて、さらに高度な手法による攻撃を計画していた疑いを調べている。 バルセロナのワゴン車襲撃 現場にいた人たちは 一連の事件に関連して、ほかに4人が逮捕されている。アルカナルの民家爆発後に一人と、バルセロナ襲撃後に、バルセロナ北約100キロにあるリポイ市で3人が逮捕された。ウカビル容疑者の兄ドリス容疑者もその一人で、出頭後に逮捕された。弟が自分の身分証を盗んで、襲撃用の車を調達したと供述しているという。 バルセロナの襲撃では、スペイン人男性一人とイタリア人男性2人の死亡が確認されたほか、ベルギー人、カナダ人、米国人も死亡したとされる。 オーストラリアの報道によると、重傷を負った母親と現場ではぐれてしまった、英豪二重国籍の7歳の男の子が行方不明になっている。 (英語記事 Barcelona attack key suspect Moussa Oukabir confirmed dead)",
"answer": "スペイン北東部の主要都市バルセロナで17日夕、繁華街のランブラス通りでワゴン車が歩行者を次々とはね、少なくとも13人が死亡し、100人以上が負傷した事件の容疑者の一人が、翌日未明に約120キロ西のカンブリスで警察に射殺された5人の一人だったことが確認された。射殺された襲撃犯たちはカンブリスでもワゴン車で歩行者を次々とはね、7人を死傷させた。"
},
answerの中の「ランブラス通り」が入力に含まれない
これは「要約タスク」ではなく「ニュース記事の2段落目以降を入力して、1段落目を生成するタスク」だと思った
そんなデータでいいんかい!と思った
これを明示的にプロンプトしてみた
"あなたは新聞記者である。下記はニュース記事の断片であり、末尾に英語記事のタイトルがある。ありそうな第一段落を創作せよ。"
時間が掛かって途中でインスタンスへの接続がおかしくなった
部分的なデータを書き出させてスコア測定、芳しくない
出力を観察。出力が長くなったことがスコアの悪化につながったと判断した。
要約タスクの肝は適度な長さの出力にすることっぽい
タスク種別ごとにスコアを測る実装
baselineがスコアの算定基準になってて2.0点なのは既知なので、baselineの結果に特定のタスクの結果だけ上書きしたものをsubmitすれば個別のタスクのスコアがわかる、以下mcが選択肢問題、sumが要約問題
過去のsubmitも分解して個別のスコアを確認した
ここまでのベスト
mc: Beluga-13B + Original Prompt: 3.0
sam: Beluga-13B + 1024tokens: 1.85658 (baseline: 2.0 に負けてる)
TheBloke/StableBeluga2-70B-GPTQ
mc: 3.29412 (best!)
sam: 1.94878 (baseline: 2.0 に負けてる)
これはプロンプトの修正も入っている
プロンプトを元に戻したものとも比較したが良い結果にはならない
結果の目視観察で「かなり長いな」と感じた
やはり長さのコントロールをファインチューニングでやることになるか
10/8
'lightblue/openorca_stx'
mc: 1.76471
sum: 2.45053 (best!)
やはり強い!
長さをファインチューニングでコントロールする実験
N=100とN=1000で実験
model01: sum: 1.42116
model02: sum: 1.45841
一応データを増やすにつれて良くはなるようだが…
データはxlsumを使ってN=7000ぐらい用意してあるけどコストの割に性能上がらなさそう...
openorca + repetition penalty:1.2
思考: 結果を観察したら単語の繰り返しが出てるケースがあった、ペナルティを増やそう
sum: 2.46645 (best!)
lightblue/openorca_stx の Training Detailsの話(thanks mizoguchicoji)
学習時に使われたプロンプトが書かれている
思考: XLSUMでファインチューニングしたことによって要約の性能が上がったのだとすると、そのファインチューニングをした時のプロンプトに揃えた方が性能が上がるのでは?
sum: 2.63799 (best!)
これはrepetition penalty:1.2がついたままだが、それも学習時のものに揃えるべきでは
sum: 2.93555 best! (10/9)
選択問題で文章再生せずに確率を参照
https://gyazo.com/11f25a73f8d219ac189cc71a0957ef5e
スターターで改善の例として紹介されていたが実装が面倒そうだなと思ってスルーしてたものを実装してシェアしてくれた人がいた(thanks piyoketa)
mc: 3.29→3.52941 (best!)
10/9
mc: 3.52941 sum: 2.93555 なので4.0超えてるしこれでいいかなーという気持ちになったから提出して終わりにした
10/13
追加データでの最終テストに参加するのにはテストデータの作成に参加することが必要だというのを理解していなかった!
感想
無料の演習環境があるのは多くの人にとっては良いことだと思う
50GPU時間が無料で全員に配られる、太っ腹
追加で75GPU時間が配られた、太っ腹
太っ腹なのはGoogleさんかもしれない
40GB VRAMのA100を1時間150円で使える
自前のハードウェアや、演習環境と比べて「並列で使える」のが良い
ある実験をしていて、何か思いついたことがあると、別の実験をしたくなる
一度に一つしか実験できない環境では、一つ目の実験が終わるまで待たなければならない
Google Colabなら多分4つまで並列で実験できる
「僕が実験に集中できる時間」は限られてるので思いついた実験を並列で走らせられるのは「僕の時間の使用効率」を高めた
1000円ずつ追加できるので、うっかり寝落ちしても1000円無くなるだけで済むのも良いところ
Google ColabのUIは素晴らしい
特にメモリとVRAMの使用量がグラフでサイドパネルに出せるのが良い
「あれ?モデルがGPUに乗ってないぞ?」という気づきが得られる
VRAMに乗るはずのモデルが、さっきは乗ってたのに、今は乗ってないぞ?というハプニングに気づける
これに気づかないと「あれー、さっきは1時間で終わったのに、今回はまだ終わってないなー」みたいな状態に陥ってしまう
「予想と違う振る舞いに素早く気づけること」は大事
「どの程度良くなったか」を判断するサービスが提供されて数百人で同じ基準で「良さ」を比べることが可能になってたのが良い体験だった
Slackによる受講者間の助け合いの場がとても有益だった
典型的なミスとその解決を自分以外の人がやってくれてるのでつまらないことにハマって時間を無駄にしないで済んだ
ログはしっかり保存した
今回最終提出物としてipynbが求められていたのですごく使ったのだけど、これは良いものだと思った
ついつい慣れた方法で「Jupyter Notebookで作業するのは不安だし混乱するからローカルにファイルを置いてgitで管理しよ」と思ってしまったが、振り返って考えるともっとNotebookに寄せてもよかった
良いところ、その1、タクスキューとしての振る舞い
何か大きな処理を走らせるとき、ローカルの開発のメンタルモデルだとそれはプロセスになりがちなわけだが、その場合「そのプロセスが終わったらこの処理をして」と後からやる方法はあまりわかりやすくない
Notebookなら「セルを追加して実行しておく」だけ
プロセスが分かれている場合と違って名前空間にアクセスできるのも良いところ
「あっ、この変数の値を保存するコードにしとけばよかった!」的なのを後付けで保存できる
実行中のスクリプトを中断させて変数の値を見たりできるのも良い
出力がデフォルトで保存される
ローカルのスクリプトで開発してて、printで表示したものって、teeとかでファイルに保存してない限り後から振り返りたくなっても行方不明になりがち
もちろんloggingとかでファイルにログを書いてtailとかで読めばいいんだけどね
そういうことを考えなくてもprintもエラー時のスタックトレースも全部まとめて「その時に実行したコード」とセットで管理されるのが良い
この特徴のためには実行中に書き換えないことが必要
いじりたくなったら別名保存して別のカーネルにつなげば良い
「別名保存」がgitでブランチを作ることに相当する
ファイルシステム
ブラウザ上で動かすのは永続化とかが不安になるところ
演習環境では永続化されるディレクトリがあった
ColabではGoogle Driveをマウントすれば良い
runpodをおすすめされたので今後検討する(thanks satoru_hataya) Github CopilotみたいなことをGoogle Colab上でできる
Pro+だから?
締め切りがあることと「みんなやってる」感があることが良かったのだなという気がしてきた
図書館で試験勉強するみたいな
実際は2000人Slackにいて500人しかsubmitしてないわけだから「みんな」ではないけど