在之前提到过,标记器(tokenizer)是用来对文本进行预处理的一个工具。
首先,标记器会把输入的文档进行分割,将一个句子分成单个的word(或者词语的一部分,或者是标点符号)
这些进行分割以后的到的单个的word被称为tokens。
第二步,标记器会把这些得到的单个的词tokens转换成为数字,经过转换成数字之后,我们就可以把它们送入到模型当中。
为了实现这种能把tokens转换成数字的功能,标记器拥有一个词表,这个词汇表是在我们进行实例化并指明模型的时候下载的,这个标记器使用的词汇表与模型在预训练时使用的词汇表相同。
举个例子说:
from transformers import AutoTokenizer,AutoModelForSequenceClassification
Model_name = 'distillery-base-uncashed-finetuned-still-2-english'
model=AutoModelForSequenceClassification.from_pretrained(model_name)
tokenizer=AutoTokenizer.from_pretrained(model_name)
sentence="We are very happy to show you the Transformers library"
inputs = tokenizer(sentence)
然后打印一下得到的结果:
print(inputs)
{'input_ids': [101, 2057, 2024, 2200, 3407, 2000, 2265, 2017, 1996, 100, 19081, 3075, 1012, 102],
'attention_mask': [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]}
可以看到,返回值是一个字典,这个字典里面有两个键值对,第一个键值对'input_ids'是对输入的句子转换成数字以后的结果,并且长度为这个句子的单词的个数。
第二个'attention_mask'这里面全部都是1,表示让模型关注里面所有的词,具体相关的应用后面会再提到。
上面的例子是拿一个句子放入标记器中得到的结果,如果希望一次放入一批(batch)语句,希望将这一批句子都转换成为数字送到模型里面去,那么你可以这么做
sentences=["We are very happy to show you the Transformers library",
"We hope you don't hate it"]
Pt_batch = tokenizer(
Sentences,
padding=True,
truncation=True,
max_length=512,
return_tensors="Pt"
)
首先padding属性是用来指明是否启用填补。他会自动补全结果中的input_ids以及attention_mask右边缺失的值。
打印一下结果来看一下:
for key,value in pt_batch.items():
print(f"{key}:{value.numpy().tolist()}")
input_ids: [[101, 2057, 2024, 2200, 3407, 2000, 2265, 2017, 1996, 100, 19081, 3075, 1012, 102], [101, 2057, 3246, 2017, 2123, 1005, 1056, 5223, 2009, 1012, 102, 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, 0, 0, 0]]
可以看到结果中第二个句子的最右边补充了一些0,这是因为使用了padding属性,第二个句子没有第一个句子长,而我们希望得到的结果都是一样长的,所以会自动的在结尾补充0,并且在attention_mask字段里面也补充了0。
当我们对输入的数据使用标记器进行处理之后,可以直接把它送到模型当中,这些数据会包含所有模型需要的相关信息。
在使用pytorch的时候,你需要可以用下面的方法对字典类型进行解包:
Pt_outputs = pt_model(**pt_batch)
在Transformers中,所有的输出都是一个元组(tuple)
Print(pt_ourputs)
(tensor([[-4.0833, 4.3364],
[ 0.0818, -0.0418]], grad_fn=),)
可以看到得到的结果
接下来使用SoftMax激活函数进行预测,并打印一下最终的结果
Import torch.nn.functional as F
pt_predictions = F.softmax(py_output[0],dim=-1)
print(pt_predictions)
tensor([[2.2043e-04, 9.9978e-01],
[5.3086e-01, 4.6914e-01]], grad_fn=)
这里输出的只是经过了softmax函数后得到的结果,那么如果有标签的时候,需要在使用模型的时候,在label字段指明标签
import torch
pt_output = pt_model(**pt_batch,labels = torch.tensor([1,0]))
在Transformers提供了一个Trainer类来帮助训练
在模型进行微调之后,可以对模型以及标记器进行保存操作
save_directory='E:/my model/'
tokenizer.save_pretrained(save_directory)
model.save_pretrained(save_directory)
这样就可以将模型进行保存
如果想要重新加载之前训练好并保存的模型,可以使用一个from_pretrained()方法,通过传入保存了模型的文件夹路径。
tokenizer = AutoTokenizer.from_pretrained(save_directory)
model = AutoModel.from_pretrained(save_directory)
如果希望读取TensorFlow模型,那么需要一点点改变
model=AutoModel.from_pretrained(save_directory,from_tf=True)
最终,如果在使用模型的时候,你希望得到的不仅仅是最终的输出,还希望能得到所有的隐藏层状态以及注意力权重,你可以这样做:
pt_outputs = pt_model(**pt_batch,output_hidden_states= True,output_attentions=True)
All_hidden_states ,all_attentions = pt_outputs[-2:]
之前用到的AutoModel与AutoTokenizer两个类实际上可以和任何的预训练模型一起工作。
在之前的实例中,模型使用的是"distilbert-base-uncashed-finetuned-still-2-enghish",这意味着我们使用的是DistilBERT的结构。
在创建模型的时候用到的AutoModelForSequenceClassification会自动创建一个DistilBertForSequenceCLassification。
如果不使用自动的方式构建,我们可以使用下面的代码:
from transformers import DistilBertTokenizer,DistilBertForSequenceClassification
model_name = "distilbert-base-uncashed-fintuned-still-2-english"
model = DistilBertForSequenceClassification.from_pretrain(model_name)
tokenizer = DIstilBertTokenizer.from_pretrained(model_name)
如果希望改变的一些参数,来定义自己的特殊的类,那么可以使用模型特定的或者说相关的配置文件(configuration)比如说,在之前用熬的DistilBERT中,可以使用DistilBertConfig来设置隐藏层纬度,dropout rate等等。
具体来说:
from transformers import DIstilBertConfig,DIstilBertTokenizer,DistilBertForSequence
config = DistilBertTokenizer(n_heads=8,dim=512,hidden_dim=4*512)
tokenizer=DistilBertTokenizer.from_pretrained('distilbert-base-uncased')
model = DistilBertForSequenceClassification(config)
如果你希望改变的只是模型的头,比如说标签的数量,那么你只需要直接改变模型创建时候的参数即可
from transformers import DIstilBertConfig,DistilBertTokenizer,DistilBertForSequenceClassification
model_name='distilbert-base-uncased'
model = DistilBertForSequenceClassification.from_pretrained(model_name,num_labels=10)
tokenizer = DistilBertTokenizer.from_pretrained(model_name)