当前位置: 首页 > 知识库问答 >
问题:

算法 - 本地部署使用 miniCpmV2-6 、chatglm 这些本地 LLM 的时候,如何实现统计 token?

南门鸿振
2024-11-14

使用智谱的 glm 在线服务的时候,会返回使用的 token:

  • prompt_tokens
  • completion_tokens
  • total_tokens
Completion(model='glm-4v-plus', created=1731402350, choices=[CompletionChoice(index=0, finish_reason='stop', message=CompletionMessage(content='', role='assistant', tool_calls=None))], request_id='20241112170540c45eaf5a3144487f', id='20241112170540c45eaf5a3144487f', usage=CompletionUsage(prompt_tokens=0, completion_tokens=0, total_tokens=0))

但是如果我是自己本地部署 chatglm、minicpm、qwen 这些模型,怎么统计 token 呢?

示例代码

# test.py
# test.py
import torch
from PIL import Image
from modelscope import AutoModel, AutoTokenizer

model = AutoModel.from_pretrained('OpenBMB/MiniCPM-V-2_6', trust_remote_code=True,
    attn_implementation='sdpa', torch_dtype=torch.bfloat16) # sdpa or flash_attention_2, no eager
model = model.eval().cuda()
tokenizer = AutoTokenizer.from_pretrained('OpenBMB/MiniCPM-V-2_6', trust_remote_code=True)

image = Image.open('image.png').convert('RGB')
question = 'What is in the image?'
msgs = [{'role': 'user', 'content': [image, question]}]

res = model.chat(
    image=None,
    msgs=msgs,
    tokenizer=tokenizer
)
print(res)

## if you want to use streaming, please make sure sampling=True and stream=True
## the model.chat will return a generator
res = model.chat(
    image=None,
    msgs=msgs,
    tokenizer=tokenizer,
    sampling=True,
    stream=True
)

generated_text = ""
for new_text in res:
    generated_text += new_text
    print(new_text, flush=True, end='')

返回的 res 本身就是字符串了,而不是一个结构化对象

这个统计 token 的方式,每个 llm 都一样吗?

共有1个答案

杜烨伟
2024-11-14

回答

在本地部署使用 miniCPM-V2-6chatglm 等本地 LLM(大型语言模型)时,统计 token 的方式通常并不直接由模型库提供,因为不同的模型库和框架可能有不同的实现方式。以下是一种通用的方法来实现 token 统计:

  1. 使用 Tokenizer 统计
    你可以使用对应的 tokenizer 来统计输入和输出文本的 token 数量。通常,tokenizer 会有一个 encodetokenize 方法,可以将文本转换为 token 列表,然后你可以计算这个列表的长度来得到 token 数量。
  2. 修改模型调用代码
    在你的代码中,你可以在将输入传递给模型之前和从模型接收输出之后,分别使用 tokenizer 来统计 token 数量。
  3. 注意事项

    • 对于图像输入(如你的示例中的 image),tokenizer 通常无法直接处理,你需要先处理图像(如提取文本或使用某种表示方法),然后再统计 token。
    • 对于多模态模型(如同时处理文本和图像的模型),统计 token 可能需要更复杂的逻辑,因为输出可能包含多种类型的数据。
  4. 示例修改
    以下是对你的示例代码的一个简单修改,用于统计输入和输出文本的 token 数量(注意,这只是一个基本示例,可能需要根据你的具体模型和 tokenizer 进行调整):
import torch
from PIL import Image
from modelscope import AutoModel, AutoTokenizer

model = AutoModel.from_pretrained('OpenBMB/MiniCPM-V-2_6', trust_remote_code=True,
    attn_implementation='sdpa', torch_dtype=torch.bfloat16)
model = model.eval().cuda()
tokenizer = AutoTokenizer.from_pretrained('OpenBMB/MiniCPM-V-2_6', trust_remote_code=True)

image = Image.open('image.png').convert('RGB')
question = 'What is in the image?'
msgs = [{'role': 'user', 'content': [image, question]}]  # 注意:这里 image 可能需要特殊处理才能用于 tokenizer

# 假设我们暂时忽略图像,只统计文本的 token
input_text_tokens = tokenizer.tokenize(question)
prompt_tokens = len(input_text_tokens)

