Transformer: Training and fine-tuning(六)

本文介绍了如何在PyTorch中对Transformer模型进行微调,特别是BERT模型用于句子分类任务。讲解了如何初始化模型、设置优化器、冻结编码器、使用GPU训练以及学习率调度。同时提到了Trainer接口的使用,它是进行训练和评估Transformer模型的便捷工具。
摘要由CSDN通过智能技术生成

1.Fine-tuning in native本地 PyTorch

模型类model class不是以TF开头的都是以Pytorch来运行的。

接下来考虑微调fine-tune一个BERT模型来做句子分类任务。当我们使用from_pretrained()实例化一个模型时,所指定模型的配置configuration 和预训练的权重会被用于初始化模型,这个库library也会包含一些指定任务(task-specific)的最后一层final layer或者头head。当final layers 和head 没有出现在指定的预训练模型中时,会随机分配权重给它们。

举例:实例化一个模型,用的是
BertForSequenceClassification.from_pretrained('bert-base-uncased', num_labels=2)
就会创建一个实例,这个实例会带有来自bert-base-uncased 模型的encoder weights,编码权重。并且随机初始化句子分类头(sequence classification head)在encoder上,output size是2。
模型是默认在eval模式下进行初始化的。我们可以用model.train() 来将其放进训练模式中(to put it in train mode)

from transformers import BertForSequenceClassification
model = BertForSequenceClassification.from_pretrained('bert-base-uncased')
model.train()

这是有用的,因为这允许我们利用预训练的BERT编码器(encoder),简单地在任何我们选择的分类数据集上进行训练。我们可以用任何Pytorch的优化器optimizer。同时我们也提供了AdamW()优化器,其实现梯度偏差校正以及权重衰减。

from transformers import AdamW
optimizer = AdamW(model.parameters(), lr=1e-5)

优化器允许我们为特定的参数组应用不同的超参数。 例如,我们可以将权重衰减应用于除bias和layer归一化以外的所有参数:

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)

接下来我们可以设置一个极其简单的training batch,使用__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参数的分类模型,返回的第一个元素就是预测值和传进去的标签值之间的Cross Entropy loss交叉熵损失。设置好我们的优化器optimizer后,我们可以就可以做后向传播并更新权重了。

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并计算自己的损失值,下面的代码跟上面等价

from torch.nn import functional as F
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()

我们强烈推荐使用**Trainer()**会在下面讨论,很方便的训练Transformer模型,

1.1 Freezing the encoder 冻结编码器

在有些情况下,你需要保持预训练编码器的权重冻结,只对head layers的权重进行优化,要这么做的话,只需要在encoder 参数上设置requires_grad 为 False,这样就可以使库中任何task-specific model上的base_model子模块来访问它:

for param in model.base_model.parameters():
    param.requires_grad = False

2.在tensorflow上微调

3.Trainer

我们也提供了简单,但功能完善的训练和评估接口:Trainer()TFTrainer(),你可以用于训练,微调,评估任何Transformer模型,有这非常多的训练options可供选择,还有许多内建的属性比如 logging, gradient accumulation, and mixed precision.

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
)

接下来,简单的使用trainer.train() 来训练,使用 trainer.evaluate() 来评估,你也可以是用你自己的模块,但是第一个从forward返回的参数必须是损失值,这个损失值是用来优化的

Trainer()使用的是内建的函数来收集batches并准备好将它们传进模型中,如果需要,也可以使用data_collator参数来传你自己的collator function(校对函数),这个校对函数传进以你提供的数据集的格式的数据,返回可以传进模型的batch。

要计算除损失之外的其他指标,您还可以定义自己的compute_metrics函数并将其传递给Trainer。

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来查看结果,包括所有计算的指标。、

一个轻量化的colab demo,展示IMDb电影情感分析,使用的Trainer,链接

from transformers import BertForSequenceClassification, BertTokenizerFast, Trainer, TrainingArguments
from nlp import load_dataset
import torch
import numpy as np
from sklearn.metrics import accuracy_score, precision_recall_fscore_support
model = BertForSequenceClassification.from_pretrained('bert-base-uncased')
tokenizer = BertTokenizerFast.from_pretrained('bert-base-uncased')
def tokenize(batch):
    return tokenizer(batch['text'], padding=True, truncation=True)

train_dataset, test_dataset = load_dataset('imdb', split=['train', 'test'])
train_dataset = train_dataset.map(tokenize, batched=True, batch_size=len(train_dataset))
test_dataset = test_dataset.map(tokenize, batched=True, batch_size=len(train_dataset))
train_dataset.set_format('torch', columns=['input_ids', 'attention_mask', 'label'])
test_dataset.set_format('torch', columns=['input_ids', 'attention_mask', 'label'])
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
    }

training_args = TrainingArguments(
    output_dir='./results',
    num_train_epochs=1,
    per_device_train_batch_size=16,
    per_device_eval_batch_size=64,
    warmup_steps=500,
    weight_decay=0.01,
    evaluate_during_training=True,
    logging_dir='./logs',
)

trainer = Trainer(
    model=model,
    args=training_args,
    compute_metrics=compute_metrics,
    train_dataset=train_dataset,
    eval_dataset=test_dataset
)
trainer.train()
trainer.evaluate()
{'epoch': 1.0,
 'eval_accuracy': 0.93552,
 'eval_f1': 0.9362089434111595,
 'eval_loss': 0.18167165885476963,
 'eval_precision': 0.926311667971809,
 'eval_recall': 0.94632}
  • 4
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值