Tokenizer分词

news2025/1/3 5:24:02

分词的一般流程

在使用神经网络处理自然语言处理任务时,我们首先需要对数据进行预处理,将数据从字符串转换为神经网络可以接受的格式,一般会分为如下几步:

(1)分词:使用分词器对文本数据进行分词(字、字词)得到token;

(2)构建词典:根据数据集分词的结果,构建词典映射,形成一个vocabulary dict用于存放每一个token(这一步并不绝对,如果采用预训练词向量,词典映射要根据词向量文件进行处理),vocabulary dict形式如下:

{token1:0,token2:1,token3:2,token4:4........}

(3)数据转换:根据构建好的词典,将分词处理后的数据做映射,将文本序列转换为数字序列;

(4)数据填充与截断:在以batch输入到模型的方式中,需要对过短的数据进行填充,过长的数据进行截断,保证数据长度符合模型能接受的范围,同时batch内的数据维度大小一致。

分词的三种粒度

(1)粗糙的有词粒度(word)

例如“我来做中国”会被分成[我,来,自,中国]

优点:能够保存较为完整的语义信息

缺点:

1、词汇表会非常大,大的词汇表对应模型需要使用很大的embedding层,这既增加了内存,又增加了时间复杂度。通常,transformer模型的词汇量很少会超过50,000,特别是如果仅使用一种语言进行预训练的话,而transformerxl使用了常规的分词方式,词汇表高达267735;

2、 word-level级别的分词略显粗糙,无法发现更加细节的语义信息,例如模型学到的“old”, “older”, and “oldest”之间的关系无法泛化到“smart”, “smarter”, and “smartest”。

3、word-level级别的分词对于拼写错误等情况的鲁棒性不好;

4、 oov(out of vocabulary)问题不好解决,例如分词时数据集中只有cat,测试时遇到cats边无法处理

(2)精细的有字粒度(char)

例如“我来做中国”会被分成[我,来,自,中,国]

一个简单的方法就是将word-level的分词方法改成 char-level的分词方法,对于英文来说,就是字母界别的,比如 "China"拆分为"C","h","i","n","a",对于中文来说,"中国"拆分为"中","国",

优点:

1、这可以大大降低embedding部分计算的内存和时间复杂度,以英文为例,英文字母总共就26个,中文常用字也就几千个。

2、char-level的文本中蕴含了一些word-level的文本所难以描述的模式,因此一方面出现了可以学习到char-level特征的词向量FastText,另一方面在有监督任务中开始通过浅层CNN、HIghwayNet、RNN等网络引入char-level文本的表示;

缺点:

1、但是这样使得任务的难度大大增加了,毕竟使用字符大大扭曲了词的意义,一个字母或者一个单中文字实际上并没有任何语义意义,单纯使用char-level往往伴随着模型性能的下降;

2、增加了输入的计算压力,原本”I love you“是3个embedding进入后面的cnn、rnn之类的网络结构,而进行char-level拆分之后则变成 8个embedding进入后面的cnn或者rnn之类的网络结构,这样计算起来非常慢;

(3)现在最常用的是子词粒度sub-word,介于两者之间。

为了两全其美,transformer使用了混合了char-level和word-level的分词方式,称之为subword-level的分词方式。

subword-level的分词方式遵循的原则是:尽量不分解常用词,而是将不常用词分解为常用的子词

例如,"annoyingly"可能被认为是一个罕见的单词,并且可以分解为"annoying"和"ly"。"annoying"并"ly"作为独立的子词会更频繁地出现,同时,"annoyingly"是由"annoying"和"ly"这两个子词的复合含义构成的复杂含义,这在诸如土耳其语之类的凝集性语言中特别有用,在该语言中,可以通过将子词串在一起来形成(几乎)任意长的复杂词。

