TT Lab
はじめる
学ぶ 学習パス コース

MiniMind — 小さな言語モデルを最初から最後まで自分で学習する

小さなモデルにできることとできないことを数字で分ける

TT Labで続きを見る

目標

基準の事前学習モデルとSFTモデルのパープレキシティとBPBを測り、文書100個で過学習の曲線を作ります。SFTで見た質問と見ていない質問、2桁の足し算、学習した長さの外の位置、事前学習モデルが事実を知っているかを測って、このモデルが何をできないのかを、数字で残します。

なぜ重要なのか

損失が低く、見た質問にすべて正しく答えるモデルも、1つ分布の外に出れば崩れます。その境界を知らないと、モデルを間違った場所で使うことになります。大きなモデルでは、複数の原因が混ざってぼんやり見えますが、100万パラメーターのモデルでは、「規則は汎化し、事実は暗記する」、「知っていることも、質問の形が違うと取り出せない」、「新しい形式を学びながら、昔の能力を忘れる」が、それぞれはっきりした数字で表れます。 評価は、新しく教えたものだけを測ることではありません。SFTやDPOのあとに、元の能力を測り直してはじめて、忘れたものが記録されます。このラボの最初のステップが、それです。

ステップ

  1. 基準の事前学習モデルとSFTモデルの、検証コーパス全体の損失・パープレキシティ・BPBを書いてください(出力先: /root/mm/eval/ppl.json)。
  2. 学習コーパスの先頭の文書100個だけで、300学習ステップ学習して、25学習ステップごとの学習損失・検証損失と、最後の重みを残してください(記録: /root/mm/eval/overfit_log.csv、重み: /root/mm/eval/overfit.pth)。
  3. 基準のSFTモデルの正答率(口調は無視)を、SFTで見た質問と見ていない質問に分けて書いてください(出力先: /root/mm/eval/heldout.json)。
  4. 2桁の足し算10個の答えと正答率を書いてください(出力先: /root/mm/eval/ood.json)。
  5. 256トークンのウィンドウで、位置1–127と128–255の平均損失を書いてください(出力先: /root/mm/eval/length.json)。
  6. 事前学習モデルが、村ごとに特産物・守護動物を続けて書けるかを数えて書いてください(出力先: /root/mm/eval/probe.json)。
  7. ## 무엇을 재나 ## 과적합 ## 작은 모델이 못 하는 것の3つのセクションを書き、事前学習モデルのBPBと2桁の足し算の正答率を入れてください(出力先: /root/mm/eval/report.md)。韓国語の見出しは、順に「何を測るのか」「過学習」「小さなモデルにできないこと」という意味です。

参考

パープレキシティとBPBを測る

/opt/mm/ref/val.npyを128トークンずつ重ならないように切ったウィンドウすべてで、基準の事前学習(pretrain.pth)モデルとSFT(sft.pth)モデルの平均損失(ウィンドウ数で重み付けした平均)、パープレキシティ(平均損失のexp)、BPBを、{"pretrain": {"loss", "ppl", "bpb"}, "sft": {…}}の形で書いてください(出力先: /root/mm/eval/ppl.json)。

BPBの分母は、ウィンドウごとに最初のトークンを除いた残りのトークン(3以上、つまり特殊トークンを除く)をtok.decodeして、UTF-8で数えたバイト数です。SFTモデルのパープレキシティが、なぜ数百なのかを思い出してみてください。何を1e-3で学んだのかを。

文書100個で過学習させる

/opt/mm/ref/train.npyから、101番目のbosの手前まで(文書100個)だけを切り出し、mmkit.seed_all(0)で新しいモデルを作って、バッチ8・長さ128・lr 3e-3(スケジュールなし)で300学習ステップ学習し、25学習ステップごとのstep,train_loss,val_loss(検証はmmkit.lm_loss(model, val, n_batches=4))と、最後の重みを残してください(記録: /root/mm/eval/overfit_log.csv、重み: /root/mm/eval/overfit.pth)。

