transformers基础组件之Tokenizer

一:Tokenizer简介

tokenizer用来对数据进行预处理,以下是传统的数据预处理的步骤:

  1. 分词:使用分词器对文本数据进行分词(字、字词)
  2. 构建词典:根据数据集分词的结果,构建词典映射(这一步并不绝对,如果采用预训练词向量,词典映射要根据词向量文件进行处理)
  3. 数据转换:根据构建好的词典,将分词处理后的数据做映射,将文本序列转换为数字序列
  4. 数据填充与截断:在以batch输入到模型中的方式中,需要对过短的数据进行填充,过长的数据进行截断,保证数据长度符合模型能够接受的范围,同时batch内的数据维度大小一致。

举例:假设我们有以下文本数据:

文本1:我爱自然语言处理

文本2:自然语言处理是一门有趣的学科

  1. 分词

    使用分词器对文本进行分词,得到以下结果:

    文本1:["我", "爱", "自然", "语言", "处理"]

    文本2:["自然", "语言", "处理", "是", "一门", "有趣", "的", "学科"]
     
  2. 构建词典:

    根据分词结果构建词典映射:
    vocab = {
        "我": 0,
        "爱": 1,
        "自然": 2,
        "语言": 3,
        "处理": 4,
        "是": 5,
        "一门": 6,
        "有趣": 7,
        "的": 8,
        "学科": 9
    }
  3. 数据转换:

    根据词典将分词后的数据映射为数字序列:

    文本1:[0, 1, 2, 3, 4]

    文本2:[2, 3, 4, 5, 6, 7, 8, 9]
     
  4. 数据填充与截断:

    假设我们设定最大长度为 6。对文本进行填充和截断:

    文本1(长度为 5,填充到 6):[0, 1, 2, 3, 4, -1] (-1 表示填充)

    文本2(长度为 8,截断到 6):[2, 3, 4, 5, 6, 7]

  5. 最终结果:

    最终得到的批量数据可以是:

    batch_data = [
        [0, 1, 2, 3, 4, -1],  # 文本1
        [2, 3, 4, 5, 6, 7]    # 文本2
    ]

现在,以上这些操作流程可以使用tokenizer一步完成。

二:Tokenizer基本使用

from transformers import AutoTokenizer

sen = "弱小的我也有大梦想!"

Step1: 加载与保存

# 从HuggingFace加载,输入模型名称,即可加载对于的分词器
tokenizer = AutoTokenizer.from_pretrained("uer/roberta-base-finetuned-dianping-chinese")
tokenizer
# tokenizer 保存到本地
tokenizer.save_pretrained("./roberta_tokenizer")
# 从本地加载tokenizer
tokenizer = AutoTokenizer.from_pretrained("./roberta_tokenizer/")
tokenizer

Step2:句子分词

tokens = tokenizer.tokenize(sen)
tokens

输出结果:

['弱', '小', '的', '我', '也', '有', '大', '梦', '想', '!']

Step3: 查看词典

# 查看词典
tokenizer.vocab

输出结果是一个字典,key:字或字词, value:对应的数字id。以下是部分结果截图:

# 查看词典大小
tokenizer.vocab_size

输出:21128。 代表词典中有 21128 个键值对。

Step4: 索引转换

# 将词序列转换为id序列
ids = tokenizer.convert_tokens_to_ids(tokens)
ids

输出:[2483, 2207, 4638, 2769, 738, 3300, 1920, 3457, 2682, 106]

# 将id序列转换为token序列
tokens = tokenizer.convert_ids_to_tokens(ids)
tokens

输出:['弱', '小', '的', '我', '也', '有', '大', '梦', '想', '!']

# 将token序列转换为string
str_sen = tokenizer.convert_tokens_to_string(tokens)
str_sen

输出:弱小的我也有大梦想!

更便捷的实现方式:

# 将字符串转换为id序列,又称之为编码
ids = tokenizer.encode(sen, add_special_tokens=True)
ids

输出:[101, 2483, 2207, 4638, 2769, 738, 3300, 1920, 3457, 2682, 106, 102]

# 将id序列转换为字符串,又称之为解码。 
str_sen = tokenizer.decode(ids, skip_special_tokens=False) # skip_special_tokens=False表示解码时显示句子的开始和结束两个特殊token
str_sen

输出:[CLS] 弱小的我也有大梦想! [SEP]

Step5:填充与截断

# 填充
ids = tokenizer.encode(sen, padding="max_length", max_length=15)
ids

输出:[101, 2483, 2207, 4638, 2769, 738, 3300, 1920, 3457, 2682, 106, 102, 0, 0, 0]
从输出结果可以看出,原本的句子长度不足15,最后用数字0补充。

# 截断
ids = tokenizer.encode(sen, max_length=5, truncation=True)
ids

输出:[101, 2483, 2207, 4638, 102]
从输出结果可以看出,句子的长度被截断为5.

Step6:  其他输入部分

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

输出:

([101, 2483, 2207, 4638, 2769, 738, 3300, 1920, 3457, 2682, 106, 102, 0, 0, 0],
 [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0],
 [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])

其中,第1个列表是句子编码后的结果;第2个列表是attention_mask,1:代表关注,会计算注意力权重,0:与1的含义相反。因为最后三个token是用来填充的,所以在计算注意力权重时,不需要关注;第3个列表是token_type_ids,指明哪些token属于同一个句子。

Step7: 快速调用方式

# 方法1
inputs = tokenizer.encode_plus(sen, padding="max_length", max_length=15)
inputs

输出:

{'input_ids': [101, 2483, 2207, 4638, 2769, 738, 3300, 1920, 3457, 2682, 106, 102, 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, 1, 1, 1, 1, 1, 0, 0, 0]}
# 方法2
inputs = tokenizer(sen, padding="max_length", max_length=15)
inputs

输出:

{'input_ids': [101, 2483, 2207, 4638, 2769, 738, 3300, 1920, 3457, 2682, 106, 102, 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, 1, 1, 1, 1, 1, 0, 0, 0]}

Step8:处理batch数据

sens = ["弱小的我也有大梦想",
        "有梦想谁都了不起",
        "追逐梦想的心,比梦想本身,更可贵"]
res = tokenizer(sens)
res

输出:

{'input_ids': [[101, 2483, 2207, 4638, 2769, 738, 3300, 1920, 3457, 2682, 102], [101, 3300, 3457, 2682, 6443, 6963, 749, 679, 6629, 102], [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, 0, 0, 0, 0, 0, 0, 0, 0, 0]], 'attention_mask': [[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]]}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值