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

news2024/12/26 22:30:59

由于神经网络模型不能直接处理文本,因此我们需要先将文本转换为数字,这个过程被称为编码 (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:区分输入段落的标记。

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

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

相关文章

通过LabVIEW项目判断开发环境是否正版

在接收或分析他人提供的LabVIEW项目时&#xff0c;判断其开发环境是否为正版软件对于保护知识产权和避免使用非法软件至关重要。本文将详细介绍如何通过项目文件、可执行程序及开发环境信息判断LabVIEW是否为正版。 ​ 1. 从项目文件判断 LabVIEW项目的源码&#xff08;VI 文件…

node.js基础学习-url模块-url地址处理(二)

前言 前面我们创建了一个HTTP服务器&#xff0c;如果只是简单的http://localhost:3000/about这种链接我们是可以处理的&#xff0c;但是实际运用中一般链接都会带参数&#xff0c;这样的话如果我们只是简单的判断链接来分配数据&#xff0c;就会报404找不到链接。为了解决这个问…

思科网络设备常用命令整理

思科网络设备的配置命令非常丰富&#xff0c;广泛应用于路由器、交换机和其他网络设备的管理与配置。以下是一些常见的思科设备配置命令&#xff0c;按照功能分类&#xff0c;以帮助你快速查找和使用。 一、基本命令 查看当前配置和状态 show running-config&#xff1a;查看…

2024年信号处理与神经网络应用(SPNNA 2024)

会议官网&#xff1a;www.spnna.org 会议时间&#xff1a;2024年12月13-15日 会议地点&#xff1a;中国武汉

Leecode经典题3-删除排序数组中的重复项

删除排序数组中的重复项 题目描述&#xff1a; 给你一个 非严格递增排列 的数组 nums &#xff0c;请你 原地 删除重复出现的元素&#xff0c;使每个元素 只出现一次 &#xff0c;返回删除后数组的新长度。元素的 相对顺序 应该保持 一致 。然后返回 nums 中唯一元素的个数。 …

无人机数据处理系统:原理与核心系统

一、数据处理系统的运行原理 数据获取&#xff1a;无人机在飞行过程中&#xff0c;通过搭载的传感器&#xff08;如相机、激光雷达等&#xff09;采集到各种类型的数据&#xff0c;例如图像、点云等。这些数据是后续处理和分析的基础。 数据传输&#xff1a;采集到的数据会通…

ElasticSearch学习篇19_《检索技术核心20讲》搜推广系统设计思想

目录 主要是包含搜推广系统的基本模块简单介绍&#xff0c;另有一些流程、设计思想的分析。 搜索引擎 基本模块检索流程 查询分析查询纠错 广告引擎 基于标签倒排索引召回基于向量ANN检索召回打分机制&#xff1a;非精确打分精准深度学习模型打分索引精简&#xff1a;必要的…

【尚筹网】五、管理员维护

【尚筹网】五、管理员维护 任务清单分页管理管理员信息目标思路代码引入 PageHelperAdminMapper 中编写 SQL 语句AdminMapper 接口生成方法AdminServiceAdminHandler页面显示主体在页面上使用 Pagination 实现导航条 关键词查询页面上调整表单在翻页时保持关键词查询条件 单条删…

MySQL 启动失败问题分析与解决方案:`mysqld.service failed to run ‘start-pre‘ task`

目录 前言1. 问题背景2. 错误分析2.1 错误信息详解2.2 可能原因 3. 问题排查与解决方案3.1 检查 MySQL 错误日志3.2 验证 MySQL 配置文件3.3 检查文件和目录权限3.4 手动启动 MySQL 服务3.5 修复 systemd 配置文件3.6 验证依赖环境 4. 进一步优化与自动化处理结语 前言 在日常…

Apache storm UI如何更换默认8080端口

在搭建Apache storm环境的时候&#xff0c;遇到Apache storm UI默认端口是8080&#xff0c;但是这个端口会被其他java程序占用&#xff0c;导致Apache storm UI服务无法启动。报错Exception in thread “main” java.lang.RuntimeException: java.io.IOException: Failed to bi…

FPGA实现串口升级及MultiBoot(十)串口升级SPI FLASH实现

本文目录索引 工程架构example9工程设计Vivado设计Vitis设计example9工程验证1、读取FLASH ID2、擦除整个FLASH3、Blank-Check4、烧写Golden区位流5、读取FLASH内容6、烧写MultiBoot区位流(升级位流)7、MultiBoot区位流(升级位流)启动example10工程设计Vivado设计Vitis设计exam…

图解人工智能:从规则到深度学习的全景解析

&#x1f31f;作者简介&#xff1a;热爱数据分析&#xff0c;学习Python、Stata、SPSS等统计语言的小高同学~&#x1f34a;个人主页&#xff1a;小高要坚强的博客&#x1f353;当前专栏&#xff1a;Python之机器学习&#x1f34e;本文内容&#xff1a;图解人工智能&#xff1a;…

Binder架构

一、架构 如上图&#xff0c;binder 分为用户层和驱动层两部分&#xff0c;用户层有客户端&#xff08;Client&#xff09;、服务端&#xff08;Server&#xff09;、服务管理&#xff08;ServiceManager&#xff09;。 从用户空间的角度&#xff0c;使用步骤如下&#xff08;…

基于springboot中小型制造企业质量管理系统源码和论文

信息数据从传统到当代&#xff0c;是一直在变革当中&#xff0c;突如其来的互联网让传统的信息管理看到了革命性的曙光&#xff0c;因为传统信息管理从时效性&#xff0c;还是安全性&#xff0c;还是可操作性等各个方面来讲&#xff0c;遇到了互联网时代才发现能补上自古以来的…

Flutter 权限申请

这篇文章是基于permission_handler 10.2.0版本写的 前言 在App开发过程中我们经常要用到各种权限&#xff0c;我是用的是permission_handler包来实现权限控制的。 pub地址&#xff1a;https://pub.dev/packages/permission_handler permission_handler 权限列表 变量 Androi…

MATLAB期末复习笔记(下)

五、数据和函数的可视化 1.MATLAB的可视化对象 图形对象是 MATLAB用来创建可视化数据的组件。每个对象都有一个名为句柄 的唯一标识符。使用该句柄&#xff0c;您可以通过设置对象 属性 来操作现有图形对象的特征 ROOT: &#xff1a;即电脑屏幕 Figure &#xff1a;图窗…

web安全从0到1:burp-suite3

声明&#xff01; 学习视频来自B站up主 **泷羽sec** 有兴趣的师傅可以关注一下&#xff0c;如涉及侵权马上删除文章&#xff0c;笔记只是方便各位师傅的学习和探讨&#xff0c;文章所提到的网站以及内容&#xff0c;只做学习交流&#xff0c;其他均与本人以及泷羽sec团队无关&a…

深度学习:梯度下降法

损失函数 L&#xff1a;衡量单一训练样例的效果。 成本函数 J&#xff1a;用于衡量 w 和 b 的效果。 如何使用梯度下降法来训练或学习训练集上的参数w和b &#xff1f; 成本函数J是参数w和b的函数&#xff0c;它被定义为平均值&#xff1b; 损失函数L可以衡量你的算法效果&a…

Linux:文件系统inode

早期&#xff0c;存储文件的设备是磁盘&#xff08;当下的市场几乎都是SSD&#xff09;&#xff0c;但大家习惯的把它们都称为磁盘&#xff0c;磁盘是用来表示区分内存的存储设备。而在操作系统看来&#xff0c;这个存储设备的结构就是一个线性结构&#xff0c;这一点很重要。 …

94.【C语言】解析预处理(2)

目录 1.带有副作用的宏参数 代码 一个判断最大值的宏代码 运行结果 分析 "副作用"的解释 2.宏替换规则 解释 3.宏和函数的对比 附一张对比表 承接93.【C语言】解析预处理(1)文章 1.带有副作用的宏参数 代码 一个判断最大值的宏代码 #define MAX(a, b) (…