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 |
|
通过 softmax 函数我们可以将输出结果转成总和为 1 的小数,每个小数就是输出概率,这就是大模型最后算出的结果
1 |
|
比如第五个值被选中的概率是 24.19%,这里每个数组的索引就是前面提到的 token id,第五个值代表 token id 为 5。
如果我们将输出结果除以 0.1,结果就变成如下:
1 |
|
这时第五个值的概率变成 63.64% 了,被选中的概率大幅增加,输出结果更为稳定
而如果是除以 2,就变成:
1 |
|
这时各个列的输出概率就被压平了,第五个值的的概率变成 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 及选词策略,因为这是在大模型应用时控制输出的重要机制,在不改变大模型参数的情况下,我们可以:
- 提升推理速度,比如 Speculative Sampling,它的原理是用个小模型来生成一段,再让大模型来挑选是否可用,这个方式能提升 2-3 倍推理速度。
- 优化推理效果,比如使用 Beam search 来搜索更好的结果,它通过多次搜索来找到更优结果,但会牺牲性能,因此实际应用中比较少见。
- 控制输出格式,在应用中我们通常需要大模型输出 JSON 格式,而大模型有时候会幻觉导致输出错误,这时可以在解码时进行干预,比如发现新 token 会导致 JSON 语法错误就自动修正,比起全部输出后再修正效果更好。