HuggingFace Transformers 基础组件之Model(上)
Reference:【HuggingFace Transformers-入门篇】基础组件之Model(上),Huggingface NLP Course
背景知识
Encoder & Decoder
补充一下Transformer的背景知识,简单来说,Transformer分为Encoder(编码器)和Decoder(解码器)两个部分,其中基于掩码的注意力机制是模型的重点,是面向seq2seq任务的,一些细节可以参考之前写的一个Transformer学习笔记。
现在大部分的预训练语言模型(PLMs)都是基于Transformer block的堆叠,堆叠的方式有三种:
- 基于Encoder,适合文本分类、命名实体识别、抽取式问答任务等;
- 基于Decoder,适合文本生成任务;
- 结合Encoder和Decoder,适合总结摘要、翻译、生成式问答任务等。
官网给出了这三种堆叠方式下的经典模型,如下图。 up在视频中也给出了这三类模型的简要介绍。
Model Head
对于model head,官网给出的解释是将高维向量映射映射到不同的维度上。我觉得可以理解为模型在output前经过的最后一层,通常为1或多个全连接层,作用是将模型的编码结果根据不同类型的任务映射成不同类型的内容。 调用模型本身只会返回一个基于这个模型的编码结果(hidden states),所以需要model head来当任务头。不同的model head对应不同的任务,有很多种选择:
- *Model(检索隐藏状态)
- *ForCausalLM
- *ForMaskedLM
- *ForMultipleChoice
- *ForQuestionAnswering
- *ForSequenceClassification
- *ForTokenClassification
基本使用
这次使用的模型是哈工大推出的三层Roberta模型,在官网可以找到,大小在一百多兆。(好在不大不然我这破机子真的跑不起来...)
模型的加载与保存
先导包。 1
from transformers import AutoConfig, AutoModel, AutoTokenizer
1
model = AutoModel.from_pretrained("hfl/rbt3", force_download=True)
还可以使用git clone的方式进行下载,模型会保存到当前目录的rbt3文件夹下。由于我没配置git,就没有尝试。总之第一种git方式是下了所有文件,第二种git方式是下载指定的pytorch版本的bin文件。
1 |
|
离线加载
如果模型比较大,网不好的话下载不了,可以采取离线下载的方式。也就是进到模型详情页把文件都下载下来。
可以看到有三个较大的文件,这三个文件时这个模型用不同框架实现的三个版本,即flax版、tensorflow版和pytorch版。我们用到的是pytorch版,因此其他两个版本模型不用下载,只要其他文件和pytorch版模型就行。下载后存储到指定路径中,即可进行加载。
1 |
|
我这里就是把模型保存在同一个目录下的文件夹内。
模型加载参数
加载模型后,可以看到模型本身的一些参数,可以对模型进行配置。
除此之外,还可以在训练过程中修改模型的一些参数,这里要调用AutoConfig
。
1 |
|
打印出来的结果和之前一样,但是输入config.的时候会出来很多选项,都是可以设置的参数。 这个模型是一个bert模型,所以可以进入BertConfig中去看更加具体的参数。而BertConfig又继承自PretrainConfig类,里面的参数同样可以进行配置。
1 |
|
以设置参数output_attentions
为例,如果调用模型时没有将它设置为True,可以看到模型会输出隐藏状态、池化结果等,但最后的attention都是none。
1 |
|
如果设置参数output_attentions=True
,则会输出attention。
1 |
|
模型调用
这里的return_tensors="pt"
是指定tokenizer返回pytorch
tensor形式的数据。 1
2
3sen = "弱小的我也有大梦想!"
tokenizer = AutoTokenizer.from_pretrained("hflrbt3")
inputs = tokenizer(sen, return_tensors="pt")
无Model Head的模型调用
AutoModel
不带model
head编码,模型实际上是对输入的序列进行编码,输出的编码结果就是last_hidden_state。
1 |
|
可以看到last_hidden_state的维度是112768,其中1是batch的维度(只有一个句子),12是这个句子中token的个数,也就是"input_ids"
的长度。
有Model Head的模型调用
AutoModelForSequenceClassification
就是一个带model
head编码的模型,它会将last_hidden_state从高维度向量映射成指定的低维向量,如这里指定num_label=10
,即十分类任务,就为映射成十维向量。
1
2
3
4from transformers import AutoModelForSequenceClassification, BertForSequenceClassification
clz_model = AutoModelForSequenceClassification.from_pretrained("hflrbt3", num_labels=10)
output = clz_model(**inputs)
至于能够通过修改num_label
就能修改映射维度,是因为这个模型是继承自Bert文本分类模型的,里面定义了将hidden_size
映射成num_label
的维度,所以可以这么做。
深入看下这个bert文本分类模型的细节,可以发现他就是三层连在一起,即bert层、dropout层和一个全连接层。
模型的input先经过forward函数,得到output,再将output中的池化结果取出来,也就是[CLS]的向量结果。这是因为在分类任务中,[CLS]是整个序列的类别标签,用于表示该序列所属类。在训练过程中,[CLS]充当预测目标,Bert通过预测[CLS]的类别来学习整个序列的语义信息,并将该类别作为整个序列的预测结果。
而后模型会对我们有没有输入label进行判断,进而判断这是回归任务、二分类任务还是多分类任务,并且根据不同的任务类型去计算loss。最后还指定了返回值的格式,如果没有指定以字典形式返回,则以默认方式返回。