大语言模型之十-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)混淆。
使用sentence piece编码中文的例子见Sentencepiece_python_module_example.ipynb

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

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

相关文章

[2023.09.21]:源码已上传,供大家了解Rust Yew的前后端开发

这个资源是Rust的源代码压缩包&#xff0c;供大家了解Rust Yew的前后端开发。 资源中的代码非常简洁易懂&#xff0c;虽然离商用场景还有一段距离&#xff0c;但是涵盖了前端的组件搭建、事件通信和反向代理&#xff0c;以及后端的Restful API的路由、功能实现和数据库访问。此…

Learn Prompt-Prompt 高级技巧:MetaGPT

MetaGPT是一项引起广泛关注的研究成果&#xff0c;它引入了一个将人工工作流程与多智能体协作无缝集成的框架。通过将标准化操作&#xff08;SOP&#xff09; 程序编码为提示&#xff0c;MetaGPT确保解决问题时采用结构化方法&#xff0c;从而减少出错的可能性。 &#x1f389…

【深度学习】ONNX模型快速部署【入门】

【深度学习】ONNX模型快速部署【入门】 提示:博主取舍了很多大佬的博文并亲测有效,分享笔记邀大家共同学习讨论 文章目录 【深度学习】ONNX模型快速部署【入门】前言搭建打包环境打包可执行文件总结 前言 之前的内容已经尽可能简单、详细的介绍CPU【Pytorch2ONNX】和GPU【Pyto…

蓝桥杯打卡Day12

文章目录 接龙数列冶炼金属 一、接龙数列OJ链接 本题思路:本题是一道经典的dp问题&#xff0c;设第i个数的首位数字是first&#xff0c; 末位数字是last。因为第i个数只可能加到一个以first结尾的接龙数列中使得这个接龙数列长度加1并且结尾数字变成last.所以状态转移方程为d…

设计模式_解释器模式

解释器模式 案例 角色 1 解释器基类 &#xff08;BaseInterpreter&#xff09; 2 具体解释器1 2 3... (Interperter 1 2 3 ) 3 内容 (Context) 4 用户 (user) 流程 (上下文) ---- 传…

Redis 面试题——缓存穿透、缓存击穿和缓存雪崩

目录 1.缓存穿透2.缓存击穿3.缓存雪崩4.总结 参考文章&#xff1a; 缓存实战&#xff08;1&#xff09;缓存雪崩、缓存击穿和缓存穿透入门简介及解决方案 1.缓存穿透 &#xff08;1&#xff09;问题描述&#xff1a;缓存穿透是指在高并发场景下&#xff0c;大量的请求访问一个…

23种设计模式汇总详解

设计原则 中文名称英文名称含义解释单一职责原则Single Responsibility Principle(SRP)任何一个软件模块都应该只对某一类行为者负责一个类只干一件事&#xff0c;实现类要单一开闭原则Open-Close Principle(OCP)软件实体&#xff08;类、模块、函数等&#xff09;应该是可以扩…

使用scss简化媒体查询

在进行媒体查询的编写的时候&#xff0c;我们可以利用scss与与编译器&#xff0c;通过include混入的方式对代码进行简化&#xff0c;从而大大提高了代码的可维护性&#xff0c;也减少了代码的编写量&#xff0c;废话不多说&#xff0c;直接上代码&#xff1a; // 断点列表 相当…

ChatGpt介绍和国产ChatGpt对比

1.ChatGPT是美国OpenAI研发的聊天机器人程序&#xff0c;2022年11月30日发布。ChatGPT是人工智能技术驱动的自然语言处理工具&#xff0c;它能够通过理解和学习人类的语言来进行对话。 2.ChatGPT是一种基于自然语言处理的聊天机器人程序。它使用深度学习技术&#xff0c;通过对…

JLBANK-IRS统计报表相关的两个存储过程

1、 债项评级统计报表 CREATE OR REPLACE PROCEDURE SP_DEBT_RATING_RESULT_QUERY( P_RATING_TIME VARCHAR2, P_ORGSEQ VARCHAR2, P_SMALL_CORP_LOAN_CD VARCHAR2, P_CUR OUT IRS_REF.T_CURSOR) AS V_ORGSEQ VARCHAR2(12) : …

