データセットの準備ができました。でも、モデルはそのままじゃテキストを読めません。AIの「言語」は数字なんです。
今回は、テキストを数値(トークン)に変換するトークン化(Tokenization)と、長さをそろえるパディング(Padding)について学びます。地味に見えるけど、超重要なステップですよ!
モデルは人間みたいには読めない
言語モデルは文を読みません。トークンっていう、意味の一部を表す小さなサブワード単位を処理します。
例えばこんなやり取り:
ユーザー: フランスの首都は何ですか?
アシスタント: フランスの首都はパリです。
モデルがこれから学習するには、前処理パイプラインを通す必要があります:
- トークン化:テキストを小さく意味のある単位(トークン)に分割
- 変換:トークンを数値IDにマップ
- パディングとマスキング:バッチ処理のため長さをそろえて、何を無視すべきか伝える
この変換が、すべてのファインチューニングワークフローの基礎なんです。
トークン化の仕組み
「テキストを分割」って、スペースで区切ればいいじゃん?って思いますよね。でもそれだと:
- 短縮形(「don’t」)
- 複合語(「state-of-the-art」)
- 新しい単語(「ChatGPT」)
こういうのに対応できません。
現代のLLMはサブワードトークン化を使います。単語を「意味のある小さな断片」に分けるんです。
例:「unbelievable(信じられない)」
→ ["un", "believ", "able"]
こうすることで:
- 語彙を管理可能(通常30k〜50kトークン)に保つ
- 未知の単語を馴染みのある部分の組み合わせで表現できる
モデルは各部分をすでに知っているので、新しい単語にも即座に対応できるわけです!
実際にトークン化してみよう
Hugging Faceのトークナイザーを使うのは簡単です:
from transformers import AutoTokenizer
# Llama 3.2のトークナイザーを読み込む
tokenizer = AutoTokenizer.from_pretrained("meta-llama/Llama-3.2-1B-Instruct")
# テキストをトークン化
text = "Hello, how are you?"
tokens = tokenizer.tokenize(text)
print(tokens)
# 出力例: ['Hello', ',', 'Ġhow', 'Ġare', 'Ġyou', '?']
# トークンIDに変換
ids = tokenizer.convert_tokens_to_ids(tokens)
print(ids)
# 出力例: [9906, 11, 1268, 527, 499, 30]
「Ġ」は「スペースの前」を意味する特殊マーカーです。こうやって、単語の区切りを保持しているんですね。
特別なトークン
トークナイザーは、いくつかの特別なトークンを使います:
- BOS(Beginning of Sequence):シーケンスの開始
- EOS(End of Sequence):シーケンスの終了
- PAD:パディング用(後で説明!)
- UNK(Unknown):未知のトークン
例えば、Llama 3では:
tokenizer.bos_token # '<|begin_of_text|>'
tokenizer.eos_token # '<|end_of_text|>'
tokenizer.pad_token # '<|finetune_right_pad_id|>'
これらが文章に構造を与えるんです。
パディング:長さをそろえる
トークン化すると、各文の長さが違います:
- 文A:10トークン
- 文B:25トークン
- 文C:15トークン
でも、モデルはバッチ(複数の例をまとめて)でトレーニングします。そのためには、全部同じ長さにする必要があるんです。
そこでパディング!短い文にPADトークンを追加して、最長の文に合わせます:
文A:[10トークン] + [15個のPAD] = 25トークン
文B:[25トークン] = 25トークン
文C:[15トークン] + [10個のPAD] = 25トークン
Pythonコードで:
# パディングを有効にしてトークン化
encoded = tokenizer(
["Hello", "How are you doing today?"],
padding=True,
return_tensors="pt"
)
print(encoded["input_ids"])
# すべてのシーケンスが同じ長さになる
注意マスク:「本物」と「フィラー」を区別
でも、ここで問題が!PADトークンは「フィラー(埋め草)」です。モデルがこれから学習しちゃダメですよね。
そこで注意マスク(Attention Mask)の出番!
注意マスクは、各トークンについて「本物かどうか」を示す0と1の列です:
- 1:本物のトークン、注意を払う
- 0:PADトークン、無視する
例:
print(encoded["attention_mask"])
# [[1, 1, 1, 1, 0, 0, 0], # 最初の文(4トークン + 3PAD)
# [1, 1, 1, 1, 1, 1, 1]] # 2番目の文(全部本物)
モデルは注意マスクを見て、「ここは無視していいんだな」って判断します。
チャットテンプレート:会話をフォーマット
チャットボットの場合、ユーザーとアシスタントの会話をフォーマットする必要があります。
Hugging Faceのapply_chat_template()メソッドが便利:
messages = [
{"role": "user", "content": "フランスの首都は?"},
{"role": "assistant", "content": "パリです。"}
]
formatted = tokenizer.apply_chat_template(
messages,
tokenize=False
)
print(formatted)
# 出力例:
# '<|begin_of_text|><|start_header_id|>user<|end_header_id|>
# フランスの首都は?<|eot_id|>
# <|start_header_id|>assistant<|end_header_id|>
# パリです。<|eot_id|>'
これで、モデルが「ユーザーの発言」と「アシスタントの回答」を区別できるようになります!
まとめ:トークン化とパディングの3ステップ
- トークン化:テキストをサブワード単位に分割
- パディング:すべてのシーケンスを同じ長さに
- 注意マスク:どのトークンが本物か伝える
この前処理があって初めて、モデルはテキストから学習できるんです。
次のレッスンでは、「アシスタントのみマスキング」の詳細を学びます。命令ファインチューニングで、どうやってモデルに「ユーザーの質問を予測するな、アシスタントの回答を予測しろ」って教えるのか。楽しみにしていてください!

コメント