AI・データ●●●○○

トークン

Token ・ とーくん

LLMが文章を扱う最小単位。料金・コンテキスト長・生成速度はすべてトークン数で数えられる。

✦ 30秒で試す — 航海漢字1文字が、AIには2つのかけらに見えていることがある日本語の依頼文は、何トークンになる?予想してみる

概要

トークンは、LLM(大規模言語モデル)が文章を読み書きするときの最小単位です。モデルは文章を1文字ずつでも1単語ずつでもなく、「サブワード」と呼ばれる中間の大きさの断片に切り分けてから処理します。たとえば GPT-4o のトークナイザは、英語の “unforecastable” を “un” + “forecast” + “able” の3つに、日本語の「東京都に住んでいます」を「東京都」「に」「住」「ん」「で」「います」の6つに分けます。この切り分けを行うプログラムがトークナイザで、切り方はモデルごとに違います。

トークンが実務で重要なのは、LLM にまつわる数字がほぼすべてトークン単位で決まるからです。APIの料金は入出力のトークン数に対する従量課金、モデルが一度に読める量(コンテキストウィンドウ)は「20万トークンまで」のようにトークン数で表され、生成速度も「毎秒何トークン出せるか」で語られます。LLM を使う開発では、文字数ではなくトークン数で見積もる感覚が欠かせません。

なお、認証・認可の文脈で出てくる「アクセストークン」やJWTの「トークン」は、まったく別の概念です。どちらも「何かを代理する小さな断片」という語源を共有しているだけで、この記事で扱うのは LLM の処理単位としてのトークンです。

なぜ生まれたか

機械学習で言語を扱うには、まず文章を離散的な単位の列に変え、各単位に番号(ID)を振る必要があります。素直な候補は「単語」と「文字」ですが、どちらにも深刻な問題がありました。

単語単位では語彙が爆発します。英語だけでも活用形・複合語・固有名詞・スペルミスまで含めれば単語の種類は事実上無限で、モデルが持てる語彙表(数万〜数十万件)には収まりません。語彙表にない単語はすべて「未知語」という同じ記号に潰され、“believe” を知っていても “unbelievable” には手も足も出ません。そもそも日本語は単語の間に空白がないので、単語に切るだけで別の解析が要ります。一方、文字単位なら未知語は消えますが、系列が何倍にも長くなり、モデルは「文字を綴って単語を組み立てる」ところから学ばなければならず、計算量も学習の難しさも跳ね上がります。

中間の解がサブワード分割です。元は1994年に Philip Gage が発表したデータ圧縮の手法 BPE(Byte Pair Encoding)で、「いちばん頻繁に隣り合う2記号を1つの新しい記号に置き換える」ことを繰り返します。2016年に Sennrich らがこれを機械翻訳の語彙づくりに転用し、「よく出る語は丸ごと1トークン、珍しい語は既知の断片の組み合わせ」という語彙を、データの頻度から自動で作れることを示しました。2019年の GPT-2 は、文字ではなく UTF-8 のバイトから結合を始める byte-level BPE を採用し、どんな文字列でも最悪バイト単位まで分解すれば表せる(未知語が原理的に出ない)ようにしました。語彙爆発と未知語の問題を同時に解いたこの方式が、現在のLLMの標準です。BERT が使った WordPiece や、空白のない言語もそのまま扱える SentencePiece(2018年)も同じ系譜にあります。

詳細

トークナイザの働き

トークナイザは、学習時に作った語彙表と結合の規則に従って、入力文字列をトークン列に分け、各トークンを整数 ID に変えます。モデル本体が見ているのはこの ID の列だけで、内部では各 ID が埋め込みベクトルに変換されてTransformerの層に入ります。生成はその逆で、モデルが「次のトークンの ID」を1つずつ選び、トークナイザがそれを文字列に戻します。LLMの生成が1トークンずつ進み、応答時間が出力トークン数にほぼ比例するのはこのためです。

入力テキストThe weather is unforecastableトークナイザで分割トークン列(␣ は先頭の空白もトークンに含まれることを示す)The␣weather␣is␣unforecastable97611122382537120983562IDよく出る語は丸ごと1トークン、見慣れない語は既知の断片の組み合わせモデルが受け取るのは ID の整数の並びだけ。文字の綴りは直接には見えていないID の値と切り方はトークナイザごとに異なる(ここでは GPT-4o の o200k_base)
文章がトークン列、そして ID 列になる — GPT-4o のトークナイザ(o200k_base)での実際の分割

語彙はどう作られるか — BPE の結合を追う

BPE の学習は驚くほど単純です。第一に、学習用のテキストをすべて最小の単位(文字、または byte-level ならバイト)に分けます。第二に、隣り合う2トークンの組をすべて数え、いちばん多い組を1つ選びます。第三に、その組をテキスト中のあらゆる場所で1つのトークンに置き換え、新しいトークンを語彙表に1件足します。これを語彙表が目標の大きさ(GPT-2 で約5万、GPT-4 の cl100k_base で約10万、GPT-4o の o200k_base で約20万)になるまで繰り返します。記録した結合の順番がそのままトークナイザの規則になり、新しい文章を分けるときも同じ順番で結合を当てはめます。

