KEN’S CAT LOG
▣

RTX 4090一枚でGPT-2をゼロから作ってみた。1日で本家超え、チャットもできるようにした

自宅のRTX 4090一枚で、GPT-2(124M)をゼロから学習してみた。データの準備から事前学習、チャットできるようにする指示チューニング(SFT)まで、全部自分のPCでやってる。

先に結論を書くと、こんな感じ。

  • 事前学習は約21時間で完了。 常識推論テストのHellaSwagで30.5%。本家GPT-2 124Mの29.4%を超えた
  • SFTは2時間弱。 学習開始からわずか5分で会話っぽい返事をするようになった
  • ただし中身はハルシネーションだらけ。「パリの人口は24億人」「12+7=30」とか平気で言ってくる

GPT-2がだんだん賢くなっていく様子が面白かったので、その過程をまとめておく。

環境

  • GPU: RTX 4090(24GB)
  • CPU: i7-13700K / メモリ64GB
  • OS: Windows 11(WSLは使わず、Windowsでそのまま)
  • PyTorch 2.11 nightly(CUDA 12.8)+ triton-windows

コードはKarpathyのnanoGPT/build-nanogptと同じやり方。Claude Codeに「このPCのGPUで1日でできる範囲のGPT-2を作って」と頼んで、構成の提案からスクリプト作成、学習の監視まで一緒にやってもらった。

データの準備:10Bトークンが12分で揃った

学習データはFineWeb-Edu(教育系の高品質な英語Webテキスト)の10Bトークン版。parquetで約27GB。

最初は素のHugging Faceのダウンロードで1.7MB/sしか出なくて、全部落とすのに4時間以上かかる計算だった。hf_transferを入れたら60〜70MB/sになって、2GBのファイルが30秒で落ちてくる。ボトルネックがトークナイズ側に移って、ダウンロードとトークナイズ合わせて約12分で全部揃った。

ちなみに最初、キャッシュの保存先を変えるHF_HOMEをhuggingface_hubのimportの後に書いてたせいで、設定が効かずに別ドライブにダウンロードされてた。この環境変数はimport時に読まれるので、importより前に設定すること。地味にハマる。

学習の設定

項目 内容
モデル GPT-2 small(12層・768次元、1億2400万パラメータ)
1ステップ 約52万トークン(16×1024を32回の勾配累積)
ステップ数 16,000(約8.4Bトークン)
速度 約12万トークン/秒
VRAM 約12GB

Windowsだとtorch.compileは動かないからWSLで、という話をよく聞くけど、triton-windows入りの環境ではそのまま動いた。

10Bトークン全部だと24時間を超えるので、1日に収まるように8.4Bトークンに削ってる。

小ワザとして、語彙数を50257から**50304(128の倍数)**に切り上げてる。GPUの行列計算が速くなるKarpathyの有名なテクニックで、これが後のチャット化で思わぬ形で役に立った。

事件:2.5時間で学習が止まった

途中経過を見たら、学習が止まってた。原因はHellaSwagの評価データ。nanoGPT系のコードはGitHubのrowanz/hellaswagからデータを取ってくるんだけど、そこが**「451 Unavailable For Legal Reasons」**(法的理由で公開停止)になってた。404エラーで評価ごと学習が落ちてた。

Hugging Face上のRowan/hellaswag(中身は同じ10,042問)から読むように直して、500ステップごとに保存してたチェックポイントから再開。評価が失敗しても学習は止めないように、try/exceptで囲んだ。

長時間の学習では、評価やログみたいな「本体以外」の失敗で学習を落とさない。 これ大事。

結果:本家GPT-2を超えた

検証データのlossはこんな感じ。最初の1時間で一気に下がって、あとはじわじわ下がっていく。

検証データのlossの推移

開始時のlossの10.95は、ln(50304)≒10.83とほぼ同じ。つまり5万語から完全にあてずっぽうで選んでる状態からスタートしてる。

HellaSwagの正答率はこう。

HellaSwag正答率の推移

約6.3Bトークン(step 12,000)で本家GPT-2 124Mの29.4%を超えて、最終的に30.5%。本家GPT-2はWebTextで学習してる。こっちはFineWeb-Eduで、教育系の質の高いデータを使ったのが効いてると思う。

だんだん賢くなっていく様子

学習中、1時間ごとに同じプロンプトで文章を生成して記録してた。これが一番面白かった。

学習前(ランダムな状態)

Hello, I'm a language model,CHR 351ointment Education rodents Effectiveantically emulatorprot grievance...

単語が完全にランダムに並んでるだけ。

37分後(0.26Bトークン)

The capital of France is a capital trade market ... is often referred to as the capital city of Scotland

文の形にはなってる。「首都の話」なのは分かってるのに、フランスの首都をスコットランドの首都って言ってる。

約2時間後(0.79Bトークン)

Photosynthesis is the process by which oxygen gas is converted into ammonia by removing the nitrogen hydroxylates (NTP).

文法はかなり自然になった。そのかわり、専門用語を並べてそれっぽいウソをつくようになった。ハルシネーションの原型って感じ。

約2.1Bトークン

The capital of France is Paris, and the country is also France. France makes approximately 50% of the world's steel production.

