
自分のブログ49記事でミニGPTを学習させたら、「位置エンコーディング」と「.envを呼ぶ」を書き出した
Self-Attentionを実装し、位置エンコーディングを実装し、手書きのMLPとAdamを拡散モデル・GAN・Flowで何度も書いた。部品は全部揃っている。
組み立てたら、GPTになるはずだ。
というわけで、2層Transformer(d=128、4ヘッド)の文字レベルGPTをnumpyだけで実装し、**このブログ自身の全49記事(12万字)**で学習させた。自分の書いたものを食べさせたら、何を書き出すのか。
まず、実装が正しいことを確認する
Transformerの逆伝播は手で書くと間違えやすい。学習が進まないとき「アルゴリズムのせい」なのか「バグのせい」なのか分からなくなるので、先に数値微分と突き合わせた。
Wq0 : 数値 -3.850818e-04 解析 -3.850818e-04 相対誤差 8.33e-09
W11 : 数値 -6.456322e-04 解析 -6.456322e-04 相対誤差 8.05e-09
Wout: 数値 1.003423e-03 解析 1.003423e-03 相対誤差 3.58e-08
パラメータを微小量ずらして損失の差から求めた勾配と、自分の書いた逆伝播が出す勾配が相対誤差1e-8で一致。これで「以降の結果はバグではなく学習の性質だ」と言える土台ができた。この確認に30秒かけるかどうかで、後のデバッグ時間が何時間も変わる。
生成文は、こう育った
学習中の6時点で、同じ「この実験では」という書き出しから続きを生成させた。

段階がはっきり分かれていて面白かった。
- step 1: 完全なランダム。1372種類の文字から一様に選んでいる
- step 200: 助詞(「の」「で」「は」)と句読点が正しい位置に現れ始める。頻度の高い文字とその並びを先に覚える
- step 600: 「変わりにす」「考えまでは」など、日本語の単語らしき断片
- step 1500: 「低周波」「ノイズ」「次元」——技術用語が出てくる。このブログのコーパスを食べていることが分かる
- step 3000: 文の構造ができる。「結果は見えなった(データはどちら…」
- step 6000: 「位置エンコーディング」「パーセプトロン学習則」「.envを呼ぶ」。さらに
**(markdownの太字)や-(箇条書き)まで再現している
最後の生成文を全文で見ると、こうだ。
この実験ではなくなったの、位置エンコーディングアプ競約1パックセストロン学習則**。「.envを呼ぶの分布図」をアニメーションとしても、何もっきりしていない状態が認知りやすい相手が求めると、こうしてよく聞いた。 - **自分の考え方を計算し、入力させる
意味は全く通っていない。 でも「アニメーションとしても」「〜という状態が」「自分の考え方を」あたりの言い回しは、確かに自分が書きそうな文だ。7万パラメータ程度の小さなモデルが12万字から学べるのは、意味ではなく文体なのだと分かる。
損失の下がり方

損失は7.2から2.5へ。1372種類の文字から完全にランダムに選ぶと なので、初期値はぴったり理論値だ(実装が正しい傍証にもなる)。最終的な2.5は、次の1文字の候補が実質12個くらいに絞れている状態を意味する。
attentionは何を見ていたか
学習後のモデルに「拡散モデルを実装した結果、」を読ませて、attentionの重みを覗いた。

ヘッドごとに役割が分かれていた。
- 層1ヘッド1: 対角線のすぐ下——つまり直前の1文字への注目。日本語では直前の文字が次の文字を強く決める(「拡」の次は「散」)ので、これは合理的
- 層2ヘッド1: 文頭の「拡」「散」へ遠距離の注目。話題を保持する役割に見える
- 層2ヘッド3: 2〜3文字前の「モデル」「実装」といったまとまりへの注目
誰も「そう分業しなさい」と指示していない。損失を下げるという1つの目的だけから、役割分担が自然に生まれた。Self-Attentionの記事で「学習済みの射影行列がないと『it』は『animal』に注目しない」と確かめたが、今回はその学習済みの射影行列を自分で作ったことになる。
温度を変えると性格が変わる
生成時の温度(確率分布の尖らせ方)を振ってみた。
- 温度0.4(慎重): 「この実験では、「このデータ」の値を持ち上げるほど、ここまではなく…」——無難な言い回しに寄る
- 温度0.8(標準): 「この抑えられた次元になっているがかりましています。…こここで人生の使うのかもののは、実際に自分のブログ」
- 温度1.2(大胆): 「とも代わりにせる。1つの小法起きやすい 原因は絶対ればuけないメートを作り出して…」——語彙は豊かになるが崩壊も増える
ε-greedyの記事の探索率と同じ構図だ。安全に行くほど平凡になり、冒険するほど当たりも外れも増える。
手を動かして意外だったこと
一番面白かったのは、意味より先に文体を覚えることだった。step 6000のモデルは何も理解していない。それでも「アニメーションとしても」「という状態が」といった、自分の手癖のような言い回しを再現する。文体とは、意味を組み立てる能力とは独立した、文字の並び方の統計にすぎないのかもしれない。文章の個性だと思っていたものの結構な部分が、実は12万字から抽出できる表層のパターンだったわけだ。
もう1つは、この実験が過去記事の総決算になったこと。Self-Attentionも位置エンコーディングもAdamも、それぞれの記事では単体で動かしただけだった。それを全部繋いだら、(おもちゃとはいえ)言語モデルとして動いた。部品を1つずつ手で書いてきた蓄積が、最後に1つの動くものになる——1ヶ月半かけて積んだブロックが噛み合った瞬間で、この連載でいちばん嬉しかった実験だった。
まとめ
- Self-Attention・位置エンコーディング・手書きMLP・Adamという過去記事の実装を全部組み立て、2層Transformer(d=128、4ヘッド)の文字レベルGPTをnumpyだけで構築
- 数値微分との突き合わせで相対誤差1e-8を確認してから学習(実装の正しさを先に保証する)
- このブログ自身の全49記事12万字で6000ステップ学習。損失7.22(理論上のランダム値)→2.5
- 生成文の進化: ランダムな漢字 → 助詞と句読点 → 単語断片 → 技術用語 → 文構造 → ブログ特有の語彙とmarkdown記法
- attentionはヘッドごとに「直前の文字」「文頭への遠距離注目」「2〜3文字前のまとまり」と自然に役割分担していた
- 意味は最後まで通らない。それでも文体は再現される——文体の相当部分は、意味とは独立した文字並びの統計である


