token介绍

引言

https://platform.openai.com/tokenizer
OpeA的大型语言模型(即GPT)使用标记处理文本,标记是一组文本中常见的字符序列。模型学习理解这些标记之间的统计关系,并擅长生成标记序列中的下一个标记。您可以使用相关工具来了解语言模型如何对一段文本进行标记,以及该段文本中标记的总数

token是什么

在自然语言处理(NLP)中,token是指一组相关的字符序列,例如一个单词或一个标点符号。将文本分解为token是NLP的一项基本任务,因为它是许多其他任务的先决条件,例如词性标注、命名实体识别和机器翻译。在文本处理中,token可以是一个词语、数字、标点符号、单个字母或任何可以成为文本分析的单个元素。

在分解文本时,通常会根据空格、标点符号和其他特定的分割符号来确定token的边界。
例如,在以下句子中,标点符号和空格用于分解成为不同的token:
“我喜欢吃冰淇淋。”
这个句子中,每个汉字和标点符号都可以切分开成一个tokn。但是,一个字一个字去理解整句话的意思,可能反而会理解错误。
例如“冰淇淋”,就是一个完整的词,分开成“冰”“淇”“淋”三个字反而无法理解了。
类似的,NLP中,token还可以是比词更高级别的语言单位,例如短语或句子。例如,对于短语token,“红色的苹果”可以被视为一个token,而不是单独的“红色”和“苹果”token.。因为存在不同的切分方式,所以“红色的苹果”,就需要切分成“红”“红色”的”苹果””“果”“红色的苹果”等多个token:去理解。
在处理文本时,理解token的概念是非常重要的,因为它是许多文本分析任务的基础。NLP算法会使用token来构建文本的表示形式,理解自然语言,以便进行其他分析任务。
因此,对于NLP系统来说,选择正确的分词方法(tokenization)非常重要,它将直接影响到其他任务的准确性和效率。
我们结合Chatgpt进一步了解下token和tokenization。

ChatGPT中的token

一句话输入大模型之后后先拆分成token,ChatGPT的词表一共有100256个不同符号(BPE格式)。
常见单词对应的token索引id小。如果一个单词单独出现时被拆分成了两个token,但是前面加上空格后可以分配到一个token,说明该单词在段落中间出现的概率高。
token 其实还包括了一些空白字符,因此在边界容易出问题,这是在应用时需要注意的。
以前面「Once upon a time」的例子说明,”Once “(后面有空格)的 token id 是 [7454, 220],其中空格的 id 是 220,但如果是 "Once upon",token id 就是 [7454, 2402],其中 " upon"(前面有空格) 的 id 是 2402,而 “upon” 这个不加前面空格的单词 token 是 27287,前面提到过 id 值大意味着概率低,在大模型眼里,提示词结尾加不加空格是完全不同,加了就是用 [7454, 220] 预测 27287,不加就是用 [7454] 预测 2402,第一种是概率更低更难的,因此在写提示词的时候结尾不要加空格

https://www.youtube.com/watch?v=zduSFxRajkE

看完了 token,接下来介绍选词,前面提到大模型最终输出结果是每个 token 的概率,要选择哪个 token 作为下一个词呢?最简单的想法是选择概率最大的,但这样并不好,一方面是单次概率最大不代表全局最优,另一方面导致大模型同一个问题每次输出结果都一样,对于创意类的场景不合适。因此目前的做法是根据输出概率来做采样,概率高的 token 更容易输出。

在实际应用的时候,大模型通常会有个可调整的参数叫 Temperature,它可以控制大模型输出结果更稳定还是更多样,它是怎么实现的呢?这里用代码来解释一下,比如我们假设大模型输出了这个向量

1
output = torch.FloatTensor([0.1, 0.2, 0.3, 0.4, 0.5])

通过 softmax 函数我们可以将输出结果转成总和为 1 的小数,每个小数就是输出概率,这就是大模型最后算出的结果

1
2
torch.nn.functional.softmax(output, -1) 
# 输出为 [0.1621, 0.1792, 0.1980, 0.2188, 0.2419]

比如第五个值被选中的概率是 24.19%,这里每个数组的索引就是前面提到的 token id,第五个值代表 token id 为 5。

如果我们将输出结果除以 0.1,结果就变成如下:

1
2
3
temperature = 0.1
torch.nn.functional.softmax(output / temperature, -1)
# 输出为 [0.0117, 0.0317, 0.0861, 0.2341, 0.6364]

这时第五个值的概率变成 63.64% 了,被选中的概率大幅增加,输出结果更为稳定

而如果是除以 2,就变成:

1
2
3
temperature = 2
torch.nn.functional.softmax(output / temperature, -1)
# 输出为 [0.1805, 0.1898, 0.1995, 0.2097, 0.2205]

这时各个列的输出概率就被压平了,第五个值的的概率变成 22%,而之前第一个值的概率从 1% 变成了 18.05%,比之前更有可能被选中了,这就使得大模型输出结果更多样,也意味着跟容易瞎说。
因此将 temperature 值设小一点模型就能很稳定输出,另外 temperature 是被除数,所以不可以为 0,有些平台支持 0 是做了特殊处理,比如可以转成 top_k 为 1。

不过改成 0 也不能完全保证结果唯一,根据 OpenAI 员工 boris 的说法,GPU 浮点数计算的时候有不确定性,而且多个 GPU 推理时 a*b*c 可能被计算为 (a*b)*c 或 a*(b*c),这两个结果可能会微小不同,导致最终结果不唯一。

前面花了很多篇幅介绍 token 及选词策略,因为这是在大模型应用时控制输出的重要机制,在不改变大模型参数的情况下,我们可以:

  1. 提升推理速度,比如 Speculative Sampling,它的原理是用个小模型来生成一段,再让大模型来挑选是否可用,这个方式能提升 2-3 倍推理速度。
  2. 优化推理效果,比如使用 Beam search 来搜索更好的结果,它通过多次搜索来找到更优结果,但会牺牲性能,因此实际应用中比较少见。
  3. 控制输出格式,在应用中我们通常需要大模型输出 JSON 格式,而大模型有时候会幻觉导致输出错误,这时可以在解码时进行干预,比如发现新 token 会导致 JSON 语法错误就自动修正,比起全部输出后再修正效果更好。

token介绍
https://chunfei-he.github.io/2024/06/30/token介绍/
作者
Chunfei He
发布于
2024年6月30日
许可协议