分词算法BBPE详解和Qwen的应用

news2025/7/27 20:41:23

一、TL;DR

  1. BPE有什么问题:依旧会遇到OOV问题,并且中文、日文这些大词汇表模型容易出现训练中未出现过的字符
  2. Byte-level BPE怎么解决:与BPE一样是高频字节进行合并,但BBPE是以UTF-8编码UTF-8编码字节序列而非字符序列
  3. Byte-level BPE利用utf-8编码,利用动态规划解码,最大程度的还原字符的语义和上下文信息(这是我理解为什么LLM能够通过NTP进行理解的最主要原因)
  4. Qwen是使用BBPE算法,增加了中文的能力,词汇表包括151,643 tokens

二、实际业务的使用

字节级别字节对编码(BBPE)是一种高效的分词算法,它将输入文本分割为可变长度的字节 n-gram(子词),并将其映射为词汇表中的 token ID。以下是 BBPE 分词算法将输入文本转换为 token ID 的详细过程,以及如何结合词表进行文件操作:

2.1  输入文本的字节表示

  • UTF-8 编码:首先,输入文本(如一行字符串)会被转换为 UTF-8 字节序列。UTF-8 编码将每个 Unicode 字符映射为 1 到 4 个字节。

  • 示例:假设输入文本是 "Hello, 世界",其 UTF-8 字节序列为:

    [72, 101, 108, 108, 111, 44, 32, 228, 189, 160, 229, 165, 189]

    其中,"Hello," 是 ASCII 字符,每个字符占用 1 个字节;而 "世界" 是 UTF-8 编码的中文字符,每个字符占用 3 个字节。

2.2 BBPE 分词

  • 学习词汇表:BBPE 通过迭代合并最频繁出现的字节对来构建词汇表。词汇表中包含基本字节(0-255)和通过 BPE 合并生成的字节 n-gram。

  • 分词过程:输入的字节序列会被分割成词汇表中存在的子词(字节 n-gram)。这些子词是通过 BPE 合并规则生成的。

  • 示例:假设词汇表中有以下条目:

72, 101, 108, 108, 111, 44, 32, 228, 189, 160, 229, 165, 189
72 101, 108 108, 111 44, 32 228, 189 160, 229 165 189

2.3 映射为 Token ID

  • 词汇表文件:BBPE 的词汇表通常存储在一个文件中,文件格式类似于:

  • 72
    101
    108
    108 108
    111
    44
    32
    228
    189
    160
    229 165 189
  • 映射过程:分词器将分割后的子词与词汇表文件进行匹配,找到对应的 token ID。

  • 示例:假设分词后的子词为 [72 101, 108 108, 111 44, 32 228, 189 160, 229 165 189],其对应的 token ID 可能是:

    [10, 15, 20, 25, 30, 35]

    其中,72 101 在词汇表中的行号是 10,108 108 的行号是 15,依此类推。

 2.4 文件操作

  • 加载词汇表:分词器在初始化时会加载词汇表文件,将其内容存储到内存中,以便快速查找。

# 假设词汇表文件名为 vocab.txt
with open('vocab.txt', 'r', encoding='utf-8') as f:
    vocab = [line.strip() for line in f.readlines()]

# 将子词映射为 token ID
def tokenize(input_text):
    # 将输入文本转换为 UTF-8 字节序列
    byte_sequence = input_text.encode('utf-8')
    # 分词(这里简化为直接匹配,实际分词器会更复杂)
    tokens = []
    for subword in byte_sequence.split():
        subword_str = ' '.join(map(str, subword))
        token_id = vocab.index(subword_str)
        tokens.append(token_id)
    return tokens

input_text = "Hello, 世界"
token_ids = tokenize(input_text)
print(token_ids)

2.5 总结

  • 输入文本UTF-8 字节序列BBPE 分词映射为 Token ID

  • 词汇表文件是 BBPE 分词的核心,它存储了所有可能的子词及其对应的 token ID。

三、Byte-level BPE算法原理

