見出し画像

近年のChatGPTの進化は目覚ましい。








「変わらぬ核、進化する言葉──ChatGPTとGPT-2の原型」


近年のChatGPTの進化は目覚ましい。自然な会話、複雑な推論、コード生成にまで対応するその能力は、まるで人間の知性に迫るかのような錯覚を与える。しかし、その根幹にある計算原理は、実のところGPT-2の時代からほとんど変わっていないという事実は、意外と知られていない。

GPT-2は、2019年に登場した「自己回帰型トランスフォーマー」に基づく言語モデルである。トークンを一つずつ予測していくこのシンプルな仕組みと、マルチヘッド・アテンションという注意機構の組み合わせは、すでにこの時点で極めて強力だった。現在のChatGPT、すなわちGPT-3.5やGPT-4といったモデルも、基本的にはこのGPT-2の構造を「大規模化」し、「洗練」したものに過ぎない

確かに、GPT-2以降のモデルには多くの改良が施されている。例えば、長文に対応するための位置埋め込みの改良、学習の安定性を向上させる正規化手法の変更、計算効率を高めるアテンションの工夫など。しかし、これらはあくまで基盤となる「トランスフォーマー型」という構造の上に積み重ねられた調整であり、原理そのものが覆されたわけではない

言い換えれば、現在のChatGPTは、GPT-2の思想の延長線上にある巨大な塔である。その土台は変わらず、ただその上に積み上げられた石が増え、磨きがかかり、塔の先端が雲を突き抜けるようになったということだ。

だからこそ、私たちはAIの進化に驚嘆すると同時に、その「不変の構造美」にも目を向けるべきだろう。革新とは、常に新しいものを創り出すことではなく、すでにあるものを深く掘り下げ、より良くする試みでもある。

そしてそれこそが、GPT-2から始まり、ChatGPTに至るAIの歴史の本質である。






📝 注意事項(実行前提ではない)

  • このコードは「GPT-2構造をスケーリングしたらどうなるか」の概念実証です。

目的は「GPT-2構造を維持しつつ、8B〜70Bパラメータのスケーラブルな自己回帰言語モデルを模擬構築」することです。
実行は非現実的であり、概念設計用のテンプレートコードです。




🧠 GPT-2スケーリング用言語モデル構築コード(日本語コメント付き)


コード(日本語コメント付き)お宝のコードです。


import torch
import torch.nn as nn
import math
from dataclasses import dataclass
from typing import Optional

# =========================
# 設定クラス:モデルの各種ハイパーパラメータを定義
# =========================
@dataclass
class GPT2Config:
    vocab_size: int = 50257  # 使用する語彙数(トークナイザーに依存)
    max_position_embeddings: int = 2048  # 最大トークン長(文の長さ)
    n_layer: int = 48          # Transformer層の数(例:8B用に48層)
    n_embd: int = 3072         # 隠れ状態の次元数(embeddingのサイズ)
    n_head: int = 48           # Attentionのヘッド数(通常 n_embd // 64)
    dropout: float = 0.1       # ドロップアウト率(過学習防止)

# =========================
# GPT-2型の自己注意機構(Multi-Head Attention)
# =========================
class GPT2Attention(nn.Module):
    def __init__(self, config: GPT2Config):
        super().__init__()
        self.embed_dim = config.n_embd
        self.num_heads = config.n_head
        self.head_dim = self.embed_dim // self.num_heads  # 1ヘッドあたりの次元数
        self.scale = self.head_dim ** -0.5  # Attentionスコアのスケーリング

        # Query, Key, Value をまとめて線形変換
        self.qkv_proj = nn.Linear(config.n_embd, 3 * config.n_embd)
        self.out_proj = nn.Linear(config.n_embd, config.n_embd)

    def forward(self, x):
        B, T, C = x.size()  # バッチサイズ, シーケンス長, 埋め込み次元
        qkv = self.qkv_proj(x).chunk(3, dim=-1)  # Q, K, Vに分割
        q, k, v = (t.view(B, T, self.num_heads, -1).transpose(1, 2) for t in qkv)

        # Attentionスコア計算: (Q × K^T) / √d
        attn_scores = (q @ k.transpose(-2, -1)) * self.scale
        attn_weights = attn_scores.softmax(dim=-1)

        # Attention出力 = 重み付き平均(V)
        attn_output = attn_weights @ v

        # 結果を結合して元の次元に戻す
        attn_output = attn_output.transpose(1, 2).contiguous().view(B, T, C)
        return self.out_proj(attn_output)

