LLM Foundations Story
このドキュメントは、Mini Transformer Lab のハンズオンと一緒に読むための基礎概念ガイドです。
登場人物は、学習者である「あなた」と、小さな言語モデル Mini です。Mini はまだ何も知らない状態から、文字列の続きを予測する練習だけで少しずつ言葉やコードの癖を覚えていきます。
大事な前提があります。この lab で作るのは、ChatGPT のような instruction-tuned assistant ではなく、もっと手前の 小さな causal language model です。つまり、目的は「親切に答えること」ではなく、「次の token を当てること」です。
読み方
まず docs/HANDS_ON.md の順番でコマンドを実行し、各章の「連動するハンズオン」を読んでください。
| 章 | 概念 | 連動するハンズオン | 何に影響するか |
|---|---|---|---|
| 1 | tokenization | Hands-on 1 | 語彙数、系列長、未知語、コード構文の扱いやすさ |
| 2 | next-token prediction | Hands-on 2, 3 | 学習目標、loss、生成の基本性質 |
| 3 | embedding / d_model | Hands-on 4 | 表現力、parameter 数、過学習、学習時間 |
| 4 | context / causal mask | Hands-on 6 | 参照できる過去、計算量、長文・長いコードの扱い |
| 5 | attention / heads | Hands-on 4, 5 | token 間の依存、構文らしさ、head ごとの見方 |
| 6 | layers / feed-forward | Hands-on 5 | 抽象化の段数、parameter 数、必要データ量 |
| 7 | dataset | Hands-on 2, 3, 7 | 文体、知識、癖、バイアス、暗記 |
| 8 | train loss / valid loss | Hands-on 4, 5, 7 | 学習不足、過学習、比較判断 |
| 9 | decoding | mini-transformer-generate | 出力のランダム性、安定性、見た目の品質 |
| 10 | prompt / instruction following | 発展 | agent 開発で prompt だけに頼れる範囲 |
全体像はこの流れです。
flowchart LR
A["text / code dataset"] --> B["tokenizer"]
B --> C["token IDs"]
C --> D["token embedding + position embedding"]
D --> E["Transformer blocks"]
E --> F["logits over vocabulary"]
F --> G["training: compare with next token"]
F --> H["generation: sample next token"]
G --> I["loss"]
H --> J["append token and repeat"]
この図の各箱を、ハンズオンのコマンドで1つずつ触っていきます。Transformer の原論文は Vaswani et al. の Attention Is All You Need、視覚的な理解には Jay Alammar の The Illustrated Transformer と The Illustrated GPT-2 が定番です。
1. Text Becomes Tokens
Mini が最初に学ぶのは、日本語でも Python code でもありません。最初に見るのは token ID の列です。
吾輩は小さな言語モデルである。
char tokenizer では、ほぼ1文字ずつ token になります。
吾 | 輩 | は | 小 | さ | な | ...
regex tokenizer では、コードの def, return, 空白、記号などをまとまりとして扱います。
def | | add | ( | x | , | | y | ) | :
概念補助: tokenizer は、text や code を model が処理できる token 列へ変換する前処理です。token は、モデルが一度に扱う記号単位です。token ID は、語彙表上の整数番号です。
vocab_sizeは語彙表に含まれる token 種類数で、token_countは特定の入力が何 token に分割されたかを表します。
flowchart TB
T1["吾輩は小さな言語モデル"] --> C1["char tokenizer"]
C1 --> C2["吾 | 輩 | は | 小 | さ | な | ..."]
T2["def add(x, y):"] --> R1["regex tokenizer"]
R1 --> R2["def | space | add | ( | x | , | y | ) | :"]
C2 --> I1["many short tokens"]
R2 --> I2["fewer syntax-aware chunks"]
連動するハンズオン:
devbox run compare
uv run mini-transformer-compare-tokenizers --file data/natural/tiny.txt
uv run mini-transformer-compare-tokenizers --file data/code/tiny.py.txt
何に影響するか:
vocab_size: 出力候補の数。大きいほど出力層も大きくなる。token_count: 同じ文章が何 token になるか。多いほど同じcontext_lengthに収まる情報が減る。- 未知語: vocab にない token は
<UNK>になる。未知語が多いと情報が潰れる。 - コード: identifier、indent、operator、newline をどう切るかで、構文の覚えやすさが変わる。
この lab では src/mini_transformer_lab/tokenizers.py を読むと、tokenizer の違いがそのままコードで見えます。
参考: Hugging Face の Tokenization algorithms は BPE / WordPiece / Unigram の違いを整理しています。入門向けには Hugging Face Course の Tokenizers も読みやすいです。
2. The Only Homework: Predict the Next Token
Mini の宿題は単純です。今までの token を見て、次の token を当てます。
input : 吾 輩 は 小 さ
target: 輩 は 小 さ な
sequenceDiagram
participant Mini
participant Data
Data->>Mini: input tokens: 吾 輩 は 小 さ
Mini->>Mini: predict distribution for each next position
Data->>Mini: target tokens: 輩 は 小 さ な
Mini->>Mini: compute loss from wrong predictions
これは src/mini_transformer_lab/data.py の make_lm_batch が作っています。入力と正解は1つずれているだけです。
概念補助: next-token prediction は、過去 token から次 token の確率分布を推定する学習目標です。
logitsは、softmax で確率に変換する前の未正規化スコアです。softmax は全候補のスコアを合計1の確率に変換し、loss は正解 token に十分な確率を置けなかった度合いを表します。
連動するハンズオン:
devbox run train:natural
devbox run train:code
何に影響するか:
- loss: 次 token の予測が外れるほど大きくなる。
- 生成: 生成時も「いままでの出力から次 token を選ぶ」を繰り返す。
- 限界: 事実を検索しているのではなく、学習済みの分布から続きを出している。
この理解は重要です。LLM は「文章を一度に書く」のではなく、「次 token を選ぶ」を高速に繰り返して文章に見えるものを作ります。
参考: Hugging Face の Causal language modeling は、causal LM が左側の token だけを見て次 token を予測する task だと説明しています。コードで追うなら Andrej Karpathy の build-nanogpt が有名です。
3. Embedding and d_model
token ID はただの番号です。Mini はその番号を、そのまま意味として扱えません。そこで embedding が token ID をベクトルに変換します。
token id 42 -> [0.12, -0.03, 0.88, ...]
このベクトルの幅が d_model です。d_model=32 なら32次元、d_model=128 なら128次元です。
概念補助:
d_modelは、モデル内部で各 token を表すベクトルの幅です。幅が大きいほど多くの特徴を同時に表せますが、embedding、attention、feed-forward の parameter 数も増えます。dataset が小さい場合は、表現幅を増やしても汎化せず、学習データの暗記に寄りやすくなります。
flowchart LR
A["token id"] --> B["embedding table lookup"]
B --> C["d_model-dimensional vector"]
C --> D["attention"]
C --> E["feed-forward"]
D --> F["larger d_model = wider working space"]
E --> F
連動するハンズオン:
uv run mini-transformer-train --dataset data/natural/tiny.txt --tokenizer char --steps 80 --d-model 32 --n-heads 4 --n-layers 2 --context-length 64 --output-dir runs/d32
uv run mini-transformer-train --dataset data/natural/tiny.txt --tokenizer char --steps 80 --d-model 128 --n-heads 4 --n-layers 2 --context-length 64 --output-dir runs/d128
何に影響するか:
- 表現力: token の違いや文脈の違いをより広い空間で表せる。
- parameter 数: embedding、attention、feed-forward の重みが増える。
- 学習時間: 計算量が増える。
- 過学習: 小さい dataset では、大きいモデルほど覚え込みやすい。
n_heads:d_modelはn_headsで割り切れる必要がある。
d_model は「知識量そのもの」ではありません。より正確には、各 token や中間表現を置くための作業空間の広さです。
参考: The Illustrated Transformer は embedding、position、attention へ tensor が流れる様子を視覚的に説明しています。元の Transformer 設計は Attention Is All You Need が一次情報です。
4. Context Length and the Causal Mask
Mini は未来を見てはいけません。次 token を当てる練習で未来を見てしまうと、答えを盗み見ているだけになるからです。
そこで causal mask を使います。
token 1 can see: token 1
token 2 can see: token 1, token 2
token 3 can see: token 1, token 2, token 3
causal mask は、下三角の「見てよい領域」を作ります。
flowchart TB
R1["position 1 sees: 1"] --> R2["position 2 sees: 1, 2"]
R2 --> R3["position 3 sees: 1, 2, 3"]
R3 --> R4["position 4 sees: 1, 2, 3, 4"]
F["future positions are masked"] -.-> R1
context_length は、Mini が一度に見られる過去の token 数です。
概念補助:
context_lengthは、1回の forward pass で参照できる token 数です。causal mask は、未来位置への attention score を無効化する仕組みです。これにより、各位置は自分より右側の正解 token を見ずに、左側の文脈だけから次 token を予測します。
連動するハンズオン:
uv run mini-transformer-train --dataset data/natural/tiny.txt --tokenizer char --steps 80 --context-length 32 --output-dir runs/ctx32
uv run mini-transformer-train --dataset data/natural/tiny.txt --tokenizer char --steps 80 --context-length 128 --output-dir runs/ctx128
何に影響するか:
- 長い依存関係: 前に出た主語、関数名、変数名を参照しやすくなる。
- 計算量: attention は sequence length の影響を強く受ける。
- メモリ使用量: 長い context ほど重い。
- データ効率: dataset が短すぎると、長い context を活かせない。
長い context は便利ですが、無料ではありません。agent 開発でも、何でも context に詰める設計は遅く、高く、ノイズが増えます。
参考: causal masking は decoder 側 self-attention の基本です。原論文 Attention Is All You Need と、図解として The Illustrated Transformer の decoder self-attention 解説が役立ちます。
5. Attention and Heads
attention は、ある token が過去のどの token を強く見るかを決める仕組みです。
コードなら、return は直前の式や関数の中にある変数を見たいかもしれません。自然言語なら、「その」「これ」「モデル」のような語が、前の説明を見たいかもしれません。
n_heads は、この見方をいくつに分けるかです。
概念補助: attention は、現在位置の表現を作るために、過去 token の情報を重み付きで混ぜる仕組みです。query は参照先を探すための表現、key は照合される表現、value は混ぜ込まれる情報です。head はこの計算を複数の部分空間で並列に行う単位で、
head_dimは、1つの head が使う表現幅です。
head 1: 直前の token を見る
head 2: 改行や indent を見る
head 3: 変数名の再登場を見る
head 4: 文末表現を見る
flowchart LR
X["current token vector"] --> Q["query"]
C["past token vectors"] --> K["keys"]
C --> V["values"]
Q --> S["query-key scores"]
K --> S
S --> W["softmax weights"]
V --> Z["weighted sum"]
W --> Z
Z --> O["attention output"]
実際の head が必ずこのように綺麗に分担するわけではありません。ただし、複数 head は「1種類の見方だけでは足りない」という問題に対応します。
連動するハンズオン:
uv run mini-transformer-train --dataset data/code/tiny.py.txt --tokenizer regex --steps 80 --d-model 64 --n-heads 4 --n-layers 2 --context-length 64 --output-dir runs/code-heads
何に影響するか:
- token 間の依存を拾う力。
- 構文らしさ、繰り返し、対応関係。
head_dim:d_model / n_heads。head を増やしすぎると1 head あたりの幅が狭くなる。- 計算量: head 数だけでなく、sequence length と
d_modelも効く。
この lab では src/mini_transformer_lab/model.py の CausalSelfAttention が該当します。
参考: multi-head attention の一次情報は Attention Is All You Need です。直感的な絵は The Illustrated Transformer が特に有名です。
6. Layers and Feed-Forward Networks
Transformer block は、attention と feed-forward network を残差接続で積み重ねます。
embedding
-> block 1
-> block 2
-> block 3
-> logits
flowchart TB
A["token + position embeddings"] --> B["LayerNorm"]
B --> C["causal self-attention"]
C --> D["residual add"]
D --> E["LayerNorm"]
E --> F["feed-forward network"]
F --> G["residual add"]
G --> H["next block or logits"]
attention は token 同士を混ぜます。feed-forward は各位置の表現を変換します。層を重ねると、浅いパターンから少し複雑なパターンへ進めます。
概念補助: Transformer layer は、self-attention と feed-forward network を組み合わせた処理単位です。self-attention は token 間の情報を混ぜ、feed-forward network は各位置の表現を非線形に変換します。residual connection は入力表現を次の処理へ足し戻す経路で、深い層でも情報と勾配を流しやすくします。
連動するハンズオン:
uv run mini-transformer-train --dataset data/code/tiny.py.txt --tokenizer regex --steps 80 --d-model 64 --n-heads 4 --n-layers 1 --context-length 64 --output-dir runs/code-layer1
uv run mini-transformer-train --dataset data/code/tiny.py.txt --tokenizer regex --steps 80 --d-model 64 --n-heads 4 --n-layers 4 --context-length 64 --output-dir runs/code-layer4
何に影響するか:
- 表現の段数: 複雑な規則を表しやすくなる。
- parameter 数: 層数にほぼ比例して増える。
- 学習時間: 深いほど遅くなる。
- 必要データ量: 深いモデルほど、小さい dataset では過学習しやすい。
層数を増やすことは、単純な性能向上ボタンではありません。dataset、正則化、学習 step と一緒に考える必要があります。
参考: Transformer block の構成は Attention Is All You Need が一次情報です。Karpathy の build-nanogpt は decoder-only GPT 風の実装をコードで追う教材として有名です。
7. Dataset Is the Model’s World
Mini は dataset にない世界を見ていません。自然言語だけを読ませれば自然言語の癖を覚え、Python code だけを読ませれば code の癖を覚えます。
概念補助: dataset は、モデルが近似しようとする分布です。自然言語が多い dataset では自然言語の文体や語彙が、code が多い dataset では構文や identifier の出方が強く学習されます。bias は dataset の偏りが出力に反映されること、memorization は訓練例を一般化せずそのまま再現しやすくなることです。
flowchart LR
A["natural text"] --> M["same architecture"]
B["Python code"] --> M
C["your notes"] --> M
M --> O1["style"]
M --> O2["vocabulary"]
M --> O3["memorized fragments"]
M --> O4["biases and errors"]
連動するハンズオン:
devbox run train:natural
devbox run train:code
任意 dataset:
uv run mini-transformer-train --dataset path/to/your.txt --tokenizer char --steps 200 --output-dir runs/my-text
何に影響するか:
- 文体: 丁寧、硬い、くだけた、コードっぽいなど。
- 語彙: dataset に多い語は出やすい。
- 能力: code completion、物語調、箇条書きなどの得意不得意。
- バイアス: dataset の偏りは出力に反映される。
- 暗記: 小さい dataset では文をそのまま覚えやすい。
- セキュリティ: 秘密鍵や個人情報を入れると、生成で漏れる可能性がある。
agent 開発では、RAG や tool の前に「何を model に入れて、何を外部情報として渡すか」を分けて考える必要があります。
参考: dataset と model size と compute の関係は、Kaplan et al. の Scaling Laws for Neural Language Models と Hoffmann et al. の Training Compute-Optimal Large Language Models が代表的です。Hugging Face Course の Training a causal language model from scratch は「既存モデルの fine-tuning ではなく from scratch にする理由」を実務寄りに説明しています。
8. Train Loss and Valid Loss
Mini の計器盤は loss です。
train_loss: 学習に使った data での外れ具合
valid_loss: 学習に直接使っていない data での外れ具合
概念補助: train loss は学習に使った data 上の予測誤差で、valid loss は学習に直接使っていない data 上の予測誤差です。train loss だけが下がる場合は overfitting、つまり訓練 data には合うが未見 data には弱い状態を疑います。generalization は、未見 data にも学習した規則が通用することです。
flowchart LR
A["step 1: train high / valid high"] --> B["step 2: both go down"]
B --> C["step 3: train keeps falling"]
C --> D{"valid also falls?"}
D -->|yes| E["learning useful pattern"]
D -->|no| F["possible overfitting"]
連動するハンズオン:
devbox run train:natural
出力例:
{"step": 20, "train_loss": 4.15, "valid_loss": 4.54}
何に影響するか:
- train loss も valid loss も高い: まだ学習不足。
- train loss だけ下がる: dataset を覚えているが、汎化していない可能性。
- valid loss が下がる: 未見部分にも少し通用している。
- 生成文の見た目: loss が低いほど良い傾向はあるが、完全には一致しない。
実務では、loss だけでなく、実際の task eval、危険な出力、tool 使用の正確さも見る必要があります。
参考: language modeling の loss と scaling は Scaling Laws for Neural Language Models が代表的です。この lab では大規模 scaling の再現ではなく、loss の読み方を小さい実験で体感します。
9. Decoding Changes the Voice, Not the Knowledge
学習後、Mini は次 token の候補に確率を出します。生成時は、その確率から token を選びます。
概念補助: decoding は、model が出した確率分布から実際に次 token を選ぶ手順です。temperature は logits の鋭さを調整し、高いほど低確率 token も選ばれやすくなります。
top_kは候補を上位 k 個に制限する方法です。decoding は出力のばらつきを変えますが、model が学習していない知識を追加するものではありません。
flowchart LR
A["logits"] --> B["softmax probabilities"]
B --> C{"decoding setting"}
C -->|temperature 0| D["argmax: stable"]
C -->|temperature high| E["sample: varied"]
C -->|top_k| F["sample from limited candidates"]
D --> G["next token"]
E --> G
F --> G
uv run mini-transformer-generate --run runs/natural-char --prompt "小さな" --temperature 0
uv run mini-transformer-generate --run runs/natural-char --prompt "小さな" --temperature 0.8
何に影響するか:
temperature=0: 一番確率の高い token を選びやすく、安定する。- 高い temperature: ランダム性が増え、崩れやすいが多様になる。
top_k: 候補を上位 k 個に絞る。- 知識: decoding は学習済みの知識や能力を増やさない。
agent 開発では、temperature を上げても reasoning 能力や事実性が増えるわけではありません。出力の揺れ方が変わるだけです。
参考: Hugging Face の Causal language modeling は、学習後の model を text generation に使う流れも扱っています。
10. Why This Is Not Yet ChatGPT
この lab の Mini は、system prompt や user prompt に従う assistant ではありません。単に続きを予測する base language model です。
概念補助: system prompt や user prompt は、モデルの重みを書き換える設定ではありません。推論時に入力 context として渡され、model が次 token を予測するときの条件になります。chat template は system/user/assistant などの role を token 列へ変換する形式で、instruction tuning は指示と望ましい応答の例で model を追加学習する工程です。agent では prompt だけでなく、tool 権限、schema validation、retrieval context も分けて設計します。
ChatGPT のような挙動には、少なくとも次の追加要素が関係します。
flowchart TB
B["base language model"] --> I["instruction tuning"]
I --> P["preference / RLHF-style tuning"]
P --> C["chat template and roles"]
C --> T["tools / function schemas"]
T --> R["retrieval context"]
R --> V["validation and guardrails"]
V --> A["agent behavior"]
| 要素 | 役割 | 何に影響するか |
|---|---|---|
| chat template | system/user/assistant の構造を token 列に変換する | prompt の読まれ方 |
| instruction tuning | 指示に従う例で追加学習する | 命令追従、回答形式 |
| preference tuning | 好ましい回答を選ぶ方向に調整する | 安全性、丁寧さ、有用性 |
| tool schema | model が呼べる操作を構造化する | agent の行動範囲 |
| validation | 出力を外側で検証する | JSON 破損、危険操作、誤実行の抑制 |
| retrieval | 外部知識を context に入れる | 最新情報、社内情報、根拠提示 |
何に影響するか:
- system prompt は、数値の「重み」だけで効くものではない。
- role は、API と chat template が作る構造であり、model がその形式を学んでいる必要がある。
- prompt だけで安全性や正確性を保証するのは弱い。
- agent 開発では、prompt、tool 権限、RAG、schema validation、ログ監査を分けて設計する。
この lab は、その手前にある「token 列を見て次 token を予測する機械」を理解するための土台です。
参考: instruction following の代表的な論文は Ouyang et al. の Training language models to follow instructions with human feedback です。OpenAI API の current docs は Message roles and instruction following で、instructions や message role の優先関係を説明しています。
Concept Impact Checklist
実験するときは、変更したものと影響を見るものを1対1に近づけます。
| 変えるもの | 直接影響するもの | 観察するもの |
|---|---|---|
| dataset | 文体、語彙、暗記、偏り | sample.txt, train/valid loss |
| tokenizer | token 数、vocab、未知語 | mini-transformer-compare-tokenizers |
d_model | 表現力、parameter 数、速度 | 起動時の parameters, loss |
n_heads | attention の分割、head_dim | エラー、loss、生成の崩れ方 |
n_layers | 変換の段数、parameter 数 | train/valid loss の差 |
context_length | 見られる過去、計算量 | 長い文脈の保持、実行時間 |
steps | 学習の進み具合 | loss の推移、暗記 |
temperature | 出力のランダム性 | 同じ prompt での揺れ |
1回の実験で多くを変えると、何が効いたのかわからなくなります。まずは1つだけ変え、runs/<name>/metrics.jsonl と runs/<name>/sample.txt を比較してください。
Source Guide
このドキュメントでは、一次情報と有名な解説ページを分けて使います。
| 用途 | Source | 位置づけ |
|---|---|---|
| Transformer の一次情報 | Attention Is All You Need | attention、multi-head、position、block 構成の原典 |
| Transformer の図解 | The Illustrated Transformer | 有名な視覚的解説 |
| GPT 系 decoder-only LM の図解 | The Illustrated GPT-2 | GPT-style generation の視覚的解説 |
| tokenizer | Hugging Face Tokenization algorithms | tokenizer の公式 docs |
| causal LM | Hugging Face Causal language modeling | next-token prediction task の公式 docs |
| from-scratch training | Hugging Face Course: Training a causal language model from scratch | from-scratch training の実務的説明 |
| code-first GPT | Karpathy build-nanogpt | GPT を小さく実装して追う教材 |
| scaling | Scaling Laws for Neural Language Models | model size、data、compute と loss の関係 |
| data/model balance | Training Compute-Optimal Large Language Models | training tokens と parameter 数のバランス |
| instruction following | Training language models to follow instructions with human feedback | base LM から assistant 的挙動へ進む代表例 |
| prompt roles | OpenAI Message roles and instruction following | API 上の instructions / roles の公式説明 |