(microgpt の前処理)= # microgpt の前処理 ## この章で学ぶこと - `input.txt` から文書リスト `docs` を作る流れ - 文字トークナイザー(`uchars`、`BOS`、`vocab_size`)の意味 - {numref}`microgpt の構造` の **B1(データセット)** と **B2(トークナイザー)** に対応するコード {numref}`microgpt の構造`({ref}`microgpt の構造`)の全体地図のうち、入力テキストをトークン列にそろえるまでを見ていきます。 ### データセット 最初にやっているのは、学習に使う文字列を集めることです。 ```{literalinclude} ../../../src/part3/microgpt.py :language: python :lines: 31-37 :lineno-match: ``` **行ごとの意味** - **L35** `docs = [line.strip() ...]` — ファイルを 1 行ずつ読み、前後の空白を除いたうえで中身が空でない行だけを `docs` に集める(1 行が 1 文書)。 - **L36** `random.shuffle(docs)` — 学習ループで取り出す順序を毎エポックでばらけさせる。 - **L37** `print(f"num docs: ...")` — 収集した文書数を表示する。 :::{note} **ダウンロード処理(L31〜L34)** `input.txt` がカレントディレクトリに無い場合のみ、Karpathy の `makemore` リポジトリから人名リスト(`names.txt`)を `urllib.request.urlretrieve` で自動取得します。手動で `input.txt` を置いた場合はスキップされます。 ::: ```{mermaid} flowchart TB subgraph file["input.txt(上から順に)"] r1["行: anna"] r2["行: 空"] r3["行: 空白のみ"] r4["行: bob"] end r1 --> acc["docs に追加"] r2 -.->|strip 後は空なので偽| skip["リストに入れない"] r3 -.->|同上| skip r4 --> acc acc --> list["docs = ['anna', 'bob', ...]"] ``` **図: 有効な 1 行ずつが `docs` に積まれるイメージ**(空行・空白のみの行はスキップ) ここでは人名の一覧を使います。大きな文章ではないので、モデルの仕組みに集中しやすいです。たとえば長い文書を扱う前に、まず「次トークンを当てる」感覚をつかむには、このくらい単純なデータがちょうどよいです。 ### トークナイザー 次に、文字を整数 ID に変えます。 ```{literalinclude} ../../../src/part3/microgpt.py :language: python :lines: 43-46 :lineno-match: ``` **行ごとの意味** - **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` なら、`a`、`n`、`n`、`a` を順番に ID に変えます。さらに `BOS` という特別な記号を置いて、「ここから始まる」という合図も作っています。 ここで出てくる主な要素は次の通りです。 - `uchars` — データに現れる文字を並べた一覧(ID はインデックス)。 - `BOS` — 文の開始・終了を表す特別なトークン ID。 - `vocab_size` — 語彙に含まれるトークン数(文字 + BOS)。