大语言模型之十-Byte Pair Encoding

Tokenizer

诸如GPT-3/4以及LlaMA/LlaMA2大语言模型都采用了token的作为模型的输入输出,其输入是文本,然后将文本转为token(正整数),然后从一串token(对应于文本)预测下一个token。
进入OpenAI官网提供的tokenizer可以看到GPT-3tokenizer采用的方法。这里以Hello World为例说明。
在这里插入图片描述
总共30个token,英文单词一般会用单独的token表示,大小写也会区分不同的token,如Hello和hello,另外有一些由空格前导的单词也会单独编码,这会使得编码整个句子效率更高(这将省去每个空格的编码),对于中文token化,会使用两到三个ID(正整数表示),比如上面的中英文的!。
在这里插入图片描述

BPE编码算法

Byte Pair Encoding则是大语言模型当前使用最多的Tokenizer方法。一个直观的tokenize的方法是:
将每个单词看成一个token,然后对其编号,这符合人类语言习惯,但这并不是一个高效的编码方式,这是因为一门语言通常有几万到几十万的单词量,而现在的大语言模型都是支持多国的,如果每个单词独立编码,这就需要语言模型在预测的时候从几万到几百万这样规模的词汇表中选择一个(预测这些词的概率情况),这样的计算量是非常大的。

BPE 是一种简单的数据压缩算法,它在 1994 年发表的文章“A New Algorithm for Data Compression”中被首次提出。其核心思想是:
BPE每一步都将最常见的一对相邻数据单位替换为该数据中没有出现过的一个新单位,反复迭代直到满足停止条件。其目的是用一个有限的词表在token数量降到最低的情况下解决所有单词的分词,这是可能的,英文单词词根、词源以及时态等语法,这就意味着很多词都有着相同的部分,
如aaabdaaabac这个序列,首先a频率是最高的,其次是aa,这是用Z替换aa,然后两个字符连在一起频率最高的是ab,因而用Y替换ab,得到ZYdZYac,可以依次类推,这样将第一行的原始序列压缩为了最后一样的序列。
在这里插入图片描述摘自Byte Pair Encoding — The Dark Horse of Modern NLP

NLP BPE

NLP中的Subword基于BPE算法,其过程主要如下:
1.准备语料库,确定subword此表总数;
2.在每个单词的末尾添加后缀,统计每个单词出现的词频,如nice的词频为5,则其可记为:“nice ”:5
3.计算语料库中两个字符组成的词频,用新标记替换语料库中两个字符频率最高的,将新标记n-gram添加到词汇表中。
4.递归进行步骤3中的高频词频合并,当词表数量大于subword的总数时,递归进行合并统计词频,知道设置的subword数达到为止。
这一过程的python代码如下:

import re
from collections import Counter, defaultdictdef build_vocab(corpus: str) -> dict:"""Step 1. Build vocab from text corpus"""# Separate each char in word by space and add mark end of tokentokens = [" ".join(word) + " </w>" for word in corpus.split()]# Count frequency of tokens in corpusvocab = Counter(tokens)  return vocabdef get_stats(vocab: dict) -> dict:"""Step 2. Get counts of pairs of consecutive symbols"""pairs = defaultdict(int)for word, frequency in vocab.items():symbols = word.split()# Counting up occurrences of pairsfor i in range(len(symbols) - 1):pairs[symbols[i], symbols[i + 1]] += frequencyreturn pairsdef merge_vocab(pair: tuple, v_in: dict) -> dict:"""Step 3. Merge all occurrences of the most frequent pair"""v_out = {}bigram = re.escape(' '.join(pair))p = re.compile(r'(?<!\S)' + bigram + r'(?!\S)')for word in v_in:# replace most frequent pair in all vocabularyw_out = p.sub(''.join(pair), word)v_out[w_out] = v_in[word]return v_outvocab = build_vocab(corpus)  # Step 1num_merges = 50  # Hyperparameter
for i in range(num_merges):pairs = get_stats(vocab)  # Step 2if not pairs:break# step 3best = max(pairs, key=pairs.get)vocab = merge_vocab(best, vocab)

BPE在字符和单词级别的混合表示之间实现了完美的平衡,使其能够管理大型语料库。这种行为还允许使用适当的子单词标记对词汇表中的任何稀有单词进行编码,而不引入任何“未知”标记。这尤其适用于德语等外语,因为德语中存在许多复合词,很难学习到丰富的词汇。有了这种标记化算法,每个单词现在都可以克服被遗忘的恐惧(athazagoraobia)。

