OpenAI Python API - Cost Estimation With TikToken

最簡單的 token 計算,當然是之前介紹的 Tokenizer

把你想計算的文字,直接複製貼上,網頁就告訴你結果。

不過,實際應用上,當然還是呼叫程式計算。

OpenAi 官方教學

官方教學有一些額外資訊,感興趣的朋友請參考(Jupyter Notebook 格式):

How to count tokens with tiktoken?

tiktoken

為了避免看到帳單時嚇一跳,用程式預先計算,將花費控制在可接受的範圍。

BPE (Byte Pair Encoding)

tiktoken 使用 BPE 演算法

BPN 演算法,主要是把重覆出現的字串,用另新的字串代替,依此類推。例如:

  1. 原始字串

    aaabdaaabac

  2. 第一次壓縮 Z = aa
    aaabdaaabac 會成為

    ZabdZabac
    Z=aa

  3. 第二次壓縮 Y=ab
    ZabdZabac 會成為

    ZYdZYac
    Y=ab
    Z=aa

  4. 第三次壓縮 X=ZY
    ZYdZYac 會成為

    XdXac
    X=ZY
    Y=ab
    Z=aa

到無法再壓縮時,就算壓縮完成。

要解壓時,把上述程式倒過來即可。

我們看看 OpenAI 在 github 中,如何描述 BPE:

  1. 可逆且無損壓縮,因此可以將標記轉換回原始文件。

  2. 適用於任意文件,甚至是不在標記器訓練數據中的文件。

  3. 壓縮文件:令牌序列(token sequence)比原始文件短。實際上,每個令牌(token)平均對應大約 4 個 bytes。

  4. 它試圖讓模型看到常見的子詞(subwords)。

    例如,“ing"是英語中的常見子詞,因此 BPE 編碼通常會將"encoding"拆分為"encod"和"ing"等標記(而不是"enc"和"oding”)。

    因為模型隨後會在不同的上下文中一次又一次地看到"ing"標記,所以它有助於模型概括和更好地理解語法。

編碼方式

tiktoken 有三種編碼方式,不同 model 對應的 encoding 如下表:

Encoding name OpenAI models
cl100k_base gpt-4, gpt-3.5-turbo, text-embedding-ada-002
p50k_base Codex models, text-davinci-002, text-davinci-003
r50k_base (or gpt2) GPT-3 models like davinci

GPT-4 和 GPT-3.X 的比較,這篇這的蠻詳細:

實際應用

就是把 OpenAI 的 num_tokens_from_messages 直接拿來用即可。

以下計算 token 函式來自 OpenAI github - How to count tokens with tiktoken

更新日期:2023年5月6日

def num_tokens_from_messages(messages, model="gpt-3.5-turbo-0301"):
    """Returns the number of tokens used by a list of messages."""
    try:
        encoding = tiktoken.encoding_for_model(model)
    except KeyError:
        print("Warning: model not found. Using cl100k_base encoding.")
        encoding = tiktoken.get_encoding("cl100k_base")
    if model == "gpt-3.5-turbo":
        print("Warning: gpt-3.5-turbo may change over time. Returning num tokens assuming gpt-3.5-turbo-0301.")
        return num_tokens_from_messages(messages, model="gpt-3.5-turbo-0301")
    elif model == "gpt-4":
        print("Warning: gpt-4 may change over time. Returning num tokens assuming gpt-4-0314.")
        return num_tokens_from_messages(messages, model="gpt-4-0314")
    elif model == "gpt-3.5-turbo-0301":
        tokens_per_message = 4  # every message follows <|start|>{role/name}\n{content}<|end|>\n
        tokens_per_name = -1  # if there's a name, the role is omitted
    elif model == "gpt-4-0314":
        tokens_per_message = 3
        tokens_per_name = 1
    else:
        raise NotImplementedError(f"""num_tokens_from_messages() is not implemented for model {model}. See https://github.com/openai/openai-python/blob/main/chatml.md for information on how messages are converted to tokens.""")
    num_tokens = 0
    for message in messages:
        num_tokens += tokens_per_message
        for key, value in message.items():
            num_tokens += len(encoding.encode(value))
            if key == "name":
                num_tokens += tokens_per_name
    num_tokens += 3  # every reply is primed with <|start|>assistant<|message|>
    return num_tokens

不過我們實際使用時,不需要(也不應該)自己把上面這段 code 複製到自己的程式中,因為 OpenAI 可能會不定期版本更新。使用的方法如下:

import tiktoken

def num_tokens_from_string(string: str, encoding_name: str) -> int:
    """Returns the number of tokens in a text string."""
    encoding = tiktoken.get_encoding(encoding_name)
    num_tokens = len(encoding.encode(string))
    return num_tokens

num_tokens_from_string("tiktoken is great!", "cl100k_base")

以上示範程式來自 OpenAI 官網 - How can I tell how many tokens a string has before I embed it?

補充:你可以從 前面表格(tiktoken 的編碼方式) 中左側的「Encoding name」或右側的「OpenAI models」選擇編碼方式:

encoding = tiktoken.get_encoding(“cl100k_base”)

encoding = tiktoken.encoding_for_model(“gpt-4”)

延伸閱讀

  1. 找資料的過程中,看到一段說明,提及 tiktoken 的 _educational 能提供更視覺化的演算法理解。原文找不到了,這裡是 github 中的程式碼:
  1. 關於 Token Count,這裡有另一堂共學課程的參考: 1️⃣ Section 10. 文字嵌入(Text Embedding)
1個讚