19. microgpt の前処理

19.1. この章で学ぶこと

  • input.txt から文書リスト docs を作る流れ

  • 文字トークナイザー(ucharsBOSvocab_size)の意味

  • 18 章B1(データセット)B2(トークナイザー) に対応するコード

18 章microgpt の構造)の全体地図のうち、入力テキストをトークン列にそろえるまでを見ていきます。

19.1.1. データセット

最初にやっているのは、学習に使う文字列を集めることです。

31if not os.path.exists('input.txt'):
32    import urllib.request
33    names_url = 'https://raw.githubusercontent.com/karpathy/makemore/988aa59/names.txt'
34    urllib.request.urlretrieve(names_url, 'input.txt')
35docs = [line.strip() for line in open('input.txt') if line.strip()]
36random.shuffle(docs)  # 学習時の順序をランダム化
37print(f"num docs: {len(docs)}")

行ごとの意味

  • L35 docs = [line.strip() ...] — ファイルを 1 行ずつ読み、前後の空白を除いたうえで中身が空でない行だけを docs に集める(1 行が 1 文書)。

  • L36 random.shuffle(docs) — 学習ループで取り出す順序を毎エポックでばらけさせる。

  • L37 print(f"num docs: ...") — 収集した文書数を表示する。

注釈

ダウンロード処理(L31〜L34)

input.txt がカレントディレクトリに無い場合のみ、Karpathy の makemore リポジトリから人名リスト(names.txt)を urllib.request.urlretrieve で自動取得します。手動で input.txt を置いた場合はスキップされます。

diagram

図: 有効な 1 行ずつが docs に積まれるイメージ(空行・空白のみの行はスキップ)

ここでは人名の一覧を使います。大きな文章ではないので、モデルの仕組みに集中しやすいです。たとえば長い文書を扱う前に、まず「次トークンを当てる」感覚をつかむには、このくらい単純なデータがちょうどよいです。

19.1.2. トークナイザー

次に、文字を整数 ID に変えます。

43uchars = sorted(set(''.join(docs)))  # データセット内の全ユニーク文字 → ID 0..n-1
44BOS = len(uchars)                    # 文の開始/終了を示す特殊トークン(Beginning of Sequence)
45vocab_size = len(uchars) + 1         # 語彙サイズ(文字数 + BOS)
46print(f"vocab size: {vocab_size}")

行ごとの意味

  • L43 uchars = sorted(set(''.join(docs))) — 全文書をつなげた文字列から重複のない文字集合を作り、ソートして並べる。インデックス 0 len(uchars)-1 が各文字の ID になる。

  • L44 BOS = len(uchars) — 通常文字に使わない ID として、語彙サイズと同じ番号を「文頭・文末の特別トークン」に割り当てる。

  • L45 vocab_size = len(uchars) + 1 — 通常文字数に BOS を 1 つ足した語彙サイズ(出力 logits の次元数)。

  • L46 print(...) — 語彙サイズを表示する。

この実装は単語単位ではなく、文字単位です。たとえば anna なら、anna を順番に ID に変えます。さらに BOS という特別な記号を置いて、「ここから始まる」という合図も作っています。

ここで出てくる主な要素は次の通りです。

  • uchars — データに現れる文字を並べた一覧(ID はインデックス)。

  • BOS — 文の開始・終了を表す特別なトークン ID。

  • vocab_size — 語彙に含まれるトークン数(文字 + BOS)。