【Huggingface系列学习】Finetuning一个预训练模型
文章目录
- Processing the data
- Load a dataset from the Hub
- Preprocessing a dataset
- Dynamic padding
- Fine-tuning a model with the Trainer API
- Training
- Evaluation
- Trainer背后的过程
- 训练前的准备
Processing the data
Load a dataset from the Hub
我们可以利用下面的代码来训练一个 sequence 分类器
import torch
from transformers import AdamW, AutoTokenizer, AutoModelForSequenceClassification# Same as before
checkpoint = "bert-base-uncased"
tokenizer = AutoTokenizer.from_pretrained(checkpoint)
model = AutoModelForSequenceClassification.from_pretrained(checkpoint)
sequences = ["I've been waiting for a HuggingFace course my whole life.","This course is amazing!",
]
batch = tokenizer(sequences, padding=True, truncation=True, return_tensors="pt")# This is new
batch["labels"] = torch.tensor([1, 1])optimizer = AdamW(model.parameters())
loss = model(**batch).loss
loss.backward()
optimizer.step()
显然,不可能用两个句子就能得到好的结果,因此我们需要更大的数据集
huggingface 也保存了很多数据集,可以通过
load_data
来下载from datasets import load_datasetraw_datasets = load_dataset("glue", "mrpc") # GLUE benchmark 中的 MRPC数据集 raw_datasets > DatasetDict({train: Dataset({features: ['sentence1', 'sentence2', 'label', 'idx'],num_rows: 3668})validation: Dataset({features: ['sentence1', 'sentence2', 'label', 'idx'],num_rows: 408})test: Dataset({features: ['sentence1', 'sentence2', 'label', 'idx'],num_rows: 1725}) })
我们可以通过索引来访问每一对句子
raw_train_dataset = raw_datasets["train"] raw_train_dataset[0]>{'idx': 0,'label': 1,'sentence1': 'Amrozi accused his brother , whom he called " the witness " , of deliberately distorting his evidence .','sentence2': 'Referring to him as only " the witness " , Amrozi accused his brother of deliberately distorting his evidence .'}
如果想知道数据集的每个部分的含义,可以通过
features
属性来查看raw_train_dataset.features {'sentence1': Value(dtype='string', id=None),'sentence2': Value(dtype='string', id=None),'label': ClassLabel(num_classes=2, names=['not_equivalent', 'equivalent'], names_file=None, id=None),'idx': Value(dtype='int32', id=None)}
Preprocessing a dataset
tokenizer 可以直接处理成对的数据,就是BERT
希望的那样
inputs = tokenizer("This is the first sentence.", "This is the second one.")
inputs
>{ 'input_ids': [101, 2023, 2003, 1996, 2034, 6251, 1012, 102, 2023, 2003, 1996, 2117, 2028, 1012, 102],'token_type_ids': [0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1],'attention_mask': [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]
}
token_type_ids
是用来区分第一个句子和第二个句子的,这未必在每个 tokenizer 中都有。只有当模型知道如何处理它们时,它们才会返回,因为它在预训练期间已经看到了它们。- 这里
BERT
在预训练时用到了 token_type_dis - 如果我们解码,会发现这个格式是 [CLS] sentence1 [SEP] sentence2 [SEP]
- 这里
我们可以让tokenizer处理 a list of pairs of sentence,通过给它第一个句子的列表和第二个句子的列表
tokenized_dataset = tokenizer(raw_datasets["train"]["sentence1"],raw_datasets["train"]["sentence2"],padding=True,truncation=True,
)
这样返回的是一个字典,我们可以将这个返回结果添加到原来的数据集当中去
def tokenize_function(example):return tokenizer(example["sentence1"], example["sentence2"], truncation=True)
tokenized_datasets = raw_datasets.map(tokenize_function, batched=True)
- 我们在调用map时使用了batched=True,这样函数就会同时应用到数据集的多个元素上,而不是分别应用到每个元素上(比较快)
- 如果预处理函数为数据集中的一个现有 key 返回一个新值,我们也可以更改现有的字段
Dynamic padding
负责将samples放到一个batch的函数是 collate function
(是DataLoader的一个参数,默认将samples转成pytorch的tensor,并把他们连接起来)
我们故意推迟填充,只在每批处理中应用它,并避免有大量填充的过长输入。
- 这将使训练更快
- 但是在 TPU 上会有问题,TPU更喜欢固定的 shape
为了在实践中做到这一点,我们必须定义一个collate函数,该函数将对我们想要批处理的数据集中的项应用正确的填充量
from transformers import DataCollatorWithPaddingdata_collator = DataCollatorWithPadding(tokenizer=tokenizer)
samples = tokenized_datasets["train"][:8]
batch = data_collator(samples)
- 在初始化时需要给一个 tokenize,这样他才能知道用什么token来填充,在左边还是右边来填充
Fine-tuning a model with the Trainer API
transformers提供了Trainer class来帮助在自己的数据上fine-tune预训练模型,当做完了数据处理,只剩一些定义 Trainer 的步骤
我们总结之前的操作
from datasets import load_dataset
from transformers import AutoTokenizer, DataCollatorWithPaddingraw_datasets = load_dataset("glue", "mrpc")
checkpoint = "bert-base-uncased"
tokenizer = AutoTokenizer.from_pretrained(checkpoint)def tokenize_function(example):return tokenizer(example["sentence1"], example["sentence2"], truncation=True)tokenized_datasets = raw_datasets.map(tokenize_function, batched=True)
data_collator = DataCollatorWithPadding(tokenizer=tokenizer)
Training
在定义trainer之前,需要定义TrainingArguments类,这包括所有的参数。我们只用提供模型要保存的位置,其他参数保持默认也能训练的不错
from transformers import TrainingArgumentstraining_args = TrainingArguments("test-trainer")
定义一个模型
from transformers import AutoModelForSequenceClassificationmodel = AutoModelForSequenceClassification.from_pretrained(checkpoint, num_labels=2)
定义一个Trainer
from transformers import Trainertrainer = Trainer(model,training_args,train_dataset=tokenized_datasets["train"],eval_dataset=tokenized_datasets["validation"],data_collator=data_collator,tokenizer=tokenizer,
)
- 当我们传入 tokenizer,这里data_collator就会默认是我们上面定义的那样,因此我们可以省略这一步
训练
trainer.train()
- 会每500steps输出training loss,但不会告诉我们模型有多好:
- 没有让 trainer 在训练的时候evaluate(通过设置 evaluation_strategy to steps/epoch)
- 没有提供
compute_metrics()
来在evaluate期间计算一个 metric,只是返回loss,这并不直观
Evaluation
我们可以使用 Trainer.predict() 来使我们的模型进行预测
predictions = trainer.predict(tokenized_datasets["validation"])
print(predictions.predictions.shape, predictions.label_ids.shape)
>(408, 2) (408,)
- 输出是包括三个字段的 tuple(predictions,label_ids,metrics)
- 这里metrics只有loss,以及一些运行时间,如果我们定义了自己的 compute_metrics() 函数并将其传递给 Trainer ,该字段还将包含compute_metrics() 的结果
- predictions是数据集每个元素的 logits
要将我们的预测的可以与真正的标签进行比较,我们需要在第二个轴上取最大值的索引:
import numpy as nppreds = np.argmax(predictions.predictions, axis=-1)
建立compute_metraic(),我们可以使用Evaluate库
import evaluatemetric = evaluate.load("glue", "mrpc")
metric.compute(predictions=preds, references=predictions.label_ids)
> {'accuracy': 0.8578431372549019, 'f1': 0.8996539792387542}
最后将所有东西整合起来,我们得到 compute_metrics() 函数
def compute_metrics(eval_preds):metric = evaluate.load("glue", "mrpc")logits, labels = eval_predspredictions = np.argmax(logits, axis=-1)return metric.compute(predictions=predictions, references=labels)
此时我们可以定义新的Trainer
training_args = TrainingArguments("test-trainer", evaluation_strategy="epoch")
model = AutoModelForSequenceClassification.from_pretrained(checkpoint, num_labels=2)trainer = Trainer(model,training_args,train_dataset=tokenized_datasets["train"],eval_dataset=tokenized_datasets["validation"],data_collator=data_collator,tokenizer=tokenizer,compute_metrics=compute_metrics,
)
- 注意,每过一个 epoch,都会进行evaluate。这一次,它将在训练loss之外,还会输出每个 epoch 结束时的验证loss和指标
Trainer背后的过程
数据处理的简短总结
from datasets import load_dataset
from transformers import AutoTokenizer, DataCollatorWithPaddingraw_datasets = load_dataset("glue", "mrpc")
checkpoint = "bert-base-uncased"
tokenizer = AutoTokenizer.from_pretrained(checkpoint)def tokenize_function(example):return tokenizer(example["sentence1"], example["sentence2"], truncation=True)tokenized_datasets = raw_datasets.map(tokenize_function, batched=True)
data_collator = DataCollatorWithPadding(tokenizer=tokenizer)
训练前的准备
我们需要对 tokenized_datasets做一些处理,具体来说:
- 删除与模型不期望的值相对应的列(如
sentence1
和sentence2
列)。 - 将列名
label
重命名为labels
(因为模型期望参数是labels
)。 - 设置数据集的格式,使其返回 PyTorch 张量而不是列表。
tokenized_datasets = tokenized_datasets.remove_columns(["sentence1", "sentence2", "idx"])
tokenized_datasets = tokenized_datasets.rename_column("label", "labels")
tokenized_datasets.set_format("torch")
tokenized_datasets["train"].column_names
加载 DataLoader
from torch.utils.data import DataLoadertrain_dataloader = DataLoader(tokenized_datasets["train"], shuffle=True, batch_size=8, collate_fn=data_collator
)
eval_dataloader = DataLoader(tokenized_datasets["validation"], batch_size=8, collate_fn=data_collator
)
加载模型
from transformers import AutoModelForSequenceClassificationmodel = AutoModelForSequenceClassification.from_pretrained(checkpoint, num_labels=2)
模型加载到 gpu 上
import torchdevice = torch.device("cuda") if torch.cuda.is_available() else torch.device("cpu") model.to(device)
加载 optimizer
from transformers import AdamWoptimizer = AdamW(model.parameters(), lr=5e-5)
加载 scheduler
from transformers import get_schedulernum_epochs = 3
num_training_steps = num_epochs * len(train_dataloader)
lr_scheduler = get_scheduler("linear",optimizer=optimizer,num_warmup_steps=0,num_training_steps=num_training_steps,
)
训练循环
from tqdm.auto import tqdmprogress_bar = tqdm(range(num_training_steps)) # 进度条model.train()
for epoch in range(num_epochs):for batch in train_dataloader:batch = {k: v.to(device) for k, v in batch.items()}outputs = model(**batch)loss = outputs.lossloss.backward()optimizer.step()lr_scheduler.step()optimizer.zero_grad()progress_bar.update(1)
evaluate循环
import evaluatemetric = evaluate.load("glue", "mrpc")
model.eval()
for batch in eval_dataloader:batch = {k: v.to(device) for k, v in batch.items()}with torch.no_grad():outputs = model(**batch)logits = outputs.logitspredictions = torch.argmax(logits, dim=-1)metric.add_batch(predictions=predictions, references=batch["labels"])metric.compute()
- 当我们使用
add_batch()
方法进行预测循环时,实际上该指标可以为我们累积所有batch
的结果。一旦我们累积了所有batch
,我们就可以使用metric.compute()
得到最终结果
使用Accelerate加速循环训练:一个完整的训练 - Hugging Face Course
【Huggingface系列学习】Finetuning一个预训练模型相关推荐
- 2021 第五届“达观杯” 基于大规模预训练模型的风险事件标签识别】3 Bert和Nezha方案
目录 相关链接 1 引言 2 NEZHA方案 2.1 预训练 2.2 微调 3 Bert 方案 3.1 预训练 3.2 微调 3 模型融合和TTA测试集数据增强 4 总结和反思 5 参考资料 相关链接 ...
- 《智源社区周刊:预训练模型》第2期:Facebook用“预微调”改进预训练性能、再议GPT-3中的东方主义偏见...
超大规模预训练模型是当前人工智能领域研究的热点,为了帮助研究与工程人员了解这一领域的进展和资讯,智源社区整理了第2期<智源社区周刊:预训练模型>,从论文推荐.研究动态.热点讨论等几个维度推 ...
- Transformer再下一城!low-level多个任务榜首被占领,北大华为等联合提出预训练模型IPT
来自Transformer的降维打击!北京大学等最新发布论文,联合提出图像处理Transformer.通过对low-level计算机视觉任务,如降噪.超分.去雨等进行研究,提出了一种新的预训练模型IP ...
- 腾讯基于预训练模型的文本内容理解实践
分享嘉宾:赵哲博士 腾讯 高级研究员 编辑整理:张书源 爱丁堡大学 出品平台:DataFunTalk 导读:预训练已经成为自然语言处理任务的重要组成部分,为大量自然语言处理任务带来了显著提升.本文将围 ...
- 零样本迁移?全新多语言预训练模型DeltaLM!
作者 | 马树铭 MSRA 研究员 整理 | DataFunSummit 目前,多语言神经机器翻译受到越来越多的研究人员的关注,多语言预训练模型对神经机器翻译可以起到非常重要的作用.预训练模型自身的跨 ...
- 预训练模型,NLP的版本答案!
作者 | 中二青年 整理 | NewBeeNLP 1. 碎碎念 大概是两年前,跟百度的nlp组,参与合作过Ernie在对话系统上的应用. 问题其实很多,模型训练慢,一个月迭代一次很正常(现在做业务,两 ...
- 语音识别预训练模型Hidden-Unit BERT (HuBERT)
1.简介 本文根据2021年<HuBERT: Self-Supervised Speech Representation Learning by Masked Prediction of Hid ...
- CVPR 2021 | Transformer进军low-level视觉!北大华为等提出预训练模型IPT
点击下方卡片,关注"CVer"公众号 AI/CV重磅干货,第一时间送达 作者丨Happy 来源丨极市平台 导读 来自Transformer的降维打击!北京大学.华为诺亚等最新发 ...
- 多模态模型学习1——CLIP对比学习 语言-图像预训练模型
多模态模型学习1--CLIP对比学习 语言-图像预训练模型 学习前言 什么是CLIP模型 代码下载 CLIP实现思路 一.网络结构介绍 1.Image Encoder a.Patch+Position ...
最新文章
- 【观点】“另类”设计模式
- 手机控制树莓派linux,怎样用PC或手机远程控制树莓派
- Python基础教程(十二):GUI编程、版本区别、IDE
- 全球及中国增强现实产业战略布局及运营前景决策分析报告2021-2027年
- python plotly 多个表格_Plotly Python - 更改表格
- python中fork创建新的进程
- 本地安装 SAP WebIDE 的本地存储研究
- 在Data Lake Analytics中使用视图
- 解读Mybatis数据库开发框架
- Centos 7 密码重置
- python常用的库与包_python常用到哪些库?
- Docker 运行Tensorboard 和 jupyter的正确方法
- progressDialog 为什么设置了setProgress()方法无反应?
- 如何查看MySQL源码
- 软件定义网络带来新的自动化优势和挑战
- matlab批量修改指定像素
- 倒残差与线性瓶颈浅析 - MobileNetV2
- 关于巨杉数据库的学习
- 计算机数学基础⑤(Graphs)
- kaggle实战—泰坦尼克(四、数据可视化)
热门文章
- 怎样卸载deepin系统_大师教您win7系统双系统下卸载Deepin的具体方法
- Posterino for Mac(图像编辑软件)
- 鸿蒙和中兴新支点系统,鸿蒙和中兴新支点操作系统共同打造国产操作系统生态圈...
- 打开windows(电脑)自带的画图工具的几种方法
- JS函数调用、修改全局变量的知识
- cad单位_老司机帮您 win10系统设置cad画图比例的流程 -win10使用教程
- vue.js 和 bootstrap 实现简单的购物车
- python编程语言期中试题_《Python程序设计》期中考试卷
- 快手日常实习面经java后端【主站技术部】
- 从各个角度深度分析,医美行业的龙头【爱美客】是否值得我们投资