【大模型实战篇】大模型分词算法WordPiece分词及代码示例

news2024/11/26 18:33:25

        继《大模型数据词元化处理BPE(Byte-Pair Encoding tokenization)》之后,我们针对大模型原始数据的分词处理,继续分享WordPiece分词技术【1】。

1. 原理分析

        WordPiece 是 Google 开发的分词算法,用于预训练 BERT。此后,它被多个基于 BERT 的 Transformer 模型重用,如 DistilBERT、MobileBERT、Funnel Transformers 和 MPNET。与 BPE 的训练过程非常相似,但实际的分词方式有所不同。与 BPE 类似,WordPiece 从一个包含模型使用的特殊标记和初始字母表的小词汇表开始。由于它通过添加前缀(如 BERT 中的 ##)来识别子词,因此每个单词最初通过在单词内的所有字符前添加该前缀来分割。例如,“word” 被分割为:

w ##o ##r ##d

        因此,初始字母表包含单词开头的所有字符以及以 WordPiece 前缀开头的单词内字符。然后,像 BPE 一样,WordPiece 学习合并规则。主要区别在于选择合并对的方式。WordPiece 不是选择最频繁的对,而是对每一对计算一个分数,使用以下公式:

\text{score} = \frac{\text{freq\_of\_pair}}{\text{freq\_of\_first\_element} \times \text{freq\_of\_second\_element}}

        通过将对的频率除以其组成部分的频率的乘积,算法优先合并在词汇表中频率较低的组成部分。例如,它不会合并("un", "##able"),即使该对在词汇表中非常频繁,因为“un”和“##able”这两个部分可能会在许多其他单词中出现并具有高频率。相比之下,像("hu", "##gging")这样的对可能会更快被合并(假设单词“hugging”在词汇表中频繁出现),因为“hu”和“##gging”各自的频率较低。

        来看一个与 BPE 训练示例相同的词汇表:

("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)

        所以初始词汇表将是 ["b", "h", "p", "##g", "##n", "##s", "##u"]。最频繁的对是("##u", "##g")(出现 20 次),但“##u”的单独频率非常高,因此其分数不是最高(为 1 / 36)。所有带有“##u”的对实际上都有相同的分数(1 / 36),因此最佳分数属于对("##g", "##s")——唯一没有“##u”的对——为 1 / 20,第一次学习的合并是("##g", "##s")->("##gs")。

        当合并时,会移除两个标记之间的 ##,因此将“##gs”添加到词汇表,并在语料库中的单词上应用合并:

词汇表: ["b", "h", "p", "##g", "##n", "##s", "##u", "##gs"]
语料库: ("h", "##u", "##g", 10), ("p", "##u", "##g", 5), ("p", "##u", "##n", 12), ("b", "##u", "##n", 4), ("h", "##u", "##gs", 5)

        此时,“##u”出现在所有可能的对中,因此它们都最终得到了相同的分数。假设在这种情况下,第一个对被合并,所以("h", "##u")->“hu”。因此可以得到:

词汇表: ["b", "h", "p", "##g", "##n", "##s", "##u", "##gs", "hu"]
语料库: ("hu", "##g", 10), ("p", "##u", "##g", 5), ("p", "##u", "##n", 12), ("b", "##u", "##n", 4), ("hu", "##gs", 5)

        接下来,最好的分数由("hu", "##g")和("hu", "##gs")共享(分别为 1/15,与其他所有对的 1/21 相比),因此具有最大分数的第一个对被合并:

词汇表: ["b", "h", "p", "##g", "##n", "##s", "##u", "##gs", "hu", "hug"]
语料库: ("hug", 10), ("p", "##u", "##g", 5), ("p", "##u", "##n", 12), ("b", "##u", "##n", 4), ("hu", "##gs", 5)

        从上述例子可以看到,WordPiece 和 BPE 的分词方式不同,WordPiece 只保存最终的词汇表,而不保存学习到的合并规则(也就是我们在BPE中提到的merges对象)。从要分词的单词开始,WordPiece 查找词汇表中最长的子词,然后在其上进行分割。例如,如果使用上述示例中学习到的词汇表,对于单词“hugs”,从开头开始最长的子词是“hug”,所以我们在这里进行分割,得到 ["hug", "##s"]。接着继续处理“##s”,它在词汇表中,因此“hugs”的分词是 ["hug", "##s"]。

        使用 BPE,则会按顺序应用学习到的合并,将其分词为 ["hu", "##gs"],因此编码是不同的。

        作为另一个例子,单词“bugs”将如何被分词。“b”是从单词开头开始的最长子词,因此我们在此分割,得到 ["b", "##ugs"]。然后,“##u”是“##ugs”开头的最长子词,所以在此分割,得到 ["b", "##u", "##gs"]。最后,“##gs”在词汇表中,因此这个列表就是“bugs”的分词。

        当分词到达一个阶段,无法在词汇表中找到子词时,整个单词将被标记为未知——例如,“mug”将被分词为 ["[UNK]"],而“bum”也是如此(即使可以从“b”和“##u”开始,“##m”不在词汇表中,最终的分词将只是 ["[UNK]"],而不是 ["b", "##u", "[UNK]"])。这是与 BPE 的另一个区别,后者只将不在词汇表中的个别字符标记为未知。

2. 代码实现示例

        使用与 BPE 示例相同的语料库:

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.",
]

        首先,需要将语料库预分词为单词。由于需要复现一个 WordPiece 分词器(如 BERT),因此将使用 bert-base-cased 分词器进行预分词,同样的,我们从model scope上下载bert-base-cased预训练模型。下载速度很快。

import torch
from modelscope import snapshot_download, AutoModel, AutoTokenizer
import os
 
model_dir = snapshot_download('AI-ModelScope/bert-base-cased', cache_dir='/root/autodl-tmp', revision='master')

          加载模型:

from transformers import AutoTokenizer

mode_name_or_path = '/root/autodl-tmp/AI-ModelScope/bert-base-cased'
tokenizer = AutoTokenizer.from_pretrained(mode_name_or_path, trust_remote_code=True)

        在预分词的过程中计算语料库中每个单词的频率。字母表是由所有单词的首字母和带前缀 "##" 的所有其他字母组成的唯一集合。

        将模型使用的特殊词元添加到词汇表的开头。在 BERT 的情况下,这个列表为 ["[PAD]", "[UNK]", "[CLS]", "[SEP]", "[MASK]"]

vocab = ["[PAD]", "[UNK]", "[CLS]", "[SEP]", "[MASK]"] + alphabet.copy()

        将每个单词拆分,除了第一个字母外的所有字母前面加上 "##":

        接下来计算词对的得分:

def compute_pair_scores(splits):
    letter_freqs = defaultdict(int)
    pair_freqs = defaultdict(int)
    for word, freq in word_freqs.items():
        split = splits[word]
        if len(split) == 1:
            letter_freqs[split[0]] += freq
            continue
        for i in range(len(split) - 1):
            pair = (split[i], split[i + 1])
            letter_freqs[split[i]] += freq
            pair_freqs[pair] += freq
        letter_freqs[split[-1]] += freq

    scores = {
        pair: freq / (letter_freqs[pair[0]] * letter_freqs[pair[1]])
        for pair, freq in pair_freqs.items()
    }
    return scores

        查看初始拆分后的字典部分,找到得分最高的词对。

pair_scores = compute_pair_scores(splits)
best_pair = ""
max_score = None
for pair, score in pair_scores.items():
    if max_score is None or max_score < score:
        best_pair = pair
        max_score = score

print(best_pair, max_score)

        基于最大得分,第一个学习的合并是 ('a', '##b') -> 'ab',并将 'ab' 添加到词汇表:

vocab.append("ab")

        在拆分字典中应用该合并:

def merge_pair(a, b, splits):
    for word in word_freqs:
        split = splits[word]
        if len(split) == 1:
            continue
        i = 0
        while i < len(split) - 1:
            if split[i] == a and split[i + 1] == b:
                merge = a + b[2:] if b.startswith("##") else a + b
                split = split[:i] + [merge] + split[i + 2 :]
            else:
                i += 1
        splits[word] = split
    return splits
splits = merge_pair("a", "##b", splits)
splits["about"]

        接下来,将目标设定为词汇大小为 70,进行循环找到合并词对,生成词汇表:

        对新文本进行分词,先进行预分词,拆分,然后在每个单词上应用分词算法。也就是说,从第一个单词的开始寻找最大的子词并进行拆分,然后对剩下的部分重复这个过程:

def encode_word(word):
    tokens = []
    while len(word) > 0:
        i = len(word)
        while i > 0 and word[:i] not in vocab:
            i -= 1
        if i == 0:
            return ["[UNK]"]
        tokens.append(word[:i])
        word = word[i:]
        if len(word) > 0:
            word = f"##{word}"
    return tokens

测试一下:

print(encode_word("Hugging"))
print(encode_word("yuanquan"))

设置对文本进行分词处理的函数(先进行预分词,然后再应用WordPiece分词算法):

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]
    encoded_words = [encode_word(word) for word in pre_tokenized_text]
    return sum(encoded_words, [])

测试:

tokenize("This is the amazing course. Thanks, Hugging Face!")

参考材料

【1】WordPiece tokenization

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

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

相关文章

uni-app中添加自定义相机(微信小程序+app)

一、微信小程序中 微信小程序中可以直接使用camera标签&#xff0c;这个标签不兼容app&#xff0c;官方文档 <cameradevice-position"back"flash"off":style"{ height: lheight px, width: lwidth px }"class"w-full"></c…

vue3【实战】 渲染 md 文件(markdown语法 .md后缀的文件)

1. 安装相关插件 npm i unplugin-vue-markdown markdown-it-prism prism unhead/vue2. 添加配置 src/main.ts // 给 md 文件创建头部 import { createHead } from unhead/vue // md 文件中代码高亮的样式 import prismjs/themes/prism.css // 自定义 md 文件的样式 import /as…

【JAVA面试题】什么是Springboot的自动配置以及注意事项

文章目录 强烈推荐核心概念&#xff1a;自动配置的关键特点&#xff1a;示例&#xff1a; 需要注意的点1.默认配置可能不适合所有场景2.Bean 冲突与覆盖3.应用启动慢的问题4.过度依赖自动配置5.安全性问题6.依赖冲突与版本兼容7.过多不必要的自动配置8.调试困难 专栏集锦 强烈推…

.net framework 3.5sp1安装错误卡住不动怎么解决

解决 .NET Framework 3.5 SP1 安装错误卡住的问题&#xff0c;可以尝试以下几种方法&#xff1a; 1.使用 DISM 工具&#xff1a; 将下载的 NetFx3.cab 文件放置在 C:\Windows 文件夹下。 以管理员身份打开命令提示符&#xff0c;输入以下命令&#xff1a; dism /online /En…

【web前端设计】jquery图标动画特效

学习目标 学习web前端设计技术&#xff08;HTML、css、JavaScript、jQuery等&#xff09;&#xff0c;综合运用技术&#xff0c;将其与HTML元素结合&#xff0c;设计样式、监听事件、添加动画等&#xff0c;给用户呈现出更好的视觉交互效果。本文主要学习分页按钮自动放大、元…

HCIP-HarmonyOS Application Developer 习题(十二)

&#xff08;多选&#xff09;1、声明式开发范式的转场动画包含以下哪几种类型? A、页面间转场 B、应用间转场 C、共享元素转场 D、组件内转场 答案&#xff1a;ACD 分析&#xff1a; &#xff08;多选&#xff09;2、公共事件服务为应用程序提供哪些能力。 A、取消发布公共…

IPMA能力基础线是什么?项目管理工具有哪些应用场景?

作为资深团队管理者&#xff0c;常常面临如何提升团队项目管理能力的挑战。其实在现代的项目管理世界中&#xff0c;有许多标准和模型帮助我们更好地理解项目的复杂性&#xff0c;IPMA&#xff08;International Project Management Association&#xff09;能力基础线就是其中…

iOS静态库(.a)及资源文件的生成与使用详解(Swift版本)

引言 在 iOS 开发中&#xff0c;开发者常常需要将一些功能模块封装成可重用的库&#xff0c;以便在多个项目中共享使用。除了常见的Framework&#xff08;动态库/静态库&#xff09;&#xff0c;静态库&#xff08;.a文件&#xff09;也是一种非常实用的封装方式。静态库在编译…

Java全栈经典面试题剖析4】JavaSE高级 -- 包装类,String, 类方法

目录 面试题3.1 什么是自动装箱与拆箱&#xff1f;用什么方式来装箱与拆箱&#xff1f; 面试题3.2 int和Integer有什么区别&#xff1f; 面试题3.3 Integer常量池 面试题3.4 字符串常量池 面试题3.5 这句代码创建了几个对象? String str1 new String("xyz");…

前端拦截302重定向

背景: 根据业务场景需要拦截302做后续的逻辑处理 尝试一: : axios拦截 、、、、、async created() {// 获取302请求返回的location后手动修改video的src路径let targetSrc;try {await axios.get(this.video).then((res) > {const { headers, status } res;const { locat…

Android 图片相识度比较(pHash)

概述 在 Android 中&#xff0c;要比对两张 Bitmap 图片的相似度&#xff0c;常见的方法有基于像素差异、直方图比较、或者使用一些更高级的算法如 SSIM&#xff08;结构相似性&#xff09;和感知哈希&#xff08;pHash&#xff09;。 1. 基于像素的差异比较 可以逐像素比较…

学习笔记——Test.pwn

前言&#xff1a;笔者也才接触Pwn&#xff0c;写这篇wp&#xff0c;记录目前所得感悟、思考、理解等。 存在错误&#xff0c;或者解释不通的地方&#xff0c;还请提出&#xff0c;已补足笔记的缺陷。 Pwn是什么&#xff1f; 我Pwn掉了你的电脑、我Pwn掉了你的设备…… 通俗的…

重庆大学软件工程考研,难度如何?

C哥专业提供——计软考研院校选择分析专业课备考指南规划 重大软件专业可谓是最好上岸的985院校&#xff01;重庆大学24考研各大学院复试录取情况已出&#xff0c; 我们先说学硕部分&#xff1a; 招生人数&#xff1a; 重庆大学软件工程学硕近几年计划统招人数都不多&#xf…

入选ECCV 2024!浙江大学联合微软亚洲研究院提出统一医学图像预训练框架UniMedI,打破医学数据异构化藩篱

让 AI 在某些条件下具备类似人类的反应能力&#xff0c;从而代替人类高效地从事特定工作&#xff0c;是 AI 领域研究人员孜孜不倦的追求。正如在医学图像和人工智能的交叉领域&#xff0c;基于视觉语言预训练的深度模型 (Visual-Language Pre-training, VLP) 凭借其自动化的特点…

Docker本地镜像发布到阿里云镜像服务的简易指南

1 阿里云容器镜像服务 阿里云容器镜像服务&#xff08;Alibaba Cloud Container Registry&#xff0c;简称ACR&#xff09;是一个为容器镜像、Helm Chart等云原生资产提供安全托管及高效分发的平台。它支持多架构容器镜像&#xff0c;包括Linux、Windows、ARM等&#xff0c;以…

心觉:感恩日记:每天5分钟,重新定义你的人生

​Hi&#xff0c;我是心觉&#xff0c;与你一起玩转潜意识、脑波音乐和吸引力法则&#xff0c;轻松掌控自己的人生&#xff01; 挑战每日一省写作207/1000天 你是否觉得生活节奏太快&#xff0c;总是有做不完的事、解决不完的问题&#xff1f; 有一个简单的方法&#xff0c;…

DEPT_ DECOMPOSED PROMPT TUNING FOR PARAMETER-EFFICIENT FINE-TUNING

论文汇总 当前的问题 (1)Prompt Tuning通常收敛缓慢&#xff0c;并且对初始化敏感&#xff1b; (2)Prompt Tuning延长了输入序列的总长度&#xff0c;从而加剧了计算需求(即训练/推理时间和内存成本)&#xff0c;这是由于Transformer的二次复杂度(Vaswani et al, 2017)。 解…

机器视觉系统硬件组成之工业相机篇

工业相机是一种非常重要的机器视觉器件&#xff0c;它能够将被采集的图像信息通过电路转换成电信号&#xff0c;再通过模数转换器&#xff08;ADC&#xff09;将其转化为数字信号&#xff0c;最后以标准的视频信号输出。工业相机在机器视觉领域得到了广泛应用&#xff0c;包括质…

springboot055服装生产管理的设计与实现(论文+源码)_kaic

毕业设计(论文) 协力服装厂服装生产管理系统 的设计与实现 学生姓名 XXX 学 号 XXXXXXXX 分院名称 XXXXXXXX 专业班级 XXXXX 指导教师 XXXX 填写…

CROss PlatformS (CROPS) 与 Docker

CROPS 是一个开源的、跨平台的开发框架&#xff0c;专为利用 Docker 容器在 Windows、macOS 和 Linux 系统上创建和管理构建主机而设计。它简化了在非 Linux 系统上运行 Yocto 项目及其他基于 Linux 的工具的过程&#xff0c;同时提供了一个可扩展的开发环境&#xff0c;支持多…