paper链接: https://arxiv.org/pdf/1909.03341

papr:Neural Machine Translation with Byte-Level Subwords

3.1 为什么要开发Byte-level BPE

  1. 解决不了中文/日语这种语言:几乎所有的分词算法都是基于字符级词汇表构建的(字符、子词或单词),但对于日语和中文的字符丰富且存在噪声文本的语言,罕见字符可能会不必要地占据词汇表的槽位,从而限制其紧凑性
  2. 字节表示会引入计算成本:使用字节级别表示文本,并将 256 个字节集作为词汇表可以解决这个问题,但是会引入高昂的计算成本

3.2 实际合并方法和举例

与BPE算法的差异:

来自日语 - 英语的不同词汇表分词示例。

空格被下划线替换,而空格用于分隔词元。,随着分词粒度从细到粗,词元的形态是如何变化的:字节(256)→ 字节级别字节对编码(BBPE,1K、2K、4K、8K)→ 字符(8K)→ 字节级别字节对编码(BBPE,16K、32K)→ 字节对编码(BPE,16K、32K)。

BBPE算法在基于字节(Byte)进行合并过程和BPE一致、也是选取出现频数最高的字符对进行合并,合并过程如下图所示: 关注到红色箭头,输入是日文当词表大小是1K时,A8 BC 两个字节并没有合并成一个 Token,在词表大小是2K时,A8BC被BBPE合并成一个Token。

3.3 原理上具体怎么做?

别看了,直接用就好,最重要的还是理解对input text进行分词后查表再转成encoder的过程

字节级别表示的编码:

  1. 使用 UTF-8 编码文本,它将每个 Unicode 字符编码为 1 到 4 个字节。这使得我们可以将句子建模为字节序列,而不是字符序列。
  2.  13.8 万个 Unicode 字符覆盖了 150 多种语言,但我们使用 UTF-8 字节(256 个可能字节中的 248 个)来表示任何语言的句子。

如何解决计算成本高昂的问题?

字节级别的n-gram方法来减少计算成本:

编码过程:

  1. 将Unicode字符映射为1-4个字节
  2. 将字节序列分割为可变长度的 n 元组(字节级别的“子词”)
  3. 使用深度卷积层或双向循环层与门控循环单元(GRU)来对 BBPE  embedding进行上下文化

解码过程:

  1. 采用动态规划算法从字节序列恢复Unicode字符
  2. 对于给定的字节序列 {B}kN​,我们用 f(k) 表示我们可以从中恢复的最大字符数。然后 f(k) 具有最优子结构

        如果 {B}kj​ 对应一个有效的字符,则 g(i,j)=1,否则为 0。当 f(k) 递归计算时,我们还在每个位置 k 记录选择,以便通过回溯恢复解决方案。

