🧮

OpenAI 言語モデルで日本語を扱う際のトークン数推定指標

2023/03/30に公開

はじめに

OpenAI の言語モデルで日本語を扱う際に、コスト概算などの目的で処理されるトークン数を推定したい場合がありますが、英語以外の言語に関しては OpenAI のドキュメントや記事に具体的な指標が記載されておらず、個人の経験則に基づいて推定するしかない状況でした。
そこで、実際どのくらいになるのか、ある程度大きなデータセットを使って指標を計算してみました。

How words are split into tokens is also language-dependent. For example ‘Cómo estás’ (‘How are you’ in Spanish) contains 5 tokens (for 10 chars). The higher token-to-char ratio can make it more expensive to implement the API for languages other than English.

tl;dr

結果はこちら

実測

1. データセット

Wiki-40B日本語データセット を使いました。この中には、2020 年 データセット公開時点での 828,236 の Wikipedia 日本語記事が含まれています。データセットは traintestvalidation の 3 つのスプリットに分割されていますが、全てのスプリットを使いました。

2. 前処理

データセットには特殊なマーカー文字列が含まれるため、これらを取り除きました。

  • _START_ARTICLE_ (記事のタイトル)
  • _START_SECTION_ (セクションの開始)
  • _START_PARAGRAPH_ (段落の開始)
  • _NEWLINE_ (段落内の改行)

以下は「地球」の例です。前述のとおり内容は Wiki-40B データセットが公開された当時のものですので、現在の記事とは異なる可能性があります。

生データ

_START_ARTICLE_
地球
_START_SECTION_
概要
_START_PARAGRAPH_
地球とは我々人類が住んでいる天体、つまり我々の足元にある天体のことである。「地」という字・概念と「球」という字・概念でそれを表現している。英語 (Earth) やラテン語 (Tellus, Terra) など他の言語でも多くは「大地」を表す語が当てられている。単語としての「地球」は中国語由来である。中国語の「地球」は明朝の西学東漸期に初めて見られ、イタリア人宣教師マテオ・リッチ(1552年-1610年)の『坤輿万国全図』がこの単語が使用された最初期の資料である。清朝後期に西洋の近代科学が中国に入ってくると、大地球体説が中国の人々によって次第に受け入れられるようになり、「地球」(または地毬)という単語が広く使われるようになった。当時の新聞申報の創刊号には「地球説」に関する文章が掲載されている。日本には幕末から明治期に中国語から借入され、定着した。_NEWLINE_地球は太陽系の惑星の一つである。その形は、ほぼ回転楕円体で、赤道の半径は6378kmほどで、極半径は6357km。(より精度の高い数字については後述の「物理的性質」の項を参照のこと)その運動に着目すると、365日強で太陽の周囲を一周し、24時間で1回 自転しており、太陽からの平均距離は1億4960万km。_NEWLINE_その内部は大まかに地殻、マントル、核の3部分から成っている。地球全体の平均密度は1cm³当たり5.514gである。表面は大気に覆われている。_NEWLINE_放射性元素による隕石の年代測定と、アポロ計画によって持ち帰られた月の岩石分析から、地球は誕生してから約46億年経過していると推定される。_NEWLINE_太陽系の年齢もまた隕石の年代測定に依拠するので、地球は太陽系の誕生とほぼ同時に形成されたとしてよい。10個程度の火星サイズの原始惑星の衝突合体によって形成されたと考えられている。_NEWLINE_太陽系内の惑星としては、太陽から2天文単位内の位置に存在し、岩石質外層と鉄を主成分とする中心核を持つ「地球型惑星」に分類され、太陽系の地球型惑星の中で大きさ、質量、密度ともに最大のものである。_NEWLINE_組成は地表面からの深さによって異なる。地殻に存在する元素は、酸素(質量比49.5%)とケイ素(同25.8%)が主体で、以下アルミニウム・鉄・カルシウム・ナトリウム・カリウム・マグネシウムなどの金属元素が含まれる。この元素別質量百分率はクラーク数として纏められている。ほとんどはケイ酸塩など金属酸化物の形で存在する。_NEWLINE_対照的に、中心部分は鉄やニッケルが主体である。地表面の71.1%は液体の水(海)で被われており、地表から上空約100kmまでの範囲には窒素・酸素を主成分とする大気がある。大気の組成は高度によって変化する。
_START_SECTION_
公転
_START_PARAGRAPH_
円に近い楕円形の軌道を描いて太陽の周りを1.0000太陽年に1回公転し、また0.9973平均太陽日に1回自転している。天の北極から見て、自転、公転ともに反時計回りである。_NEWLINE_この楕円の形は10万年ほどの周期で変化することが天文学者の研究でわかっている。楕円の軌道離心率は0.0167である。_NEWLINE_1太陽年とは太陽が春分点から春分点まで一巡りする時間、すなわち季節が一巡する時間をいい、365.242 190 402日である。地球の歳差により春分点が移動するため、1太陽年は、恒星が動かないものとして見た時に地球が太陽の周りを一周する時間として定義される1年(恒星年)より短い。1恒星年は365.256 363 004日である。
...