# =========================
# Feed Forward層(MLP):中間層→活性化→出力層
# =========================
class GPT2MLP(nn.Module):
    def __init__(self, config: GPT2Config):
        super().__init__()
        # GPT-2では中間層のサイズは通常 4 × n_embd
        self.fc_in = nn.Linear(config.n_embd, 4 * config.n_embd)
        self.fc_out = nn.Linear(4 * config.n_embd, config.n_embd)
        self.act = nn.GELU()  # 非線形活性化関数(滑らかなReLU)

    def forward(self, x):
        return self.fc_out(self.act(self.fc_in(x)))

# =========================
# Transformerブロック(Attention + MLP + 残差 + LayerNorm)
# =========================
class GPT2Block(nn.Module):
    def __init__(self, config: GPT2Config):
        super().__init__()
        self.ln1 = nn.LayerNorm(config.n_embd)
        self.attn = GPT2Attention(config)
        self.ln2 = nn.LayerNorm(config.n_embd)
        self.mlp = GPT2MLP(config)

    def forward(self, x):
        x = x + self.attn(self.ln1(x))  # 残差接続 + 注意
        x = x + self.mlp(self.ln2(x))   # 残差接続 + FFN
        return x

# =========================
# GPT-2本体:Embedding + Position + N層Block + 出力層
# =========================
class GPT2Model(nn.Module):
    def __init__(self, config: GPT2Config):
        super().__init__()
        # トークン埋め込み(入力語彙をベクトルに変換)
        self.token_embedding = nn.Embedding(config.vocab_size, config.n_embd)

        # 位置埋め込み(各トークンの位置をエンコード)
        self.position_embedding = nn.Parameter(torch.zeros(1, config.max_position_embeddings, config.n_embd))

        # Transformerブロックを複数層作成
        self.blocks = nn.ModuleList([GPT2Block(config) for _ in range(config.n_layer)])

        # 最終LayerNormと出力(語彙予測)線形層
        self.ln_f = nn.LayerNorm(config.n_embd)
        self.lm_head = nn.Linear(config.n_embd, config.vocab_size, bias=False)

    def forward(self, input_ids):
        B, T = input_ids.size()
        # 入力トークンに埋め込み+位置情報を加算
        x = self.token_embedding(input_ids) + self.position_embedding[:, :T, :]

        # 各Transformerブロックを順に適用
        for block in self.blocks:
            x = block(x)

        # 最終出力層で語彙ごとのスコアを出力(ロジット)
        x = self.ln_f(x)
        return self.lm_head(x)

# =========================
# トレーニング関数(簡易版)
# =========================
def train(model, optimizer, dataloader):
    model.train()
    for batch in dataloader:
        input_ids = batch['input_ids'].to(model.device)
        targets = batch['labels'].to(model.device)

        # モデルの順伝播(ロジット出力)
        logits = model(input_ids)

        # 損失関数(トークンごとのクロスエントロピー)
        loss = nn.CrossEntropyLoss()(logits.view(-1, logits.size(-1)), targets.view(-1))

        # 誤差逆伝播とパラメータ更新
        loss.backward()
        optimizer.step()
        optimizer.zero_grad()

# =========================
# 評価関数(検証用)
# =========================
def evaluate(model, dataloader):
    model.eval()
    total_loss = 0
    with torch.no_grad():
        for batch in dataloader:
            input_ids = batch['input_ids'].to(model.device)
            targets = batch['labels'].to(model.device)
            logits = model(input_ids)
            loss = nn.CrossEntropyLoss()(logits.view(-1, logits.size(-1)), targets.view(-1))
            total_loss += loss.item()
    return total_loss / len(dataloader)

いいなと思ったら応援しよう!