这是用户在 2024-4-19 4:52 为 https://docs.mistral.ai/guides/tokenization/ 保存的双语快照页面,由 沉浸式翻译 提供双语支持。了解如何保存?
Skip to main content

Tokenization

Open In Colab


分词是LLM的一个基本步骤。它是指将文本分解成更小的子单词单元的过程,称为令牌。我们最近在Mistral AI开源了我们的分词器。本指南将介绍分词的基本原理、有关我们开源分词器的详细信息以及如何在Python中使用它们。

 什么是分词?​​


分词是文本处理和建模的第一步和最后一步。在模型中,文本需要被表示为数字,以便我们的模型能够理解。分词将文本分解成令牌,每个token都被分配了一个数值表示或索引,这些可以用来喂给模型。在一个典型的LLM工作流程中:


  • 我们首先使用分词器将输入文本编码为令牌。在分词器的词汇表中,每个唯一的token都被分配了一个特定的索引号。

  • 一旦文本被分词,这些标记就被传递到模型中,该模型通常包括嵌入层和变压器块。嵌入层将标记转换为密集向量,捕捉语义含义。请查看我们的嵌入指南以获取详细信息。然后,变压器块处理这些嵌入向量以理解上下文并生成结果。

  • 最后一步是解码,它将输出令牌重新映射回人类可读的文本。这是通过使用令牌化器的词汇表将令牌映射回它们对应的单词来完成的。
drawing


大多数人只对文本进行分词。我们的第一个版本包含了分词功能。我们的分词器超越了常规的文本<->标记,增加了工具解析和结构化对话的支持。我们还发布了用于我们API的验证和规范化代码。具体来说,我们使用控制令牌,这是一种特殊类型的标记,用于指示不同类型的元素。这些标记不被视为字符串,而是直接添加到代码中。请注意,我们仍在迭代分词器。事情可能会改变,这是当前的状态。


我们发布了三个版本的令牌化器,分别支持不同模型的集合。

  • v1: open-mistral-7b, open-mixtral-8x7b, mistral-embed
  • v2: mistral-small-latest, mistral-large-latest
  • v3: open-mixtral-8x22b

Below is an example of 3 turns of conversations using v3, showcasing how the control tokens are structured around the available tools, user message, tool calls and tool results. This guide will focus on our latest v3 tokenizer.

drawing

Building the vocabulary

There are several tokenization methods used in Natural Language Processing (NLP) to convert raw text into tokens such as word-level tokenization, character-level tokenization, and subword-level tokenization including the Byte-Pair Encoding (BPE). Our tokenizers use the Byte-Pair Encoding (BPE) with SentencePiece, which is an open-source tokenization library to build our tokenization vocabulary.

In BPE, the tokenization process starts by treating each byte in a text as a separate token. Then, it iteratively adds new tokens to the vocabulary for the most frequent pair of tokens currently appearing in the corpus. For example, if the most frequent pair of tokens is "th" + "e", then a new token "the" will be created and occurrences of "th"+"e" will be replaced with the new token "the". This process continues until no more replacements can be made. 

Our tokenization vocabulary 

Our tokenization vocabulary is released in the https://github.com/mistralai/mistral-common/tree/main/tests/data folder. Let’s take a look at the vocabulary of our v3 tokenizer. 

Vocabulary size 

Our vocabulary consists of 32k vocab + 768 control tokens. The 32k vocab includes 256 bytes and 31,744 characters and merged characters. 

Control tokens 


我们的词汇从10个控制令牌开始,这些令牌是我们用于编码过程中的特殊令牌,用于表示特定的指令或指示:

<unk>
<s>
</s>
[INST]
[/INST]
[TOOL_CALLS]
[AVAILABLE_TOOLS]
[/AVAILABLE_TOOLS]
[TOOL_RESULTS]
[/TOOL_RESULTS]


令牌化器不会编码控制令牌,这些令牌有助于防止一种称为提示注入的情况。例如,控制令牌“token[INST]”用于表示用户消息:


  • 如果没有控制令牌,分词器会将“[INST]”视为普通字符串,并对整个序列“[INST] 我爱巴黎 [/INST]”进行编码。这可能会使用户在其消息中包含“[INST]”和“[/INST]”标签,从而导致模型混淆,因为它可能将用户的某些消息解释为助手的消息。

  • 使用控制令牌时,令牌化器会将控制令牌与编码消息连接起来:[INST] + encode("我喜欢巴黎") + [/INST]。这确保只有用户的消息被编码,并且编码后的消息具有正确的[INST]和[/INST]标签。


您可能已经注意到我们有768个控制令牌插槽。剩余的761个控制令牌插槽实际上是空的,以便我们在未来添加更多的控制令牌,同时也确保我们的词汇量大小为32,768(2 ^ 15)。计算机喜欢2的幂!

 字节


在控制token插槽之后,我们有256个字节的语言词汇量。一个字节是数字信息的单位,由8位组成。每一位都可以表示两个值中的一个,即0或1。因此,一个字节可以表示256种不同的值。

<0x00>
<0x01>
...


任何字符,无论使用何种语言或符号,都可以用一个或多个字节序列来表示。当一个单词不在词汇表中时,它仍然可以用表示其单个字符的字节来表示。这对于处理未知单词和字符非常重要。

Characters and merged characters 


