19. テキストを数値に変換!トークン化とパディングの基本

スポンサーリンク

データセットの準備ができました。でも、モデルはそのままじゃテキストを読めません。AIの「言語」は数字なんです。

今回は、テキストを数値(トークン)に変換するトークン化(Tokenization)と、長さをそろえるパディング(Padding)について学びます。地味に見えるけど、超重要なステップですよ!

モデルは人間みたいには読めない

言語モデルは文を読みません。トークンっていう、意味の一部を表す小さなサブワード単位を処理します。

例えばこんなやり取り:

ユーザー: フランスの首都は何ですか?
アシスタント: フランスの首都はパリです。

モデルがこれから学習するには、前処理パイプラインを通す必要があります:

  1. トークン化:テキストを小さく意味のある単位(トークン)に分割
  2. 変換:トークンを数値IDにマップ
  3. パディングとマスキング:バッチ処理のため長さをそろえて、何を無視すべきか伝える

この変換が、すべてのファインチューニングワークフローの基礎なんです。

トークン化の仕組み

「テキストを分割」って、スペースで区切ればいいじゃん?って思いますよね。でもそれだと:

  • 短縮形(「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ステップ

  1. トークン化:テキストをサブワード単位に分割
  2. パディング:すべてのシーケンスを同じ長さに
  3. 注意マスク:どのトークンが本物か伝える

この前処理があって初めて、モデルはテキストから学習できるんです。

次のレッスンでは、「アシスタントのみマスキング」の詳細を学びます。命令ファインチューニングで、どうやってモデルに「ユーザーの質問を予測するな、アシスタントの回答を予測しろ」って教えるのか。楽しみにしていてください!

コメント

タイトルとURLをコピーしました