🤗 Transformers 中的模型类被设计为与本机PyTorch和TensorFlow 2兼容,并且可以与其中任何一个无缝使用。在这个快速入门中,我们将展示如何使用两种框架中可用的标准培训工具来微调(或从头开始培训)模型。我们还将展示如何使用包含的Trainer()类,它可以为您处理很多复杂的训练。
本指南假设您已经熟悉加载和使用我们的模型进行推理;否则,请参见任务摘要。我们还假设您熟悉深度神经网络的训练。
在原生PyTorch中进行微调
🤗 Transformers 中不以TF开头的模型类是PyTorch模块,这意味着您可以像使用PyTorch中的任何模型一样使用它们进行推理和优化。
让我们考虑在序列分类数据集上微调像BERT这样的掩码语言模型的常见任务。当我们用from_pretrained()实例化模型时,将使用指定模型的模型配置和预先训练过的权值来初始化模型。该库还包括许多特定于任务的最终层或“头”,它们的权值在指定的预训练模型中不存在时被随机实例化。例如,用 BertForSequenceClassification.from_pretrained('bert-base-uncased', num_labels=2) 将创建一个BERT模型实例,其编码器权重从bert-base-uncased模型复制而来,并在编码器上随机初始化一个输出大小为2的序列分类头。 模型默认以评估模式初始化。我们可以调用model.train()将其置于训练模式。
from transformers import BertForSequenceClassification
model = BertForSequenceClassification.from_pretrained('bert-base-uncased')
model.train()
这是很有用的,因为它允许我们使用预先训练好的 BERT 编码器,并在我们选择的任何序列分类数据集上轻松训练它。我们可以使用任何PyTorch优化器,但我们的库也提供了AdamW()优化器,它实现了梯度偏差校正以及权重衰减:
from transformers import AdamW
optimizer = AdamW(model.parameters(), lr=1e-5)
优化器允许我们为特定的参数组应用不同的超参数。例如,我们可以对除偏差和层归一化项外的所有参数应用权重衰减:
no_decay = ['bias', 'LayerNorm.weight']
optimizer_grouped_parameters = [
{'params': [p for n, p in model.named_parameters() if not any(nd in n for nd in no_decay)], 'weight_decay': 0.01},
{'params': [p for n, p in model.named_parameters() if any(nd in n for nd in no_decay)], 'weight_decay': 0.0}
]
optimizer = AdamW(optimizer_grouped_parameters, lr=1e-5)
现在我们可以使用__call__()设置一个简单的虚拟训练批次。这将返回一个 BatchEncoding() 实例,它准备了我们可能需要传递给模型的所有东西。
from transformers import BertTokenizer
tokenizer = BertTokenizer.from_pretrained('bert-base-uncased')
text_batch = ["I love Pixar.", "I don't care for Pixar."]
encoding = tokenizer(text_batch, return_tensors='pt', padding=True, truncation=True)
input_ids = encoding['input_ids']
attention_mask = encoding['attention_mask']
当我们调用一个带有标签参数的分类模型时,第一个返回的元素是预测和传递的标签之间的交叉熵损失。在已经设置好优化器后,我们就可以进行反向传播,更新权重。
labels = torch.tensor([1,0]).unsqueeze(0)
outputs = model(input_ids, attention_mask=attention_mask, labels=labels)
loss = outputs.loss
loss.backward()
optimizer.step()
或者,你也可以直接得到logits,然后自己计算损失。下面的示例与前面的示例是等价的:
labels = torch.tensor([1,0])
outputs = model(input_ids, attention_mask=attention_mask)
loss = F.cross_entropy(outputs.logits, labels)
loss.backward()
optimizer.step()
当然,你也可以像往常一样通过调用to('cuda')对模型和输入进行GPU训练。
我们还提供了一些学习率调度工具。通过下面的方法,我们可以设置一个调度器,这个调度器会对num_warmup_steps进行预热,然后在训练结束时线性衰减为0。
from transformers import get_linear_schedule_with_warmup
scheduler = get_linear_schedule_with_warmup(optimizer, num_warmup_steps, num_train_steps)
然后,我们要做的就是在optimizer.step()之后调用scheduler.step()。
loss.backward()
optimizer.step()
scheduler.step()
冻结编码器
在某些情况下,你可能会对保持冻结预训练编码器的权重、只优化头部层的权重感兴趣。要做到这一点,只需在编码器参数上将 requires_grad 属性设置为 False,就可以在库中的任何特定任务模型上使用 base_model 子模块进行访问。
for param in model.base_model.parameters():
param.requires_grad = False
在原生 TensorFlow 2 中进行微调
模型也可以在TensorFlow 2中进行原生训练。就像PyTorch一样,TensorFlow模型可以用from_pretrained()来实例化,从预训练的模型中加载编码器的权重。
from transformers import TFBertForSequenceClassification
model = TFBertForSequenceClassification.from_pretrained('bert-base-uncased')
让我们使用tensorflow_datasets从GLUE加载MRPC数据集。然后我们可以使用内置的glue_convert_examples_to_features()对MRPC进行标记化,并将其转换为TensorFlow Dataset对象。请注意,tokenizer是框架无关的,所以不需要在预训练的tokenizer名称前加上TF。
from transformers import BertTokenizer, glue_convert_examples_to_features
import tensorflow as tf
import tensorflow_datasets as tfds
tokenizer = BertTokenizer.from_pretrained('bert-base-uncased')
data = tfds.load('glue/mrpc')
train_dataset = glue_convert_examples_to_features(data['train'], tokenizer, max_length=128, task='mrpc')
train_dataset = train_dataset.shuffle(100).batch(32).repeat(2)
该模型可以编译和训练为任何Keras模型:
optimizer = tf.keras.optimizers.Adam(learning_rate=3e-5)
loss = tf.keras.losses.SparseCategoricalCrossentropy(from_logits=True)
model.compile(optimizer=optimizer, loss=loss)
model.fit(train_dataset, epochs=2, steps_per_epoch=115)
Trainer
我们还通过Trainer()和TFTrainer()提供了一个简单但功能齐全的训练和评估界面。您可以通过广泛的训练选项和内置的功能(如日志、梯度累积和混合精度)来训练、微调和评估任何🤗Transformers 模型。
PyTorch版:
from transformers import BertForSequenceClassification, Trainer, TrainingArguments
model = BertForSequenceClassification.from_pretrained("bert-large-uncased")
training_args = TrainingArguments(
output_dir='./results', # output directory
num_train_epochs=3, # total # of training epochs
per_device_train_batch_size=16, # batch size per device during training
per_device_eval_batch_size=64, # batch size for evaluation
warmup_steps=500, # number of warmup steps for learning rate scheduler
weight_decay=0.01, # strength of weight decay
logging_dir='./logs', # directory for storing logs
)
trainer = Trainer(
model=model, # the instantiated 🤗 Transformers model to be trained
args=training_args, # training arguments, defined above
train_dataset=train_dataset, # training dataset
eval_dataset=test_dataset # evaluation dataset
)
TensorFlow版:
from transformers import TFBertForSequenceClassification, TFTrainer, TFTrainingArguments
model = TFBertForSequenceClassification.from_pretrained("bert-large-uncased")
training_args = TFTrainingArguments(
output_dir='./results', # output directory
num_train_epochs=3, # total # of training epochs
per_device_train_batch_size=16, # batch size per device during training
per_device_eval_batch_size=64, # batch size for evaluation
warmup_steps=500, # number of warmup steps for learning rate scheduler
weight_decay=0.01, # strength of weight decay
logging_dir='./logs', # directory for storing logs
)
trainer = TFTrainer(
model=model, # the instantiated 🤗 Transformers model to be trained
args=training_args, # training arguments, defined above
train_dataset=tfds_train_dataset, # tensorflow_datasets training dataset
eval_dataset=tfds_test_dataset # tensorflow_datasets evaluation dataset
)
现在只需调用 trainer.training() 进行训练,调用 trainer.evaluation() 进行评估。你也可以使用你自己的模块,但是从 forward 返回的第一个参数必须是你想优化的损失。
Trainer() 使用一个内置的默认函数来整理批次并准备将它们输入模型。如果需要,你也可以使用 data_collator 参数来传递你自己的整理函数,该函数以你的数据集提供的格式来接收数据,并返回一个准备好被输入到模型中的批次。注意 TFTrainer() 期望传递的数据集是来自 tensorflow_datasets 的数据集对象。
要计算除了损失之外的其他指标,你还可以定义自己的 compute_metrics 函数,并将其传递给训练者。
from sklearn.metrics import accuracy_score, precision_recall_fscore_support
def compute_metrics(pred):
labels = pred.label_ids
preds = pred.predictions.argmax(-1)
precision, recall, f1, _ = precision_recall_fscore_support(labels, preds, average='binary')
acc = accuracy_score(labels, preds)
return {
'accuracy': acc,
'f1': f1,
'precision': precision,
'recall': recall
}
最后,你可以通过在你指定的 logging_dir 目录下启动 tensorboard 来查看结果,包括任何计算的指标。
其他资源
-
A lightweight colab demo, 使用Trainer进行IMDb情感分类
-
🤗 Transformers Examples 包括GLUE、SQuAD和其他一些任务的训练和微调脚本。
-
How to train a language model, 一个详细的colab笔记本,它使用Trainer在世界语上从头开始训练一个屏蔽语言模型。
-
🤗 Transformers Notebooks 其中包含了来自社区的几十个例子笔记本,用于在各种任务中训练和使用🤗Transformers。