解码过程中-说人话

  1. 使用动态规划去恢复最有效(g代表有效性指示函数)和可恢复的最大字符数(动态词汇表便于最大化的数据还原

四、Qwen的应用

4.1 Qwen3的技术报告原文:

4.2 Qwen实际代码实现:

参考:https://github.com/QwenLM/Qwen/blob/main/tokenization_note.md

from transformers import AutoTokenizer

tokenizer = AutoTokenizer.from_pretrained('Qwen/Qwen-7B', trust_remote_code=True)

特殊字符的处理:

特殊标记对模型具有特殊功能,例如表示文档结束。理论上,这些标记在输入文本中不存在,仅在输入文本经过处理后才会出现。

可以在微调或其他需要它们的框架中这样指定特殊标记:

from transformers import AutoTokenizer

tokenizer = AutoTokenizer.from_pretrained('Qwen/Qwen-7B', trust_remote_code=True, pad_token='<|endoftext|>')

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

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

相关文章

多线程下使用缓存+锁Lock, 出现“锁失效” + “缓存未命中竞争”的缓存击穿情况,双重检查缓存解决问题

多线程情况下&#xff0c;想通过缓存同步锁的机制去避免多次重复处理逻辑&#xff0c;尤其是I/0操作&#xff0c;但是在实际的操作过程中发现多次访问的日志 2025-06-05 17:30:27.683 [ForkJoinPool.commonPool-worker-3] INFO Rule - [vagueNameMilvusReacll,285] - embeddin…

Playwright 测试框架 - .NET

💖亲爱的技术爱好者们,热烈欢迎来到 Kant2048 的博客!我是 Thomas Kant,很开心能在CSDN上与你们相遇~💖 本博客的精华专栏: 【自动化测试】

命令行以TLS/SSL显式加密方式访问FTP服务器

昨天留了一个小尾巴~~就是在命令行或者代码调用命令&#xff0c;以TLS/SSL显式加密方式&#xff0c;访问FTP服务器&#xff0c;上传和下载文件。 有小伙伴可能说ftp命令不可以吗&#xff1f;不可以哦~~ ftp 命令本身不支持显式加密。要实现 FTP 的显式加密&#xff0c;可以使…

Linux配置yum 时间同步服务 关闭防火墙 关闭ESlinux

1、配置yum 1.1、Could not resolve host: mirrorlist.centos.org; 未知的错误 https://blog.csdn.net/fansfi/article/details/146369946?fromshareblogdetail&sharetypeblogdetail&sharerId146369946&sharereferPC&sharesourceRockandrollman&sharefr…

LLaMA-Factory和python版本的兼容性问题解决

引言 笔者今天在电脑上安装下LLaMA-Factory做下本地的模型调优。 从github上拉取代码git clone https://github.com/hiyouga/LLaMA-Factory.git. pycharm建立工程,按照官网指导如下: LLaMA-Factory 安装 在安装 LLaMA-Factory 之前&#xff0c;请确保您安装了下列依赖: 运行以…

每日算法-250605

每日算法 - 20240605 525. 连续数组 题目描述 给定一个二进制数组 nums , 找到含有相同数量的 0 和 1 的最长连续子数组&#xff0c;并返回该子数组的长度。 思路 前缀和 哈希表 解题过程 核心思想是将问题巧妙地转换为寻找和为特定值的子数组问题。 转换问题&#xff1a;我…

分布式锁-Redisson实现

目录 本地锁的局限性 Redisson解决分布式锁问题 在分布式环境下&#xff0c;分布式锁可以保证在多个节点上的并发操作时数据的一致性和互斥性。分布式锁有多种实现方案&#xff0c;最常用的两种方案是&#xff1a;zookeeper和redis&#xff0c;本文介绍redis实现分布式锁方案…

C++学习-入门到精通【14】标准库算法

C学习-入门到精通【14】标准库算法 目录 C学习-入门到精通【14】标准库算法一、对迭代器的最低要求迭代器无效 二、算法1.fill、fill_n、generate和generate_n2.equal、mismatch和lexicographical_compare3.remove、remove_if、remove_copy和remove_copy_if4.replace、replace_…

HarmonyOS运动语音开发:如何让运动开始时的语音播报更温暖

##鸿蒙核心技术##运动开发##Core Speech Kit&#xff08;基础语音服务&#xff09;# 前言 在运动类应用中&#xff0c;语音播报功能不仅可以提升用户体验&#xff0c;还能让运动过程更加生动有趣。想象一下&#xff0c;当你准备开始运动时&#xff0c;一个温暖的声音提醒你“…

vscode使用系列之快速生成html模板

一.欢迎来到我的酒馆 vscode&#xff0c;yyds! 目录 一.欢迎来到我的酒馆二.vscode下载安装1.关于vscode你需要知道2.开始下载安装 三.vscode快速创建html模板 二.vscode下载安装 1.关于vscode你需要知道 Q&#xff1a;为什么使用vscode? A&#xff1a;使用vscode写…

网页前端开发(基础进阶4--axios)

Ajax Ajax(异步的JavaScript和XML) 。 XML是可扩展标记语言&#xff0c;本质上是一种数据格式&#xff0c;可以用来存储复杂的数据结构。 可以通过Ajax给服务器发送请求&#xff0c;并获取服务器响应的数据。 Ajax采用异步交互&#xff1a;可以在不重新加载整个页面的情况下&am…

软件安全:漏洞利用与渗透测试剖析、流程、方法、案例

在数字时代&#xff0c;软件已深度融入生活与工作的方方面面&#xff0c;从手机应用到企业核心系统&#xff0c;软件安全至关重要。而漏洞利用与渗透测试&#xff0c;作为软件安全领域中相互关联的两个关键环节&#xff0c;一个是黑客攻击的手段&#xff0c;一个是安全防护的方…

Haproxy的基础配置

1、参考文档 官方文档&#xff1a;HAProxy version 2.2.22 - Configuration Manual 运维派配置手册&#xff1a;Haproxy-基础配置详解 - 运维派 Haproxy 的配置文件haproxy.cfg由两大部分组成&#xff0c;分别是global和proxies部分。 2、haproxy global 配置 global&…

考研系列—操作系统:冲刺笔记(1-3章)

目录 第一章 计算机系统概述 1.基本概念 2.内核态和用户态 3.中断(外中断)、异常(内中断-与当前执行的) 4.系统调用 5.操作系统引导程序 2021年真题: 6.操作系统结构 大纲新增 (1)分层结构 (2)模块化 (3)外核 7.虚拟机 第二章 进程管理 1.画作业运行的顺序和甘…

Java调用大模型API实战指南

文章目录 前言调用大模型的流程概述和基本原理获取 DeepSeek 的 API keyJava 实现调用大模型 API 的Demo进阶扩展建议 前言 随着大语言模型&#xff08;如 OpenAI、DeepSeek、通义千问等&#xff09;的发展&#xff0c;我们可以很方便地用 API 接口调用这些强大的智能助手。在…

单片机0-10V电压输出电路分享

一、原理图 二、芯片介绍 GP8101是一个PWM信号转模拟信号转换器&#xff0c;相当于一个PWM信号输入&#xff0c;模拟信号输出的DAC。此 芯片可以将占空比为0%到100%的PWM信号线性转换成0-5V或者0-10V的模拟电压&#xff0c;并且输出电压 精度小于1%。GP8101M可以处理高频调制的…

大模型模型部署和暴露接口

创建环境 激活案件 安装相关依赖 conda create -n fastApi python3.10 conda activate fastApi conda install -c conda-forge fastapi uvicorn transformers pytorch pip install safetensors sentencepiece protobuf 新建文件夹 mkdir App cd App touch main.py 复制代码…

2025服装收银系统推荐:智能管理助力服装商家高效经营

在服装批发零售行业&#xff0c;一套高效的收银系统不仅能简化日常经营流程&#xff0c;还能通过数据分析帮助商家优化库存、提升销售。随着AI技术的普及&#xff0c;现代收银系统已不再局限于简单的记账功能&#xff0c;而是能提供智能选品、库存预警、精准营销等进阶服务。 …

Microsoft Copilot Studio - 尝试一下Agent

1.简单介绍 Microsoft Copilot Studio以前的名字是Power Virtual Agent(简称PVA)。Power Virutal Agent是2019年出现的&#xff0c;是低代码平台Power Platform的一部分。当时Generative AI还没有出现&#xff0c;但是基于已有的Conversation AI技术&#xff0c;即Microsoft L…

【Python 算法零基础 4.排序 ⑨ 堆排序】

目录 一、问题描述 二、算法对比 1.朴素算法 ① 数组模拟容器 ② 有序数组模拟容器 2.二叉堆 ① 二叉堆特点 ② 数组表示二叉树 ③ 堆 ④ 大顶堆 ⑤ 小顶堆 ⑥ 元素插入 ⑦ 获取堆顶 ⑧ 堆顶元素删除 三、代码分析 1.工具函数 2.调整大顶堆函数 Ⅰ、计算子节点索引 Ⅱ、找出最…