LLM学习笔记(13)分词器 tokenizer

由于神经网络模型不能直接处理文本,因此我们需要先将文本转换为数字,这个过程被称为编码 (Encoding),其包含两个步骤:

  1. 使用分词器 (tokenizer) 将文本按词、子词、字符切分为 tokens;
  2. 将所有的 token 映射到对应的 token ID。

分词策略

根据切分粒度的不同,分词策略可以分为以下几种:

按词切分 (Word-based)

特点

  • 以空格、标点符号为界,将文本分割为单词。
  • 每个单词被视为一个独立的 token。

优点:

  • 实现简单,分词器只需根据空格或标点分割。

缺点:

  • 对于形态变化的词(如 runrunning)无法识别它们之间的关系。
  • 分词表会很大,可能导致内存占用过多。
  • 遇到分词表中没有的词(Out-Of-Vocabulary,OOV),分词器会用特殊的 [UNK] token 表示,影响模型效果。

例子

直接利用 Python 的 split() 函数按空格进行分词,其默认分隔符为空格:

tokenized_text = "Jim Henson was a puppeteer".split()
print(tokenized_text)

结果:

['Jim', 'Henson', 'was', 'a', 'puppeteer']

问题:词形变化和未知词

  • 词形变化问题:
    • 示例:dogdogsrunrunning,被分词器视为不同的 token,无法识别它们的词根关系。
  • 未知词问题:
    • 如果单词不在词汇表中(Out-Of-Vocabulary, OOV),分词器会用 [UNK](Unknown Token)表示。
    • 问题:
      • [UNK] 会丢失单词原始的语义信息。
      • 如果分词策略不够好,句子中会有大量 [UNK]

词表(Vocabulary)

什么是词表?

词表: 一个映射字典,将 token 映射到数字 ID(从 0 开始)。

  • 示例:

    {'Jim': 100, 'Henson': 101, 'was': 102, 'a': 103, 'puppeteer': 104}

词表的作用

  • 将 token 转换为对应的数字 ID。
  • 神经网络只能处理数字,不能直接理解字符串。

遇到 OOV 的处理

  • 如果分词结果中出现词表中没有的单词(如 puppeteering),分词器会用 [UNK] 替代。

按字符切分 (Character-based)

这种策略把文本切分为字符(字母)而不是词语,这样就只会产生一个非常小的词表,并且很少会出现词表外的 tokens。

可以使用 Python 的内置函数 list() 将输入字符串转换为字符列表。即

但是从直觉上来看,字符本身并没有太大的意义,因此将文本切分为字符之后就会变得不容易理解。这也与语言有关,例如中文字符会比拉丁字符包含更多的信息,相对影响较小。此外,这种方式切分出的 tokens 会很多,例如一个由 10 个字符组成的单词就会输出 10 个 tokens,而实际上它们只是一个词。

因此现在广泛采用的是一种同时结合了按词切分和按字符切分的方式——按子词切分 (Subword tokenization)。

按子词切分(Subword Tokenization)

子词切分是一种分词策略,能够将输入文本分解为更小的单元(子词或子字符串),其主要特点如下:

