在这篇博客文章中,我们将模拟一个真实的客户服务用例,并使用Hugging Face生态系统的机器学习工具来解决它。
我们强烈推荐将这个笔记本作为一个模板/示例来解决你的真实用例。
定义任务、数据集和模型
在开始实际编码之前,重要的是清楚地定义您想要自动化或部分自动化的用例。清晰地定义用例有助于确定最适合您用例的任务、数据集和模型。
定义你的自然语言处理任务
好的,让我们深入探讨一个我们希望使用自然语言处理模型解决的假设性问题。假设我们正在销售一种产品,我们的客户支持团队收到成千上万条包括反馈、投诉和问题的消息,理想情况下应该都得到回复。
很快就变得明显,客户支持绝对无法回复每一条消息。因此,我们决定只回复最不满意的客户,并致力于回答100%的这些消息,因为与其他中性和积极的消息相比,这些消息很可能是最紧急的。
假设a)非常不满意的客户的消息只占所有消息的一小部分,并且b)我们可以以自动化的方式过滤出不满意的消息,那么客户支持应该能够达到这个目标。
为了以自动化的方式过滤出不满意的消息,我们计划应用自然语言处理技术。
第一步是将我们的用例-过滤出不满意的消息-映射到一个机器学习任务上。
Hugging Face Hub的任务页面是一个很好的起点,可以看到哪个任务最适合给定的场景。每个任务都有详细的描述和潜在的用例。
找到最不满意的客户消息的任务可以建模为一个文本分类任务:将一条消息分类为以下5个类别之一:非常不满意,不满意,中立,满意,或非常满意。
寻找合适的数据集
在确定任务之后,接下来,我们应该找到模型将要训练的数据。对于您的用例的性能来说,这通常比选择正确的模型架构更重要。记住,一个模型的好坏取决于它所训练的数据。因此,在策划和/或选择数据集时,我们应该非常谨慎。
由于我们考虑的是过滤出不满意的消息的假设用例,请查看可用的数据集。
对于您的真实用例,您很可能有最能代表您的NLP系统所处理实际数据的内部数据。因此,您应该使用这些内部数据来训练您的NLP系统。然而,包含公开可用的数据也可以提高模型的泛化能力。
让我们看一下Hugging Face Hub上所有可用的数据集。在左侧,您可以根据任务类别和更具体的任务进行过滤。我们的用例对应于文本分类-情感分析,所以让我们选择这些筛选器。在编写本笔记的时候,我们还剩下大约80个数据集。在选择数据集时,应该评估两个方面:
- 质量:数据集的质量如何?更具体地说:数据是否符合您在用例中预期要处理的数据?数据是否多样、公正等。
- 大小:数据集有多大?通常可以说,数据集越大,越好。
高效评估数据集是否具有高质量是相当棘手的,了解数据集是否存在偏见更具挑战性。高质量的有效合理的启发法则是查看下载统计信息。下载次数越多,使用次数越多,数据集的质量就越高。大小很容易评估,因为通常可以快速阅读。让我们来看一下下载次数最多的数据集:
- Glue
- 亚马逊极性
- 推特评估
- Yelp评论全文
- 亚马逊评论多语言
现在我们可以通过阅读数据集卡片来更详细地检查这些数据集,理想情况下应该提供所有相关和重要的信息。此外,数据集查看器是一个非常强大的工具,可以检查数据是否适合您的用例。
让我们快速浏览上面模型的数据集卡片:
- GLUE是一个由小型数据集组成的集合,主要用于研究人员比较新的模型架构。这些数据集太小,与我们的用例不够相关。
- 亚马逊极性是一个巨大且非常适合客户反馈的数据集,因为该数据涉及客户评价。然而,它只有二进制标签(积极/消极),而我们正在寻找更细致的情感分类。
- Tweet eval使用不同的表情符号作为标签,这些标签不能轻松地映射到从不满意到满意的范围。
- 亚马逊评论多似乎是最合适的数据集。我们有情感标签从1到5,对应于亚马逊上的1到5星。这些标签可以映射到非常不满意、中立、满意、非常满意。我们在数据集查看器上检查了一些示例,以验证评论看起来非常类似于实际的客户反馈评论,所以这似乎是一个非常好的数据集。此外,每个评论都有一个
product_category
标签,因此我们甚至可以只使用与我们正在处理的产品类别相对应的评论。该数据集是多语言的,但我们现在只对英文版本感兴趣。 - Yelp完整评论看起来是一个非常合适的数据集。它很大,包含产品评论和从1到5的情感标签。不幸的是,数据集查看器在这里无法工作,而且数据集卡片也相对稀缺,需要更多时间来检查数据集。在这一点上,我们应该阅读论文,但考虑到这篇博文的时间限制,我们将选择亚马逊评论多。总结一下,让我们专注于亚马逊评论多数据集并考虑所有训练示例。
最后,我们建议即使在使用私有数据集时也要利用Hub的数据集功能。Hugging Face Hub、Transformers和Datasets完美地集成在一起,使用它们来训练模型是非常简单的。
此外,Hugging Face Hub还提供:
- 每个数据集的数据集查看器
- 使用小部件轻松演示每个模型
- 私有和公共模型
- 存储库的Git版本控制
- 最高安全机制
寻找合适的模型
在确定了任务和最能描述我们用例的数据集之后,现在可以选择要使用的模型。
很可能,您将不得不对预训练模型进行微调以适应自己的用例,但值得检查一下Hub是否已经有合适的微调模型。在这种情况下,您可能只需在您的数据集上继续微调这样的模型,就可以获得更高的性能。
让我们来看看所有在亚马逊评论多上进行微调的模型。您可以在右下角找到模型列表 – 点击“浏览在该数据集上微调的模型”可以查看所有在该数据集上微调并公开可用的模型的列表。请注意,我们只对英文版本的数据集感兴趣,因为我们的客户反馈只会用英文表示。大多数下载量最多的模型都是在多语言版本的数据集上训练的,而那些不是多语言的模型则信息很少或性能较差。在这一点上,与其使用上述链接中已经进行过微调的模型之一,不如微调一个纯粹的预训练模型更明智。
好了,现在的下一步是找到一个合适的预训练模型用于微调。鉴于Hugging Face Hub上有大量的预训练和微调模型,这实际上比看起来更困难。通常最好的选择是尝试不同的模型,看看哪个表现最好。我们还没有找到在Hugging Face上比较不同模型检查点的完美方法,但我们提供了一些值得参考的资源:
- 模型摘要提供了不同模型架构的简要概述。
- 在Hugging Face Hub上进行特定任务的搜索,例如文本分类模型的搜索,可以显示下载量最多的检查点,这也是这些检查点表现如何的指标。
然而,以上两种资源目前都不是最佳选择。模型摘要并不总是由作者及时更新。新模型架构发布速度快,旧模型架构变得过时,使得难以获得关于所有模型架构的最新摘要。同样,并不意味着下载量最多的模型检查点就是最好的。例如,bert-base-cased
是最多下载的模型检查点之一,但已经不是性能最好的检查点了。
最佳方法是尝试各种模型架构,通过关注该领域的专家以及查看知名排行榜来了解最新的模型架构。
对于文本分类,需要关注的重要基准是GLUE和SuperGLUE。这两个基准评估了预训练模型在各种文本分类任务上的表现,例如语法正确性、自然语言推理、是/否问题回答等等,这些任务与我们的情感分析目标任务非常相似。因此,选择这些基准中的领先模型之一作为我们的任务是合理的。
在撰写这篇博文时,表现最好的模型是包含超过100亿参数的非常大的模型,其中大部分模型并没有开源,例如ST-MoE-32B,Turing NLR v5或ERNIE 3.0。其中一个排名靠前且易于获取的模型是DeBERTa。因此,让我们尝试DeBERTa的最新基础版本 – 即 microsoft/deberta-v3-base
。
使用🤗 Transformers和🤗 Datasets进行训练/微调模型
在本节中,我们将深入探讨如何端到端地微调模型,以便自动过滤非常不满意的客户反馈信息。
太棒了!让我们首先安装所有必要的pip包并设置好我们的代码环境,然后看看如何对数据集进行预处理,最后开始训练模型。
以下笔记本可以在启用了GPU运行时环境的Google Colab Pro上在线运行。
安装所有必要的包
首先,让我们安装git-lfs
,以便在训练期间自动将训练的检查点上传到Hub。
apt install git-lfs
此外,我们还需要安装🤗 Transformers和🤗 Datasets库以运行此笔记本。由于本博文中将使用DeBERTa,因此还需要安装sentencepiece
库来进行标记化。
pip install datasets transformers[sentencepiece]
接下来,让我们登录到Hugging Face账户,以便模型在您的用户名下正确上传。
from huggingface_hub import notebook_login
notebook_login()
输出:
登录成功
您的令牌已保存到/root/.huggingface/token
通过git凭据存储进行身份验证,但这不是在您的计算机上定义的助手。
如果您想将此凭据助手设置为默认值,请在终端中运行以下命令以重新进行身份验证
git config --global credential.helper store
预处理数据集
在我们开始训练模型之前,我们应该将数据集转换为模型可理解的格式。
幸运的是,🤗 Datasets库使这变得非常容易,如下面的代码所示。
load_dataset
函数加载数据集,并将其整理成预定义的属性,例如review_body
和stars
,最后使用arrow格式将新整理的数据保存到磁盘上。arrow格式可以实现快速和内存高效的数据读写。
让我们加载并准备amazon_reviews_multi
数据集的英文版本。
from datasets import load_dataset
amazon_review = load_dataset("amazon_reviews_multi", "en")
输出:
正在下载并准备数据集amazon_reviews_multi/en(下载:82.11 MiB,生成:58.69 MiB,后处理:未知大小,共计:140.79 MiB)到/root/.cache/huggingface/datasets/amazon_reviews_multi/en/1.0.0/724e94f4b0c6c405ce7e476a6c5ef4f87db30799ad49f765094cf9770e0f7609...
数据集amazon_reviews_multi已下载并准备好,保存到/root/.cache/huggingface/datasets/amazon_reviews_multi/en/1.0.0/724e94f4b0c6c405ce7e476a6c5ef4f87db30799ad49f765094cf9770e0f7609。后续调用将重用此数据。
太好了,速度很快🔥。我们来看一下数据集的结构。
print(amazon_review)
输出:
{.output .execute_result execution_count="5"}
DatasetDict({
train: Dataset({
features: ['review_id', 'product_id', 'reviewer_id', 'stars', 'review_body', 'review_title', 'language', 'product_category'],
num_rows: 200000
})
validation: Dataset({
features: ['review_id', 'product_id', 'reviewer_id', 'stars', 'review_body', 'review_title', 'language', 'product_category'],
num_rows: 5000
})
test: Dataset({
features: ['review_id', 'product_id', 'reviewer_id', 'stars', 'review_body', 'review_title', 'language', 'product_category'],
num_rows: 5000
})
})
我们有200,000个训练样本,以及5000个验证和测试样本。这对于训练来说听起来是合理的!我们只对输入的"review_body"
列和目标的"starts"
列感兴趣。
让我们查看一个随机例子。
random_id = 34
print("Stars:", amazon_review["train"][random_id]["stars"])
print("Review:", amazon_review["train"][random_id]["review_body"])
输出:
Stars: 1
Review: This product caused severe burning of my skin. I have used other brands with no problems
数据集以人类可读的格式存在,但现在我们需要将其转换为“机器可读”的格式。让我们定义模型存储库,其中包含了所有必要的工具来预处理和微调我们决定的检查点。
model_repository = "microsoft/deberta-v3-base"
接下来,我们加载模型存储库的分词器,它是DeBERTa的分词器。
from transformers import AutoTokenizer
tokenizer = AutoTokenizer.from_pretrained(model_repository)
如前所述,我们将使用"review_body"
作为模型的输入,"stars"
作为模型的目标。接下来,我们使用分词器将输入转换为模型可以理解的标记ID序列。分词器正是这样做的,并且还可以帮助您限制输入数据的长度,以避免内存问题。在这里,我们将最大长度限制为128个标记,对于DeBERTa来说,这大约对应于100个单词,又对应于大约5-7个句子。再次查看数据集查看器,我们可以看到这几乎涵盖了所有的训练示例。 重要提示:这并不意味着我们的模型不能处理更长的输入序列,它只是表示我们在训练时使用了最大长度为128,因为它涵盖了99%的训练数据,我们不想浪费内存。Transformer模型在训练后已经表现出很好的推广能力,可以处理更长的序列。
如果您想了解更多关于分词的信息,请查看Tokenizers文档。
标签很容易转换,因为它们已经以原始形式对应于数字,即从1到5的范围。在这里,我们只需将标签转换为0到4的范围,因为索引通常从0开始。
太好了,让我们将我们的想法转化为一些代码。我们将定义一个preprocess_function
,将其应用于每个数据样本。
def preprocess_function(example):
output_dict = tokenizer(example["review_body"], max_length=128, truncation=True)
output_dict["labels"] = [e - 1 for e in example["stars"]]
return output_dict
要将此函数应用于数据集中的所有数据样本,我们使用先前创建的amazon_review
对象的map
方法。这将在amazon_review
的所有拆分的所有元素上应用该函数,因此我们的训练、验证和测试数据将在一个命令中预处理。我们以batched=True
模式运行映射函数,以加快处理速度,并删除所有列,因为我们不再需要它们进行训练。
tokenized_datasets = amazon_review.map(preprocess_function, batched=True, remove_columns=amazon_review["train"].column_names)
让我们来看一下新的结构。
tokenized_datasets
输出:
DatasetDict({
train: Dataset({
features: ['input_ids', 'token_type_ids', 'attention_mask', 'labels'],
num_rows: 200000
})
validation: Dataset({
features: ['input_ids', 'token_type_ids', 'attention_mask', 'labels'],
num_rows: 5000
})
test: Dataset({
features: ['input_ids', 'token_type_ids', 'attention_mask', 'labels'],
num_rows: 5000
})
})
我们可以看到外层结构保持不变,但列的命名已经改变。让我们来看一下之前查看的同一个随机示例,只是现在已经经过预处理。
print("Input IDS:", tokenized_datasets["train"][random_id]["input_ids"])
print("Labels:", tokenized_datasets["train"][random_id]["labels"])
输出:
Input IDS: [1, 329, 714, 2044, 3567, 5127, 265, 312, 1158, 260, 273, 286, 427, 340, 3006, 275, 363, 947, 2]
Labels: 0
好了,输入文本被转换为一系列整数,模型可以将其转换为词嵌入,并且标签索引简单地向后移动了-1。
微调模型
在预处理数据集之后,接下来我们可以对模型进行微调。我们将使用流行的Hugging Face Trainer,它可以让我们只需几行代码即可开始训练。Trainer可以用于PyTorch中的几乎所有任务,并且通过处理训练所需的大量样板代码,非常方便。
让我们首先使用方便的AutoModelForSequenceClassification
加载模型检查点。由于模型库的检查点只是预训练的检查点,我们应该通过传递num_labels=5
来定义分类头的大小(因为我们有5个情感类别)。
from transformers import AutoModelForSequenceClassification
model = AutoModelForSequenceClassification.from_pretrained(model_repository, num_labels=5)
当初始化DebertaV2ForSequenceClassification时,模型检查点microsoft/deberta-v3-base的一些权重未被使用:['mask_predictions.classifier.bias', 'mask_predictions.LayerNorm.bias', 'mask_predictions.dense.weight', 'mask_predictions.dense.bias', 'mask_predictions.LayerNorm.weight', 'lm_predictions.lm_head.dense.bias', 'lm_predictions.lm_head.bias', 'lm_predictions.lm_head.LayerNorm.weight', 'lm_predictions.lm_head.dense.weight', 'lm_predictions.lm_head.LayerNorm.bias', 'mask_predictions.classifier.weight']
- 如果您正在从在另一个任务上训练或使用另一种架构的模型的检查点初始化DebertaV2ForSequenceClassification,则这是预期的。
- 如果您正在从与预期完全相同的模型检查点(从BertForSequenceClassification模型初始化BertForSequenceClassification模型)初始化DebertaV2ForSequenceClassification,则这是不预期的。
DebertaV2ForSequenceClassification的一些权重未从microsoft/deberta-v3-base模型检查点初始化,并且是新初始化的:['pooler.dense.bias', 'classifier.weight', 'classifier.bias', 'pooler.dense.weight']
您可能需要在下游任务上训练此模型,以便能够将其用于预测和推断。
接下来,我们加载一个数据收集器。数据收集器负责在训练期间正确填充每个批次的数据,这应该是动态发生的,因为在每个epoch之前训练样本会被重新洗牌。
from transformers import DataCollatorWithPadding
data_collator = DataCollatorWithPadding(tokenizer=tokenizer)
在训练期间,监视模型在保留的验证集上的性能非常重要。为了实现这一点,我们应该传递一个compute_metrics
函数来定义Trainer
在每个验证步骤中调用的函数。
文本分类任务中最简单的度量标准是准确率,它简单地表示多少百分比的训练样本被正确分类。然而,如果验证或测试数据非常不平衡,使用准确率度量可能会有问题。让我们通过计算每个标签的出现次数来快速验证这一点。
from collections import Counter
print("验证集:", Counter(tokenized_datasets["validation"]["labels"]))
print("测试集:", Counter(tokenized_datasets["test"]["labels"]))
输出:
验证集: Counter({0: 1000, 1: 1000, 2: 1000, 3: 1000, 4: 1000})
测试集: Counter({0: 1000, 1: 1000, 2: 1000, 3: 1000, 4: 1000})
验证集和测试集的平衡度非常高,因此我们可以安全地在这里使用准确率!
让我们通过datasets库加载准确率度量。
from datasets import load_metric
accuracy = load_metric("accuracy")
接下来,我们定义compute_metrics
函数,该函数将应用于模型的预测输出,类型为EvalPrediction
,因此可以访问模型的预测和真实标签。我们通过取模型预测的argmax
来计算预测的标签类别,并将其与真实标签一起传递给准确率度量。
import numpy as np
def compute_metrics(pred):
pred_logits = pred.predictions
pred_classes = np.argmax(pred_logits, axis=-1)
labels = np.asarray(pred.label_ids)
acc = accuracy.compute(predictions=pred_classes, references=labels)
return {"准确率": acc["accuracy"]}
太棒了,现在所有用于训练的组件都准备好了,剩下的就是定义Trainer
的超参数。我们需要确保在训练过程中将模型检查点上传到Hugging Face Hub。通过设置push_to_hub=True
,这将在每个save_steps
上自动完成,通过方便的push_to_hub
方法。
此外,我们定义了一些标准的超参数,如学习率、预热步数和训练轮数。我们将每500步记录一次损失,并每5000步运行一次评估。
from transformers import TrainingArguments
training_args = TrainingArguments(
output_dir="deberta_amazon_reviews_v1",
num_train_epochs=2,
learning_rate=2e-5,
warmup_steps=200,
logging_steps=500,
save_steps=5000,
eval_steps=5000,
push_to_hub=True,
evaluation_strategy="steps",
)
把所有东西放在一起,我们终于可以通过传递所有需要的组件来实例化Trainer了。我们将使用”validation”拆分作为训练过程中的保留数据集。
from transformers import Trainer
trainer = Trainer(
args=training_args,
compute_metrics=compute_metrics,
model=model,
tokenizer=tokenizer,
data_collator=data_collator,
train_dataset=tokenized_datasets["train"],
eval_dataset=tokenized_datasets["validation"]
)
Trainer准备就绪🚀您可以通过调用trainer.train()
开始训练。
train_metrics = trainer.train().metrics
trainer.save_metrics("train", train_metrics)
输出:
***** 正在运行训练 *****
样本数量 = 200000
轮数 = 2
每个设备的瞬时批量大小 = 8
总的训练批量大小(带有并行、分布式和累积) = 8
梯度积累步数 = 1
总的优化步数 = 50000
输出:
输出:
***** 正在评估 *****
样本数量 = 5000
批量大小 = 8
正在保存模型检查点到 deberta_amazon_reviews_v1/checkpoint-50000
配置保存在 deberta_amazon_reviews_v1/checkpoint-50000/config.json 中
模型权重保存在 deberta_amazon_reviews_v1/checkpoint-50000/pytorch_model.bin 中
tokenizer配置文件保存在 deberta_amazon_reviews_v1/checkpoint-50000/tokenizer_config.json 中
特殊token文件保存在 deberta_amazon_reviews_v1/checkpoint-50000/special_tokens_map.json 中
添加的token文件保存在 deberta_amazon_reviews_v1/checkpoint-50000/added_tokens.json 中
训练完成。不要忘记在huggingface.co/models上分享您的模型 =)
很棒,我们可以看到模型似乎学到了一些东西!训练损失和验证损失都在下降,准确率也远高于随机准确率(20%)。有趣的是,我们在仅经过5000步之后就看到了约58.6%的准确率,之后的改进并不是很大。选择一个更大的模型或者进行更长时间的训练可能会得到更好的结果,但对于我们的假设用例来说这已经足够好了!
好的,最后让我们将模型的检查点上传到Hub。
trainer.push_to_hub()
输出:
正在保存模型检查点至 deberta_amazon_reviews_v1
配置已保存至 deberta_amazon_reviews_v1/config.json
模型权重已保存至 deberta_amazon_reviews_v1/pytorch_model.bin
分词器配置文件已保存至 deberta_amazon_reviews_v1/tokenizer_config.json
特殊标记文件已保存至 deberta_amazon_reviews_v1/special_tokens_map.json
添加的标记文件已保存至 deberta_amazon_reviews_v1/added_tokens.json
将推送多个提交(2)到上游。
进度条可能不可靠。
评估/分析模型
现在,我们已经对模型进行了微调,需要非常小心地分析其性能。注意,经典的指标,如准确率,对于了解模型的性能提供了一般性的概述,但可能不足以评估模型在实际用例中的表现。更好的方法是找到一个最能描述模型实际用例的指标,并在训练期间和训练后精确地测量该指标。
让我们深入评估模型🤿。
模型已在训练后上传到Hub,名称为deberta_v3_amazon_reviews
。因此,在第一步中,让我们再次从Hub下载它。
from transformers import AutoModelForSequenceClassification
model = AutoModelForSequenceClassification.from_pretrained("patrickvonplaten/deberta_v3_amazon_reviews")
Trainer不仅是一个优秀的类用于训练模型,还可以用于在数据集上评估模型。让我们使用与之前相同的实例和函数实例化Trainer,但这次不需要传入训练数据集。
trainer = Trainer(
args=training_args,
compute_metrics=compute_metrics,
model=model,
tokenizer=tokenizer,
data_collator=data_collator,
)
我们使用Trainer的predict
函数在测试数据集上评估模型,使用相同的指标。
prediction_metrics = trainer.predict(tokenized_datasets["test"]).metrics
prediction_metrics
输出:
***** Running Prediction *****
Num examples = 5000
Batch size = 8
输出:
{'test_accuracy': 0.608,
'test_loss': 0.9637690186500549,
'test_runtime': 21.9574,
'test_samples_per_second': 227.714,
'test_steps_per_second': 28.464}
结果与验证数据集上的性能非常相似,这通常是一个好迹象,因为它表明模型没有过度拟合测试数据集。
然而,60%的准确率在一个5类分类问题上远非完美,但我们是否需要所有类别都有非常高的准确率?
由于我们主要关注非常负面的客户反馈,让我们只关注模型在分类最不满意的客户评论时的表现。我们还决定在这方面给模型一点帮助 – 所有被分类为非常不满意或不满意的反馈将由我们处理 – 以捕捉近99%的非常不满意的消息。同时,我们还测量了以这种方式回答了多少不满意的消息,以及通过回答中性、满意和非常满意客户的消息而产生了多少不必要的工作。
太棒了,让我们编写一个新的compute_metrics
函数。
import numpy as np
def compute_metrics(pred):
pred_logits = pred.predictions
pred_classes = np.argmax(pred_logits, axis=-1)
labels = np.asarray(pred.label_ids)
# 首先计算我们可以捕捉到的非常不满意消息的百分比
very_unsatisfied_label_idx = (labels == 0)
very_unsatisfied_pred = pred_classes[very_unsatisfied_label_idx]
# 现在0和1标签都是0标签,其余的都是> 0
very_unsatisfied_pred = very_unsatisfied_pred * (very_unsatisfied_pred - 1)
# 让我们计算有多少标签是0 -> 这是“非常不满意”准确率
true_positives = sum(very_unsatisfied_pred == 0) / len(very_unsatisfied_pred)
# 其次,计算我们不必要地回复了多少满意的消息
satisfied_label_idx = (labels > 1)
satisfied_pred = pred_classes[satisfied_label_idx]
# 有多少预测被标记为不满意的消息在所有满意的消息中?
false_positives = sum(satisfied_pred <= 1) / len(satisfied_pred)
return {"%_unsatisfied_replied": round(true_positives, 2), "%_satisfied_incorrectly_labels": round(false_positives, 2)}
我们再次实例化Trainer
以便轻松运行评估。
trainer = Trainer(
args=training_args,
compute_metrics=compute_metrics,
model=model,
tokenizer=tokenizer,
data_collator=data_collator,
)
让我们再次使用适用于我们用例的新度量方法运行评估。
prediction_metrics = trainer.predict(tokenized_datasets["test"]).metrics
prediction_metrics
输出:
***** 运行预测 *****
样本数量 = 5000
批次大小 = 8
输出:
{'test_%_satisfied_incorrectly_labels': 0.11733333333333333,
'test_%_unsatisfied_replied': 0.949,
'test_loss': 0.9637690186500549,
'test_runtime': 22.8964,
'test_samples_per_second': 218.375,
'test_steps_per_second': 27.297}
很棒!这已经描绘出了一个相当不错的画面。我们以自动方式捕获了大约95%的非常不满意的客户,成本是在满意消息上浪费10%的努力。
让我们进行一些快速计算。我们每天收到大约10,000条消息,预计其中约有500条非常负面。使用这种自动过滤,我们只需要查看500 + 0.12 * 10,000 = 1700条消息,并且只回复475条消息,同时错误地错过了5%的消息。非常好 – 在只错过5%的非常不满意客户的情况下,人力成本减少了83%!
显然,这些数字并不代表实际用例的获得价值,但如果有足够高质量的训练数据,我们可以接近实际情况!
让我们保存结果
trainer.save_metrics("prediction", prediction_metrics)
然后再次将所有内容上传到Hub。
trainer.push_to_hub()
输出:
正在将模型检查点保存到deberta_amazon_reviews_v1
配置保存在deberta_amazon_reviews_v1/config.json中
模型权重保存在deberta_amazon_reviews_v1/pytorch_model.bin中
tokenizer配置文件保存在deberta_amazon_reviews_v1/tokenizer_config.json中
特殊标记文件保存在deberta_amazon_reviews_v1/special_tokens_map.json中
添加的标记文件保存在deberta_amazon_reviews_v1/added_tokens.json中
正在将以下结果丢弃,因为它没有所有必要的字段:
{'task': {'name': 'Text Classification', 'type': 'text-classification'}}
To https://huggingface.co/patrickvonplaten/deberta_amazon_reviews_v1
599b891..ad77e6d main -> main
正在将结果上传到Hub。
To https://huggingface.co/patrickvonplaten/deberta_amazon_reviews_v1
ad77e6d..13e5ddd main -> main
数据现在保存在这里。
今天就到这里了 😎。作为最后一步,尝试在实际的真实数据上使用模型也是非常有意义的。可以直接在模型卡片上的推理小部件上进行。
它似乎对实际数据有很好的泛化能力🔥
优化
一旦您认为模型的性能已经足够好以供生产使用,就需要尽可能地使模型内存使用效率高并且速度快。
有一些明显的解决方案,例如选择最合适的加速硬件,例如更好的GPU,确保在前向传递过程中不计算梯度,或者降低精度,例如使用float16。
更高级的优化方法包括使用开源加速库(如ONNX Runtime)、量化和推理服务器(如Triton)。
在Hugging Face,我们一直致力于简化模型的优化,特别是通过我们的开源Optimum库。Optimum使优化大多数🤗 Transformers模型变得非常简单。
如果你正在寻找高度优化的解决方案,而不需要任何技术知识,你可能对推理 API 感兴趣。这是一个即插即用的解决方案,可用于生产中的各种机器学习任务,包括情感分析。
此外,如果你正在寻找支持你自定义用例的服务,Hugging Face 的专家团队可以帮助加速你的机器学习项目!我们的团队会在你的机器学习之旅中,从研究到生产,根据需要回答问题并找到解决方案。访问 hf.co/support 了解更多信息并请求报价。