WordPiece

Google的Bert模型在分词的时候使用的是WordPiece算法。与BPE算法类似,WordPiece算法也是每次从词表中选出两个子词合并成新的子词。与BPE的最大区别在于,如何选择两个子词进行合并:BPE选择频数最高的相邻子词合并,而WordPiece选择能够提升语言模型概率最大的相邻子词加入词表。

WordPiece选取子词的方法如下,假设句子 S = ( t 1 , t 2 , ⋯ , t n ) S=(t_1,t_2,\cdots, t_n) S=(t1,t2,,tn)由n个子词组成, t i t_i ti表示子词,且假设各个子词之间是独立存在的,则句子 S S S的语言模型似然值等价于所有子词概率的乘积:
log ⁡ P ( s ) = ∑ i = 1 N log ⁡ P ( t i ) \log P(s) = \sum_{i=1}^N \log P(t_i) logP(s)=i=1NlogP(ti)
设把相邻位置的x和y两个子词进行合并,合并后产生的子词记为z,此时句子 S S S似然值的变化可表示为:
log ⁡ P ( t z ) − ( l o g P ( t x ) + l o g P ( t y ) ) = log ⁡ ( P ( t z ) P ( t x ) P ( t y ) ) \log P(t_z) -(log P(t_x)+log P(t_y))= \log(\frac{ P(t_z) }{P(t_x)P(t_y)}) logP(tz)logP(tx)+logP(ty)=log(P(tx)P(ty)P(tz))
似然值的变化就是两个子词之间的互信息。简而言之,WordPiece每次选择合并的两个子词,他们具有最大的互信息值,也就是两子词在语言模型上具有较强的关联性,它们经常在语料中以相邻方式同时出现。

Unigram Language Model (ULM)

与WordPiece一样,Unigram Language Model(ULM)同样使用语言模型来挑选子词。不同之处在于,BPE和WordPiece算法的词表大小都是从小到大变化,属于增量法。而Unigram Language Model则是减量法,即先初始化一个大词表,根据评估准则不断丢弃词表,直到满足限定条件。ULM算法考虑了句子的不同分词可能,因而能够输出带概率的多个子词分段。
对于句子S, X = ( x 1 , x 2 , ⋯ , x m ) X=(x_1,x_2,\cdots, x_m) X=(x1,x2,,xm)为句子的一个分词结果,由m个子词组成。所以,当前分词下句子S的似然值可以表示为:
P ( X ) = ∏ i = 1 m P ( x i ) P(X)=\prod \limits_{i=1}^mP(x_i) P(X)=i=1mP(xi)
对于句子S,挑选似然值最大的作为分词结果,则可以表示为:
x ∗ = arg ⁡ max ⁡ x ∈ U ( x ) P ( X ) x^*=\arg \max_{x \in U(x)}P(X) x=argxU(x)maxP(X)

这里 U ( x ) U(x) U(x)包含了句子的所有分词结果。在实际应用中,词表大小有上万个,直接罗列所有可能的分词组合不具有操作性。针对这个问题,可通过维特比算法得到 x ∗ x^* x来解决。
每个字词的概率 P ( x i ) P(x_i) P(xi)用最大期望的方法计算,假设当前词表V,则M步最大化对象是如下似然函数:
L = ∑ s = 1 ∣ D ∣ log ⁡ ( P ( X ( s ) ) ) = ∑ s = 1 ∣ D ∣ log ⁡ ( ∑ x ∈ U ( X ( s ) ) P ( x ) ) L=\sum_{s=1}^{|D|}\log (P(X^{(s)}))=\sum_{s=1}^{|D|}\log(\sum_{x \in U(X^{(s)})}P(x)) L=s=1Dlog(P(X(s)))=s=1Dlog(xU(X(s))P(x))
其中,|D|是语料库中语料数量。上述公式的一个直观理解是,将语料库中所有句子的所有分词组合形成的概率相加。
初始时,词表V并不存在,因而,ULM算法采用不断迭代的方法来构造词表以及求解分词概率:
1.初始时,建立一个足够大的词表,一般,可用语料中的所有字符加上常见的字符串初始化词表,也可以通过BPE初始化;
2.针对当前词表,用EM算法求解买个subword在语料上的概率;
3.对于每个字词,计算当该字词从词表中移除时,总的loss降低了多少,记为该字词的loss。
4.将字词按照loss大小进行排序,丢弃一定比例loss最小的字词(比如20%),保留下来的字词生成新的词表。这里需要注意的是,单字符不能被丢弃,这是为了避免OOV情况,
5.重复步骤2到4,直到词表大小减少到设定范围。