核心概念

  • 高频单词直接保留,例如单词 do 不会被切分。

  • 低频单词会被分解为多个子词(subword)。

  • 示例:tokenization 被分解为 tokenization

    • 子词带有特殊标记(如 <w>##),表示这是子词的一部分。

优点

1. 解决 OOV(Out-of-Vocabulary)问题:

  • 即使一个单词在词表中不存在,也可以通过子词组合得到。
  • 例如,ization 可能是低频词,但可以通过 tokenization 的组合表示。

2. 减小词表大小:

  • 子词分词只需一个小词表即可覆盖大部分文本,避免了巨大的内存开销。

3. 保留词义:

  • 子词保留了部分语义信息,例如 tokenization 分别表示单词的前缀和后缀。

例子

我们可以使用 Hugging Face 的 Transformers 库中的分词器(Tokenizer)实现子词切分。例如,WordPieceByte Pair Encoding (BPE) 是常用的子词分词算法。

代码如下:

from transformers import AutoTokenizer

# 加载预训练分词器
tokenizer = AutoTokenizer.from_pretrained("bert-base-uncased")

# 测试文本
sample_text = "Let's do tokenization!"

# 使用分词器进行子词切分
tokens = tokenizer.tokenize(sample_text)

# 打印结果
print("Original Text:", sample_text)
print("Subword Tokens:", tokens)

运行结果:

Original Text: Let's do tokenization!
Subword Tokens: ['let', "'", 's', 'do', 'token', '##ization', '!']

代码解析

tokenizer = AutoTokenizer.from_pretrained("bert-base-uncased")

加载 BERT 模型对应的分词器,默认使用 WordPiece 分词算法。

结果解释

  • let's 被分解为两个独立的 token。
  • tokenization 被分解为两个子词:token##ization
    • ## 表示这是一个后续子词,属于前一个单词的一部分。

文本编码与解码

本内容展示了 Hugging Face 的 AutoTokenizer 对文本进行编码和解码的过程,分别涉及以下关键步骤。

编码过程

如前所述,文本编码 (Encoding) 过程包含两个步骤:

  1. 分词:使用分词器按某种策略将文本切分为 tokens;
  2. 映射:将 tokens 转化为对应的 token IDs。

下面我们

编码示例

1. 首先使用 BERT 分词器来对文本进行分词。

代码如下:

from transformers import AutoTokenizer

# 加载分词器
tokenizer = AutoTokenizer.from_pretrained("bert-base-cased")

# 输入文本
sequence = "Using a Transformer network is simple"

# 编码 - 分词
tokens = tokenizer.tokenize(sequence)
print(tokens)  # 打印分词后的 tokens

输出:

['using', 'a', 'transform', '##er', 'network', 'is', 'simple']

分词细节:

  • 使用子词分词策略(如 WordPiece)。
  • 将低频单词(如 Transformer)分解为 transform##er
  • ## 表示子词为前一个 token 的一部分。

2. 然后,我们通过 convert_tokens_to_ids() 将切分出的 tokens 转换为对应的 token IDs。

代码如下:

ids = tokenizer.convert_tokens_to_ids(tokens)
print(ids)

输出:

[7993, 170, 13809, 23763, 2443, 1110, 3014]

每个 token 被映射为一个整数 ID,表示其在词表中的索引。

3. 还可以通过 encode() 函数将这两个步骤合并,并且 encode() 会自动添加模型需要的特殊 token,例如 BERT 分词器会分别在序列的首尾添加 [CLS] 和 [SEP]:

# 使用 encode() 方法直接编码文本
sequence_ids = tokenizer.encode(sequence)
print(sequence_ids)

输出:

[101, 7993, 170, 13809, 23763, 2443, 1110, 3014, 102]

新增的特殊 token:

  • 101:表示 [CLS](分类起始符)。
  • 102:表示 [SEP](分隔符)。

注意,上面这些只是为了演示。在实际编码文本时,最常见的是直接使用分词器进行处理,这样不仅会返回分词后的 token IDs,还包含模型需要的其他输入。例如 BERT 分词器还会自动在输入中添加 token_type_ids 和 attention_mask.

4. BERT 的完整编码信息

tokenized_text = tokenizer("Using a Transformer network is simple")
print(tokenized_text)

输出:

{
  'input_ids': [101, 7993, 170, 13809, 23763, 2443, 1110, 3014, 102],
  'token_type_ids': [0, 0, 0, 0, 0, 0, 0, 0, 0],
  'attention_mask': [1, 1, 1, 1, 1, 1, 1, 1, 1]
}

字段说明:

  • input_ids:文本对应的 token IDs,包含 [CLS] 和 [SEP]。
  • token_type_ids:区分不同段落的标记,BERT 多段输入时用到。
  • attention_mask:掩码标记,1 表示有效的 token,0 表示 padding。

解码过程

文本解码 (Decoding) 与编码相反,负责将 token IDs 转换回原来的字符串。注意,解码过程不是简单地将 token IDs 映射回 tokens,还需要合并那些被分为多个 token 的单词。

代码:

decoded_string = tokenizer.decode([7993, 170, 13809, 23763, 2443, 1110, 3014])
print(decoded_string)

输出:

Using a transformer network is simple

解码带特殊 token 的 ID:

decoded_string = tokenizer.decode([101, 7993, 170, 13809, 23763, 2443, 1110, 3014, 102])
print(decoded_string)

输出:

[CLS] Using a Transformer network is simple [SEP]

总结

  1. 编码过程:

    • tokenize() 分词,将文本拆分为子词 token。
    • convert_tokens_to_ids() 将 token 转换为对应的 token IDs。
    • encode() 是以上两步的封装,并自动添加特殊 token(如 [CLS] 和 [SEP])。
  2. 解码过程:

    • decode() 将 token IDs 转换回原始文本,支持忽略特殊 token。
  3. 重要参数:

    • input_ids:模型的实际输入。
    • attention_mask:表示 token 的有效性。
    • token_type_ids:区分输入段落的标记。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Unity中让光点跟图片填充区的末尾一起移动

一、实现效果展示 想要实现的效果如下,就是要让白色光点图片跟随绿色圆形图片填充区末尾一起移动。 二、代码如下: using UnityEngine; using System.Collections; using UnityEngine.UI; using DG.Tweening;public class IconCircle : MonoBehaviour {public float ti…

给定一个整数可能为正,0,负数,统计这个数据的位数.

题目描述 给定一个整数可能为正,0,负数,统计这个数据的位数. 例如1234567输出7位; -12345678输出8位;0输出1位 代码实现 int main() { long long m; long long n; scanf("%lld",&n); mn; int count0;//位数 do { count; n/10;//舍弃个位 }while(n!0); printf(&…

LLamafactory API部署与使用异步方式 API 调用优化大模型推理效率

文章目录 背景介绍第三方大模型API 介绍LLamafactory 部署API大模型 API 调用工具类项目开源 背景介绍 第三方大模型API 目前&#xff0c;市面上有许多第三方大模型 API 服务提供商&#xff0c;通过 API 接口向用户提供多样化的服务。这些平台不仅能提供更多类别和类型的模型…

【关闭or开启电脑自带的数字键盘】

目录 一、按数字键盘左上角的按键【NumLK Scroll】 二、修改注册表中数字键盘对应的数值【InitialKeyboardIndicators】 1、步骤&#xff1a; 2、知识点&#xff1a; 一、按数字键盘左上角的按键【NumLK Scroll】 这是最简单快捷的方法。 关闭后若想开启&#xff0c;再按一…

【FAQ】使用Node.js 镜像 构建本地项目

在nodejs官方并没有提供使用node.js构建本地项目的方法&#xff0c;但是通过阅读官方文档&#xff0c;可以发现&#xff0c;官方在包管理器界面提供了如下语句 所以node.js容器是可以执行语句的 下面通过docker 的 -w 、-v 参数设置容器工作目录和目录映射&#xff08;实现本…

深度学习 | pytorch + torchvision + python 版本对应及环境安装

Hi&#xff0c;大家好&#xff0c;我是半亩花海。要让一个基于 torch 框架开发的深度学习模型正确运行起来&#xff0c;配置环境是个重要的问题&#xff0c;本文介绍了 pytorch、torchvision、torchaudio 及 python 的对应版本以及环境安装的相关流程。 目录 一、版本对应 二…

4399大数据面试题及参考答案(数据分析和数据开发)

对数据分析的理解 数据分析是一个从数据中提取有价值信息以支持决策的过程。它涵盖了数据收集、清洗、转换、建模和可视化等多个环节。 首先&#xff0c;数据收集是基础。这包括从各种数据源获取数据&#xff0c;例如数据库、文件系统、网络接口等。这些数据源可以是结构化的数…

fastdds:编译、安装并运行helloworld

fastdds安装可以参考官方文档&#xff1a; 3. Linux installation from sources — Fast DDS 3.1.0 documentation 从INSTALLATION MANUAL这一节可以看出来&#xff0c;fastdds支持的操作系统包括linux、windows、qnx、MAC OS。本文记录通过源码和cmake的方式来安装fastdds的…

Istio笔记01--快速体验Istio

Istio笔记01--快速体验Istio 介绍部署与测试部署k8s安装istio测试istio 注意事项说明 介绍 Istio是当前最热门的服务网格产品&#xff0c;已经被广泛应用于各个云厂商和IT互联网公司。企业可以基于Istio轻松构建服务网格&#xff0c;在接入过程中应用代码无需更改&#xff0c;…

ipad项目 蓝湖宽度

ipad项目 横屏状态时 蓝湖宽度设置930px media screen and (orientation: portrait) {/* 竖屏时的样式 */ } media screen and (orientation: landscape) {/* 默认是 横屏时的样式 */ }

14、保存与加载PyTorch训练的模型和超参数

文章目录 1. state_dict2. 模型保存3. check_point4. 详细保存5. Docker6. 机器学习常用库 1. state_dict nn.Module 类是所有神经网络构建的基类&#xff0c;即自己构建一个深度神经网络也是需要继承自nn.Module类才行&#xff0c;并且nn.Module中的state_dict包含神经网络中…

在鸿蒙应用中 Debug 对开发者的帮助

文章目录 摘要引言Debug 的意义与挑战案例&#xff1a;页面渲染性能优化中的 Bug 排查Debug 过程详解问题定位问题解决优化布局与渲染逻辑 代码详细讲解示例代码详细讲解1. 导入必要模块2. 数据生成3. 使用虚拟列表组件items 属性itemHeight 属性renderItem 属性 4. 返回完整组…

基于多VSG独立微网的多目标二次控制MATLAB仿真模型

“电气仔推送”获得资料&#xff08;专享优惠&#xff09; 模型简介 本文将一致性算法引入微电网的二次频率和电压控制&#xff0c;自适应调节功率参考值和补偿电压&#xff0c;同时实现频率电压恢复、有功 无功功率的比例均分以及功率振荡抑制&#xff0c;提高系统的暂态和稳…

洛谷 P2415 集合求和 C语言

题目&#xff1a; https://www.luogu.com.cn/problem/P2415 思路从大佬学来的思路。 如图&#xff1a; 我们可以发现&#xff0c;集合最后出现过的数字是2的&#xff08;n-1&#xff09;次方&#xff0c;所以就很好计算了。 代码如下&#xff1a; #include <iostream&g…

leaflet 的基础使用

目录 一、创建dom节点 二、创建地图 三、添加底图&#xff08;天地图&#xff09;&#xff0c;在地图创建完成后添加底图 本章主要讲述leaflet在vue中的使用&#xff1a; leaflet 详情总目录&#xff1a;传送 一、创建dom节点 <div class"map" id"map_…

Springboot 2.x升级到3.x

运维在扫描项目的时候发现了官方发布的漏洞&#xff0c;https://spring.io/security/cve-2024-38816 我们使用的是spring框架的2.x系列&#xff0c;WebMvc依赖于5.3系列&#xff0c;描述说需要更新到5.3.40&#xff0c;但是官方迟迟不再更新。同时发现官方说5.3系列也就更新到…

【HarmonyOS】@Observed和@ObjectLink嵌套对象属性更改UI不刷新问题

【HarmonyOS】Observed和ObjectLink嵌套对象属性更改UI不刷新问题 一、问题背景 使用了Observed和ObjectLink&#xff0c;修改嵌套对象的属性&#xff0c;UI还是不刷新&#xff0c;常见的问题有以下三种形式&#xff1a; 1.多级嵌套&#xff0c;嵌套对象的类并没有添加Observ…

【rustdesk】客户端和服务端的安装和部署(自建服务器,docker,远程控制开源软件rustdesk)

【rustdesk】客户端和服务端的安装和部署&#xff08;自建服务器&#xff0c;docker&#xff09; 一、官方部署教程 https://rustdesk.com/docs/zh-cn/client/mac/ 官方服务端下载地址 https://github.com/rustdesk/rustdesk-server/releases 我用的docker感觉非常方便&am…

otter 高可用策略

关于otter高可用在设计之初&#xff0c;提供了这样几个基本的需求&#xff1a; 1.网络不可靠&#xff0c;异地机房尤为明显. 2.manager/node的jvm不可靠&#xff0c;需要考虑异常crash情况 3.node的jvm不可靠&#xff0c;需要考虑异常crash的情况 4.数据库不可靠&#xff0c;需…

数据库日志

MySQL中有哪些日志 1&#xff0c;redo log重做日志 redo log是物理机日志&#xff0c;因为它记录的是对数据页的物理修改&#xff0c;而不是SQL语句。 作用是确保事务的持久性&#xff0c;redo log日志记录事务执行后的状态&#xff0c;用来恢复未写入 data file的已提交事务…