【Linux】常用工具(下)

Linux常用工具 一、Linux 项目自动化构建工具 - make/Makefile1. 依赖关系和依赖方法2. 伪目标3. make/Makefile 具有依赖性的推导能力&#xff08;语法扩展&#xff09;4. 编写一个进度条代码&#xff08;1&#xff09;缓冲区&#xff08;2&#xff09;\n 和 \r&#xff08;3&…

《C和指针》笔记29:数组名和指针

看下面的代码 int b[10];b[4]的类型是整型&#xff0c;但b的类型又是什么&#xff1f;它所表示的又是什么&#xff1f;一个合乎逻辑的答案是它表示整个数组&#xff0c;但事实并非如此。在C中&#xff0c;在几乎所有使用数组名的表达式中&#xff0c;数组名的值是一个指针常量…

Flask+pyecharts+SQLAlchemy,统计图的数据存放在mysql中,综合版

ISEE小语 有人问:“世上最廉价的东西是什么?” 在网上看到这样一个回答说: “大概就是付出吧,一贫如洗的真心、一事无成的温柔、一厢情愿的等待。” 回顾上篇 此篇是在【Flask+pyecharts结合,html统计图呈现在前端页面】和【Flask+pyecharts结合,优化前端加导航栏显示】的…

Vue实现大文件分片上传、断点续传

前言 实现大文件分片上传的断点续传以及上传进度条是一个在前端开发中常见且具有挑战性的问题。本篇博客将介绍如何使用Vue框架来实现这个功能&#xff0c;并给出代码示例。 概述 大文件分片上传指的是将一个大文件切割成多个小文件&#xff08;或称为分片&#xff09;&…

软件测试-BUG

软件测试-BUG 1.如何合理创建一个BUG 创建bug的要素&#xff1a; 软件的版本发现问题的环境发现问题的步骤预期结果实际结果 Bug报告&#xff1a; 软件版本&#xff1a;Google Chrome浏览器&#xff08;具体版本号&#xff09; 发现问题环境&#xff1a;在Windows 10操作系统…

ASO优化之如何给应用选择竞争对手

在选择竞争对手过程中&#xff0c;最常见的错误之一是没有考虑到自己的应用与同一行业的其他应用相比的范围。例如如果我们刚刚发布了一个应用程序&#xff0c;那么最好的办法就是专注于研究和自己同一级别的应用。 1、研究主要关键词。 首先选择5到10个可以定义产品类型的主要…

什么是ELK

什么是ELK ELK 并不是一个技术框架的名称&#xff0c;它其实是一个三位一体的技术名词&#xff0c;ELK 的每个字母都来自一个技术组件&#xff0c;分别是 Elasticsearch&#xff08;简称 ES&#xff09;、Logstash 和 Kibana。 三个技术组件是独立的&#xff0c;后两个被elast…

如何给API签名

前言 有时候为了保护API&#xff0c;需要用到 API 签名&#xff0c;使用 API 签名的好处&#xff1a; 让API只能被特定的人访问防止别人抓包拿到请求参数&#xff0c;通过篡改参数发起新的请求 客户端过程 给API调用者分配一个app_id和app_secret&#xff0c;app_secret调用…

【基于Thread多线程+随机数(Random)+java版本JDBC手动提交事务+EasyExcel读取excel文件,向数据库生成百万级别模拟数据】

基于Thread多线程随机数&#xff08;Random&#xff09;java版本JDBC手动提交事务EasyExcel读取excel文件&#xff0c;向数据库生成百万级别模拟数据 基于Thread多线程随机数&#xff08;Random&#xff09;java版本JDBC手动提交事务EasyExcel读取excel文件&#xff0c;向数据库…

《动手学深度学习》(pytorch版+mxnet版)2023最新

我又来推书了&#xff0c;这次分享的这本书可是重量级&#xff0c;目前已经被55个国家300所大学用于教学&#xff0c;同时受到了学术界与工业界的强烈推荐。 这本书就是李沐、阿斯顿张、立顿、斯莫拉四位大佬联合编写的《动手学深度学习》。本书面向中文读者&#xff0c;能运行…