赞
踩
基于 NLP-transformer学习:(1),这里对transformer 更近一步,学习尝试使用tokenizer,这些也是 NLP任务的基础之一
提示:以下是本篇文章正文内容,下面案例可供参考
在之前的NLP任务,做数据处理非常的麻烦,需要讲文字类数据进行分词。然后根据分词结果构建一个词典,然后统计不同词的频度,还要过滤下,把没用的滤掉。
由于伸进网络无法直接识词语,因此需要根据词典将输入的文本映射成次的向量,所以就需要一个tokenizer
数据预处理:
第一步:分词:将语句分成token,比如 I eat hamburger. j即为[I] [eat] [hamburger]
第二步:映射:根据分词结果,和词典,构建句子和词典的映射
第三步:转换:将文本序列转为数字序列,,因此[I] [eat] [hamburger] 映射为 [2018] [101] [19471]
第四步:填充截断:一个batch中,对过短的数据填充,对过长的数据截断,保证输入数据范围是模型可接受的范围,同时batch 内部的数据维度大小一致。
上述这些,transformer 统统都做好了,我们就是使用。
代码:
from transformers import AutoTokenizer
if __name__ == "__main__":
sentense = "我爱吃羊肉泡馍和肉夹馍!"
# load the tokenizer
tokenizer = AutoTokenizer.from_pretrained("uer/roberta-base-finetuned-dianping-chinese")
print(tokenizer)
# save the tokenizer to local path
tokenizer.save_pretrained("./roberta_tokenizer")
# load tokenizer from local path
tokenizer = AutoTokenizer.from_pretrained("./roberta_tokenizer/")
运行结果:
同理,第一次要下载,再运行一次就好了:
代码:
# luanch the tokenizer
tokens = tokenizer.tokenize(sentense)
print(tokens)
print(tokenizer.vocab_size)
运行结果:
当前的 这个模型是将句子在分词时分成一个字一个字的,还有其他模型可以按照词组分。
代码:
# show the vecab
print(tokenizer.vocab)
运行结果:
其中有些字是一个次,有些字是带个井号是因为为了减少词典,会将一个词拆成字词。
代码:
# convert the tokens into ids
ids = tokenizer.convert_tokens_to_ids(tokens)
print(ids)
# convert ids into tokens
tokens = tokenizer.convert_ids_to_tokens(ids)
print(tokens)
# convert the token into sentense
str_sentense = tokenizer.convert_tokens_to_string(tokens)
print(str_sentense)
运行结果:
注意:
第1行是将sentense 直接转化为tokens的结果
第2行是将tokens转为ids的结果
第3行是将ids的结果再转为tokens
第4行是讲token再变为句子
按照上述过就是之前的NLP方法,比较麻烦
huggingface 提供了更简洁的方法:
# encoder
ids = tokenizer.encode(sentense, add_special_tokens=True)
print(ids)
# decoder
str_sentense = tokenizer.decode(ids, skip_special_tokens=False)
print(str_sentense)
运行结果:
注意这里我的编码是 2760而感叹号是106,这里多了开头和结尾。
代码:
# fill
ids = tokenizer.encode(sentense, padding="max_length", max_length=20)
print("fill:" + str(ids))
# clip
ids = tokenizer.encode(sentense, max_length=5, truncation=True)
print("clip:" + str(ids))
运行结果:
注意这里fill 用0进行了填充
截断则是直接截断
在transformer 的论文中,mask 使用与在训练是不会提前知道结果进而训练错误,因此需要mask,
# clip
ids = tokenizer.encode(sentense, max_length=5, truncation=True)
print("clip:" + str(ids))
# fill
ids = tokenizer.encode(sentense, padding="max_length", max_length=20)
print("fill:" + str(ids))
#mask
attention_mask = [1 if idx != 0 else 0 for idx in ids]
token_type_ids = [0] * len(ids)
print(ids)
print(attention_mask)
print(token_type_ids)
运行结果:
代码:
# advanced tokenizer
inputs = tokenizer.encode_plus(sentense, padding="max_length", max_length=20)
print(inputs)
inputs = tokenizer(sentense, padding="max_length", max_length=20)
print(inputs)
运行结果:
数据处理时,使用batch的方式处理是最快的
# batchh import time print("batch test:") text = ["我爱吃泡馍", "吃泡馍前要先洗手然后用手掰馍", "泡馍可以有羊肉泡馍和牛肉泡馍", "吃泡馍时还要配有糖蒜", "糖蒜可以解腻", "吃完泡馍可以要一碗高汤"] start = time.time() tokens = tokenizer(text, padding="max_length", max_length=20) end = time.time() print("deal with batch:" + str(end - start)) # loop start = time.time() for i in range(len(text)): tokens = tokenizer(text[i], padding="max_length", max_length=20) end = time.time() print("deal with loop :" + str(end - start))
运行结果:
在处理数据时,用batch的方式会快一些,其实快很多,只是我这里据的例子过于简短。
fast tokenizer 是用rust 语言实现的,速度快。
slow tokenizer 使用 python 语言实现的,速度慢。
# fast
fast_tokenizer = AutoTokenizer.from_pretrained("uer/roberta-base-finetuned-dianping-chinese")
# slow
slow_tokenizer = AutoTokenizer.from_pretrained("uer/roberta-base-finetuned-dianping-chinese", use_fast=False)
这个没啥就是使用细节,能用快的就用快的。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。