跳至主要內容

point1|如何使用 tiktoken 计数令牌

AI悦创原创ChatGPTChatGPT大约 11 分钟...约 3384 字

你好,我是悦创。

tiktokenopen in new window 是 OpenAI 的一个快速开源分词器。

给定一个文本字符串(例如,"tiktoken is great!")和一个编码(例如,"cl100k_base"),分词器可以将文本字符串分割成一个令牌列表(例如,["t", "ik", "token", " is", " great", "!"])。

将文本字符串分割成令牌是有用的,因为 GPT 模型以令牌的形式看到文本。知道一个文本字符串中有多少个令牌,可以告诉你:

(a)字符串是否对于一个文本模型来说太长,无法处理,以及(b)OpenAI API 调用的成本是多少(因为使用是按照令牌计价的)。

1. 编码

编码指定了如何将文本转换成令牌。不同的模型使用不同的编码。

tiktoken 支持 OpenAI 模型使用的三种编码:

编码名称OpenAI模型
cl100k_basegpt-4, gpt-3.5-turbo, text-embedding-ada-002
p50k_baseCodex 模型, text-davinci-002, text-davinci-003
r50k_base (或 gpt2)GPT-3 模型,如 davinci

你可以使用 tiktoken.encoding_for_model() 检索模型的编码,如下所示:

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

注意p50k_baser50k_base有很大的重叠,对于非代码应用,他们通常会给出相同的令牌。

2. 按语言划分的分词器库

对于 cl100k_basep50k_base 编码:

对于 r50k_basegpt2)编码,许多语言都有可用的分词器。

(OpenAI 对第三方库不做背书或保证。)

3. 字符串通常如何被分词

在英语中,令牌通常的长度范围从一个字符到一个单词(例如,"t"" great"),尽管在一些语言中,令牌可以比一个字符短或比一个单词长。空格通常与单词的开始部分一起分组(例如," is" 而不是 "is "" " + "is" )。你可以在OpenAI分词器open in new window快速检查一个字符串是如何被分词的。

4. 使用

4.1 Install tiktoken

安装 tiktoken 库:

pip install --upgrade tiktoken

4.2 导入库

import tiktoken

4.3 加载编码

使用 tiktoken.get_encoding() 来按名称加载编码。

此操作第一次运行时,需要互联网连接进行下载。以后的运行不需要互联网连接。

encoding = tiktoken.get_encoding("cl100k_base")

使用 tiktoken.encoding_for_model() 来自动加载给定模型名称的正确编码。

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

4.4 使用 encoding.encode() 将文本转化为标记

.encode() 方法将文本字符串转换为一系列的令牌整数。

encoding.encode("tiktoken is great!")

# ---output---
[83, 1609, 5963, 374, 2294, 0]

通过计算 .encode() 返回的列表的长度来统计令牌数量。

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

n = num_tokens_from_string("tiktoken is great!", "cl100k_base")
print(n)

4.5 使用 encoding.decode() 将令牌转化为文本

.decode() 将一个令牌整数列表转换为字符串。

code
encoding.decode([83, 1609, 5963, 374, 2294, 0])

注意

警告:尽管 .decode() 可以应用于单个令牌,但请注意,对于不在 utf-8 边界上的令牌,它可能会有损失。

对于单个令牌,.decode_single_token_bytes() 安全地将单个整数令牌转换为它所代表的字节。

code
[encoding.decode_single_token_bytes(token) for token in [83, 1609, 5963, 374, 2294, 0]]

(字符串前面的 b 表示这些字符串是字节字符串。)

5. 比较编码方式

不同的编码方式在如何拆分单词、组合空格以及处理非英文字符上有所不同。使用上述方法,我们可以在几个示例字符串上比较不同的编码方式。

code
def compare_encodings(example_string: str) -> None:
    """Prints a comparison of three string encodings."""
    # print the example string
    print(f'\nExample string: "{example_string}"')
    # for each encoding, print the # of tokens, the token integers, and the token bytes
    for encoding_name in ["gpt2", "p50k_base", "cl100k_base"]:
        encoding = tiktoken.get_encoding(encoding_name)
        token_integers = encoding.encode(example_string)
        num_tokens = len(token_integers)
        token_bytes = [encoding.decode_single_token_bytes(token) for token in token_integers]
        print()
        print(f"{encoding_name}: {num_tokens} tokens")
        print(f"token integers: {token_integers}")
        print(f"token bytes: {token_bytes}")

6. 计算 chat completions API 调用的 tokens 数量

gpt-3.5-turbogpt-4 这样的 ChatGPT 模型与早期的 completions 模型以相同的方式使用 tokens,但由于其基于消息的格式,使得计算一个对话将使用多少 tokens 变得更加困难。

以下是一个示例函数,用于计算传递给 gpt-3.5-turbogpt-4 的消息的 tokens 数量。

请注意,从消息中计算 tokens 的确切方式可能会随模型而变化。请将下面函数的计数视为估计,而不是永恒的保证。

特别是,使用可选函数输入的请求将在下面计算的估计之上消耗额外的 tokens。

code1
def num_tokens_from_messages(messages, model="gpt-3.5-turbo-0613"):
    """Return 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 in {
        "gpt-3.5-turbo-0613",
        "gpt-3.5-turbo-16k-0613",
        "gpt-4-0314",
        "gpt-4-32k-0314",
        "gpt-4-0613",
        "gpt-4-32k-0613",
        }:
        tokens_per_message = 3
        tokens_per_name = 1
    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 "gpt-3.5-turbo" in model:
        print("Warning: gpt-3.5-turbo may update over time. Returning num tokens assuming gpt-3.5-turbo-0613.")
        return num_tokens_from_messages(messages, model="gpt-3.5-turbo-0613")
    elif "gpt-4" in model:
        print("Warning: gpt-4 may update over time. Returning num tokens assuming gpt-4-0613.")
        return num_tokens_from_messages(messages, model="gpt-4-0613")
    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

欢迎关注我公众号:AI悦创,有更多更好玩的等你发现!

公众号:AI悦创【二维码】

AI悦创·编程一对一

AI悦创·推出辅导班啦,包括「Python 语言辅导班、C++ 辅导班、java 辅导班、算法/数据结构辅导班、少儿编程、pygame 游戏开发、Linux、Web」,全部都是一对一教学:一对一辅导 + 一对一答疑 + 布置作业 + 项目实践等。当然,还有线下线上摄影课程、Photoshop、Premiere 一对一教学、QQ、微信在线,随时响应!微信:Jiabcdefh

C++ 信息奥赛题解,长期更新!长期招收一对一中小学信息奥赛集训,莆田、厦门地区有机会线下上门,其他地区线上。微信:Jiabcdefh

方法一:QQopen in new window

方法二:微信:Jiabcdefh

上次编辑于:
贡献者: AndersonHJB
你认为这篇文章怎么样?
  • 0
  • 0
  • 0
  • 0
  • 0
  • 0
评论
  • 按正序
  • 按倒序
  • 按热度