# 由于你的模型调用方式可能不直接返回 tokenized 文本,我们需要从生成的字符串中重新 tokenize
# 注意:这通常不是最佳实践,因为重新 tokenize 可能引入误差,但在这里用于演示
res_text = model.chat(image=None, msgs=msgs, tokenizer=tokenizer)[0]['content']  # 假设返回的是结构化对象,且 'content' 包含生成的文本
output_text_tokens = tokenizer.tokenize(res_text)
completion_tokens = len(output_text_tokens)
total_tokens = prompt_tokens + completion_tokens

print(f"Prompt tokens: {prompt_tokens}")
print(f"Completion tokens: {completion_tokens}")
print(f"Total tokens: {total_tokens}")

注意:上述代码中的 model.chat 调用和返回值的处理可能需要根据你实际使用的模型库进行调整。此外,对于图像输入的处理,你可能需要先将图像转换为文本(如使用 OCR 技术),然后再进行 token 统计。

每个 LLM 的统计 token 方式可能不完全相同,具体取决于其实现和 tokenizer 的设计。因此,在实际应用中,你可能需要参考特定模型库的文档或源代码来了解如何正确地统计 token。

 类似资料:
  • 所以有几个网站会为你计算你的链接本地ipv6地址,就像这里的这个。 尽管如此,它并没有给出任何有用的关于这个地址是如何计算的,也没有输入参数是什么。那么,如果一个人知道自己的ipv4地址、子网掩码和网关地址,计算链路本地ipv6地址的过程(或算法)是什么?我正在使用SCTP套接字做一个项目,该项目使用ISATAP网络隧道和LL ipv6地址用于构建ISATAP地址。

  • 问题内容: 我想设置全局变量,例如: 这该怎么做? 问题答案: 最简单的方法是使用来告诉您的应用程序是在开发模式下运行(使用AppEngine SDK)还是在现场(正在生产中)运行: IsDevAppServer报告App Engine应用程序是否在开发App Server中运行。 另外,您也可以使用其中包含此信息以及您的App版本的信息,并合并为一个字符串: ServerSoftware返回Ap

  • 问题内容: 我已经使用django构建了一个webapp。为了托管它,我试图使用openshift,但是很难使任何东西正常工作。似乎缺乏循序渐进的步骤。到目前为止,我的git工作正常,该应用程序可在本地开发环境上运行,并且我已经在openshift上成功创建了一个应用程序。 一旦创建了openshift上的URL,我就会得到“欢迎使用您的Openshift应用程序”的标准页面。 我已遵循此http

  • 问题内容: 我可以用 获取mac地址,但是如果我在离线计算机上使用此代码,它将无法正常工作。 那么,如何获得Mac地址? 问题答案: 在Java 6+中,你可以使用。 请记住,计算机不能有网卡,尤其是嵌入式或虚拟的网卡。它也可以有多个。你可以使用来获取所有网卡的列表。

  • 在这几周的 Serverless 应用开发里,我觉得最大的不便就是,缺少一个本地的调试环境。在这种时候,我们需要不断地部署我们的代码,不断地在我们的代码里写上几行 console.log,然后在一切正常之后,再把这些 console.log 删除。 可要是,突然间又出现了一个 bug,我仿佛看到了我们又要重来一遍。 就这样经历了几次之后,我便想尝试一些新的手段,比如 serverless-offl

  • 问题内容: 如何检测本地计算机所在的时区? 我尝试过,但是如果机器在德国,那不会给我例如时区“德国”。 有可能吗? 问题答案: 如果您的房东位于德国,则会返回您所在时区的ID(应该是柏林)。 在格式化程序中,您必须执行类似的操作才能在String中包含时区。

  • 我每次运行时都会出现以下错误:“heroku local web” .springframework.core.convert.ConversionFailed异常:无法从类型[java.lang.字符串]转换为类型[java.lang.整数]的值'$PORT';嵌套异常是java.lang.数字格式异常:对于输入字符串:"$PORT" 我的Procfile看起来像这样: web:java-Dse

  • 我正在尝试用gradle-wrapper()构建一个gradle项目。 当我使用进行构建时,它会输出文本 下载http://services.gradle.org/distributions/gradle-1.11-bin.zip 我已经单独下载了gradle-1.11-bin.zip,我不想在构建时再次下载它。 那么,我应该把gradle-1.11-bin.zip放在我的项目或系统的什么地方,这