subword-level的分词方式使模型相对合理的词汇量(不会太多也不会太少),同时能够学习有意义的与上下文无关的表示形式(另外,subword-level的分词方式通过将词分解成已知的子词,使模型能够处理以前从未见过的词(oov问题得到了很大程度上的缓解)。

subword-level又分为不同的切法,这里就到huggingface的tokenizers的实现部分了,常规的char-level或者word-level的分词用spacy,nltk之类的工具包就可以胜任了。

subword的分词往往包含了两个阶段,一个是encode阶段,形成subword的vocabulary dict,一个是decode阶段,将原始的文本通过subword的vocabulary dict 转化为 token的index然后进入embedding层。主要是因为不同的model可能在分token层面做了一些微调,并且根据使用的语料的不同,最后的subword vocabulary dict也会不同。

transfomers中tokenizer使用示例

from transformers import AutoTokenizer

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

sentence = "我是中国人"
# 查看分词结果
tokens = tokenizer.tokenize(sentence)
print("tokens:\n", tokens)  #  ['我', '是', '中', '国', '人']

# 查看词典。词典是在预训练模型时就构建好了的
# print("词典\n", tokenizer.vocab)

# 根据词典将词序列转化为数字序列
ids = tokenizer.convert_tokens_to_ids(tokens=tokens)
print("ids\n", ids) # [2769, 3221, 704, 1744, 782]

# 直接调用encode方法也能实现上述目标,但会自动增加起始和终止数字序号
ids = tokenizer.encode(sentence)
print("ids\n", ids)  #[101, 2769, 3221, 704, 1744, 782, 102]

#填充
ids = tokenizer.encode(sentence, padding="max_length", max_length=12)
print("ids\n", ids)  # [101, 2769, 3221, 704, 1744, 782, 102, 0, 0, 0, 0, 0]

# 裁剪
ids = tokenizer.encode(sentence, max_length=5, truncation=True)
print("ids\n", ids)  #  [101, 2769, 3221, 704, 102]

# attention_mask 与 token_type_id
ids = tokenizer.encode(sentence, padding="max_length", max_length=15)
attention_mask = [1 if idx != 0 else 0 for idx in ids]
token_type_ids = [0] * len(ids)
print(attention_mask)  # [1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0]
print(token_type_ids)  # [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]

# 两种快速调用方式
# 快速调用方式1
inputs = tokenizer.encode_plus(sentence, padding="max_length", max_length=15)
print(inputs)
# {
# 'input_ids': [101, 2769, 3221, 704, 1744, 782, 102, 0, 0, 0, 0, 0, 0, 0, 0], 
# 'token_type_ids': [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], 
# 'attention_mask': [1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0]
# }

# 快速调用方式2, 直接调用tokenizer本身
inputs = tokenizer(sentence, padding="max_length", max_length=15)

# batch数据和单条数据使用方式是一模一样的
sens = ["我是中国人",
        "追逐梦想的心,比梦想本身,更可贵"]
res = tokenizer(sens, padding="max_length", max_length=12)
print(res)
#{'input_ids': [[101, 2769, 3221, 704, 1744, 782, 102, 0, 0, 0, 0, 0], 
#               [101, 6841, 6852, 3457, 2682, 4638, 2552, 8024, 3683, 3457, 2682, 3315, 6716, 8024, 3291, 1377, 6586, 102]], 
# 'token_type_ids': [[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], 
#                    [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]], 
# 'attention_mask': [[1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0],
#                    [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]]}

参考链接

tokenizers小结

Transformers中Tokenizer模块快速使用

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

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

相关文章

STM32CUBEMX 待机模式最简单的RTC定时唤醒(低功耗电池产品必备)

文章意义: 看到很多技术帖子讲述RTC定时唤醒功能的时候,老是需要去读取当前时间,再设定下一个闹钟唤醒时间,无形中多了很多变量和操作。所以我决定分享一种简单的RTC定时唤醒方法,适合于不需要实现具体时间获取的场合…

企业遇到知识管理困境该怎么办?这里有解决方案!寻找Baklib

随着企业业务不断扩大,员工数量的增加,知识管理成为了企业面临的一个重要问题。企业需要管理大量的知识,如产品手册、流程规范、客户信息等,这些知识对企业的生产和经营至关重要。但是,如何高效地管理这些知识&#xf…

LeetCode_双指针_中等_24.两两交换链表中的节点

目录 1.题目2.思路3.代码实现(Java) 1.题目 给你一个链表,两两交换其中相邻的节点,并返回交换后链表的头节点。你必须在不修改节点内部的值的情况下完成本题(即,只能进行节点交换)。 示例 1&a…

第40讲:Python for-in循环语句使用索引遍历序列

文章目录 方法一:遍历的是序列的元素方法二:遍历的是序列的索引方法三:while循环遍历实现方法四:调用内置函数enumerate实现1.什么是enumerate函数2.调用内置函数enumerate实现索引遍历序列 如果在遍历序列的过程中,需…

国产高端GPU,国产替代加速(附国产厂家汇总)

前言 2022年8月9日,壁仞科技在上海发布首款通用GPU芯片BR100,标志着中国企业第一次打破了此前一直由国际巨头保持的通用GPU全球算力纪录; 8月31日,美国政府命令芯片厂商英伟达(NVIDIA)以及超威半导体&…

借助 Google Play 游戏电脑版 Com2uS 为用户打造多平台无缝体验

作者 / Google Play 游戏总监 Arjun Dayal 吸引潜在用户在 PC 端畅享游戏 《魔灵召唤:克罗尼柯战记》是韩国游戏开发商 Com2uS 于 2023 年 3 月面向全球发布的一款移动端大型多人在线角色扮演游戏。迄今为止,《魔灵召唤》在全球的下载量超过 1.8 亿&…

Aztec:混合zkRollup,而非zkEVM

1. 引言 Aztec zkRollup为混合zkRollup: 支持通用私有计算的加密zkRollup(命名为Aztec):构建trustless、可扩展的、去中心化的Layer2 zkRollup,同时支持private smart contract execution。同时支持public state和pr…

C++ Primer阅读笔记--参数传递

目录 1--三种基本传递方式 2--数组形参 3--main函数传递参数 4--传递可变形参 1--三种基本传递方式 ① 值传递: 使用值传递时,初始值会拷贝给变量,对变量的改动不会改变初始值的值; ② 指针传递: 使用指针传递时&…

Mysql 查询性能优化

查看数据库用户连接数量 show processlist;分析表结构 索引 show index from conference;查询锁状态 show status like %lock%;是否开启慢查询 show variables like %slow_query_log%;日志查询默认情况下:slow_query_log的Value为OFF 如要开启慢查询日志&#…

2023最新软件测试面试题汇总

常见的面试题汇总 1、你做了几年的测试、自动化测试,说一下 selenium 的原理是什么? 我做了五年的测试,1年的自动化测试; selenium 它是用 http 协议来连接 webdriver ,客户端可以使用 Java 或者 Python 各种编程语言…

AI奇点将至 如何成为人工智能驱动型公司

‍数据智能产业创新服务媒体 ——聚焦数智 改变商业 2023年4月16日,中泰证券首席经济学家李迅雷先生发表了《奇点将至:AI或开启新一轮科技革命》的文章。李迅雷先生认为,以智能化为特征的第四次工业革命轮廓日渐清晰,在世界百年未…

Linux网络编程:socket、客户端服务器端使用socket通信

socket socket(套接字),用于网络中不同主机间进程的通信。 socket是一个伪文件,包含读缓冲区、写缓冲区。 socket必须成对出现。 socket可以建立主机进程间的通信,但需要协议(IPV4、IPV6等)…

[230507]托福听力真题TPO66词汇 |无重复|20:50~21:55 + 8:00~8:30

目录 conversation 1 conversation 2 ​ TPO66 Lecture ppt词汇 TPO66 Lecture 笔记词汇 conversation 1 conference / ˈkɑːnfərəns /n 会议terrific / təˈrɪfɪk /adj 极好的presentation / ˌpriːz(ə)nˈteɪʃ…

发送Ajax get请求详解

发送AJAX get请求&#xff0c;前端代码&#xff1a; <!DOCTYPE html> <html lang"en"> <head> <meta charset"UTF-8"> <title>ajax get请求</title> </head> <body> <script type"text/java…

第三十一章 Unity骨骼动画

关于骨骼动画的原理&#xff0c;我们这里不再详细介绍&#xff0c;有不清楚的可以回去看DirectX课程和3dsMAX课程。接下来&#xff0c;我们来讲解一下Unity的骨骼动画系统。Unity 的动画系统基于动画剪辑&#xff08;Animation Clip&#xff09;的概念&#xff0c;它的本质就是…

Linux 安装时,各个分区的作用是什么?

在这里&#xff0c;我说说一开始Linux为什么需要分区。 因为 Linux 是一个多用户操作系统。 多用户意味着一个问题&#xff1a;并非所有用户的操作都是可控的。 而系统正常运行的话&#xff0c;必须要一定的剩余空间。 这也就意味着&#xff1a;如果一个用户自己把空间占满…

MySQL数据库之用户管理

一、数据库用户管理 1.1 新建用户 CREATE USER 用户名来源地址 [IDENTIFIED BY [PASSWORD] 密码]; 即&#xff1a;create user 用户名源地址 identified by 密码; 用户名&#xff1a; 指定将创建的用户名 来源地址&#xff1a; 指定新创建的用户可在哪些主机上登录&…

线段树练习题(日程安排表、LC-307、LC-2407、LC-699)

线段树详解&#xff1a;https://leetcode.cn/problems/range-module/solution/by-lfool-eo50/ 文章目录 线段树线段树模板[729. 我的日程安排表 I](https://leetcode.cn/problems/my-calendar-i/)[731. 我的日程安排表 II](https://leetcode.cn/problems/my-calendar-ii/)[732.…

数据库基础及用户管理授权

数据库概念 关系型数据库 数据结构二维表格 库 -> 表 -> 列&#xff08;字段&#xff09;&#xff1a;用来描述对象的的一个属性&#xff1b;行&#xff1a;用来描述一个对象的信息 mysql&#xff08;5.7/8.0&#xff09; maridb ocracle postgresql sqlserver(windows…

2D火焰特效

Unity面片实现火焰效果 一、效果说明 大家好&#xff0c;我是阿赵。这是一个火焰的效&#xff0c;不过它不是粒子做的&#xff0c;是用一个面片做的&#xff0c;可以理解成是2D的特效。这个例子很简单&#xff0c;但可以拓展一下思路&#xff0c;原来除了用序列帧和粒子做动画…