検証損失が最も低かった学習ステップを探してみてください。そのあと、学習損失はずっと下がり続けるのに、検証損失は上がります。規則の代わりに、その100個を暗記しはじめた地点です。採点ツールは、最低点が最後より前にあって、最後で0.2以上上がり、学習損失と検証損失が0.5以上開いているかを見ます。

見た質問と見ていない質問を比べる

基準のSFTモデルで、sft.jsonl(見た質問)とsft_val.jsonl(見ていない質問)のそれぞれで、1往復の対話の先頭60個に、グリーディ生成で答えさせ、終わりの입니다・이다を取り除いた(韓国語の「です」と「だ」にあたる語尾です)正答率を、質問の種類別(fact: 村についての質問、add: 足し算)に、{"seen": {…}, "held_out": {…}}の形で書いてください(出力先: /root/mm/eval/heldout.json)。

見ていない事実の質問は、事前学習コーパスには出てきたものの、SFTでその質問の形を見たことがないものです。見ていない足し算のペアの正答率と、比べてみてください。規則と事実は、違う形で汎化します。

2桁の足し算を解かせる

基準のSFTモデルに、2桁の足し算10個(12+15、23+41、30+30、45+12、17+21、50+25、11+11、34+52、26+13、40+19)を'{a} 더하기 {b}는?'(韓国語の文は「{a}たす{b}は」という意味です)の形で聞いて、答えが正解の数字で始まる割合を、accuracyとrows(q: "12+15"の形、answer: モデルの答え)として書いてください(出力先: /root/mm/eval/ood.json)。

モデルは、1桁の足し算100個しか見ていません。答えの形式(数字+語尾。語尾は韓国語の「です」または「だ」にあたります)は守りますが、数字は、1桁の足し算の答えのように出ます。規則の「範囲」までは学べていません。

学習した長さの外の位置を測る

val.npyを256トークンずつ切ったウィンドウすべてを、基準の事前学習モデルに入れて、位置ごとの次のトークンの損失を、位置1–127(loss_pos_1_127)と128–255(loss_pos_128_255)に分けて平均し、windowsとあわせて書いてください(出力先: /root/mm/eval/length.json)。

cross_entropy(…, reduction="none")で位置ごとの損失を受け取って、2つの区間に分けます。このモデルは、128トークンのウィンドウだけで学習しました。RoPEが相対位置を使うので、崩れはしませんが、見たことのない遠い距離では、精度が下がります。

事前学習モデルは事実を知っているかを調べる

/opt/mm/data/world.jsonの村ごとに、基準の事前学習モデルに[bos] + '{마을} 마을의 특산물은'と'… 수호 동물은'(プレースホルダーは村の名前で、韓国語で順に「{村}村の特産物は」「…の守護動物は」という意味の文字列です)を入れて、6トークン、グリーディ生成で続きを書かせ、正解で始まる数を数えて、specialty_known・animal_known・held_out_known_by_pretrain(取り分けておいた4つの事実のうち当てた数)として書いてください(出力先: /root/mm/eval/probe.json)。

SFTモデルが、見ていない事実の質問を間違えた理由が、「知らないから」なのか、「知っているのに質問の形式で取り出せないから」なのかを、ここで分けます。守護動物は、6種類が村の順に回るので暗記しやすく、特産物は、12個が1つずつペアになっています。

このモデルにできないことを残す

## 무엇을 재나 ## 과적합 ## 작은 모델이 못 하는 것の3つのセクションを書き、ステップ1の事前学習モデルのbpbとステップ4のaccuracyを数字で入れてください(出力先: /root/mm/eval/report.md)。韓国語の見出しは、順に「何を測るのか」「過学習」「小さなモデルにできないこと」という意味です。

最後のセクションに、「できないこと」を原因別に(知らない事実、知っているのに取り出せない事実、見たことのない範囲、忘れた能力)1行ずつ書いてみてください。このモデルをどこに使ってはいけないかが、そのままこのリストです。