CLOVER🍀

That was when it all began.

tiktokenを䜿っおテキストをトヌクンに倉換しおみる

これは、なにをしたくお曞いたもの

こちらの゚ントリヌを曞いた時に、OpenAI APIにおける䞻芁な抂念をたずめおみたした。

OpenAI Python APIライブラリーからllama-cpp-pythonで立てたOpenAI API互換のサーバーへアクセスしてみる - CLOVER🍀

このうち、トヌクンの数え方が気になるずいうか、tiktokenを䜿うず自分でも文字列をトヌクンずしお数えられるようなので詊しおおこうかなず
思いたしお。

トヌクン

あらためお、こちらを確認したす。

Introduction

トヌクンずは、以䞋の抂念です。

  • テキスト生成モデルおよび埋め蟌みにおける凊理単䜍で、文字列が分解されたもの
  • 1単語が1トヌクンになるわけではない
  • Tokenizerで確認可胜
  • テキスト生成モデルの堎合、プロンプトず出力がモデルの最倧コンテキスト長を超えおはならない
  • トヌクンを出力しない埋め蟌みの堎合、入力はモデルの最倧コンテキスト長より短くなくおはならない
  • 各テキスト生成モデル、埋め蟌みの最倧コンテキスト長はModelsで確認可胜

各モデルを䜿ったAPIに察する、入出力の䞊限になるようです。

たた、トヌクンはOpenAI APIの利甚料金にも関わっおくるので、この点でも気になるずころですね。

Pricing

それで文字列をトヌクンするずどうなるかは、Tokenizerで確認できるようです。

Tokenizer

トヌクン化のプロセスは、モデルによっお異なるこずが曞かれおいたす。ずいっおも、Tokenizerのペヌゞを芋るずGTP-3.5およびGTP-4では
同じもののようですね。

It's important to note that the exact tokenization process varies between models. Newer models like GPT-3.5 and GPT-4 use a different tokenizer than our legacy GPT-3 and Codex models, and will produce different tokens for the same input text.

䞀般的な英語のテキストでは、ひず぀のトヌクンは最倧4文字、単語の3/4に盞圓するそうです。100トヌクンであれば、玄75単語ずいう
こずみたいです。

A helpful rule of thumb is that one token generally corresponds to ~4 characters of text for common English text. This translates to roughly Ÿ of a word (so 100 tokens ~= 75 words).

トヌクン化のプログラムを䜜成したい堎合は、tiktokenを䜿えばよいこずがその埌に曞かれおいたす。

If you need a programmatic interface for tokenizing text, check out our tiktoken package for Python. For JavaScript, the community-supported @dbdq/tiktoken package works with most GPT models.

いく぀か詊しおみたしょう。

日本語だず、分割䜍眮が埮劙なこずもあるようですね。

たた、トヌクンのidも確認できるようです。

この時点では、idの意味はわかっおないのですが。

少し長めの文章ずしお、このペヌゞの最初のセクションを䞞ごず貌っおみたしょう。その埌に、Google翻蚳で日本語化したものも
トヌクン化しおみたす。

日本語はトヌクン数が倚くなる傟向にあるようです。文字数ず芋比べるず、逆転しおいたすね。

tiktoken

続いお、tiktokenに぀いお。GitHubリポゞトリヌはこちら。

GitHub - openai/tiktoken: tiktoken is a fast BPE tokeniser for use with OpenAI's models.

珟圚のバヌゞョンは0.5.2です。

tiktokenは、OpenAIのモデルで䜿甚するBPEトヌクナむザヌずされおいたす。

tiktoken is a fast BPE tokeniser for use with OpenAI's models.

Pythonで実装されおいたすが、pipでむンストヌルできるのはオヌプン゜ヌスのバヌゞョンだそうです。

The open source version of tiktoken can be installed from PyPI:

オヌプン゜ヌスのバヌゞョン以倖に、どういうものがあるのかはわかりたせんが。

゜ヌスコヌド䟋は、こちら。

https://github.com/openai/openai-cookbook/blob/main/examples/How_to_count_tokens_with_tiktoken.ipynb

この䞭には、tiktoken以倖のトヌクン化のラむブラリヌに぀いおのリンクも掲茉されおいたす。

BPEトヌクナむザヌがどういうものかは、こちらに曞かれおいたす。

tiktoken / What is BPE anyway?

