0
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

GPTをゼロから実装して理解してみる(第1部:データセットとトークナイゼーション編)

Last updated at Posted at 2025-07-02

Andrej Karpathy「Let's build GPT」解説シリーズ 第1動画・第1部

はじめに

最近、ChatGPTやGeminiなどの大規模言語モデルが話題になっていますが、「実際にどういう仕組みで動いているの?」と疑問に思ったことはありませんか?

この解説シリーズでは、OpenAIの創業者の一人であるAndrej Karpathy氏による「Neural Networks: Zero to Hero」シリーズの中の「Let's build GPT」の4本の動画を基に、GPTの仕組みを理解するために実際にゼロからGPT-2を実装していきます。

学習の流れ(全体像)

このシリーズでは、Andrej Karpathy氏の以下4つの動画を順次解説していきます:

  1. 第1動画: Let's build GPT: from scratch, in code, spelled out.

    • 本記事(第1-3部)で解説予定
  2. 第2動画: State of GPT | BRK216HFS

    • 今後の記事で解説予定
  3. 第3動画: Let's build the GPT Tokenizer

    • 今後の記事で解説予定
  4. 第4動画: Let's reproduce GPT-2 (124M)

    • 今後の記事で解説予定

構成について

  • 各動画は内容が豊富なため、1つの動画につき複数の記事に分けて詳細に解説します
  • 第1動画「Let's build GPT: from scratch, in code, spelled out.」は3部構成で解説します

第1動画の3部構成

第1部(本記事): データセットとトークナイゼーション編

  • Tiny Shakespeareデータセットの準備
  • 文字レベルトークナイゼーションの実装
  • バッチ処理の仕組み

第2部: Bigramモデルと基本的な言語モデル編

  • 最初の言語モデル実装
  • 埋め込み層の理解
  • トレーニングプロセス

第3部: Self-AttentionとTransformerアーキテクチャ編

  • Self-Attentionメカニズムの実装
  • マルチヘッドアテンション
  • 完全なGPTアーキテクチャの構築

それでは、第1部として、まずデータセットの準備とトークナイゼーションについて詳しく見ていきましょう。

今回使用するデータセット

Tiny Shakespeareデータセット

今回は学習用データセットとして「Tiny Shakespeare」を使用します。これはシェイクスピアの作品をまとめた約1.1MBのテキストファイルです。

# データセットのダウンロードと基本情報の確認
with open('input.txt', 'r', encoding='utf-8') as f:
    text = f.read()

print("データセットの文字数", len(text))
print(text[:100])
print("\nデータセット中のボキャブラリ")
chars = sorted(list(set(text)))
vocab_size = len(chars)
print("".join(chars))
print(vocab_size)

データセットの特徴

  • データサイズ: 約1.1MB(1,115,394文字)
  • 語彙数: 65文字(英字、数字、記号、改行文字を含む)
  • 特徴: シェイクスピアの古典的な英語表現が含まれている

データセット中のボキャブラリには改行文字も含まれているため、文章の構造も学習できるようになっています。

文字レベルトークナイゼーション

トークナイゼーションとは?

トークナイゼーション(tokenization)とは、テキストを機械学習モデルが理解できる数値に変換する処理のことです。今回は文字レベルでのトークナイゼーションを実装します。

# 文字レベルのエンコーダー、デコーダーの定義
stoi = {ch: i for i, ch in enumerate(chars)}  # string to integer
itos = {i: ch for i, ch in enumerate(chars)}  # integer to string

encode = lambda s: [stoi[c] for c in s]       # 文字列 → 数値リスト
decode = lambda l: ''.join(itos[i] for i in l) # 数値リスト → 文字列

# 具体例
print(encode("hii there"))  # [46, 47, 47, 1, 58, 46, 43, 56, 43]
print(decode(encode("hii there")))  # "hii there"

なぜ文字レベルなのか?

  • シンプル: 実装が簡単で理解しやすい
  • 語彙数が少ない: 65文字のみなので計算効率が良い
  • 未知語の問題がない: どんな文字でも表現できる

一方で、実用的なGPTではサブワードトークナイゼーション(BPEなど)を使用することが多いです。

データセットのテンソル化

import torch
data = torch.tensor(encode(text), dtype=torch.long)
print(data.shape, data.dtype)
print(data[:100])

# トレーニングデータとバリデーションデータに分割
n = int(0.9 * len(data))
train_data = data[:n]
val_data = data[n:]

なぜtorch.tensorに変換するのか?

  • PyTorchでの効率的な計算のため
  • GPU計算を可能にするため
  • 自動微分機能を活用するため

なぜvalidationデータが必要なのか?

  • オーバーフィッティング(過学習)を防ぐため
  • モデルの汎化性能を評価するため

バッチ処理の仕組み

バッチ処理の基本概念

言語モデルでは、効率的な学習のために複数のデータを同時に処理します。ここで重要な概念が2つあります:

  • バッチサイズ: GPUで並列処理する系列数
  • ブロックサイズ: 予測に使用する最大コンテキスト長
torch.manual_seed(1337)
batch_size = 4
block_size = 8

def get_batch(split):
    data = train_data if split == 'train' else val_data
    ix = torch.randint(len(data) - block_size, (batch_size,))
    x = torch.stack([data[i:i+block_size] for i in ix])
    y = torch.stack([data[i+1:i+block_size+1] for i in ix])
    return x, y

get_batch関数の詳細

この関数は言語モデルのトレーニング/検証用のデータバッチを生成する重要な関数です。

1. ランダムな開始位置の生成

ix = torch.randint(len(data) - block_size, (batch_size,))
  • バッチ内各サンプルの開始位置をランダムに決定
  • len(data) - block_sizeの範囲で開始位置を選ぶことで、データの境界を超えないようにする

2. 入力データxの作成

x = torch.stack([data[i:i+block_size] for i in ix])
  • 各開始位置からblock_size分のデータを抽出
  • torch.stack()でバッチ化(2次元テンソル化)

3. ターゲットデータyの作成

y = torch.stack([data[i+1:i+block_size+1] for i in ix])
  • xを1文字分右にずらしたもの(次に来る文字がターゲット)
  • これにより「次の文字予測」タスクが実現される

バッチの中身を詳しく見てみる

xb, yb = get_batch('train')
print('inputs:', xb.shape)  # torch.Size([4, 8])
print('targets:', yb.shape)  # torch.Size([4, 8])

# バッチの内容を詳細に確認
for b in range(batch_size):
    for t in range(block_size):
        context = xb[b, :t+1]
        target = yb[b, t]
        print(f"when input is {context.tolist()}, target is {target}")

出力の意味:

  • torch.Size([4, 8]): 4つの並列処理、8つのコンテキストという意味
  • 各バッチは独立した学習サンプルとして処理される
  • 1つのバッチ内で複数の予測タスクが同時に学習される

まとめ

第1部では、GPT実装の基礎となるデータ準備とトークナイゼーションについて学びました:

  1. データセット: Tiny Shakespeareを使用(約1.1MB、65文字の語彙)
  2. トークナイゼーション: 文字レベルでの数値変換
  3. バッチ処理: 効率的な学習のためのデータ構造

次回の第2部では、これらのデータを使って実際にBigram言語モデルを実装し、基本的な言語モデルの仕組みを理解していきます。
(この記事は研究室インターンで取り組みました:https://kojima-r.github.io/kojima/)

参考動画・資料

0
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?