Sentence Piece

SentencePiece实现了直接从句子训练得到subword的方法(e.g., byte-pair-encoding (BPE) [Sennrich et al.]) and unigram language model [Kudo.]),它是谷歌推出的子词开源工具包,其中集成了BPE、ULM子词算法。除此之外,SentencePiece还能支持字符和词级别的分词。更进一步,为了能够处理多语言问题,sentencePiece将句子视为Unicode编码序列,从而子词算法不用依赖于语言的表示。

Llama使用Sentence Piece Byte-Pair编码(BPE)词元分析器,该词元分析器专为Llama模型设计,不应与OpenAI模型使用的标记器(x)混淆。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/135116.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

MFC 如何启用/禁用菜单(返灰/不可点击状态)

1、为页面&#xff08;窗口&#xff09;添加一个菜单栏和子菜单 2、在XXDlg.h文件中定义一个菜单栏变量和bool变量 CMenu m_Menu; //菜单变量 bool m_EnableMenu;//菜单栏中某个子菜单禁用/启用&#xff08;变灰&#xff09;的控制变量3、在OnInitDialog函数中进行初始化&…

常见的数码管中的引脚分布情况

简单介绍 数码管&#xff0c;实际就是用了7段亮的线段表示常见的数字或字符。常见的像下面几种&#xff08;图片是网络中的截图&#xff09;。事件中使用到的知识还是单片机中最基础的矩阵扫描。记得其中重要的有“余晖效应”&#xff0c;好像是要把不用的亮段关闭&#xff0c…

SpringBoot整合Flowable

1. 配置 &#xff08;1&#xff09; 引入maven依赖 <dependency><groupId>org.flowable</groupId><artifactId>flowable-spring-boot-starter</artifactId><version>6.7.2</version></dependency><!-- MySQL连接 -->&l…

【深度学习】 Python 和 NumPy 系列教程(十七):Matplotlib详解:2、3d绘图类型(3)3D条形图(3D Bar Plot)

目录 一、前言 二、实验环境 三、Matplotlib详解 1、2d绘图类型 2、3d绘图类型 0. 设置中文字体 1. 线框图 2. 3D散点图 3. 3D条形图&#xff08;3D Bar Plot&#xff09; 一、前言 Python是一种高级编程语言&#xff0c;由Guido van Rossum于1991年创建。它以简洁、易读…

左神高级提升班2 约瑟夫环结构

目录 【案例1】 【题目描述】 【输入描述&#xff1a;】 【输出描述&#xff1a;】 【输入】 【输出】 【思路解析】 【代码实现】 【案例1】 【题目描述】 某公司招聘&#xff0c;有n个人入围&#xff0c;HR在黑板上依次写下m个正整数A1、A2、……、Am&#xff0c;然后…

【重新定义matlab强大系列十三】直方图 bin 计数和分 bin 散点图

&#x1f517; 运行环境&#xff1a;Matlab &#x1f6a9; 撰写作者&#xff1a;左手の明天 &#x1f947; 精选专栏&#xff1a;《python》 &#x1f525; 推荐专栏&#xff1a;《算法研究》 #### 防伪水印——左手の明天 #### &#x1f497; 大家好&#x1f917;&#x1f91…

七天学会C语言-第二天(数据结构)

1. If 语句&#xff1a; If 语句是一种条件语句&#xff0c;用于根据条件的真假执行不同的代码块。它的基本形式如下&#xff1a; if (条件) {// 条件为真时执行的代码 } else {// 条件为假时执行的代码 }写一个基础的If语句 #include<stdio.h> int main(){int x 10;…

xss渗透(跨站脚本攻击)

一、什么是XSS? XSS全称是Cross Site Scripting即跨站脚本&#xff0c;当目标网站目标用户浏览器渲染HTML文档的过程中&#xff0c;出现了不被预期的脚本指令并执行时&#xff0c;XSS就发生了。 这里我们主要注意四点&#xff1a; 1、目标网站目标用户&#xff1b; 2、浏览…

Idea汉化

下载IDEA官方插件包https://plugins.jetbrains.com/ 输入关键子"chinese"查询汉化包 本地安装

