首页 > 其他分享 >tokenizer分词器中的BPE分词方法的原理、样例、代码示例

tokenizer分词器中的BPE分词方法的原理、样例、代码示例

时间:2024-03-19 09:30:34浏览次数:13  
标签:vocab 字符 BPE tokenizer 示例 词汇表 合并 喜欢

Byte Pair Encoding(BPE):

想象一下你正在玩一种叫做“文字乐高”的游戏。在这个游戏中,你有很多小块,每个小块上写着一个字母或汉字。你的任务是用这些小块来构建单词或句子。开始时,你只能用单个字母或汉字的小块。但是游戏规则允许你找出那些经常一起出现的字母或汉字对,然后把它们合并成一个新的、更大的小块。随着游戏的进行,你可以创建越来越多的这种复合小块,从而更快、更高效地构建单词或句子。

BPE(Byte Pair Encoding)分词方式就像这个游戏。它的核心思想是在文本中找到最常见的字符对(比如在英文中可能是“th”、“er”等,在中文中可能是常见的词组或双字词),然后将这些字符对合并成一个新的单位。通过反复执行这个过程,我们可以将常见的字符对或字符序列合并成更长的序列,这些序列有时可以是完整的词语,有时可能是词语的一部分。

这个方法的一个优点是,它可以自动适应文本中的语言模式,而不需要预先定义词汇表。这就意味着,即使遇到了文本中从未出现过的新词,BPE 也有可能通过已经学到的字符序列来理解和处理这个新词。例如,如果 BPE 学会了“喜欢”和“吃”这两个序列,那么即使它从未见过“喜欢吃”这个短语,它也能够将其分解为已知的部分并加以理解。

总的来说,BPE 分词就像是通过观察和学习文字之间的“友谊”——哪些字母或汉字喜欢经常待在一起——然后通过将这些常见的组合“粘合”起来,以更智能、更灵活的方式来理解和处理语言。这种方法特别适用于处理大规模文本数据,能够有效地减小模型的复杂度,同时保持对文本的良好理解。

BPE的特点

Byte Pair Encoding (BPE) 算法最初是作为一种数据压缩技术被提出的。然而,在自然语言处理(NLP)领域,BPE 被重新发现并用作一种有效的子词分词方法,特别是在处理语言模型和机器翻译等任务时。提出 BPE 用于 NLP 的原因主要有以下几点:

处理未知词汇: 传统的词汇表方法面临一个挑战,即如何处理训练数据中未出现的单词(即未知词汇或 OOV,Out-Of-Vocabulary)。BPE 方法通过将单词分解为更小的单位(子词)来解决这个问题。即使是未见过的单词,也有可能由已见过的子词组合而成,因此模型能够更好地处理和理解这些新单词。

减小词汇表大小: 在大型文本数据集中,完整的词汇表可能非常庞大,这对模型的存储和计算效率都是一个挑战。BPE 通过构建一个更小、更高效的子词集来缩减词汇表的大小,同时仍保持了对原始文本的良好覆盖。这样不仅减少了模型的参数量,还提高了训练和推理的效率。

改善语言模型的泛化能力: 由于 BPE 的子词单位能够跨越单词边界,它可以帮助模型更好地学习和理解语言的词根、前缀和后缀等形态变化,从而提高模型对词形变化和复合词的处理能力。这种对词形变化的敏感性有助于模型在各种语言任务中更好地泛化。

适应性强: BPE 算法非常灵活,可以根据需要调整子词的数量,这使得它可以根据不同的应用场景和资源限制来优化性能。这种适应性使得 BPE 成为了一种在各种语言和任务中都非常实用的分词方法。

语言无关性: BPE 不依赖于任何特定语言的语法或词汇规则,使其成为一种通用的分词方法。这意味着它可以被应用于不同的语言,而无需对每种语言做特殊的适配或修改。

BPE的具体样例

让我们通过一个简化的中文样例来详细展示BPE分词的步骤。我们将使用以下句子作为样例文本:

"猫喜欢吃鱼,狗喜欢吃肉,人喜欢吃鱼,人喜欢吃肉"

我们将按以下步骤展示BPE算法的工作过程:

  1. 初始化词汇表

  2. 计算所有相邻字符对的频率

  3. 选择频率最高的字符对进行合并

  4. 重复步骤2和3指定次数

由于是演示,我们将执行少量的合并操作,假设合并次数为4次。

首先,我们将文本初始化为词汇表,包括每个字符及其频率:

