【大模型实战篇】大模型分词算法BPE(Byte-Pair Encoding tokenization)及代码示例
词元化是针对自然语言处理任务的数据预处理中一个重要步骤,目的是将原始文本切分成模型可以识别和处理的词元序列。在大模型训练任务中,就是作为大模型的输入。传统的自然语言处理方法,如基于条件随机场的序列标注,主要采用基于词汇的分词方式,这与我们人类的语言认知更为契合。但是,这种分词方法在中文等语言中,可能会导致对同一输入产生不同的分词结果,从而生成包含大量低频词的庞大词表,并可能出现未登录词(OOV)的问题。因此,一些语言模型开始使用字符作为最小单位进行分词,例如,ELMo 使用了 CNN 词编码器。近年来,子词分词器在基于 Transformer 的语言模型中得到了广泛应用,常见的方法包括 BPE 分词、WordPiece 分词和 Unigram 分词,接下来我们将参考huggingface的材料【1】来分析这几类分词器,并展示每种模型使用的标记器类型的示例。本文首先对BPE进行分享。
1. 原理讲解
字节对编码(BPE, Byte-Pair Encoding tokenization)【2】最初是作为一种文本压缩算法开发的,随后被OpenAI用于预训练GPT模型时的分词。许多Transformer模型都使用了该算法,包括GPT、GPT-2、RoBERTa、BART和DeBERTa。BPE 算法从一组基本符号(如字母和边界字符)开始,迭代地寻找语料库中的两个相邻词元,并将它们替换为新的词元,这一过程被称为合并。合并的选择标准是计算两个连续词元的共现频率,也就是每次迭代中,最频繁出现的一对词元会被选择与合并。合并过程将一直持续达到预定义的词表大小【3】。
BPE训练开始于计算语料库中使用的唯一词汇集(在完成标准化和预分词步骤后),然后通过获取写这些词所用的所有符号来构建词汇表。举个非常简单的例子,假设我们的语料库使用了以下五个词:
"hug", "pug", "pun", "bun", "hugs"
基础词汇表将是["b", "g", "h", "n", "p", "s", "u"]。在实际情况下,该基础词汇表至少会包含所有ASCII字符,并可能包括一些Unicode字符。如果一个例子使用了在训练语料库中不存在的字符,该字符将被转换为未知标记。许多NLP模型在分析包含表情符号的内容时表现不佳的原因可能这个就是其中一种。
GPT-2和RoBERTa的分词器(相似性较高)有一种方法来处理这个问题:它们将词视为由字节组成,而不是Unicode字符。这样基础词汇表的大小就很小(256),但字符仍会被包含在内,而不会被转换为未知标记。这个技巧称为字节级BPE。 字节级别的 BPE(Byte-level BPE, B-BPE)是 BPE 算法的一种扩展,它将字节视为合并操作的基本符号,从而实现更精细的分割,并解决了未登录词的问题。代表性语言模型如 GPT-2、BART 和 LLaMA 都采用了这种分词方法。具体而言,如果将所有 Unicode 字符视为基本字符,基本词表的规模会非常庞大(例如,每个汉字都作为一个基本字符)。而使用字节作为基本字符,可以将词汇表的大小限制在 256,同时确保所有基本字符都包含在内。以 GPT-2 为例,其词表大小为 50,257,包含 256 个字节的基本词元、一个特殊的文末词元,以及通过 50,000 次合并学习到的词元。通过一些处理标点符号的附加规则,GPT-2 的分词器能够有效进行分词,而无需使用 “<UNK>” 符号。
在获得这个基础词汇表后,通过学习合并规则(将现有词汇表中的两个元素合并为一个新元素的规则)添加新标记,直到达到所需的词汇大小。因此,最开始这些合并将创建两个字符的标记,随着训练的进行,合并会生成更长的子词。在分词器训练的任何步骤中,BPE算法都会寻找最常见的现有标记对。最常见的那一对将被合并,然后重复下一步。
回到之前的例子,假设这些词的频率如下:
("hug", 10), ("pug", 5), ("pun", 12), ("bun", 4), ("hugs", 5)
这意味着“hug”在语料库中出现了10次,“pug”5次,“pun”12次,“bun”4次,“hugs”5次。我们通过将每个词拆分为字符(构成我们初始词汇表的字符)开始训练,这样我们就可以将每个词视为标记的列表:
("h" "u" "g", 10), ("p" "u" "g", 5), ("p" "u" "n", 12), ("b" "u" "n", 4), ("h" "u" "g" "s", 5)
然后查看标记对。标记对("h", "u")出现在“hug”和“hugs”中,因此在语料库中总共出现15次。但这不是最常见的标记对:最常见的对是("u", "g"),出现在“hug”、“pug”和“hugs”中,在词汇表中总共出现20次。因此,分词器学到的第一个合并规则是("u", "g") -> "ug",这意味着“ug”将被添加到词汇表中,并且在语料库中的所有词中都应合并该对。在这个阶段结束时,词汇表和语料库如下所示:
词汇表: ["b", "g", "h", "n", "p", "s", "u", "ug"]
语料库: ("h" "ug", 10), ("p" "ug", 5), ("p" "u" "n", 12), ("b" "u" "n", 4), ("h" "ug" "s", 5)
现在有一些结果是超过两个字符的标记对:例如,标记对("h", "ug")(在语料库中出现15次)。然而,此时最常见的对是("u", "n"),在语料库中出现16次,因此第二个学习的合并规则是("u", "n") -> "un"。将其添加到词汇表并合并所有现有的出现结果如下:
词汇表: ["b", "g", "h", "n", "p", "s", "u", "ug", "un"]
语料库: ("h" "ug", 10), ("p" "ug", 5), ("p" "un", 12), ("b" "un", 4), ("h" "ug" "s", 5)
现在最常见的对是("h", "ug"),所以我们学习合并规则("h", "ug") -> "hug",这给我们带来了第一个三字符的标记。合并后,语料库如下:
词汇表: ["b", "g", "h", "n", "p", "s", "u", "ug", "un", "hug"]
语料库: ("hug", 10), ("p" "ug", 5), ("p" "un", 12), ("b" "un", 4), ("hug" "s", 5)
然后继续这样处理直到达到所需的词汇大小。
分词紧密跟随训练过程,新输入的分词通过以下步骤完成:
- 标准化
- 预分词
- 将词拆分为单个字符
- 在这些拆分上按顺序应用学习到的合并规则
以刚才使用的例子为例,三条学习到的合并规则为:
("u", "g") -> "ug"
("u", "n") -> "un"
("h", "ug") -> "hug"
单词“bug”将被分词为["b", "ug"]。然而,“mug”将被分词为["[UNK]", "ug"],因为字母“m”不在基础词汇表中。同样,“thug”将被分词为["[UNK]", "hug"]:字母“t”不在基础词汇表中,应用合并规则后首先会合并“u”和“g”,然后合并“h”和“ug”。
2. BPE代码实现
2.1 创建jupyter实验环境
为了快速方便验证代码,因此我们在服务器上安装了jupyter,来进行编程演示。这里记录下安装和部署的方式。
首先服务器上下载安装jupyter:
pip install jupyter
设置登录密码
jupyter notebook password
启动jupyter
jupyter notebook --no-browser --ip=0.0.0.0 --allow-root
访问jupyter-lab
一般域名就是:https://你的服务器ip地址:8888/lab
2.2 代码实现
示例语料库如下
corpus = ["This is the Hugging Face Course.","This chapter is about tokenization.","This section shows several tokenizer algorithms.","Hopefully, you will be able to understand how they are trained and generate tokens.",
]
我们需要将该语料库预分词为单词。这里将使用gpt2分词器进行预分词,国内的话,为了方便,我们依然采用model scope的模型库来操作, 下载gpt2模型到本地并加载,下载大概要花个几分钟的样子:
import torch
from modelscope import snapshot_download, AutoModel, AutoTokenizer
import os
from transformers import AutoTokenizermodel_dir = snapshot_download('AI-ModelScope/gpt2', cache_dir='/root/autodl-tmp', revision='master')
mode_name_or_path = '/root/autodl-tmp/AI-ModelScope/gpt2'
tokenizer = AutoTokenizer.from_pretrained(mode_name_or_path, trust_remote_code=True)
然后,在预分词的同时,我们计算每个单词在语料库中的频率,并且计算基础词汇表,由语料库中使用的所有字符组成,将模型使用的特殊标记添加到词汇表的开头。对于GPT-2,唯一的特殊标记是"<|endoftext|>"。另外说明下:前面带有“Ġ”符号的词(例如“Ġis”、“Ġthe”)通常是在使用字节级别的BPE(Byte-level BPE)分词时生成的。这个符号的作用是标记一个单词是以空格开头的,即这个单词前面有一个空格。这种标记方式在处理文本时有助于保持词与词之间的分隔,使模型能够更好地理解上下文。
from collections import defaultdictword_freqs = defaultdict(int)for text in corpus:words_with_offsets = tokenizer.backend_tokenizer.pre_tokenizer.pre_tokenize_str(text)new_words = [word for word, offset in words_with_offsets]for word in new_words:word_freqs[word] += 1print(word_freqs)
alphabet = []for word in word_freqs.keys():for letter in word:if letter not in alphabet:alphabet.append(letter)
alphabet.sort()print(alphabet)
将每个单词拆分为单个字符,以便开始训练。计算每个标记对的频率。找到出现次数最多的词对。
splits = {word: [c for c in word] for word in word_freqs.keys()}
def compute_pair_freqs(splits):pair_freqs = defaultdict(int)for word, freq in word_freqs.items():split = splits[word]if len(split) == 1:continuefor i in range(len(split) - 1):pair = (split[i], split[i + 1])pair_freqs[pair] += freqreturn pair_freqspair_freqs = compute_pair_freqs(splits)for i, key in enumerate(pair_freqs.keys()):print(f"{key}: {pair_freqs[key]}")if i >= 5:break
best_pair = ""
max_freq = Nonefor pair, freq in pair_freqs.items():if max_freq is None or max_freq < freq:best_pair = pairmax_freq = freqprint(best_pair, max_freq)
第一个合并学习的是 ('Ġ', 't')
-> 'Ġt'
,我们将 'Ġt'
添加到词汇表中。接下来,在分割字典中应用这个合并。
merges = {("Ġ", "t"): "Ġt"}
vocab.append("Ġt")
def merge_pair(a, b, splits):for word in word_freqs:split = splits[word]if len(split) == 1:continuei = 0while i < len(split) - 1:if split[i] == a and split[i + 1] == b:split = split[:i] + [a + b] + split[i + 2 :]else:i += 1splits[word] = splitreturn splits
splits = merge_pair("Ġ", "t", splits)
print(splits["Ġtrained"])
循环,直到学习到我们想要的所有合并。设置目标词汇表大小为 50。
vocab_size = 50while len(vocab) < vocab_size:pair_freqs = compute_pair_freqs(splits)best_pair = ""max_freq = Nonefor pair, freq in pair_freqs.items():if max_freq is None or max_freq < freq:best_pair = pairmax_freq = freqsplits = merge_pair(*best_pair, splits)merges[best_pair] = best_pair[0] + best_pair[1]vocab.append(best_pair[0] + best_pair[1])print(merges)
接下来为了对新文本进行分词,先进行预分词,再拆分,然后应用所有学习到的合并规则:
def tokenize(text):pre_tokenize_result = tokenizer._tokenizer.pre_tokenizer.pre_tokenize_str(text)pre_tokenized_text = [word for word, offset in pre_tokenize_result]splits = [[l for l in word] for word in pre_tokenized_text]for pair, merge in merges.items():for idx, split in enumerate(splits):i = 0while i < len(split) - 1:if split[i] == pair[0] and split[i + 1] == pair[1]:split = split[:i] + [merge] + split[i + 2 :]else:i += 1splits[idx] = splitreturn sum(splits, [])
3. 参考材料
【1】Summary of the tokenizers
【2】Byte-Pair Encoding tokenization
【3】RUC AI BOX 大预言模型
相关文章:

