言語モデルは文章をどう読むか
トークン化とは、言語モデルが文章をトークンという小さな部品に切る作業です。バイトペア符号化は、その部品を決めるよく使われる方法です。チャットに打った言葉も、モデルに届く前に、この方法で切られます。
部品の決め方で、入る文章の量、めずらしい語の扱い、書ける語が決まります。
このレッスンのゴール
メモ
短い文章を、バイトペアの併合でトークンに分けることができる。
キーワード
| ことば | いみ | れい |
|---|---|---|
| トークン | モデルがひとまとまりで扱う文章の部品 | さかな |
| 語彙 | モデルが知っているトークンの一覧 | |
| ペア | 隣り合う2つのトークン | か な |
| 併合 | ペアを1つの新しいトークンにまとめること | |
| バイトペア符号化 | いちばん多いペアの併合をくり返して、トークンを作る方法 | |
| トークンID | トークンを表す番号 |
学生が入力するセルは、このプレビューでは空白です。
単語で切るか、文字で切るか
前に学んだ自然言語処理では、文章を単語に切りました。言語モデルには決まった語彙が要りますが、単語ではそれが難しくなります。人の名前や打ち間違いのような新しい語は、知らない語になります。
文字で切れば、この問題はなくなります。かなと漢字があれば、どんな語も書けるからです。ただ、文が長くなり、長い入力ほど計算が増えます。
例: 同じ文章を2通りに切る
| 切り方 | 例の文章のトークン数 | 語彙 | 「たなか」を書けるか |
|---|---|---|---|
| 単語 | 5 | 3: さかな、さかなや、たかな | いいえ、知らない語 |
| 文字 | 17 | 5: さ、か、な、や、た | はい、た・な・か で書ける |
学生が入力するセルは、このプレビューでは空白です。
2種類のトークンを数える
text = "さかな、さかなや、たかな、さかなや、さかな"
# 日本語には空白がないので、読点で語に分けます。
words = text.split("、")
chars = []
for word in words:
for ch in word:
chars.append(ch)
word_vocab = []
for word in words:
if word not in word_vocab:
word_vocab.append(word)
char_vocab = []
for ch in chars:
if ch not in char_vocab:
char_vocab.append(ch)
print("単語のトークン:", len(words), "語彙:", word_vocab)
print("文字のトークン:", len(chars), "語彙:", char_vocab)
print("たなか は知っている語ですか:", "たなか" in word_vocab)
# text の最後に「、たなか」を足して、実行してください。
# どちらの語彙が、いくつ増えますか。
いちばん多いペアを併合する
バイトペア符号化は、単語と文字の間にあります。日本語には空白がないので、まず1文字ずつに分けます。ここでは読点で語を区切り、1つの語の中で隣り合うペアを数えます。いちばん多いペアを1つのトークンにまとめ、語彙に加えます。
それから数えなおして、また併合します。よく出る語は短くなり、めずらしい語は小さな部品のまま残るので、知らない語は出ません。
例: ペアを数える
| ペア | 出てくる語 | 数 |
|---|---|---|
| か な | さかな、さかなや、たかな、さかなや、さかな | 5 |
| さ か | さかな、さかなや、さかなや、さかな | 4 |
| な や | さかなや、さかなや | 2 |
| た か | たかな | 1 |
学生が入力するセルは、このプレビューでは空白です。
ラボでペアを数える
docker exec jupyter python3 -c "from collections import Counter; words = [w.split('-') for w in 'sa-ka-na sa-ka-na-ya ta-ka-na sa-ka-na-ya sa-ka-na'.split()]; print(Counter(t[i] + ' ' + t[i + 1] for t in words for i in range(len(t) - 1)).most_common(3))"ここでは表示のみで、実行されません。無料アカウントを作成すると、実行ボタンで自分のラボのターミナルに入力できます。
例: 3回の併合
| 併合 | 新しいトークン | さかな | さかなや | たかな |
|---|---|---|---|---|
| 始め | なし | さ か な | さ か な や | た か な |
| 1: か な (5) | かな | さ かな | さ かな や | た かな |
| 2: さ かな (4) | さかな | さかな | さかな や | た かな |
| 3: さかな や (2) | さかなや | さかな | さかなや | た かな |
学生が入力するセルは、このプレビューでは空白です。
1回目の併合をする
text = "さかな、さかなや、たかな、さかなや、さかな"
words = []
for word in text.split("、"):
words.append(list(word))
left = "か"
right = "な"
merged = []
for tokens in words:
out = []
i = 0
while i < len(tokens):
# ペアを1つのトークンにまとめ、2つ分先へ進みます。
if i + 1 < len(tokens) and tokens[i] == left and tokens[i + 1] == right:
out.append(left + right)
i = i + 2
else:
out.append(tokens[i])
i = i + 1
merged.append(out)
print(merged)
# ペアを "さ" と "か" に変えて、実行してください。
# 「たかな」のトークンは、いくつになりますか。
よくある間違い
注意
トークンは1つの単語のことだと考えがちです。バイトペア符号化では、よく出る語は1トークンですが、めずらしい語は何トークンにもなります。モデルにどれだけ入るかを考えるときは、単語ではなくトークンを数えてください。
トークンは番号になる
モデルは文字を見ません。語彙のトークンにはそれぞれトークンIDがあり、一覧の中の位置を表します。3回の併合のあと、語彙は さ、か、な、や、た、かな、さかな、さかなや で、0から7の番号が付きます。
「さかなや、たかな、さかな」は さかなや、た、かな、さかな になり、IDは 7、4、5、6 です。10文字が4トークンになりました。
トークンをIDに変える
docker exec jupyter python3 -c "vocab = ['sa', 'ka', 'na', 'ya', 'ta', 'kana', 'sakana', 'sakanaya']; print([vocab.index(t) for t in ['sakanaya', 'ta', 'kana', 'sakana']])"ここでは表示のみで、実行されません。無料アカウントを作成すると、実行ボタンで自分のラボのターミナルに入力できます。