頻度で結合を決めるので、よく出る語や語の断片ほど早く1つにまとまり、珍しい語は断片のまま残ります。ここから、学習データに多い言語ほど少ないトークンで表せる、という性質が生まれます。下の部品で、組を押して結合していくと、英語の語がどんどん縮む一方で、例の少ない日本語の語はほとんど縮まないことを確かめてください。

⚡ 体験: 頻度の高い組から結合して語彙を作る(BPE)
英語(例が多い)日本語(例が少ない)the×8newest×6low×5new×4widest×3lower×2東京×1京都×1学生×1先生×1大学×1学校×1隣り合う組の出現回数 — 押すと結合e+w10回n+e10回e+s9回s+t9回h+e8回t+h8回w+e8回京+都1回語彙表: 基本の文字 19 個 + 結合で増えたトークン 0 個(結合の順番がそのまま分割の規則になる)まだ結合していません
総トークン数127英語 トークン/文字1.00日本語 トークン/文字1.00縮んだ割合0%

コーパスの語はいま1文字ずつのトークンです。右の棒は隣り合う2トークンの組が何回出るか。いちばん長い棒を押して、その組を1つのトークンに結合してください。

日本語はトークンの効率が悪い

トークナイザの語彙は学習データの頻度から作られるので、データの大半を占める英語がいちばん「お得」に切られます。同じ意味の文で比べると、たとえば “Please summarize the attached contract and list the three most important risks for our company.” は 16 トークン、「添付の契約書を要約し、当社にとって最も重要なリスクを3つ挙げてください。」(36文字)は GPT-4 の cl100k_base で 39 トークン、GPT-4o の o200k_base で 31 トークンでした。語彙表を約20万件に広げて多言語のデータを増やした新しいトークナイザでは差が縮んでいますが、それでも2倍近い開きがあります。漢字1文字がバイトの断片(UTF-8 で3バイト)に割られることもまだあり、たとえば o200k_base は「吾輩」の「輩」を2つのバイト断片に分けます。

これは実務に直結します。同じ内容でも、日本語で書くとAPI料金が高くなり、コンテキストウィンドウを早く使い切り、生成にも時間がかかります。「日本語1文字 ≒ 1トークン前後」という粗い目安は持ちつつ、正確な見積もりは各社が公開しているトークナイザ(OpenAI の tiktoken など)や、API のトークン数カウント機能で実測するのが確実です。

トークンで決まる3つの数字

第一に料金です。LLM の API は「入力100万トークンあたり何ドル、出力100万トークンあたり何ドル」という従量課金が標準で、出力のほうが数倍高いのが通例です。RAGのように長い文書をプロンプトへ詰め込む構成では、入力トークン数がコストの大半を占めます。

第二にコンテキストウィンドウです。モデルが一度に読めるのは決まった数のトークンまでで、会話の履歴が長くなると古い部分から窓の外に押し出されます。プロンプトエンジニアリングで「何を入れ、何を削るか」を決めるときの予算の単位もトークンです。

第三に速度です。生成は1トークンずつの逐次処理なので、応答時間は出力トークン数にほぼ比例します。長い出力を求めるほど待ち時間もコストも増えるので、「必要なものだけを短く出させる」工夫が効きます。

落とし穴 — トークン分割が生む不思議な挙動

LLM の奇妙な失敗の多くはトークン分割に由来します。有名なのが「strawberry に r はいくつ?」に誤答する問題で、o200k_base では “strawberry” は “st” + “raw” + “berry” の3トークンです。モデルは文字の並びではなくこの3つの塊を見ているので、文字を数える・逆さに読むといった操作が苦手です。数字も “1234567” が “123” + “456” + “7” のように桁の意味と関係なく割られるので、桁の多い計算を間違えやすくなります。「モデルは文字ではなくトークンを読んでいる」と分かっていれば、文字を1つずつ区切って渡す、計算はコードに任せる、といった回避策が自然に出てきます。

試問

小さなコーパス(英語の語6つと日本語の語6つ、右の ×数字 はその語の出現回数)が、いまは1文字ずつのトークンに分かれていて、総トークン数は127です。下の棒は、隣り合う2トークンの組がコーパス全体で何回出るかで、押すとその組がすべての場所で1つのトークンに結合され、語彙表に1件増えます。

✦ 命題挑戦中

語彙に足せるのは5つまで。結合する組を選んで、コーパスの総トークン数を127から85以下に縮めよ

  • 結合は 5回まで
  • 総トークン数を 127 から 85以下に(3分の1減らす)
⚡ 体験: 頻度の高い組から結合して語彙を作る(BPE)
英語(例が多い)日本語(例が少ない)the×8newest×6low×5new×4widest×3lower×2東京×1京都×1学生×1先生×1大学×1学校×1隣り合う組の出現回数 — 押すと結合e+w10回n+e10回e+s9回s+t9回h+e8回t+h8回w+e8回京+都1回語彙表: 基本の文字 19 個 + 結合で増えたトークン 0 個(結合の順番がそのまま分割の規則になる)まだ結合していません
総トークン数127英語 トークン/文字1.00日本語 トークン/文字1.00縮んだ割合0%

コーパスの語はいま1文字ずつのトークンです。右の棒は隣り合う2トークンの組が何回出るか。いちばん長い棒を押して、その組を1つのトークンに結合してください。