{
 '猫': 1, '喜': 4, '欢': 4, '吃': 4, 
 '鱼': 2, ',': 7, '狗': 1, '肉': 2, 
 '人': 2
}

接下来,我们将展示每一步的合并过程。

## 第一次合并:首先,我们计算所有相邻字符对的频率,并找到频率最高的字符对。在这个例子中,"喜欢" 是出现频率最高的字符对,出现了4次。我们将其合并为一个新的字符 "喜欢"。
# {('猫', '喜'): 1, ('喜', '欢'): 4, ('欢', '吃'): 4, ('吃', '鱼'): 2, ('鱼', ','): 2, (',', '狗'): 1, ('狗', '喜'): 1, ('吃', '肉'): 2, ('肉', ','): 1, (',', '人'): 2, ('人', '喜'): 2, ('肉', '</w>'): 1}

{'猫': 1, '喜欢': 4, '吃': 4, '鱼': 2, ',': 3, '狗': 1, '肉': 2, '人': 2}




## 第二次合并:接下来,我们再次查找频率最高的字符对。这次 "喜欢吃" 是出现频率最高的,我们将其合并。
# 合并后的词汇表变为:
# {('猫', '喜欢'): 1, ('喜欢', '吃'): 4, ('吃', '鱼'): 2, ('鱼', ','): 2, (',', '狗'): 1, ('狗', '喜欢'): 1, ('吃', '肉'): 2, ('肉', ','): 1, (',', '人'): 2, ('人', '喜欢'): 2, ('肉', '</w>'): 1}
{'猫': 1, '喜欢吃': 4, '鱼': 2, ',': 3, '狗': 1, '肉': 2, '人': 2}

## 第三次合并:再次重复上述过程,这次我们注意到 "喜欢吃鱼" 、 "鱼,"等好几个组合频率都是2。这里为了演示,我们选择 "喜欢吃鱼" 进行合并(实际上这两个字符对的频率相同,可以任选其一)。
# 合并后的词汇表为
# {('猫', '喜欢吃'): 1, ('喜欢吃', '鱼'): 2, ('鱼', ','): 2, (',', '狗'): 1, ('狗', '喜欢吃'): 1, ('喜欢吃', '肉'): 2, ('肉', ','): 1, (',', '人'): 2, ('人', '喜欢吃'): 2, ('肉', '</w>'): 1}


{'猫': 1, '喜欢吃鱼': 2, ',': 3, '狗': 1, '喜欢吃': 2, '肉': 2, '人': 2}



## 第四次合并:最后一次合并,同上面的步骤一样,我们选择了“喜欢吃鱼,”进行合并。
# 合并后的词汇表如下:
# {('猫', '喜欢吃鱼'): 1, ('喜欢吃鱼', ','): 2, (',', '狗'): 1, ('狗', '喜欢吃'): 1, ('喜欢吃', '肉'): 2, ('肉', ','): 1, (',', '人'): 2, ('人', '喜欢吃鱼'): 1, ('人', '喜欢吃'): 1, ('肉', '</w>'): 1}

{'猫': 1, '喜欢吃鱼,': 2, '狗': 1, '喜欢吃': 2, '肉': 2, '人': 2, ',': 1}

经过4次合并后,我们得到了一个包含了更长字符序列的新词汇表。通过这个过程,BPE算法能够逐步构建出更长的、更意义丰富的字符序列,这有助于提高分词的精度和效率。需要注意的是,这里的例子非常简化,实际应用中的BPE算法会在一个更大的数据集上执行更多的合并操作,以构建出一个更完整、更有效的分词词汇表。不同的合并方式得到的词表也可能不同。

BPE简单代码示例

import re, collections

def get_stats(vocab):
    pairs = collections.defaultdict(int)
    for word, freq in vocab.items():
        symbols = word.split()
        for i in range(len(symbols)-1):
            pairs[symbols[i],symbols[i+1]] += freq
    return pairs

def merge_vocab(pair, v_in):
    v_out = {}
    bigram = re.escape(' '.join(pair))
    p = re.compile(r'(?<!\S)' + bigram + r'(?!\S)')
    for word in v_in:
        w_out = p.sub(''.join(pair), word)
        v_out[w_out] = v_in[word]
    return v_out

def build_vocab(text):
    counter = collections.defaultdict(int)
    for line in text:
        words = line.split()
        for word in words:
            counter[word] += 1
    return {" ".join(key) + " </w>": value for key, value in counter.items()}

