PyTorch2.0 Transformers

PyTorch 2.0 完全向后兼容,不需要对现有 PyTorch 代码进行任何修改,但可以通过使用 model = torch.compile(model) 添加一行代码来优化你的代码。

如果你问为什么有一个新的主要版本而没有重大更改? PyTorch 团队在他们的常见问题解答中回答了这个问题:“我们正在发布大量新功能,我们相信这些功能会改变你有意义地使用 PyTorch 的方式,因此我们将其称为 2.0。”

这些新功能包括对 TorchDynamo、AOTAutograd、PrimTorch 和 TorchInductor 的顶级支持。

这使 PyTorch 2.0 能够实现 1.3 倍到 2 倍的训练时间加速,支持来自 HuggingFace Transformers 的当今 46 种模型架构

1、搭建环境 & 安装Pytorch 2.0

我们的第一步是安装 PyTorch 2.0 和 Hugging Face Libraries,包括transformers和数据集。

# Install PyTorch 2.0 with cuda 11.7
!pip install "torch>=2.0" --extra-index-url https://download.pytorch.org/whl/cu117 --upgrade --quiet

此外,我们正在从主 git 分支安装最新版本的transformers,其中包括将 PyTorch 2.0 原生集成到 Trainer 中。

# Install transformers and dataset
!pip install "transformers==4.27.1" "datasets==2.9.0" "accelerate==0.17.1" "evaluate==0.4.0" tensorboard scikit-learn
# Install git-fls for pushing model and logs to the hugging face hub
!sudo apt-get install git-lfs --yes

此示例将使用 Hugging Face Hub 作为远程模型版本控制服务。 要将我们的模型推送到 Hub,你必须在 Hugging Face 上注册。 如果你已经有一个帐户,则可以跳过此步骤。 拥有帐户后,我们将使用 huggingface_hub 包中的登录实用程序登录我们的帐户并将我们的令牌(访问密钥)存储在磁盘上。

from huggingface_hub import login

login(
  token="", # ADD YOUR TOKEN HERE
  add_to_git_credential=True
)

2、加载并准备数据集

为了使示例简单明了,我们正在 BANKING77 数据集上训练文本分类模型。 BANKING77 数据集在银行/金融领域提供一组细粒度的意图(类)。 它包含 13,083 个标有 77 个意图的客户服务查询。 它专注于细粒度的单域意图检测。

我们将使用 🤗 Datasets 库中的 load_dataset() 方法来加载 banking77。

from datasets import load_dataset

# Dataset id from huggingface.co/dataset
dataset_id = "banking77"

# Load raw dataset
raw_dataset = load_dataset(dataset_id)

print(f"Train dataset size: {len(raw_dataset['train'])}")
print(f"Test dataset size: {len(raw_dataset['test'])}")

让我们看看数据集的一个例子。

from random import randrange

random_id = randrange(len(raw_dataset['train']))
raw_dataset['train'][random_id]
# {'text': "I can't get google pay to work right.", 'label': 2}

为了训练模型,我们需要将我们的“自然语言”转换为令牌 ID。 这是由 Tokenizer 完成的,它对输入进行标记化(包括将标记转换为预训练词汇表中相应的 ID),如果想了解更多相关信息,请参阅 Hugging Face Course 的第 6 章

from transformers import AutoTokenizer

# Model id to load the tokenizer
model_id = "bert-base-uncased"
# Load Tokenizer
tokenizer = AutoTokenizer.from_pretrained(model_id)

# Tokenize helper function
def tokenize(batch):
    return tokenizer(batch['text'], padding='max_length', truncation=True, return_tensors="pt")

# Tokenize dataset
raw_dataset =  raw_dataset.rename_column("label", "labels") # to match Trainer
tokenized_dataset = raw_dataset.map(tokenize, batched=True,remove_columns=["text"])

print(tokenized_dataset["train"].features.keys())
# dict_keys(['input_ids', 'token_type_ids', 'attention_mask','lable'])

3、微调和评估 BERT 模型

处理完数据集后,我们就可以开始训练模型了。 我们将使用 bert-base-uncased 模型。 第一步是使用 Hugging Face Hub 中的 AutoModelForSequenceClassification 类加载我们的模型。 这将初始化预训练的 BERT 权重,并将分类头置于顶部。 在这里,我们从数据集中传递类数 (77) 和标签名称,以获得可读的推理输出。

from transformers import AutoModelForSequenceClassification

# Model id to load the tokenizer
model_id = "bert-base-uncased"

# Prepare model labels - useful for inference
labels = tokenized_dataset["train"].features["labels"].names
num_labels = len(labels)
label2id, id2label = dict(), dict()
for i, label in enumerate(labels):
    label2id[label] = str(i)
    id2label[str(i)] = label

# Download the model from huggingface.co/models
model = AutoModelForSequenceClassification.from_pretrained(
    model_id, num_labels=num_labels, label2id=label2id, id2label=id2label
)