マーカー置き換え

今回は以下のように置き換えました。

  • _START_ARTICLE_ (記事のタイトル) → 行ごと削除
  • _START_SECTION_ (セクションの開始) → 行ごと削除
  • _START_PARAGRAPH_ (段落の開始) → 行ごと削除
  • _NEWLINE_ (段落内の改行) → 改行コード (\n) で置き換え
地球
概要
地球とは我々人類が住んでいる天体、つまり我々の足元にある天体のことである。「地」という字・概念と「球」という字・概念でそれを表現している。英語 (Earth) やラテン語 (Tellus, Terra) など他の言語でも多くは「大地」を表す語が当てられている。単語としての「地球」は中国語由来である。中国語の「地球」は明朝の西学東漸期に初めて見られ、イタリア人宣教師マテオ・リッチ(1552年-1610年)の『坤輿万国全図』がこの単語が使用された最初期の資料である。清朝後期に西洋の近代科学が中国に入ってくると、大地球体説が中国の人々によって次第に受け入れられるようになり、「地球」(または地毬)という単語が広く使われるようになった。当時の新聞申報の創刊号には「地球説」に関する文章が掲載されている。日本には幕末から明治期に中国語から借入され、定着した。
地球は太陽系の惑星の一つである。その形は、ほぼ回転楕円体で、赤道の半径は6378kmほどで、極半径は6357km。(より精度の高い数字については後述の「物理的性質」の項を参照のこと)その運動に着目すると、365日強で太陽の周囲を一周し、24時間で1回 自転しており、太陽からの平均距離は1億4960万km。
その内部は大まかに地殻、マントル、核の3部分から成っている。地球全体の平均密度は1cm³当たり5.514gである。表面は大気に覆われている。
放射性元素による隕石の年代測定と、アポロ計画によって持ち帰られた月の岩石分析から、地球は誕生してから約46億年経過していると推定される。
太陽系の年齢もまた隕石の年代測定に依拠するので、地球は太陽系の誕生とほぼ同時に形成されたとしてよい。10個程度の火星サイズの原始惑星の衝突合体によって形成されたと考えられている。
太陽系内の惑星としては、太陽から2天文単位内の位置に存在し、岩石質外層と鉄を主成分とする中心核を持つ「地球型惑星」に分類され、太陽系の地球型惑星の中で大きさ、質量、密度ともに最大のものである。
組成は地表面からの深さによって異なる。地殻に存在する元素は、酸素(質量比49.5%)とケイ素(同25.8%)が主体で、以下アルミニウム・鉄・カルシウム・ナトリウム・カリウム・マグネシウムなどの金属元素が含まれる。この元素別質量百分率はクラーク数として纏められている。ほとんどはケイ酸塩など金属酸化物の形で存在する。
対照的に、中心部分は鉄やニッケルが主体である。地表面の71.1%は液体の水(海)で被われており、地表から上空約100kmまでの範囲には窒素・酸素を主成分とする大気がある。大気の組成は高度によって変化する。
公転
円に近い楕円形の軌道を描いて太陽の周りを1.0000太陽年に1回公転し、また0.9973平均太陽日に1回自転している。天の北極から見て、自転、公転ともに反時計回りである。
この楕円の形は10万年ほどの周期で変化することが天文学者の研究でわかっている。楕円の軌道離心率は0.0167である。
1太陽年とは太陽が春分点から春分点まで一巡りする時間、すなわち季節が一巡する時間をいい、365.242 190 402日である。地球の歳差により春分点が移動するため、1太陽年は、恒星が動かないものとして見た時に地球が太陽の周りを一周する時間として定義される1年(恒星年)より短い。1恒星年は365.256 363 004日である。
...

3. コード

以下の Python コードで、OpenAI の言語モデルで使われている 3 つのエンコーディング (cl100k_basep50k_baser50k_base) をそれぞれ指定した際のトークン数を確認しました。コードの中で使っている tiktokentensorflow_datasets は事前に実行環境にインストールしておく必要があります。
どの言語モデルがどのエンコーディングを使っているかについては、以前の記事でまとめていますので、そちらを参照してください。

import tiktoken
import tensorflow_datasets as tfds