# 示例文本
test_corpus = "猫喜欢吃鱼,狗喜欢吃肉,人喜欢吃鱼,人喜欢吃肉"

vocab = build_vocab(test_corpus.split('\n'))
num_merges = 4
for i in range(num_merges):
    pairs = get_stats(vocab)
    print(pairs)
    if not pairs:
        break
    best = max(pairs, key=pairs.get)
    vocab = merge_vocab(best, vocab)

print(vocab)

标签:vocab,字符,BPE,tokenizer,示例,词汇表,合并,喜欢
From: https://blog.csdn.net/m0_48923489/article/details/136829740

相关文章

  • 通过FactoryMethod创建对象示例
    factory-bean:指定使用哪个工程实例,实例工厂,非静态方法创建beanfactory-method:指定使用哪个工厂实例的方法。静态工厂,静态方法创建bean判断的依据是创建bean的方法是否存在static修饰符。具体code如下:packagecom.gientech.factoryMethod;publicclassPerson{pr......
  • 一个用于强化学习的卷积神经网络基础结构示例
    classGomokuNet(nn.Module):def__init__(self,input_dim,action_space):super(GomokuNet,self).__init__()#定义网络层self.conv1=nn.Conv2d(1,32,kernel_size=3,padding=1)self.conv2=nn.Conv2d(32,64,kerne......
  • python @pytest.fixture示例及用法
    [email protected]示例及用法@pytest.fixture是pytest测试框架中的一个非常有用的功能,它允许你定义可以在多个测试用例之间共享的设置和清理代码。通过使用fixture,你可以减少重复的代码,并使得测试用例更加清晰和模块化。下面是一个简单的示例,展示了如何使用@pytest.fi......
  • go语言请求http接口示例 并解析json
    本例请求了天气api接口对接流程注册一个账号,对接免费实况天气接口阅读接口文档http://tianqiapi.com/index/doc?version=day请求接口解析json开发流程创建一个json.go文件需要引入的包import( "encoding/json" "fmt" "io/ioutil" "net/http")定义Wea......
  • 递归示例-展开编号(Excel函数集团)
    展开编号=DROP(fx(COUNTA(B:B)-1),1)fx=LAMBDA(x,IF(x>0,VSTACK(fx(x-1),SEQUENCE(INDEX(Sheet4!$B:$B,x+1),,INDEX(Sheet4!$C:$C,x+1)))))使用Lambda定义x当x小于等0时,返回False,以此作为开关;当x为1时,返回False连接SEQUENCE(INDEX(Sheet4!$B:$B,2),,INDEX(Sheet4!$C:......
  • 【Qt】使用Qt实现Web服务器(二):QtWebApp示例源码
    1、最简使用介绍Demo2演示了最简单的用法,输入url后返回“HelloWorld!”;下面详解示例代码,先看主函数1.1主函数#a)QtWebApp库中定义的名字空间stefanfringsusingnamespacestefanfrings;intmain(intargc,char*argv[]){......
  • Java常用修饰符及示例
    Java修饰符是用来改变类、方法、变量、接口等元素的行为和可见性的关键字。Java修饰符主要分为两大类:访问修饰符和非访问修饰符。访问修饰符(AccessModifiers):public:提供最大的访问权限,任何类(无论是同一包内的还是不同包的)都可以访问到public修饰的类、方法和变量。示例......
  • C++示例:学习C++标准库,std::unordered_map无序关联容器的使用
    01std::unordered_map介绍std::unordered_map是C++标准库中的一种无序关联容器模板类,它提供了一种将键映射到值的方法。它的底层基于哈希表实现,内容是无序的,可以在平均情况下在O(1)的时间复杂度内完成插入、查找和删除操作。值得注意的是,哈希表可能存在冲突,即不同的键值......
  • MongoTemplate的CRUD的操作示例:
    importorg.springframework.data.mongodb.core.MongoTemplate;importorg.springframework.data.mongodb.core.query.Criteria;importorg.springframework.data.mongodb.core.query.Query;importorg.springframework.data.mongodb.core.query.Update;importorg.spring......
  • C# 通信断线重连问题说明与示例
    引言:在开发网络应用程序时,通信断线是一个常见的问题。特别是在客户端与服务器或者两个客户端之间的通信,由于网络问题、服务器故障或者其他原因,通信可能会意外中断。作为C#开发者,我们需要确保应用程序能够优雅地处理这些情况,并且能够自动重连以恢复通信。本文将详细介绍在C#......