我们在训练期间评估模型。 Trainer 通过提供 compute_metrics 方法支持训练期间的评估。 我们使用评估库在测试拆分训练期间计算 f1 指标。

import evaluate
import numpy as np

# Metric Id
metric = evaluate.load("f1")

# Metric helper method
def compute_metrics(eval_pred):
    predictions, labels = eval_pred
    predictions = np.argmax(predictions, axis=1)
    return metric.compute(predictions=predictions, references=labels, average="weighted")

最后一步是定义我们用于训练的超参数 (TrainingArguments)。 在这里,我们添加了 PyTorch 2.0 引入的功能以加快训练时间。 要使用 PyTorch 2.0 的最新改进,我们只需要在 TrainingArguments 中传递 torch_compile 选项。

我们还利用 Trainer 的 Hugging Face Hub 集成将训练期间的检查点、日志和指标推送到存储库中。

from huggingface_hub import HfFolder
from transformers import Trainer, TrainingArguments

# Id for remote repository
repository_id = "bert-base-banking77-pt2"

# Define training args
training_args = TrainingArguments(
    output_dir=repository_id,
    per_device_train_batch_size=16,
    per_device_eval_batch_size=8,
    learning_rate=5e-5,
	num_train_epochs=3,
	# PyTorch 2.0 specifics
    bf16=True, # bfloat16 training
	torch_compile=True, # optimizations
    optim="adamw_torch_fused", # improved optimizer
    # logging & evaluation strategies
    logging_dir=f"{repository_id}/logs",
    logging_strategy="steps",
    logging_steps=200,
    evaluation_strategy="epoch",
    save_strategy="epoch",
    save_total_limit=2,
    load_best_model_at_end=True,
    metric_for_best_model="f1",
    # push to hub parameters
    report_to="tensorboard",
    push_to_hub=True,
    hub_strategy="every_save",
    hub_model_id=repository_id,
    hub_token=HfFolder.get_token(),

)

# Create a Trainer instance
trainer = Trainer(
    model=model,
    args=training_args,
    train_dataset=tokenized_dataset["train"],
    eval_dataset=tokenized_dataset["test"],
    compute_metrics=compute_metrics,
)

我们可以使用 Trainer 的 train 方法开始我们的训练。

# Start training
trainer.train()

使用 Pytorch 2.0 和转换器中支持的功能,我们可以在 457.7964 秒内用 10_000 个样本训练我们的 BERT 模型。

我们还在没有 torch_compile 选项的情况下运行训练来比较训练时间。 没有 torch_compile 的训练耗时 457 秒,train_samples_per_second 值为 65.55,f1 分数为 0.931。

{'train_runtime': 696.2701, 'train_samples_per_second': 43.1, 'eval_f1': 0.928788}

通过使用 torch_compile 选项和 adamw_torch_fused 优化,我们可以看到与没有 PyTorch 2.0 的训练相比,训练时间减少了 52.5%。

{'train_runtime': 457.7964, 'train_samples_per_second': 65.55, 'eval_f1': 0.931773}

我们的绝对训练时间从 696 秒减少到 457。train_samples_per_second 值从 43 增加到 65。f1 分数与没有 torch_compile 的训练相同/略好。

Pytorch 2.0 强大到难以置信! 🚀

让我们将结果和分词器保存到 Hugging Face Hub 并创建一个模型卡。

# Save processor and create model card
tokenizer.save_pretrained(repository_id)
trainer.create_model_card()
trainer.push_to_hub()

4、运行推理和测试模型

为了结束本教程,我们将对一些示例进行推理并测试我们的模型。 我们将使用 transformers 库中的管道方法对我们的模型进行推理。

from transformers import pipeline

# load model from huggingface.co/models using our repository id
classifier = pipeline("sentiment-analysis", model=repository_id, tokenizer=repository_id, device=0)

sample = "I have been waiting longer than expected for my bank card, could you provide information on when it will arrive?"


pred = classifier(sample)
print(pred)
# [{'label': 'card_arrival', 'score': 0.9903606176376343}]

5、结束语

在本教程中,我们学习了如何使用 PyTorch 2.0 在 BANKING77 数据集上训练文本分类模型。 我们看到 PyTorch 2.0 是一个强大的工具,可以加快你的训练时间。 在我们在 NVIDIA A10G 上运行的示例中,我们设法实现了 52.5% 的性能提升。

Hugging Face Trainer 允许你通过简单地将 torch_compile 选项添加到 TrainingArguments 来轻松地将 PyTorch 2.0 集成到您的训练管道中。 当 bf16 可用时,我们可以通过使用新的融合 AdamW 优化器进一步受益于 PyTorch 2.0。

此外,我想提一下,我们将训练时间减少了 52%,这可以解释为培训成本节省了 52%,或者迭代周期和生产时间缩短了 52%。 通过使用 A100 GPU 或减少“Trainer”开销,你应该能够看到更好的改进,例如 删除评估和日志记录。


原文链接:Getting started with Pytorch 2.0 and Hugging Face Transformers

BimAnt翻译整理,转载请标明出处