Unity 性能优化Shader分析处理函数:ShaderUtil.GetShaderGlobalKeywords用法

Unity 性能优化Shader分析处理函数&#xff1a;ShaderUtil.GetShaderGlobalKeywords用法 点击封面跳转下载页面 简介 Unity 性能优化Shader分析处理函数&#xff1a;ShaderUtil.GetShaderGlobalKeywords用法 在Unity开发中&#xff0c;性能优化是一个非常重要的方面。一个常见…

core文件的生成与使用

目录 core 设置例子 1例子 2core 名称及目录修改参考 在使用嵌入式系统时&#xff0c;出错后&#xff0c;不好使用 gdb 调试&#xff0c;这时&#xff0c;可让系统生成一个 core 文件&#xff0c;用于查看出错原因 core 设置 要生成 core 文件&#xff0c;需要先设置 core 文…

Vue3事件处理

文章目录 Vue3事件处理1. 概念2. 实例2.1 点击按钮次数12.2 v-on 可以接收一个定义的方法来调用2.3 内联 JavaScript 语句2.4 事件处理程序中调用多个方法 3. 事件修饰符4. 按键修饰符 Vue3事件处理 1. 概念 使用 v-on 指令来监听 DOM 事件&#xff0c;从而执行 JavaScript 代…

QT:使用普通按钮、网格布局管理器、标签、行编辑器、水平布局管理器、垂直布局管理器做一个小项目

widget.h #ifndef WIDGET_H #define WIDGET_H#include <QWidget> #include <QPushButton> //普通按钮 #include <QGridLayout> //网格布局管理器 #include <QLabel> //标签 #include <QLineEdit> //行编辑器 #include <QHBoxLayo…

Linux关于memory cgroup的几个要点

概述 本文讲述memory cgroup比较容易误解的一些逻辑&#xff0c;如果不太经常使用和解决问题的话&#xff0c;对于memory cgroup的认知会比较浅显&#xff1a;cgroup memory用来限制进程的内存使用&#xff0c;但是我们进一步想如下的问题&#xff1a; 进程的内存可以分很多类…

【数据结构】LinkedList与链表

文章目录 1. ArrayList的缺陷2. 链表2.1 链表的概念及结构2.2 链表的实现1.链表的功能2.初始化链表3.实现功能接口3.1头插添加元素3.2尾插法添加新元素3.3找到下标的前驱节点3.4指定位置插入元素3.5指定元素是否存在3.6找到指定元素的前驱节点3.7删除指定节点3.8删除所有元素为…

Flutter图标

https://fluttericon.cn/ Flutter 内置了丰富的图标。 Icon(Icons.ac_unit)

linux内核分析:线程和进程创建,内存管理

lec18-19:进程与线程创建 lec20-21虚拟内存管理 内核代码,全局变量这些只有一份,但是内核栈有多份,这可能就是linux线程模型1对1模式的由来。通过栈来做的 x86 CPU支持分段和分页(平坦内存模式)两种 分段,选择子那里就有特权标记了

高速DSP系统设计参考指南(一)高速DSP设计面临的挑战

&#xff08;一&#xff09;高速DSP设计面临的挑战 1. 概述2. 一般挑战3. DSP音频系统的挑战4. 视频系统的挑战5. DSP通信系统面临的挑战 资料参考来自TI官网和网络。 1. 概述 DSP芯片&#xff0c;也称数字信号处理器&#xff0c;是一种具有特殊结构的微处理器。DSP芯片的内部…

【开发】视频监控平台EasyCVR分组批量绑定/取消通道功能的后端代码设计逻辑介绍

视频监控平台/视频存储/视频分析平台EasyCVR基于云边端一体化管理&#xff0c;可支持视频实时监控、云端录像、云存储、磁盘阵列存储、回放与检索、智能告警、平台级联等功能。安防监控平台在线下场景中应用广泛&#xff0c;包括智慧工地、智慧工厂、智慧校园、智慧社区等等。 …

二进制 Deploy Kubernetes v1.23.17 超级详细部署

文章目录 1. 预备条件2. 基础配置2.1 配置root远程登录2.2 配置主机名2.3 安装 ansible2.4 配置互信2.5 配置hosts文件2.6 关闭防firewalld火墙2.7 关闭 selinux2.8 关闭交换分区swap2.9 修改内核参数2.10 安装iptables2.11 开启ipvs2.12 配置limits参数2.13 配置 yum2.14 配置…