最后,我们有词汇中的字符和合并字符。这些令牌的顺序由训练模型的数据中这些令牌出现的频率决定,最频繁的令牌排在词汇的前面。例如,两个空格“ ”、四个空格“ ”、“_t”、“in”和“er”是我们训练中最常见的令牌。随着我们在词汇列表中向下移动,令牌的出现频率逐渐降低。在词汇文件的末尾,您可能会找到不太常见的字符,如中文和韩文字符。这些字符出现频率较低是因为它们在训练数据中出现的次数较少,而不是因为它们在一般情况下使用较少。

▁▁
▁▁▁▁
▁t
in
er
...




在Python中运行我们的分词器


首先,让我们通过 pip install mistral-common 安装我们的分词器。


一旦安装了分词器,在Python环境中,我们可以从 mistral_common 导入所需的模块。

from mistral_common.protocol.instruct.messages import (
AssistantMessage,
UserMessage,
ToolMessage
)
from mistral_common.tokens.tokenizers.mistral import MistralTokenizer
from mistral_common.protocol.instruct.tool_calls import Function, Tool, ToolCall, FunctionCall
from mistral_common.tokens.instruct.normalize import ChatCompletionRequest


我们使用 MistralTokenizer 加载我们的分词器,并指定要加载的分词器版本。

tokenizer_v3 = MistralTokenizer.v3()


让我们对一系列不同类型的消息进行对话分词处理。

tokenized = tokenizer_v3.encode_chat_completion(
ChatCompletionRequest(
tools=[
Tool(
function=Function(
name="get_current_weather",
description="Get the current weather",
parameters={
"type": "object",
"properties": {
"location": {
"type": "string",
"description": "The city and state, e.g. San Francisco, CA",
},
"format": {
"type": "string",
"enum": ["celsius", "fahrenheit"],
"description": "The temperature unit to use. Infer this from the users location.",
},
},
"required": ["location", "format"],
},
)
)
],
messages=[
UserMessage(content="What's the weather like today in Paris"),
AssistantMessage(
content=None,
tool_calls=[
ToolCall(
id="VvvODy9mT",
function=FunctionCall(
name="get_current_weather",
arguments='{"location": "Paris, France", "format": "celsius"}',
),
)
],
),
ToolMessage(
tool_call_id="VvvODy9mT", name="get_current_weather", content="22"
),
AssistantMessage(
content="The current temperature in Paris, France is 22 degrees Celsius.",
),
UserMessage(content="What's the weather like today in San Francisco"),
AssistantMessage(
content=None,
tool_calls=[
ToolCall(
id="fAnpW3TEV",
function=FunctionCall(
name="get_current_weather",
arguments='{"location": "San Francisco", "format": "celsius"}',
),
)
],
),
ToolMessage(
tool_call_id="fAnpW3TEV", name="get_current_weather", content="20"
),
],
model="test",
)
)

tokens, text = tokenized.tokens, tokenized.text


这是“text”的输出结果,这是一个供您检查的调试表示。

'<s>[INST] What\'s the weather like today in Paris[/INST][TOOL_CALLS] [{"name": "get_current_weather", "arguments": {"location": "Paris, France", "format": "celsius"}, "id": "VvvODy9mT"}]</s>[TOOL_RESULTS] {"call_id": "VvvODy9mT", "content": 22}[/TOOL_RESULTS] The current temperature in Paris, France is 22 degrees Celsius.</s>[AVAILABLE_TOOLS] [{"type": "function", "function": {"name": "get_current_weather", "description": "Get the current weather", "parameters": {"type": "object", "properties": {"location": {"type": "string", "description": "The city and state, e.g. San Francisco, CA"}, "format": {"type": "string", "enum": ["celsius", "fahrenheit"], "description": "The temperature unit to use. Infer this from the users location."}}, "required": ["location", "format"]}}}][/AVAILABLE_TOOLS][INST] What\'s the weather like today in San Francisco[/INST][TOOL_CALLS] [{"name": "get_current_weather", "arguments": {"location": "San Francisco", "format": "celsius"}, "id": "fAnpW3TEV"}]</s>[TOOL_RESULTS] {"call_id": "fAnpW3TEV", "content": 20}[/TOOL_RESULTS]'


计算令牌数量,运行 len(tokens) ,得到302个令牌。

 使用案例

 自然语言处理任务


正如我们之前提到的,分词是自然语言处理(NLP)任务中的关键第一步。一旦我们对文本进行了分词,我们可以使用这些标记来创建文本嵌入,即文本的密集向量表示。然后可以使用这些嵌入来进行各种NLP任务,如文本分类、情感分析和机器翻译。


Mistral 的嵌入式 API 通过将分词和嵌入步骤合并为一个步骤简化了这一过程。使用此 API,我们可以轻松地为给定文本创建文本嵌入,而无需分别对文本进行分词并从令牌创建嵌入。

If you're interested in learning more about how to use Mistral's embedding API, be sure to check out our embedding guide, which provides detailed instructions and examples. 

Tokens count 

Mistral AI's LLM API endpoints charge based on the number of tokens in the input text. 

To help you estimate your costs, our tokenization API makes it easy to count the number of tokens in your text. Simply run len(tokens) as shown in the example above to get the total number of tokens in the text, which you can then use to estimate your cost based on our pricing information.