预训练模型
Hugging face 简介
Hugging face 是一家总部位于纽约的聊天机器人初创服务商,开发的应用在青少年中颇受欢迎,相比于其他公司,Hugging Face更加注重产品带来的情感以及环境因素。官网链接在此 https://huggingface.co/ 。
但更令它广为人知的是Hugging Face专注于NLP技术,拥有大型的开源社区。尤其是在github上开源的自然语言处理,预训练模型库 Transformers,已被下载超过一百万次,github上超过24000个star。Transformers 提供了NLP领域大量state-of-art的 预训练语言模型结构的模型和调用框架。以下是repo的链接(https://github.com/huggingface/transformers)
这个库最初的名称是pytorch-pretrained-bert,它随着BERT一起应运而生。Google2018年10月底在 https://github.com/google-research/bert 开源了BERT的tensorflow实现。当时,BERT以其强劲的性能,引起NLPer的广泛关注。几乎与此同时,pytorch-pretrained-bert也开始了它的第一次提交。pytorch-pretrained-bert 用当时已有大量支持者的pytorch框架复现了BERT的性能,并提供预训练模型的下载,使没有足够算力的开发者们也能够在几分钟内就实现 state-of-art-fine-tuning。
因为pytorch框架的友好,BERT的强大,以及pytorch-pretrained-bert的简单易用,使这个repo也是受到大家的喜爱,不到10天就突破了1000个star。在2018年11月17日,repo就实现了BERT的基本功能,发布了版本0.1.2。接下来他们也没闲着,又开始将GPT等模型也往repo上搬。在2019年2月11日release的 0.5.0版本中,已经添加上了OpenAI GPT模型,以及Google的TransformerXL。
直到2019年7月16日,在repo上已经有了包括BERT,GPT,GPT-2,Transformer-XL,XLNET,XLM在内六个预训练语言模型,这时候名字再叫pytorch-pretrained-bert就不合适了,于是改成了pytorch-transformers,势力范围扩大了不少。这还没完!2019年6月Tensorflow2的beta版发布,Huggingface也闻风而动。为了立于不败之地,又实现了TensorFlow 2.0和PyTorch模型之间的深层互操作性,可以在TF2.0/PyTorch框架之间随意迁移模型。在2019年9月也发布了2.0.0版本,同时正式更名为 transformers 。到目前为止,transformers 提供了超过100种语言的,32种预训练语言模型,简单,强大,高性能,是新手入门的不二选择。
Transfromers中BERT简单运用
前几期里,一直在分享论文的阅读心得,虽然不是第一次看,但不知道大家是不是和我一样又有所收获。本期我们一起来看看如何使用Transformers包实现简单的BERT模型调用。
安装过程不再赘述,比如安装2.2.0版本 pip install transformers==2.2.0 即可,让我们看看如何调用BERT。
1 | import torch |
可以看到,包括import在内的不到十行代码,我们就实现了读取一个预训练过的BERT模型,来encode我们指定的一个文本,对文本的每一个token生成768维的向量。如果是二分类任务,我们接下来就可以把第一个token也就是[CLS]的768维向量,接一个linear层,预测出分类的logits,或者根据标签进行训练。
如果你想在一些NLP常用数据集上复现BERT的效果,Transformers上也有现成的代码和方法,只要把数据配置好,运行命令即可,而且finetune的任务可以根据你的需要切换,非常方便。
BERT configuration
接下来,我们进一步看下Transformers的源码,我们首先进入代码的路径src/transformers 下,其中有很多的python代码文件。
以 configuration 开头的都是各个模型的配置代码,比如 configuration_bert.py。在这个文件里我们能够看到,主要是一个继承自 PretrainedConfig 的类 BertConfig的定义,以及不同BERT模型的config文件的下载路径,下方显示前三个。
1 | BERT_PRETRAINED_CONFIG_ARCHIVE_MAP = { |
我们打开第一个的链接,就能下载到bert-base-uncased的模型的配置,其中包括dropout, hidden_size, num_hidden_layers, vocab_size 等等。比如bert-base-uncased的配置它是12层的,词典大小30522等等,甚至可以在config里利用output_hidden_states配置是否输出所有hidden_state。
1 | { |
BERT tokenization
以tokenization开头的都是跟vocab有关的代码,比如在 tokenization_bert.py 中有函数如whitespace_tokenize,还有不同的tokenizer的类。同时也有各个模型对应的vocab.txt。从第一个链接进去就是bert-base-uncased的词典,这里面有30522个词,对应着config里面的vocab_size。
其中,第0个token是[pad],第101个token是[CLS],第102个token是[SEP],所以之前我们encode得到的 [101, 2182, 2003, 2070, 3793, 2000, 4372, 16044, 102] ,其实tokenize后convert前的token就是 ['[CLS]', 'here', 'is', 'some', 'text', 'to', 'en', '##code', '[SEP]'],经过之前BERT论文的介绍,大家应该都比较熟悉了。
其中值得一提的是,BERT的vocab预留了不少unused token,如果我们会在文本中使用特殊字符,在vocab中没有,这时候就可以通过替换vacab中的unused token,实现对新的token的embedding进行训练。
1 | PRETRAINED_VOCAB_FILES_MAP = { |
BERT modeling
以modeling开头的就是我们最关心的模型代码,比如 modeling_bert.py。同样的,文件中有许多不同的预训练模型以供下载,我们可以按需获取。
代码中我们可以重点关注BertModel类,它就是BERT模型的基本代码。我们可以看到它的类定义中,由embedding,encoder,pooler组成,forward时顺序经过三个模块,输出output。
1 | class BertModel(BertPreTrainedModel): |
BertEmbeddings这个类中可以清楚的看到,embedding由三种embedding相加得到,经过layernorm 和 dropout后输出。
1 | def __init__(self, config): |
BertEncoder主要将embedding的输出,逐个经过每一层Bertlayer的处理,得到各层hidden_state,再根据config的参数,来决定最后是否所有的hidden_state都要输出,BertLayer的内容展开的话,篇幅过长,读者感兴趣可以自己一探究竟。
1 | class BertEncoder(nn.Module): |
Bertpooler 其实就是将BERT的[CLS]的hidden_state 取出,经过一层DNN和Tanh计算后输出。
1 | class BertPooler(nn.Module): |
在这个文件中还有上述基础的BertModel的进一步的变化,比如BertForMaskedLM,BertForNextSentencePrediction这些是Bert加了预训练头的模型,还有BertForSequenceClassification, BertForQuestionAnswering 这些加上了特定任务头的模型。
- "Here is some text to encode"加上CLS和SEP也才八个,因为Bert的tokenizer使用了wordpiece 算法,
这句话在tokenize了以后是下面这样的['here', 'is', 'some', 'text', 'to', 'en', '##code'],加上[CLS]和[SEP]就变成了9个token。
with torch.no_grad(): last_hidden_states = model(input_ids)[0]
这里的[0], 原因是模型输出是 seq_output, pooled_output,这里取的是seq_output。
sequence_output = encoder_outputs[0]
这边的[0]是因为 取得是模型最后一层的state(因为在元组里,最后一层的state放在最上面了)
first_token_tensor = hidden_states[:, 0]
pooler里面这边的0是因为 想要取的是 整个序列第一个token也就是[CLS] token的state
基本原理
使用的基本原理也非常简单,from_pretrained的参数pretrained_model_name_or_path,可以接受的参数有几种,short-cut name(缩写名称,类似于gpt2这种)、identifier name(类似于microsoft/DialoGPT-small这种)、文件夹、文件。
对于short-cut name或identifier name,这种情况下,本地有文件,可以使用本地的,本地没有文件,则下载。(上面的例子就是没有下载文件,直接用的是short-cut name)。一些常用的short-cut name,可以从这个链接查看:https://huggingface.co/transformers/pretrained_models.html。
对于文件夹,则会从文件夹中找vocab.json、pytorch_model.bin、tf_model.h5、merges.txt、special_tokens_map.json、added_tokens.json、tokenizer_config.json、sentencepiece.bpe.model等进行加载。所以这也是为什么下载的时候,一定要保证这些名称是这几个,不能变。
对于文件,则会直接加载文件。
官方给的样例,通常都是short-cut name,这里操作就是替换成下载好文件的文件夹。至此,我们完成了模型、词典等各种文件的本地加载。
具体操作如下:
模型库
官网的模型库的地址如下:https://huggingface.co/models
使用模型
首先需要安装transformers
库,使用以下命令安装:
1 | pip install transformers |
接下来在代码中调用AutoTokenizer.from_pretrained
和AutoModel.from_pretrained
即可例如:
1 | from transformers import * |
运行后系统会自动下载相关的模型文件并存放在电脑中:
使用Windows模型保存的路径在C:\Users\[用户名]\.cache\torch\transformers\
目录下,根据模型的不同下载的东西也不相同
使用Linux模型保存的路径在~/.cache/torch/transformers/
目录下
存在的问题
这些前提是你的电脑有网络可以直接使用代码下载相应的模型文件,但是问题是有些机器是没有外网连接权限或者下载速度非常慢。
这时候就需要把模型文件下载后在导入代码中,还是以刚才的hfl/chinese-xlnet-base模型为例,直接在官网搜索模型,点击进入模型的详情界面
在界面中找到List all files in model
把弹窗内的文件全部下载下来
我们假设文件保存在E:\models\hfl\chinese-xlnet-base\
目录下
我们只需要把model_name
修改为下载的文件夹即可
1 | from transformers import * |
参考
使用transformers预训练模型
⭐ https://zhuanlan.zhihu.com/p/120315111
⭐https://zhuanlan.zhihu.com/p/147144376
https://zhuanlan.zhihu.com/p/274509234
关于hugging face/transformers的介绍