【大模型实战篇】大模型分词算法BPE(Byte-Pair Encoding tokenization)及代码示例
词元化是针对自然语言处理任务的数据预处理中一个重要步骤,目的是将原始文本切分成模型可以识别和处理的词元序列。在大模型训练任务中,就是作为大模型的输入。传统的自然语言处理方法,如基于条件随机场的序列标注,主要采用基于词…...

低功耗4G模组LCD应用示例超全教程!不会的小伙伴看这篇就够了!
希望大家通过本文的介绍,学会LCD显示屏与Air780E开发板结合使用的方法。利用LCD显示屏,你可以为你的项目增加丰富的显示内容,提升用户体验。记住,实践出真知,赶快动手尝试吧!相信这篇教程对你有所帮助~ 本文…...

Java while语句练习 C语言的函数递归
1. /* public static void main(String[] args) {int[] arr {25, 24, 12, 98, 36, 45};int max arr[0];//不能写0for (int i 1; i < arr.length; i) {if (arr[i] > max) {max arr[i];}}System.out.println(max);}*//*public static void main(String[] args) {doubl…...

illustrator免费插件 截图识别文字插件 textOCR
随手可得的截图识别文字插件 textOCR,识别出来的文字可直接输入到illustrator的当前文档中: 执行条件 1、需截图软件支持,推荐笔记截图工具 2、截好图片直接拖入面板即可完成识别 ****后期可完成实现在illustrator选择图片对象完成文字识别。…...

提升数据管理效率:ETLCloud与达梦数据库的完美集成
达梦数据库的核心优势在于其强大的数据处理能力和高可用性设计。它采用先进的并行处理技术,支持大规模的数据操作,同时具备出色的事务处理能力和数据安全保障。此外,达梦数据库还提供了丰富的功能模块,如数据备份、恢复、监控等&a…...

头歌——人工智能(搜索策略)
文章目录 第1关:搜索策略第2关:盲目搜索第3关:启发式搜索 - 扫地机器人最短路径搜索第4关:搜索算法应用 - 四皇后问题 第1关:搜索策略 什么是搜索技术 人类的思维过程可以看作是一个搜索过程。从小学到现在࿰…...

gorm.io/sharding改造:赋能单表,灵活支持多分表策略(下)
背景 分表组件改造的背景,我在这篇文章《gorm.io/sharding改造:赋能单表,灵活支持多分表策略(上)》中已经做了详细的介绍——这个组件不支持单表多个分表策略,为了突破这个限制做的改造。 在上一篇文章中&…...

域渗透AD渗透攻击利用 MS14-068漏洞利用过程 以及域渗透中票据是什么 如何利用
目录 wmi协议远程执行 ptt票据传递使用 命令传递方式 明文口令传递 hash口令传递 票据分类 kerberos认证的简述流程 PTT攻击的过程 MS14-068 漏洞 执行过程 wmi协议远程执行 wmi服务是比smb服务高级一些的,在日志中是找不到痕迹的,但是这个主…...

C++进阶-->继承(inheritance)
1. 继承的概念及定义 1.1 继承的概念 继承(inheritance)机制是面向对象程序设计使代码可以复用的最重要手段,他允许我们在保证原有类的特性基础上还进行扩展,通过继承产生的类叫做派生类(子类),被继承的类叫做基类&a…...

可视化项目 gis 资源复用思路(cesium)
文章目录 可视化项目 gis 资源复用思路底图、模型替换思路具体操作 可视化项目 gis 资源复用思路 背景: A项目的底图、模型 是现在在做的 B项目所需要的,现在要把 B项目的底图之类的替换成 A系统的 底图、模型替换思路 观察可访问系统的 gis 相关网络请…...

SQL实战测试
SQL实战测试 (请写下 SQL 查询语句,不需要展示结果) 表 a DateSalesCustomerRevenue2019/1/1张三A102019/1/5张三A18 1. **用一条 ** SQL 语句写出每个月,每个销售有多少个客户收入多少 输出结果表头为“月”,“销…...
Java 基础教学:基础语法-变量与常量
变量 变量是程序设计中的基本概念,它用于存储信息,这些信息可以在程序执行过程中被读取和修改。 变量的声明 在Java中,声明变量需要指定变量的数据类型以及变量的名称。数据类型定义了变量可以存储的数据种类(例如整数、浮点数…...

vue3使用element-plus手动更改url后is-active和菜单的focus颜色不同步问题
在实习,给了个需求做个新的ui界面,遇到了一个非常烦人的问题 如下,手动修改url时,is-active和focus颜色不同步 虽然可以直接让el-menu-item:focus为白色能解决这个问题,但是我就是想要有颜色哈哈哈,有些执…...
每天五分钟深度学习框架pytorch:从底层实现一元线性回归模型
本文重点 本节课程我们继续搭建一元线性回归模型,不同的是这里我们不使用pytorch框架已经封装好的一些东西,我们做这个目的是为了更加清楚的看到pytorch搭建模型的本质,为了更好的理解,当然实际中我们还是使用pytorch封装好的一些东西,不要重复造轮子。 模型搭建 #定义…...
编辑器加载与AB包加载组合
解释: 这个 ABResMgr 类是一个资源加载管理器,它用于整合 AB包(Asset Bundle)资源加载和 编辑器模式资源加载。通过这个管理器,可以根据开发环境选择资源加载方式,既支持 运行时使用Asset Bundle加载&…...
【c++】vector中的back()函数
nums.back() 是 C 中 std::vector 类的一个成员函数,用于获取数组(向量)中的最后一个元素。以下是一些关于 nums.back() 的详细解释和示例使用: 1. 功能 nums.back() 返回数组 nums 中的最后一个元素。如果数组为空,…...

[分享] SQL在线编辑工具(好用)
在线SQL编写工具(无广告) - 在线SQL编写工具 - Web SQL - SQL在线编辑格式化 - WGCLOUD...
element-ui隐藏表单必填星号
// 必填星号在前显示 去掉 .el-form-item.is-required:not(.is-no-asterisk) > .el-form-item__label:before { content: !important; margin-right: 0px!important; } // 必填星号在结尾显示 .el-form-item.is-required:not(.is-no-asterisk) > .el-form-item__labe…...

自动驾驶系列—激光雷达点云数据在自动驾驶场景中的深度应用
🌟🌟 欢迎来到我的技术小筑,一个专为技术探索者打造的交流空间。在这里,我们不仅分享代码的智慧,还探讨技术的深度与广度。无论您是资深开发者还是技术新手,这里都有一片属于您的天空。让我们在知识的海洋中…...
C#删除dataGridView 选中行
关键在于:从最后一行开始删除。 从前往后删只能删除其中一半,我理解是再remove行的时候dataGridView内部行序列发生了变化,包含在选中行中的特定行会被忽略,从后往前删就可避免这个问题,最后一行的行号影响不到前面的…...
RestClient
什么是RestClient RestClient 是 Elasticsearch 官方提供的 Java 低级 REST 客户端,它允许HTTP与Elasticsearch 集群通信,而无需处理 JSON 序列化/反序列化等底层细节。它是 Elasticsearch Java API 客户端的基础。 RestClient 主要特点 轻量级ÿ…...

Linux 文件类型,目录与路径,文件与目录管理
文件类型 后面的字符表示文件类型标志 普通文件:-(纯文本文件,二进制文件,数据格式文件) 如文本文件、图片、程序文件等。 目录文件:d(directory) 用来存放其他文件或子目录。 设备…...
SciencePlots——绘制论文中的图片
文章目录 安装一、风格二、1 资源 安装 # 安装最新版 pip install githttps://github.com/garrettj403/SciencePlots.git# 安装稳定版 pip install SciencePlots一、风格 简单好用的深度学习论文绘图专用工具包–Science Plot 二、 1 资源 论文绘图神器来了:一行…...

PPT|230页| 制造集团企业供应链端到端的数字化解决方案:从需求到结算的全链路业务闭环构建
制造业采购供应链管理是企业运营的核心环节,供应链协同管理在供应链上下游企业之间建立紧密的合作关系,通过信息共享、资源整合、业务协同等方式,实现供应链的全面管理和优化,提高供应链的效率和透明度,降低供应链的成…...
java 实现excel文件转pdf | 无水印 | 无限制
文章目录 目录 文章目录 前言 1.项目远程仓库配置 2.pom文件引入相关依赖 3.代码破解 二、Excel转PDF 1.代码实现 2.Aspose.License.xml 授权文件 总结 前言 java处理excel转pdf一直没找到什么好用的免费jar包工具,自己手写的难度,恐怕高级程序员花费一年的事件,也…...

MMaDA: Multimodal Large Diffusion Language Models
CODE : https://github.com/Gen-Verse/MMaDA Abstract 我们介绍了一种新型的多模态扩散基础模型MMaDA,它被设计用于在文本推理、多模态理解和文本到图像生成等不同领域实现卓越的性能。该方法的特点是三个关键创新:(i) MMaDA采用统一的扩散架构…...

算法岗面试经验分享-大模型篇
文章目录 A 基础语言模型A.1 TransformerA.2 Bert B 大语言模型结构B.1 GPTB.2 LLamaB.3 ChatGLMB.4 Qwen C 大语言模型微调C.1 Fine-tuningC.2 Adapter-tuningC.3 Prefix-tuningC.4 P-tuningC.5 LoRA A 基础语言模型 A.1 Transformer (1)资源 论文&a…...

嵌入式学习笔记DAY33(网络编程——TCP)
一、网络架构 C/S (client/server 客户端/服务器):由客户端和服务器端两个部分组成。客户端通常是用户使用的应用程序,负责提供用户界面和交互逻辑 ,接收用户输入,向服务器发送请求,并展示服务…...

AI+无人机如何守护濒危物种?YOLOv8实现95%精准识别
【导读】 野生动物监测在理解和保护生态系统中发挥着至关重要的作用。然而,传统的野生动物观察方法往往耗时耗力、成本高昂且范围有限。无人机的出现为野生动物监测提供了有前景的替代方案,能够实现大范围覆盖并远程采集数据。尽管具备这些优势…...
CSS | transition 和 transform的用处和区别
省流总结: transform用于变换/变形,transition是动画控制器 transform 用来对元素进行变形,常见的操作如下,它是立即生效的样式变形属性。 旋转 rotate(角度deg)、平移 translateX(像素px)、缩放 scale(倍数)、倾斜 skewX(角度…...