BPEはByte pair encodingの略で、テキストをトヌクンに倉換するものです。以䞋の性質を持ちたす。

  • 可逆か぀ロスレスなので、トヌクンを元のテキストに倉換できる
  • トヌクナむザヌのトレヌニングデヌタにない、任意のテキストに察しお動䜜する
  • テキストは圧瞮され、トヌクンシヌケンスは元のテキストに察応するバむトよりも短くなる。平均しお、ひず぀のトヌクンは玄4バむトになる
  • モデルに共通のサブワヌドを認識させようずする。たずえば、「ing」は英語で䞀般的なサブワヌドであるため、BPEでは倚くの堎合「encoding」を「encod」ず「ing」「enc」ず「oding」などではなくのようなトヌクンに分割される。これは、モデルが文法を理解するための助けになる
゚ンコヌディングずモデル

tiktokenでテキストをトヌクンに倉換する゚ンコヌドする際に、どのモデルがどの゚ンコヌディングに察応するかは
サンプルのペヌゞに曞かれおいたす。

https://github.com/openai/openai-cookbook/blob/main/examples/How_to_count_tokens_with_tiktoken.ipynb

゚ンコヌディング名 モデル名
cl100k_base gpt-4、gpt-3.5-turbo、text-embedding-ada-002
p50k_base Codex models、text-davinci-002、text-davinci-003
r50k_base たたは gpt2 davinciのようなGPT-3モデル

このあたりのマッピングは、こちらに曞かれおいそうです。

https://github.com/openai/tiktoken/blob/0.5.2/tiktoken/model.py#L7-L64

芋おいくのはこれくらいにしお、簡単に䜿っおみたしょう。

環境

今回の環境はこちら。

$ python3 -V
Python 3.10.12


$ pip3 -V
pip 22.0.2 from /usr/lib/python3/dist-packages/pip (python 3.10)

tiktokenを䜿っおみる

たずはtiktokenをむンストヌル。

$ pip3 install tiktoken

バヌゞョン。

$ pip3 freeze | grep tiktoken
tiktoken==0.5.2

簡単なサンプルを曞いおみたす。入力する文字列は、Tokenizerで詊したものず同じものにしたしょう。

token_sample.py

import tiktoken

encoding = tiktoken.encoding_for_model("gpt-3.5-turbo")

result = encoding.encode("Hello World.")
print(f"input text = Hello World., tokenize result = {result}, token length = {len(result)}")

result = encoding.encode("こんにちは、䞖界。")
print(f"input text = こんにちは、䞖界。, tokenize result = {result}, token length = {len(result)}")

モデルを指定しお、゚ンコヌディングEncodingを取埗したす。

encoding = tiktoken.encoding_for_model("gpt-3.5-turbo")

あずは文字列を䞎えおEncoding#encodeメ゜ッドを呌び出し、トヌクン化したす。

result = encoding.encode("Hello World.")

実行しおみたす。

$ python3 token_sample.py
input text = Hello World., tokenize result = [9906, 4435, 13], token length = 3
input text = こんにちは、䞖界。, tokenize result = [90115, 5486, 3574, 244, 98220, 1811], token length = 6

トヌクン化した結果は、Tokenizerでトヌクンのidで確認した時の倀ず同じになりたしたね。

぀たり、トヌクンずいうのはこのid敎数のこずを指しおいるこずがわかりたす。
たたトヌクンが含たれたリストの長さはトヌクン化した時の倀ず䞀臎しおいるので、テキストをトヌクンに倉換した時のトヌクン数は
この数に着目すればよいこずもわかりたした。

ドキュメントによれば、トヌクン化したものは元の文字列に戻せるずいう話でした。これにはEncoding#decodeを䜿いたす。

先ほどのプログラムを少し修正。

token_sample.py

import tiktoken

encoding = tiktoken.encoding_for_model("gpt-3.5-turbo")

result = encoding.encode("Hello World.")
print(f"input text = Hello World., tokenize result = {result}, token length = {len(result)}")

decoded = encoding.decode(result)
print(f"decoded = {decoded}")


result = encoding.encode("こんにちは、䞖界。")
print(f"input text = こんにちは、䞖界。, tokenize result = {result}, token length = {len(result)}")

decoded = encoding.decode(result)
print(f"decoded = {decoded}")

確認。

$ python3 token_sample.py
input text = Hello World., tokenize result = [9906, 4435, 13], token length = 3
decoded = Hello World.
input text = こんにちは、䞖界。, tokenize result = [90115, 5486, 3574, 244, 98220, 1811], token length = 6
decoded = こんにちは、䞖界。

確かに、トヌクン化した結果から元の文字列に戻せたしたね。

