Transformers 简介(下)
作者|huggingface
编译|VK
来源|Github
Transformers是TensorFlow 2.0和PyTorch的最新自然语言处理库
Transformers(以前称为pytorch-transformers和pytorch-pretrained-bert)提供用于自然语言理解(NLU)和自然语言生成(NLG)的最先进的模型(BERT,GPT-2,RoBERTa,XLM,DistilBert,XLNet,CTRL …) ,拥有超过32种预训练模型,支持100多种语言,并且在TensorFlow 2.0和PyTorch之间具有深厚的互操作性。
微调和使用脚本
在运行微调脚本之前,设置你的环境来运行示例。
这个库包含了几个SOTA执行NLU和NLG任务的例子脚本:
run_glue.py
:对Bert、XLNet和XLM在9个不同的GLUE任务上进行微调的示例(序列级分类)run_squad.py
:对Bert、XLNet和XLM在问题回答数据集集SQuAD 2.0上进行微调的示例(词语级别分类)run_generation.py
:一个使用GPT、GPT-2、CTRL、Transformer-XL和XLNet生成语言的例子- 其他特定于模型的示例(参见文档)。
以下是这三个脚本的快速使用示例:
run_glue.py
: 微调GLUE任务的序列级分类
通用语言理解评估(GLUE)基准测试是一个包含九个句子或句子对的语言理解任务的集合,用于评估和分析自然语言理解系统。
在运行这些GLUE任务之前,你应该下载
GLUE数据
https://gluebenchmark.com/tasks
这个脚本
https://gist.github.com/W4ngatang/60c2bdb54d156a41194446737ce03e2e
解压到某个目录$GLUE_DIR
。
你应该安装例子所需的额外软件包:
pip install -r ./examples/requirements.txt
export GLUE_DIR=/path/to/glue
export TASK_NAME=MRPC
python ./examples/run_glue.py \
--model_type bert \
--model_name_or_path bert-base-uncased \
--task_name $TASK_NAME \
--do_train \
--do_eval \
--do_lower_case \
--data_dir $GLUE_DIR/$TASK_NAME \
--max_seq_length 128 \
--per_gpu_eval_batch_size=8 \
--per_gpu_train_batch_size=8 \
--learning_rate 2e-5 \
--num_train_epochs 3.0 \
--output_dir /tmp/$TASK_NAME/
其中任务名可以是CoLA, SST-2, MRPC, STS-B, QQP, MNLI, QNLI, RTE, WNLI。
dev集结果将出现在指定的output_dir中的文本文件’eval_results.txt’。对于MNLI,由于有两个独立的开发集,匹配的和不匹配的,除了“/tmp/MNLI/”之外,还有一个单独的输出文件夹,称为“/tmp/MNLI-MM/”。
在STS-B回归任务上微调XLNet模型
这个示例代码使用一个具有4个V100 gpu的服务器上的并行训练对STS-B语料库上的XLNet进行微调。
并行训练是一种使用多个gpu的简单方法(但是比分布式训练更慢,灵活性更差,见下文)。
export GLUE_DIR=/path/to/glue
python ./examples/run_glue.py \
--model_type xlnet \
--model_name_or_path xlnet-large-cased \
--do_train \
--do_eval \
--task_name=sts-b \
--data_dir=${GLUE_DIR}/STS-B \
--output_dir=./proc_data/sts-b-110 \
--max_seq_length=128 \
--per_gpu_eval_batch_size=8 \
--per_gpu_train_batch_size=8 \
--gradient_accumulation_steps=1 \
--max_steps=1200 \
--model_name=xlnet-large-cased \
--overwrite_output_dir \
--overwrite_cache \
--warmup_steps=120
因此,在这台机器上,我们的batch大小为32,如果你有一台更小的机器,请增加gradient_accumulation_steps
以达到相同的batch大小。这些超参数将导致开发集的Pearson相关系数+0.917
。
对MRPC分类任务的Bert模型进行微调
此示例代码使用8个V100 gpu上的分布式训练,对Microsoft Research的释义语料库(MRPC)上的Bert词屏蔽模型进行微调,以达到F1 > 92。
python -m torch.distributed.launch --nproc_per_node 8 ./examples/run_glue.py \
--model_type bert \
--model_name_or_path bert-large-uncased-whole-word-masking \
--task_name MRPC \
--do_train \
--do_eval \
--do_lower_case \
--data_dir $GLUE_DIR/MRPC/ \
--max_seq_length 128 \
--per_gpu_eval_batch_size=8 \
--per_gpu_train_batch_size=8 \
--learning_rate 2e-5 \
--num_train_epochs 3.0 \
--output_dir /tmp/mrpc_output/ \
--overwrite_output_dir \
--overwrite_cache \
利用这些超参数进行训练,得到以下结果:
acc = 0.8823529411764706
acc_and_f1 = 0.901702786377709
eval_loss = 0.3418912578906332
f1 = 0.9210526315789473
global_step = 174
loss = 0.07231863956341798
run_squad.py
:对在SQuAD进行fine-tuning
这个示例代码使用8个V100 gpu上的分布式训练和BERT全字屏蔽无大小写模型对班组数据集上的BERT进行微调,以达到F1 > 93:
python -m torch.distributed.launch --nproc_per_node=8 ./examples/run_squad.py \
--model_type bert \
--model_name_or_path bert-large-uncased-whole-word-masking \
--do_train \
--do_eval \
--do_lower_case \
--train_file $SQUAD_DIR/train-v1.1.json \
--predict_file $SQUAD_DIR/dev-v1.1.json \
--learning_rate 3e-5 \
--num_train_epochs 2 \
--max_seq_length 384 \
--doc_stride 128 \
--output_dir ../models/wwm_uncased_finetuned_squad/ \
--per_gpu_eval_batch_size=3 \
--per_gpu_train_batch_size=3 \
利用这些超参数进行训练,得到以下结果:
python $SQUAD_DIR/evaluate-v1.1.py $SQUAD_DIR/dev-v1.1.json ../models/wwm_uncased_finetuned_squad/predictions.json
{"exact_match": 86.91579943235573, "f1": 93.1532499015869}
这个模型以bert-large-uncased-whole-word-masking-finetuned-squad
提供。
run_generation.py
使用GPT、GPT-2、CTRL、Transformer-XL和XLNet生成文本
其中还包括一个条件生成脚本,用于从提示符生成文本。
生成脚本包括由Aman Rusia提出的技巧,以获得使用Transformer-XL和XLNet等高质量生成模型(包括使短输入变长的预定义文本)。
下面是运行脚本与小版本的OpenAI GPT-2模型:
python ./examples/run_generation.py \
--model_type=gpt2 \
--length=20 \
--model_name_or_path=gpt2 \
从Salesforce的CTRL模型:
python ./examples/run_generation.py \
--model_type=ctrl \
--length=20 \
--model_name_or_path=ctrl \
--temperature=0 \
--repetition_penalty=1.2 \
快速浏览模型共享
从v2.2.2
开始,你现在可以使用库中内置的CLI,向社区上传和共享经过调优的模型。
首先,在https://huggingface.co/join上创建一个帐户。然后:
transformers-cli login
# 使用与huggingface.co上相同的凭据登录
上传模型
transformers-cli upload ./path/to/pretrained_model/
#上传包含权重/分词/配置的文件夹
# 通过.save_pretrained()`保存
transformers-cli upload ./config.json [--filename folder/foobar.json]
# 上传单个文件
# 你可以选择覆盖其文件名,该文件名可以嵌套在文件夹中
你的模型将通过它的标识符来访问,你的用户名和上面的文件夹名的连接:
"username/pretrained_model"
在model_cards/
下请添加README.md model card用于的repo,包括:模型描述、训练参数(数据集、预处理、超参数)、评估结果、预期用途和限制等。
你的模型现在有了一个关于huggingface的页面。
任何人都可以从代码加载:
tokenizer = AutoTokenizer.from_pretrained("username/pretrained_model")
model = AutoModel.from_pretrained("username/pretrained_model")
列出所有S3上的文件:
transformers-cli s3 ls
你也可以删除不需要的文件:
transformers-cli s3 rm …
快速浏览管道
新版本“v2.3”:Pipeline
是高级对象,它自动处理标记化,通过转换器模型运行数据并将结果输出到一个结构化对象中。
你可以为下列下游任务创建“管道”对象:
feature-extraction
:为输入序列生成一个张量表示ner
:为输入序列中的每个单词生成命名实体映射。sentiment-analysis
:给出整个输入序列的情感分析(正/负)。text-classification
:直接初始化一个TextClassificationPipeline
,或者查看sentiment-analysis
。question-answer
:提供一些上下文和一个与上下文相关的问题,它将提取上下文中的问题的答案。fill-mask
:接受包含掩码标记(例如)的输入序列,并返回最可能填充序列的列表及其概率。
from transformers import pipeline
# 为情感分析分配一个管道
nlp = pipeline('sentiment-analysis')
nlp('We are very happy to include pipeline into the transformers repository.')
>>> {'label': 'POSITIVE', 'score': 0.99893874}
# 分配一个用于回答问题的管道
nlp = pipeline('question-answering')
nlp({
'question': 'What is the name of the repository ?',
'context': 'Pipeline have been included in the huggingface/transformers repository'
})
>>> {'score': 0.28756016668193496, 'start': 35, 'end': 59, 'answer': 'huggingface/transformers'}
从pytorch-transformer迁移到transformer
以下是从pytorch-transformer
迁移到transformer
时应该注意的事项的快速摘要。
一些模型的关键输入参数(attention_mask
,token_type_ids
…)改变了
为了能够使用Torchscript(参见#1010,#1204和#1195),某些模型的特定顺序关键输入 (attention_mask
, token_type_ids
…)已经改变。
如果你曾经使用关键字参数的关键字名称来调用模型,例如。model(inputs_ids, attention_mask=attention_mask, token_type_ids=token_type_ids)
,这应该不会导致任何更改。
如果你使用关键字参数的位置输入来调用模型,例如model(inputs_ids, attention_mask, token_type_ids),你可能需要仔细检查输入参数的确切顺序。
从pytorch-pretrained-bert到transformers
下面是一个简短的总结,告诉你从pytorch-pretrained-bert
到transformers
时应该注意什么。
模型总是输出tuples
从pytorch-pretrained-bert
迁移到transformers
时,主要的中断变化是每个模型的forward方法总是输出一个“tuple”,其中包含依赖于模型和配置参数的各种元素。
每个模型的元组的确切内容在模型的文档字符串和文档中有详细说明
在几乎所有的情况下,只要将输出的第一个元素作为之前在pytorch-pretrained-bert
中使用的输出就可以了。
这里有一个pytorch-pretrained-bert
转换为transformers
的例子,用于BertForSequenceClassification
分类模型:
# 加载模型
model = BertForSequenceClassification.from_pretrained('bert-base-uncased')
# 如果你以前在pytorch-pretrained-bert中使用此行:
loss = model(input_ids, labels=labels)
# 现在,只需在transformers中使用此即可从输出元组中提取损失:
outputs = model(input_ids, labels=labels)
loss = outputs[0]
# 在transformers中,你还可以访问logits:
loss, logits = outputs[:2]
# 甚至是注意力权重,如果你将模型配置为输出它们(以及其他输出,也请参阅文档字符串和文档)
model = BertForSequenceClassification.from_pretrained('bert-base-uncased', output_attentions=True)
outputs = model(input_ids, labels=labels)
loss, logits, attentions = outputs
用隐藏状态
通过启用配置选项output_hidden_states
,可以检索编码器的最后隐藏状态。在pytorch-transformers
和transformers
中,返回值略有变化:all_hidden_states
现在还包括嵌入的隐藏状态,以及编码层的隐藏状态。这使用户可以轻松访问嵌入的最终状态。
序列化
from_pretrained()
方法的重大更改:
-
现在,在使用
from_pretrained()
方法实例化时,默认情况下将模型设置为评估模式。要训练它们,不要忘记将它们重新设置为训练模式(model.train()
)以激活退出模块。 -
提供给
from_pretrained()
方法的附加* input
和** kwargs
参数曾经被直接传递给基类__init __()方法。现在,它们被用来更新模型配置属性,这可以破坏基于先前的BertForSequenceClassification
示例构建的派生模型类。我们正在努力通过转发模型的__init __()方法来减轻重大变化
同样,虽然没有什么大的变化,但是序列化方法已经标准化,如果以前使用过任何其他序列化方法,则可能应该切换到新方法save_pretrained(save_directory)
。这是一个例子:
### 加载一个模型和分词器
model = BertForSequenceClassification.from_pretrained('bert-base-uncased')
tokenizer = BertTokenizer.from_pretrained('bert-base-uncased')
### 对我们的模型和分词进行一些处理
tokenizer.add_tokens(['[SPECIAL_TOKEN_1]', '[SPECIAL_TOKEN_2]'])
model.resize_token_embeddings(len(tokenizer))
# 训练模型
train(model)
### 现在让我们将模型和分词器保存到目录中
model.save_pretrained('./my_saved_model_directory/')
tokenizer.save_pretrained('./my_saved_model_directory/')
### 重新加载模型和分词器
model = BertForSequenceClassification.from_pretrained('./my_saved_model_directory/')
tokenizer = BertTokenizer.from_pretrained('./my_saved_model_directory/')
优化器:BertAdam和OpenAIAdam现在改成AdamW,schedules是标准的PyTorch schedules
以前包括的两个优化器,BertAdam
和OpenAIAdam
,已由单个的AdamW
优化器代替,但有一些区别:
- 仅实现权重衰减校正,
- schedules现在是外部的(请参阅下文),
- 梯度裁剪现在也是外部的(请参阅下文)。
新的优化器AdamW
与PyTorchAdam
优化器API匹配,可让你使用标准的PyTorch或apex方法进行计划和裁剪。
现在,这些schedules已成为标准的PyTorch学习率调度程序,现在不再是优化程序的一部分。
以下是转换示例:
# 参数:
lr = 1e-3
max_grad_norm = 1.0
num_training_steps = 1000
num_warmup_steps = 100
warmup_proportion = float(num_warmup_steps) / float(num_training_steps) # 0.1
### 以前,BertAdam优化器是这样实例化的:
optimizer = BertAdam(model.parameters(), lr=lr, schedule='warmup_linear', warmup=warmup_proportion, t_total=num_training_steps)
### 并像这样使用:
for batch in train_data:
loss = model(batch)
loss.backward()
optimizer.step()
### 在“Transformer”中,优化器和schedules按如下方式拆分和实例化:
optimizer = AdamW(model.parameters(), lr=lr, correct_bias=False) # 要重现BertAdam特定的行为,请设置correct_bias = False
scheduler = get_linear_schedule_with_warmup(optimizer, num_warmup_steps=num_warmup_steps, num_training_steps=num_training_steps) # PyTorch调度程序用法如下:
for batch in train_data:
model.train()
loss = model(batch)
loss.backward()
torch.nn.utils.clip_grad_norm_(model.parameters(), max_grad_norm) # 梯度裁剪不再在AdamW中了(因此你可以毫无问题地使用放大器)
optimizer.step()
scheduler.step()
optimizer.zero_grad()
我们现在有一篇论文你可以引用:
@article{Wolf2019HuggingFacesTS,
title={HuggingFace's Transformers: State-of-the-art Natural Language Processing},
author={Thomas Wolf and Lysandre Debut and Victor Sanh and Julien Chaumond and Clement Delangue and Anthony Moi and Pierric Cistac and Tim Rault and R'emi Louf and Morgan Funtowicz and Jamie Brew},
journal={ArXiv},
year={2019},
volume={abs/1910.03771}
}
欢迎关注磐创博客资源汇总站:
http://docs.panchuang.net/
欢迎关注PyTorch官方中文教程站:
http://pytorch.panchuang.net/
OpenCV中文官方文档:
http://woshicver.com/