ついにParisって言えた!……と思ったら、直後に「フランスは世界の鉄鋼の50%を生産」とウソの統計を付け足してくる。

完成したベースモデルに質問してみた

Question: ... Answer:の形で10問聞いてみた。

  • What is the capital of France? → (a)〜(i)の選択肢を並べて、問題集を作り始める
  • Who was Albert Einstein? → 「1918年11月16日、ミズーリ州セントルイス生まれ。父は鉱夫で、本人は学校の先生」。全部ウソだけど、伝記っぽい書き方はできてる
  • What is 12 plus 7? → 「12 plus 7 is an arithmetic expression.」。計算せずに定義を語りだす

知識はそこそこ持ってるけど、「質問に答える」という振る舞いを知らない。ベースモデルはあくまで「文章の続きを書く」機械なので、そこは当然。

SFTでチャットできるようにした

ここから、ChatGPTみたいに質問に答えられるようにする**指示チューニング(SFT)**をやった。

  • データ: Hugging Faceのsmol-smoltalk(約46万会話、2.7億トークン)
  • チャット形式: <|user|> <|assistant|> <|end|>みたいな区切り記号を追加。ここで、さっき語彙を50304に切り上げた空き番号を使い回した。モデルの構造を変えずに特殊トークンを追加できたので、速度目的の小ワザがここで役に立った
  • 学習するのは回答部分だけ: 質問文は読むだけで、真似させるのはアシスタントの回答と、最後の<|end|>だけ
  • 2エポック、約1時間50分

ポイントは<|end|>まで学習させること。これで、モデルが言い終わったら自分で止まるようになる。ChatGPTとかも、終わりの記号を出したら生成を止めるっていう同じ仕組み。

たった5分で会話っぽくなった

SFTを始める前(step 0)は、知らない区切り記号に混乱して「jakjakjakjak…」と無限ループしてた。それが500ステップ(約5分)でもう会話っぽくなった。

The capital of France, Paris, is a city known for its numerous landmarks, including the Eiffel Tower, Louvre Museum, and Notre-Dame Cathedral.

しかもちゃんと言い終わって止まる。話し方を覚えるのは一瞬だった。

ただし知識は相変わらず。途中のモデルは「パリは世界最大の都市で、人口は約24億人」とか言ってた。

SFT前後で比べてみた

同じ質問でSFT前(ベースモデル)と後を比べた。

質問 SFT前 SFT後
What is the capital of France? 選択肢(a)〜(i)を並べだす 「The capital of France, Paris, is a city located in the northern part of the country, along the Seine River.」
Who are you? 「I am the person who has the gift for all that I do.」 「I'm a language learning AI assistant with over 10 years of experience」(AIなのに経験10年)
Translate "Good morning" into French. 質問と関係ない話をしだす 「Bonjour!」(正解。でもその後「Good morning (modifier)」を延々繰り返す)
What is 12 plus 7? 「arithmetic expressionです」 「12 + 7 = 21」→「12 + 7 = 30」→「35 + 7 = 34」と、それっぽい解き方でどんどん間違える
Who was Albert Einstein? 父は鉱夫の学校の先生 「prominent physicist」と大枠は合ってる。ただし「1905年2月24日ウィーン生まれ」はウソ

口調や形式は完全にアシスタント。中身はウソが多い。 計算は壊滅的だった。

実際にチャットしてみた

ターミナルで会話できるchat.pyを作って、話しかけてみた。

You: What is the capital of Japan? Answer in one sentence.
AI: The capital of Japan is Tokyo, a city known for its historical landmarks and cultural significance.

「1文で」っていう指示に従えてる。 これはベースモデルにはできなかったこと。

別の会話で、首都を聞いたあとに続けて人口を聞いてみた。

You: What is the population there?
AI: In Japan, the population is estimated to be around 50,000 people. ... the northern part of the country, where about 1.5 billion people live...

前の会話を受けて「there=日本」と理解はしてる。でも人口5万人と言った直後に北部に15億人住んでるとか、もう滅茶苦茶。

日本語で「日本の首都は?」と聞いたら、こう返ってきた。

AI: I'm ready to help you with your writing. Please go ahead and provide the text...

英語のデータしか学習してないので、日本語は「添削してほしい謎の文章」に見えたらしい。

最後に「GPUについての俳句を書いて」と頼んだら、「I see the world, the thoughts, the emotions」を延々と繰り返す詩になった。俳句とは。

やってみて分かったこと

  • 4090一枚で、1日あれば本家GPT-2を超えるモデルが作れる。 GPUの電力は約430W。電気代はGPUだけでざっくり300円くらい(推定)
  • 話し方は一瞬で身につくけど、知識は事前学習で決まる。 SFTは5分で会話形式になったけど、事実の正確さはほとんど変わらない
  • 124Mのモデルは、文法はほぼ完璧だけど中身はウソだらけ。 流暢さと正しさは別物っていうのが、手に取るように分かる
  • 長時間学習はインフラ側でコケる。 今回止まったのは、モデルじゃなくて評価データの置き場所が消えてたせい

自分で一から作ると、ChatGPTみたいなAIが「文章の続きを予測する機械」に「会話の作法」を教えたものなんだっていうのが、体感で分かる。次は、もう少し実用に寄せたモデル作りもやってみたい。