LLM Foundations Story

このドキュメントは、Mini Transformer Lab のハンズオンと一緒に読むための基礎概念ガイドです。

登場人物は、学習者である「あなた」と、小さな言語モデル Mini です。Mini はまだ何も知らない状態から、文字列の続きを予測する練習だけで少しずつ言葉やコードの癖を覚えていきます。

大事な前提があります。この lab で作るのは、ChatGPT のような instruction-tuned assistant ではなく、もっと手前の 小さな causal language model です。つまり、目的は「親切に答えること」ではなく、「次の token を当てること」です。

読み方

まず docs/HANDS_ON.md の順番でコマンドを実行し、各章の「連動するハンズオン」を読んでください。

概念連動するハンズオン何に影響するか
1tokenizationHands-on 1語彙数、系列長、未知語、コード構文の扱いやすさ
2next-token predictionHands-on 2, 3学習目標、loss、生成の基本性質
3embedding / d_modelHands-on 4表現力、parameter 数、過学習、学習時間
4context / causal maskHands-on 6参照できる過去、計算量、長文・長いコードの扱い
5attention / headsHands-on 4, 5token 間の依存、構文らしさ、head ごとの見方
6layers / feed-forwardHands-on 5抽象化の段数、parameter 数、必要データ量
7datasetHands-on 2, 3, 7文体、知識、癖、バイアス、暗記
8train loss / valid lossHands-on 4, 5, 7学習不足、過学習、比較判断
9decodingmini-transformer-generate出力のランダム性、安定性、見た目の品質
10prompt / 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 TransformerThe 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.pymake_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_modeln_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.pyCausalSelfAttention が該当します。

参考: 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 templatesystem/user/assistant の構造を token 列に変換するprompt の読まれ方
instruction tuning指示に従う例で追加学習する命令追従、回答形式
preference tuning好ましい回答を選ぶ方向に調整する安全性、丁寧さ、有用性
tool schemamodel が呼べる操作を構造化する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
tokenizertoken 数、vocab、未知語mini-transformer-compare-tokenizers
d_model表現力、parameter 数、速度起動時の parameters, loss
n_headsattention の分割、head_dimエラー、loss、生成の崩れ方
n_layers変換の段数、parameter 数train/valid loss の差
context_length見られる過去、計算量長い文脈の保持、実行時間
steps学習の進み具合loss の推移、暗記
temperature出力のランダム性同じ prompt での揺れ

1回の実験で多くを変えると、何が効いたのかわからなくなります。まずは1つだけ変え、runs/<name>/metrics.jsonlruns/<name>/sample.txt を比較してください。

Source Guide

このドキュメントでは、一次情報と有名な解説ページを分けて使います。

用途Source位置づけ
Transformer の一次情報Attention Is All You Needattention、multi-head、position、block 構成の原典
Transformer の図解The Illustrated Transformer有名な視覚的解説
GPT 系 decoder-only LM の図解The Illustrated GPT-2GPT-style generation の視覚的解説
tokenizerHugging Face Tokenization algorithmstokenizer の公式 docs
causal LMHugging Face Causal language modelingnext-token prediction task の公式 docs
from-scratch trainingHugging Face Course: Training a causal language model from scratchfrom-scratch training の実務的説明
code-first GPTKarpathy build-nanogptGPT を小さく実装して追う教材
scalingScaling Laws for Neural Language Modelsmodel size、data、compute と loss の関係
data/model balanceTraining Compute-Optimal Large Language Modelstraining tokens と parameter 数のバランス
instruction followingTraining language models to follow instructions with human feedbackbase LM から assistant 的挙動へ進む代表例
prompt rolesOpenAI Message roles and instruction followingAPI 上の instructions / roles の公式説明