介绍
我个人确实相信,所有有趣的ML研究和先进的AI算法工作,只有在它们可以应用到现实项目中,而不需要用户提供大量的资源和过多的领域知识的时候,才具有非常大的价值。
Hugging Face搭建了这座桥。Hugging Face是数千名经过预训练的模型的家,这些模型通过开源和开放科学为人工智能的民主化做出了巨大贡献。
今天,我想给你一个端到端的代码演示,通过执行多标签文本分类分析,比较两个最流行的预训练模型。
第一个模型是SentenceTransformers(SBERT)。这实际上是达姆施塔特技术大学的知识处理实验室的团队为各种任务创建的一系列预先训练的模型的集合。我在以前的项目中多次使用SBERT。他们甚至有一个python库,为你提供了不使用Hugging Face API和Pytorch框架的灵活性。在这里查看:https://www.sbert.net/docs/installation.html。
第二个模型是Data2vec,这是Meta(Facebook)的AI团队提供的一个强大的预训练模型。这是一个自监督的框架(教师模式→ 学生模型)设计用于文本、音频和图像编码。如果你对它是如何开发的感兴趣,你可以在这里找到原文:https://arxiv.org/abs/2202.03555
数据
对于数据,我使用了一个著名的开源文本数据集:BBC News Group(其许可证如下:https://opendatacommons.org/licenses/dbcl/1-0/). 你可以通过执行以下操作加载数据:
from sklearn.datasets import fetch_20newsgroups
dataset = fetch_20newsgroups(subset="all",
shuffle=True,
remove=("headers", "footers", "quotes"))
documents = dataset.data
labels = dataset.target
或者,你可以从我的GitHub报告中找到预处理的CSV版本:https://github.com/jinhangjiang/Medium_Demo/blob/main/Data2vec_vs_SBERT/bbc-text.csv
代码演示
步骤1:安装并导入我们需要的包
pip install torch transformers memory_profiler datasets
import torch
import random
from transformers.file_utils import is_tf_available, is_torch_available, is_torch_tpu_available
from transformers import AutoTokenizer, AutoModelForSequenceClassification, Trainer, TrainingArguments
from datasets import load_metric
from sklearn.model_selection import train_test_split
import pandas as pd
import numpy as np
%load_ext memory_profiler
步骤2:分割数据以进行验证
# Make data
X = Data
y = Target
y = pd.factorize(y)[0] # convert labels to numbers
# Split Data
X_train, X_test, y_train, y_test = train_test_split(X.tolist(), y, test_size=0.33)
注意这里的一个细节:我使用的是CSV文件,而不是从sklearn导入数据。所以我调用X.tolist()将输入数据作为列表。如果不这样做,模型稍后将抛出错误。
步骤3:分词
# Call the Tokenizer
tokenizer = AutoTokenizer.from_pretrained(model_name, do_lower_case=True)
# Encode the text
train_encodings = tokenizer(X_train, truncation=True, padding=True, max_length=512)
valid_encodings = tokenizer(X_test, truncation=True, padding=True, max_length=512)
以下是一些说明:
modelname:此参数应该是一个字符串,其中包含你要使用的经过预训练的模型的名称。你可以找到可用的模型:https://huggingface.co/models
maxlength:此参数将直接影响训练时间和训练速度。如果每个文档都很长,则需要指定模型要为每个文档处理的文本的长度。
padding:如果给定max_length,请将此参数设置为True。填充到批次中最长的序列(如果只提供一个序列,则不填充)
步骤4:将嵌入转换为torch数据集
class MakeTorchData(torch.utils.data.Dataset):
def __init__(self, encodings, labels):
self.encodings = encodings
self.labels = labels
def __getitem__(self, idx):
item = {k: torch.tensor(v[idx]) for k, v in self.encodings.items()}
item["labels"] = torch.tensor([self.labels[idx]])
return item
def __len__(self):
return len(self.labels)
# convert our tokenized data into a torch Dataset
train_dataset = MakeTorchData(train_encodings, y_train.ravel())
valid_dataset = MakeTorchData(valid_encodings, y_test.ravel())
步骤5:调用模型
# Call Model
model = AutoModelForSequenceClassification.from_pretrained(model_name, num_labels = num_labels).to("cuda")
AutoModelForSequenceClassification:将帮助你自动识别要使用的正确模型。ForSequenceClassification”专门用于分类问题。
to(“cuda”):如果你的机器上有GPU,你可以在末尾附加此函数以利用GPU功能。如果没有此功能,训练时间通常会显著增加。
步骤6:定义评估指标
# Load Metrics
metric = load_metric(metrics_name) # e.g. "f1"
# Create Metrics
def compute_metrics(eval_pred):
predictions, labels = eval_pred
predictions = np.argmax(predictions, axis=1)
# 'micro', 'macro', etc. are for multi-label classification. If you are running a binary classification, leave it as default or specify "binary" for average
return metric.compute(predictions=predictions, references=labels, average="micro")
metrics_name:这应该是一个字符串。对于我们的演示,我选择了“f1”作为评估指标。你可以在此处找到可用的选项:https://github.com/huggingface/datasets/tree/master/metrics
平均值:我通过了这个参数,因为我使用f1分数来评估多标签分类问题。它不是通用参数。
步骤7:微调预训练的模型
# Specifiy the arguments for the trainer
training_args = TrainingArguments(
output_dir='./results', # output directory
num_train_epochs=num_epochs, # total number of training epochs
per_device_train_batch_size=8, # batch size per device during training
per_device_eval_batch_size=20, # 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
load_best_model_at_end=True, # load the best model when finished training (default metric is loss)
metric_for_best_model = "f1", # select the base metrics
logging_steps=200, # log & save weights each logging_steps
save_steps=200,
evaluation_strategy="steps", # evaluate each `logging_steps`
)
# Call the Trainer
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=valid_dataset, # evaluation dataset
compute_metrics=compute_metrics, # the callback that computes metrics of interest
)
# Train the model
trainer.train()
# Call the summary
trainer.evaluate()
步骤8:保存经过微调的模型,使其可重用
当你想使用经过微调的模型时,只需将步骤3和步骤5中的模型名称字符串替换为指向你自己模型的路径。
你可以在此处访问完整代码脚本:https://github.com/jinhangjiang/Medium_Demo/blob/main/Data2vec_vs_SBERT/Data2vec_vs_SBERT_512.ipynb
结果
对于SBERT(max_length=512,epoch=5):
f1最佳分数:0.985034
f1平均得分:0.959524
训练时间:15分钟36秒
内存:5.0294 GB
对于Data2vec(max_length=512,epoch=5):
f1最佳成绩:0.976871
f1平均得分:0.957822
训练时间:15分钟8秒
内存增加:0.3213 GB
每次运行模型时,结果可能会略有不同。总的来说,经过5次尝试后,我可以得出结论,SBERT在f1最佳分数方面表现更好,而Data2vec使用的内存更少。两款模型的f1平均得分非常接近。
阅读完今天的演示后,你应该了解以下要点:
- 如何使用预训练的模型对文本数据分词
- 如何将数据正确转换为torch数据集
- 如何利用和微调预训练的模型
- 如何保存模型以备将来使用
- Data2vec和SBERT之间的性能比较
参考
Baevski et al. (2022). data2vec: A General Framework for Self-supervised Learning in Speech, Vision and Language. https://arxiv.org/pdf/2202.03555.pdf
Hugging Face. (2022). Text classification. https://huggingface.co/docs/transformers/tasks/sequence_classification
Reimers, N. and Gurevych, I. (2019). Sentence-BERT: Sentence Embeddings using Siamese BERT-Networks. https://arxiv.org/pdf/1908.10084.pdf
感谢阅读!