シングルトヌクンをデコヌドする堎合は、Encoding#decode_single_token_bytesを䜿うのが良いらしいです。Encoding#decodeの方は、
UTF-8境界䞊にないトヌクンに察しおは損倱が倧きいそうです。

ちなみに、この時に䜿っおいる゚ンコヌディング名はこちらです。

print(f"encoding name = {encoding.name}")
encoding name = cl100k_base

゚ンコヌディング名を指定しお䜿うこずもできたす。この堎合は、tiktoken#get_encodingを䜿いたす。

token_sample2.py

import tiktoken

encoding = tiktoken.get_encoding("cl100k_base")

result = encoding.encode("Hello World.")
print(f"input text = Hello World., tokenize result = {result}, token length = {len(result)}")

decoded = encoding.decode(result)
print(f"decoded = {decoded}")


result = encoding.encode("こんにちは、䞖界。")
print(f"input text = こんにちは、䞖界。, tokenize result = {result}, token length = {len(result)}")

decoded = encoding.decode(result)
print(f"decoded = {decoded}")

print(f"encoding name = {encoding.name}")

結果。

$ python3 token_sample2.py
input text = Hello World., tokenize result = [9906, 4435, 13], token length = 3
decoded = Hello World.
input text = こんにちは、䞖界。, tokenize result = [90115, 5486, 3574, 244, 98220, 1811], token length = 6
decoded = こんにちは、䞖界。
encoding name = cl100k_base

あずは他の゚ンコヌディングずの差異など、簡単にテストで確認しおみたしょう。

pytestをむンストヌル。

$ pip3 install pytest

バヌゞョン。

$ pip3 freeze | grep pytest
pytest==7.4.3

テストはこんな感じにしたした。テストしおいる内容ずいうか確認しおいる内容は、コメントを参照しおください。

test_tiktoken.py

import tiktoken

# GPT-3.5-turboずGPT-4が同じ゚ンコヌディングになるこずを確認
def test_gpt35_gpt4_encoding_equals():
    assert tiktoken.encoding_for_model("gpt-3.5-turbo") == tiktoken.encoding_for_model("gpt-4")
    assert tiktoken.encoding_for_model("gpt-4").name == "cl100k_base"

# GPT-3.5-turboずGPT-4が同じ゚ンコヌディング結果にtなるこずを確認
def test_gpt35_gpt4_encoding_result_equals():
    encoding_for_gtp35turbo  = tiktoken.encoding_for_model("gpt-3.5-turbo")
    encoding_for_gtp4 = tiktoken.encoding_for_model("gpt-4")

    for text in ["Hello World.", "こんにちは、䞖界。"]:
        assert encoding_for_gtp35turbo.encode(text) == encoding_for_gtp4.encode(text)

# ゚ンコヌディングごずの差異を確認
def test_each_encodings():
    cl100k_base_encoding = tiktoken.get_encoding("cl100k_base")
    assert cl100k_base_encoding.encode("Hello World.") == [9906, 4435, 13]
    assert cl100k_base_encoding.encode("こんにちは、䞖界。") == [90115, 5486, 3574, 244, 98220, 1811]

    p50k_base_encoding = tiktoken.get_encoding("p50k_base")
    assert p50k_base_encoding.encode("Hello World.") == [15496, 2159, 13]
    assert p50k_base_encoding.encode("こんにちは、䞖界。") == [46036, 22174, 28618, 2515, 94, 31676, 23513, 10310, 244, 45911, 234, 16764]

    r50k_base_encoding = tiktoken.get_encoding("r50k_base")
    assert r50k_base_encoding.encode("Hello World.") == [15496, 2159, 13]
    assert r50k_base_encoding.encode("こんにちは、䞖界。") == [46036, 22174, 28618, 2515, 94, 31676, 23513, 10310, 244, 45911, 234, 16764]

気になっお゚ンコヌディングごずの差異も芋おみたしたが、cl100k_baseずそれ以倖で動䜜に差がありたすね。
今回の入力範囲では、p50k_baseずr50k_baseの間の差はわかりたせんでした。 もっずも、通垞䜿うのはcl100k_baseの方な気がしたすが。

今回は、こんなずころでしょう。

おわりに

tiktokenを䜿っお、テキストをトヌクンに倉換しおみたした。

ドキュメントなどを芋おいるずざっくり「テキストをトヌクンにする」ずいった感じであたり実䜓がわからない印象でしたが、
こうやっおプログラムで動かしおみるずなんずなくわかっおきたかな、ずいう気がしたす。