def count_tokens(text):
    ret_list = []
    for encoding_name in ["cl100k_base", "p50k_base", "r50k_base"]:
        encoding = tiktoken.get_encoding(encoding_name)
        token_integers = encoding.encode(text)
        num_tokens = len(token_integers)
        ret_list.append(num_tokens)
    return ret_list

def remove_markers(text):
    return(text.replace("_START_ARTICLE_\n", "").replace("_START_SECTION_\n", "").replace("_START_PARAGRAPH_\n", "").replace("_NEWLINE_", "\n"))

splits = ["test", "train", "validation"]
for split in splits:
    ds = tfds.load('wiki40b/ja', split=split)
    record_count = 0
    char_count = 0
    token_counts = [0, 0, 0]
    for idx, record in enumerate(ds):
        text = record['text'].numpy().decode('utf-8')
        text_replaced = remove_markers(text)
        char_count += len(text_replaced)
        token_counts = [x + y for x, y in zip(token_counts, count_tokens(text_replaced))]
        record_count += 1
    print("split: %s" % split)
    print("record_count: %s" % record_count)
    print("char_count: %s" % char_count)
    print("token_count (cl100k_base): %s" % token_counts[0])
    print("token_count (p50k_base): %s" % token_counts[1])
    print("token_count (r50k_base): %s" % token_counts[2])

ちなみに、処理はこのくらいのスペックの Windows 11 マシンで数十分程度で終わりました。初回実行時はデータセットのダウンロードが発生するため余計に時間がかかります。

プロセッサ	11th Gen Intel(R) Core(TM) i7-11370H @ 3.30GHz   3.30 GHz
実装 RAM	32.0 GB (31.8 GB 使用可能)
システムの種類	64 ビット オペレーティング システム、x64 ベース プロセッサ

[補足] GPT-4o のエンコーディングについて

2024 年 5 月 14 日の GPT-4o の発表と同じタイミングで公開された tiktoken のバージョン 0.7.0 を使うと GPT-4o のエンコーディングを確認することができ、それによると o200k_base という新たなエンコーディングが使われているようです。本項更新時点で GPT-4o の API はまだ公開されていませんが、参考のため追加で o200k_base を指定した際のトークン数の確認を行いました。

コード:

import tiktoken
print(tiktoken.encoding_for_model('gpt-4o'))

出力:

<Encoding 'o200k_base'>

参考

4. 結果

結果の一覧表です。トークン推定の指標として、各エンコーディングにおける 1 トークンあたりの文字数1 文字あたりのトークン数を計算しました。

スプリット レコード数 文字数 トークン数 (o200k_base) トークン数 (cl100k_base) トークン数 (p50k_base) トークン数 (r50k_base)
test 41,268 38,591,027 30,874,301 42,077,561 54,037,268 54,043,708
train 745,392 701,788,342 561,507,091 765,348,310 983,557,663 983,697,862
validation 41,576 38,505,964 561,507,091 41,936,982 53,857,786 53,864,392
合計 828,236 778,885,333 623,149,632 849,362,853 1,091,452,717 1,091,605,962
トークンあたりの文字数 --- --- 1.2499 0.9170 0.7136 0.7135
文字あたりのトークン数 --- --- 0.8001 1.0905 1.4013 1.4015

※小数第 5 位四捨五入

4.1. モデルごとの推定最大文字数 (日本語)

この結果から、OpenAI の代表的なモデルにおける日本語の最大文字数を推定すると以下のようになります。ただし、あくまでもざっくりこのくらいの文字数まで扱えるという目安ですので、実際にアプリケーションに組み込む際は tiktoken を使って入力トークン数を確認して最大トークンを超えないように制御する必要があります。

モデル エンコーディング 最大トークン 推定最大文字数 (日本語)
GPT-4o o200k_base 128,000 (入力)
4,096 (出力)
約 159,987
約 5,120
gpt-4-vision-preview
(GPT-4 Turbo with Vision)
cl100k_base 128,000 (入力)
4,096 (出力)
約 117,376
約 3,756
gpt-4-0125-preview
(GPT-4 Turbo)
cl100k_base 128,000 (入力)
4,096 (出力)
約 117,376
約 3,756
gpt-4-1106-preview
(GPT-4 Turbo)
cl100k_base 128,000 (入力)
4,096 (出力)
約 117,376
約 3,756
gpt-4-32k cl100k_base 32,768 (入出力合計) 約 30,049
gpt-4 cl100k_base 8,192 (入出力合計) 約 7,512
gpt-3.5-turbo cl100k_base 4,096 (入出力合計) 約 3,756

参考

おわりに

以上です。🍵

Microsoft (有志)

Discussion