精通Transformer——微调语言模型用于文本分类

Transformers 模型微调方法 Transformer 调参 阅读详情
AI摘要

本文介绍了配置预训练模型进行文本分类及微调以适应下游任务的方法,涵盖情感分析、多类分类、多标签分类和句子对回归等。使用知名和自定义数据集,借助Trainer类或原生PyTorch训练,还提供了模型评估和推理示例,最后分享大模型学习经验和资料。

在本章中,我们将学习如何配置一个预训练模型以进行文本分类,并如何微调它以适应任何文本分类的下游任务,例如情感分析、多类分类或多标签分类。我们还将讨论如何处理句子对和回归问题,并提供一个实现示例。我们将使用如 GLUE 等知名数据集以及我们自己的自定义数据集。随后,我们将利用 Trainer 类来处理训练和微调过程中的复杂性。

首先,我们将学习如何使用 Trainer 类微调单句二分类情感分析模型。然后,我们将使用原生 PyTorch 进行情感分类训练,而不使用 Trainer 类。在多类分类和多标签分类中,我们将考虑两个以上的类别。我们将进行七个类的分类微调任务。接下来,我们将训练一个文本回归模型,以预测带有句子对的数值。

本章将涵盖以下主题:

  • 文本分类简介
  • 使用 Trainer 类微调 BERT 模型进行单句二分类
  • 使用原生 PyTorch 训练分类模型
  • 使用自定义数据集微调 BERT 进行多类分类
  • 微调 BERT 进行句子对回归
  • 多标签文本分类
  • 利用 run_glue.py 微调模型

技术要求

我们将使用 Jupyter Notebook 来运行编码练习。你需要 Python 3.6 或更高版本,并确保安装以下包:

  • sklearn
  • transformers 4.0+
  • datasets

本章的所有编码练习的笔记本将可以在以下 GitHub 链接中找到:github.com/PacktPublis…

文本分类简介

文本分类(也称为文本归类)是一种将文档(如句子、推文、书籍章节、电子邮件内容等)映射到预定义类别列表(类)中的方法。当类别只有两个且标记为正面和负面时,我们使用二分类——更具体地说,就是情感分析。对于两个以上的类别,我们称之为多类分类,其中类别是互斥的;或者是多标签分类,其中类别不是互斥的,这意味着一个文档可以有多个标签。例如,一篇新闻文章的内容可能同时涉及体育和政治。除此之外,我们可能还希望对文档进行评分,范围在 [-1,1] 之间,或在 [1-5] 之间进行排名。这类问题可以通过回归模型来解决,其中输出类型为数值型,而不是类别型。

幸运的是,变换器架构使我们能够高效地解决这些问题。对于句子对任务,如文档相似度或文本蕴含,输入不是单个句子,而是两个句子,如下图所示。我们可以评估两个句子在语义上的相似程度或预测它们是否在语义上相似。另一个句子对任务是文本蕴含,其中问题被定义为多类分类。在这里,两个序列被映射为 GLUE 基准中的包含/矛盾/中立:

在这里插入图片描述

微调 BERT 模型进行单句二分类

在本节中,我们将讨论如何微调预训练的 BERT 模型以进行情感分析,使用的将是流行的 IMDb 情感数据集。使用 GPU 可以加快学习过程,但如果没有这样的资源,也可以使用 CPU 进行微调。让我们开始吧。

要了解并保存当前设备,我们可以执行以下代码:

from torch import cuda
device = 'cuda' if cuda.is_available() else 'cpu'

我们将在这里使用 DistilBertForSequenceClassification 类,它继承自 DistilBert 类,并在顶部有一个特殊的序列分类头。我们可以利用这个分类头来训练分类模型,默认情况下类别数为 2:

from transformers import (
    DistilBertTokenizerFast, DistilBertForSequenceClassification)
model_path = 'distilbert-base-uncased'
tokenizer = DistilBertTokenizerFast.from_pretrained(model_path)
model = DistilBertForSequenceClassification.from_pretrained(
    model_path,
    id2label={0: "NEG", 1: "POS"},
    label2id={"NEG": 0, "POS": 1})

注意,我们传递了两个参数 id2label 和 label2id 给模型,用于推理时。或者,我们可以实例化一个特定的配置对象并将其传递给模型,如下所示:

config = AutoConfig.from_pretrained(....)
SequenceClassification.from_pretrained(.... config=config)

现在,让我们选择一个流行的情感分类数据集,称为 IMDb 数据集。原始数据集包含两个数据集:25,000 个训练样本和 25,000 个测试样本。我们将数据集拆分为测试集和验证集。注意,数据集的前一半样本是正面的,而后一半样本都是负面的。我们可以如下分配样本:

from datasets import load_dataset
imdb_train = load_dataset('imdb', split="train")
imdb_test = load_dataset('imdb', split="test[:6250]+test[-6250:]")
imdb_val = load_dataset('imdb',
    split="test[6250:12500]+test[-12500:-6250]")

让我们检查数据集的形状:

imdb_train.shape, imdb_test.shape, imdb_val.shape
# 输出: ((25000, 2), (12500, 2), (12500, 2))

根据你的计算资源,你可以选择数据集的一小部分。对于较小的部分,你可以运行以下代码,选择 4,000 个样本用于训练,1,000 个用于测试,1,000 个用于验证:

imdb_train = load_dataset('imdb',
    split="train[:2000]+train[-2000:]")
imdb_test = load_dataset('imdb',
    split="test[:500]+test[-500:]")
imdb_val = load_dataset('imdb',
    split="test[500:1000]+test[-1000:-500]")

现在,我们可以通过 tokenizer 模型将这些数据集进行处理,使其准备好进行训练:

enc_train = imdb_train.map(lambda e: tokenizer(e['text'],
    padding=True, truncation=True), batched=True,
    batch_size=1000)
enc_test = imdb_test.map(lambda e: tokenizer(e['text'],
    padding=True, truncation=True), batched=True,
    batch_size=1000)
enc_val = imdb_val.map(lambda e: tokenizer(e['text'],
    padding=True, truncation=True), batched=True,
    batch_size=1000)

让我们看看训练集的样子。tokenizer 已经将注意力掩码和输入 ID 添加到数据集中,以便 BERT 模型可以处理它们:

import pandas as pd
pd.DataFrame(enc_train)

输出结果如下:

在这里插入图片描述

此时,数据集已经准备好进行训练和测试。Trainer 类(对于 TensorFlow 是 TFTrainer)和 TrainingArguments 类(对于 TensorFlow 是 TFTrainingArguments)将帮助我们处理大部分训练的复杂性。我们将在 TrainingArguments 类中定义我们的参数集,然后将其传递给 Trainer 对象。

让我们定义每个训练参数的作用:

在这里插入图片描述

有关更多信息,请查看 TrainingArguments 的 API 文档或在 Python Notebook 中执行以下代码:

TrainingArguments?

虽然像 LSTM 这样的深度学习架构需要许多 epochs(有时超过 50 个),但对于基于 Transformer 的微调,我们通常会满足于 3 个 epochs,因为迁移学习的原因。大多数情况下,这个数字足够用于微调,因为预训练模型在预训练阶段已经学到了很多关于语言的知识,预训练阶段通常需要约 50 个 epochs。为了确定正确的 epochs 数量,我们需要监控训练和评估的损失。我们将在第 11 章学习如何跟踪训练过程。

对于许多下游任务问题,这将足够,如我们将在这里看到的那样。在训练过程中,我们的模型检查点将每 200 步保存到 ./MyIMDBModel 文件夹下:

from transformers import TrainingArguments, Trainer

training_args = TrainingArguments(
    output_dir='./MyIMDBModel',
    do_train=True,
    do_eval=True,
    num_train_epochs=3,
    per_device_train_batch_size=32,
    per_device_eval_batch_size=64,
    warmup_steps=100,
    weight_decay=0.01,
    logging_strategy='steps',
    logging_dir='./logs',
    logging_steps=200,
    evaluation_strategy='steps',
    fp16=cuda.is_available(),
    load_best_model_at_end=True
)

在实例化 Trainer 对象之前,我们将定义 compute_metrics() 方法,这有助于我们根据特定的指标(例如精度、RMSE、皮尔逊相关系数、BLEU 等)监控训练进度。文本分类问题(如情感分类和多类分类)通常通过微平均或宏平均 F1 分数进行评估。宏平均方法对每个类别给予相等的权重,而微平均则对每个文本或每个标记的分类决策给予相等的权重。微平均等于模型正确决策的次数与总决策次数的比率。另一方面,宏平均方法计算每个类别的精度、召回率和 F1 分数的平均值。对于我们的分类问题,宏平均更方便用于评估,因为我们希望对每个标签给予相等的权重,如下所示:

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='macro')
    acc = accuracy_score(labels, preds)
    return {
        'Accuracy': acc,
        'F1': f1,
        'Precision': precision,
        'Recall': recall
    }

我们几乎准备好开始训练过程了。现在,让我们实例化 Trainer 对象并启动它。由于 transformers 库的支持,Trainer 类是一个非常强大且优化的工具,用于组织复杂的 PyTorch 和 TensorFlow(TFTrainer 对于 TensorFlow)训练和评估过程:

trainer = Trainer(
    model=model,
    args=training_args,
    train_dataset=enc_train,
    eval_dataset=enc_val,
    compute_metrics=compute_metrics
)

最后,我们可以开始训练过程:

results = trainer.train()

上述调用将开始记录指标,我们将在第 11 章中详细讨论这些指标。整个 IMDb 数据集包括 25,000 个训练示例。批次大小为 32 时,我们有 25K/32 ≈ 782 步,需要 2,346 步(782 x 3)来完成 3 个 epochs,如下进度条所示:

在这里插入图片描述

Trainer 对象在训练结束时会保存验证损失最小的检查点。它选择了第 1,400 步的检查点,因为此步的验证损失最小。让我们在三个数据集(训练集/验证集/测试集)上评估最佳检查点:

q = [trainer.evaluate(eval_dataset=data) for data in [enc_train, enc_val, enc_test]]
pd.DataFrame(q, index=["train", "val", "test"]).iloc[:, :5]

输出如下:

在这里插入图片描述

干得好!我们已经成功完成了训练/测试阶段,并在宏平均下获得了 92.6 的准确率和 F1 分数。要更详细地监控训练过程,可以使用高级工具如 TensorBoard。这些工具可以解析日志,并让我们跟踪各种指标以进行全面分析。我们已经在 ./logs 文件夹中记录了性能和其他指标。只需在 Python notebook 中运行以下 tensorboard 函数即可,如下所示(我们将在第 11 章详细讨论 TensorBoard 和其他监控工具):

%reload_ext tensorboard
%tensorboard --logdir logs

现在,我们将使用模型进行推理,以检查它是否正常工作。让我们定义一个预测函数以简化预测步骤,如下所示:

def get_prediction(text):
    inputs = tokenizer(text, padding=True, truncation=True,
        max_length=250, return_tensors="pt").to(device)
    outputs = model(inputs["input_ids"].to(device),
        inputs["attention_mask"].to(device))
    probs = outputs[0].softmax(1)
    return probs, probs.argmax()

现在,运行模型进行推理:

text = "I didn't like the movie it bored me "
get_prediction(text)[1].item()

我们得到的结果是 0,表示负面情感。我们已经定义了哪个 ID 对应哪个标签。我们可以使用这种映射方案来获取标签。或者,我们可以将所有这些繁琐的步骤直接传递给专用的 API,即 Pipeline,我们已经很熟悉了。在实例化之前,让我们保存最佳模型以备后续推理使用:

model_save_path = "MyBestIMDBModel"
trainer.save_model(model_save_path)
tokenizer.save_pretrained(model_save_path)

Pipeline API 是使用预训练模型进行推理的一种简单方法。我们从保存位置加载模型并将其传递给 Pipeline API,后者会处理其余部分。我们可以跳过这一步保存过程,直接将内存中的模型和 tokenizer 对象传递给 Pipeline API。如果这样做,你会得到相同的结果。

如下代码所示,当我们执行二分类任务时,需要指定 Pipeline 的任务名称参数为 sentiment-analysis:

from transformers import (
    pipeline, DistilBertForSequenceClassification,
    DistilBertTokenizerFast)
model = DistilBertForSequenceClassification.from_pretrained("MyBestIMDBModel")
tokenizer = DistilBertTokenizerFast.from_pretrained("MyBestIMDBModel")
nlp = pipeline("sentiment-analysis", model=model, tokenizer=tokenizer)

测试模型:

nlp("the movie was very impressive")

输出:

[{'label': 'POS', 'score': 0.9621992707252502}]

再测试一次:

nlp("the text of the picture was very poor")

输出:

[{'label': 'NEG', 'score': 0.9938313961029053}]

Pipeline API 知道如何处理输入,并且以某种方式学习了哪个 ID 对应哪个标签(POS 或 NEG)。它还提供了类别概率。

干得好!我们已经使用 Trainer 类为 IMDb 数据集微调了情感预测模型。在下一节中,我们将使用原生 PyTorch 进行相同的二分类训练,并使用不同的数据集。

使用原生 PyTorch 训练分类模型

Trainer 类非常强大,我们要感谢 Hugging Face 团队提供了这样一个有用的工具。然而,在本节中,我们将从头开始微调预训练模型,以了解其内部工作原理。让我们开始吧。

首先,加载用于微调的模型。我们将选择 DistilBert,因为它是 BERT 的一个小型、快速且廉价的版本:

from transformers import DistilBertForSequenceClassification
model = DistilBertForSequenceClassification.from_pretrained('distilbert-base-uncased')

为了微调任何模型,我们需要将其置于训练模式,如下所示:

model.train()

接下来,我们需要加载 tokenizer:

from transformers import DistilBertTokenizerFast
tokenizer = DistilBertTokenizerFast.from_pretrained('bert-base-uncased')

由于 Trainer 类为我们组织了整个过程,我们在之前的 IMDb 情感分类练习中没有涉及优化和其他训练设置。现在,我们需要自己实例化优化器。在这里,我们必须选择 AdamW,它是 Adam 算法的一个实现,但修正了权重衰减问题。最近的研究表明,AdamW 在训练损失和验证损失上表现得比 Adam 更好。因此,它在许多 transformer 训练过程中被广泛使用:

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

为了从头设计微调过程,我们必须了解如何实现单步的前向传播和反向传播。我们可以将一个批次的数据通过 transformer 层,得到输出,这称为前向传播。然后,我们必须使用输出和实际标签计算损失,并根据损失更新模型权重,这称为反向传播。

以下代码接收与标签相关联的三句话,进行一次批次的前向传播。最后,模型会自动计算损失:

import torch
texts = ["this is a good example", "this is a bad example", "this is a good one"]
labels = [1, 0, 1]
labels = torch.tensor(labels).unsqueeze(0)
encoding = tokenizer(texts, return_tensors='pt', padding=True, truncation=True, max_length=512)
input_ids = encoding['input_ids']
attention_mask = encoding['attention_mask']
outputs = model(input_ids, attention_mask=attention_mask, labels=labels)
loss = outputs.loss
loss.backward()
optimizer.step()

输出如下:

SequenceClassifierOutput(
    [('loss', tensor(0.7178, grad_fn=<NllLossBackward>)), 
     ('logits', tensor([[ 0.0664, -0.0161], [ 0.0738, 0.0665], [ 0.0690, -0.0010]], grad_fn=<AddmmBackward>))])

模型接收 input_ids 和 attention_mask,这些是由 tokenizer 生成的,并使用实际标签计算损失。我们可以看到输出包括损失和 logits。loss.backward() 计算了张量的梯度,通过输入和标签对模型进行评估。optimizer.step() 执行单步优化,并使用计算出的梯度更新权重,这被称为反向传播。当我们将这些步骤放入一个循环时,我们还将添加 optimizer.zero_grad(),它清除所有参数的梯度。重要的是在循环开始时调用这个方法,否则我们可能会积累来自多个步骤的梯度。输出中的第二个张量是 logits。在深度学习中,logits 是神经网络的最后一层,包括预测值(实数)。在分类的情况下,logits 需要通过 softmax 函数转换为概率。否则,它们仅仅是用于回归的标准化值。

如果我们要手动计算损失,我们不能将标签传递给模型。因此,模型只会产生 logits,而不会计算损失。在以下示例中,我们手动计算了交叉熵损失:

from torch.nn import functional
labels = torch.tensor([1, 0, 1])
outputs = model(input_ids, attention_mask=attention_mask)
loss = functional.cross_entropy(outputs.logits, labels)
loss.backward()
optimizer.step()

输出:

tensor(0.6101, grad_fn=<NllLossBackward>)

通过以上操作,我们了解了如何在前向传播过程中处理批量输入。现在,是时候设计一个循环,以批量的形式遍历整个数据集,从而训练模型多个周期。为此,我们将从设计 Dataset 类开始。它是 torch.Dataset 的一个子类,继承了成员变量和函数,并实现了 __init__() 和 __getitem__() 抽象函数:

from torch.utils.data import Dataset
class MyDataset(Dataset):
    def __init__(self, encodings, labels):
        self.encodings = encodings
        self.labels = labels

    def __getitem__(self, idx):
        item = {key: torch.tensor(val[idx]) for key, val in self.encodings.items()}
        item['labels'] = torch.tensor(self.labels[idx])
        return item

    def __len__(self):
        return len(self.labels)

我们将使用一个名为 Stanford Sentiment Treebank v2 (sst2) 的情感分析数据集来微调模型。我们还将加载 sst2 对应的评估指标,如下所示:

import datasets
from datasets import load_dataset
sst2 = load_dataset("glue", "sst2")
from datasets import load_metric
metric = load_metric("glue", "sst2")

我们将提取句子和标签:

texts = sst2['train']['sentence']
labels = sst2['train']['label']
val_texts = sst2['validation']['sentence']
val_labels = sst2['validation']['label']

现在,我们可以通过 tokenizer 处理数据集,并实例化 MyDataset 对象,使 BERT 模型可以使用它们:

train_dataset = MyDataset(tokenizer(texts, truncation=True, padding=True), labels)
val_dataset = MyDataset(tokenizer(val_texts, truncation=True, padding=True), val_labels)

让我们实例化 DataLoader 类,它提供了一个接口,通过加载顺序迭代数据样本。这也有助于批处理和内存固定:

from torch.utils.data import DataLoader
train_loader = DataLoader(train_dataset, batch_size=16, shuffle=True)
val_loader = DataLoader(val_dataset, batch_size=16, shuffle=True)

以下代码检测设备并正确定义 AdamW 优化器:

from transformers import AdamW
device = torch.device('cuda') if torch.cuda.is_available() else torch.device('cpu')
model.to(device)
optimizer = AdamW(model.parameters(), lr=1e-3)

到目前为止,我们已经了解了如何实现前向传播,这是在一个批次的示例中处理数据的过程。在一个步骤中,每一层从第一层到最后一层都通过批量数据进行处理,经过激活函数后传递给下一层。为了通过多个周期遍历整个数据集,我们设计了两个嵌套循环:外部循环用于 epoch,内部循环用于每个批次的步骤。内部部分由两个块组成,一个是训练,另一个是评估每个 epoch。正如你所注意到的,我们在第一个训练循环中调用了 model.train(),而在第二个评估块中,我们调用了 model.eval()。这很重要,因为我们将模型置于训练和推理模式。

我们已经讨论了内部块。请注意,我们通过对应的 metric 对象跟踪模型的性能:

for epoch in range(3):
    model.train()
    for batch in train_loader:
        optimizer.zero_grad()
        input_ids = batch['input_ids'].to(device)
        attention_mask = batch['attention_mask'].to(device)
        labels = batch['labels'].to(device)
        outputs = model(input_ids, attention_mask=attention_mask, labels=labels)
        loss = outputs[0]
        loss.backward()
        optimizer.step()
    model.eval()
    for batch in val_loader:
        input_ids = batch['input_ids'].to(device)
        attention_mask = batch['attention_mask'].to(device)
        labels = batch['labels'].to(device)
        outputs = model(input_ids, attention_mask=attention_mask, labels=labels)
        predictions = outputs.logits.argmax(dim=-1)
        metric.add_batch(predictions=predictions, references=batch["labels"])
    eval_metric = metric.compute()
    print(f"epoch {epoch}: {eval_metric}")

输出:

epoch 0: {'accuracy': 0.9048165137614679}
epoch 1: {'accuracy': 0.8944954128440367}
epoch 2: {'accuracy': 0.9094036697247706}

干得好!我们已经微调了模型,并获得了约 90.94 的准确率。剩下的过程,例如保存、加载和推理,将类似于我们在 Trainer 类中所做的。

到此为止,我们已经完成了二分类任务。在下一节中,我们将学习如何为非英语语言实现多类分类模型。

使用自定义数据集微调 BERT 进行多类分类

在本节中,我们将微调土耳其语 BERT,即 BERTurk,以执行七类分类的下游任务,数据集来自土耳其报纸,包含七个类别。我们将从获取数据集开始。你也可以在本书的 GitHub 仓库中找到这个数据集,或者从 Kaggle 下载。

首先,在 Python Notebook 中运行以下代码以获取数据:

!wget https://raw.githubusercontent.com/savasy/TurkishTextClassification/master/TTC4900.csv

然后,我们加载数据:

import pandas as pd
data = pd.read_csv("TTC4900.csv")
data = data.sample(frac=1.0, random_state=42)

接下来,我们将使用 id2label 和 label2id 来组织 ID 和标签,以便模型能够识别每个 ID 对应的标签。我们还将传递标签数量 NUM_LABELS 给模型,以指定 BERT 模型顶部的薄分类头层的大小:

labels = ["teknoloji", "ekonomi", "saglik", "siyaset", "kultur", "spor", "dunya"]
NUM_LABELS = len(labels)
id2label = {i: l for i, l in enumerate(labels)}
label2id = {l: i for i, l in enumerate(labels)}
data["labels"] = data.category.map(lambda x: label2id[x.strip()])
data.head()

输出结果如下:

在这里插入图片描述

让我们使用 pandas 对象计算并绘制类别数量的饼图:

data.category.value_counts().plot(kind='pie')

如下面的图示所示,数据集的类别分布相对均匀:

在这里插入图片描述

以下代码实例化了一个序列分类模型,设置了标签数量(7)、标签 ID 映射以及 BERTurk 模型:

>>> model

输出将是模型的总结,内容较长,此处不一一展示。我们将重点关注最后一层:

(classifier): Linear(in_features=768, out_features=7, bias=True)

你可能注意到,我们没有选择 DistilBert,因为没有为土耳其语预训练的无大写 DistilBert 模型:

from transformers import BertTokenizerFast
tokenizer = BertTokenizerFast.from_pretrained("dbmdz/bert-base-turkish-uncased", max_length=512)
from transformers import BertForSequenceClassification
model = BertForSequenceClassification.from_pretrained(
    "dbmdz/bert-base-turkish-uncased",
    num_labels=NUM_LABELS,
    id2label=id2label, label2id=label2id
)
model.to(device)

接下来,让我们准备训练集(50%)、验证集(25%)和测试集(25%),如下所示:

SIZE = data.shape[0]
# 句子
train_texts = list(data.text[:SIZE//2])
val_texts = list(data.text[SIZE//2:(3*SIZE)//4])
test_texts = list(data.text[(3*SIZE)//4:])
# 标签
train_labels = list(data.labels[:SIZE//2])
val_labels = list(data.labels[SIZE//2:(3*SIZE)//4])
test_labels = list(data.labels[(3*SIZE)//4:])
# 检查大小
len(train_texts), len(val_texts), len(test_texts)
# 输出: (2450, 1225, 1225)

以下代码将三个数据集的句子进行分词,并将其转换为整数(input_ids),然后输入到 BERT 模型中:

train_encodings = tokenizer(train_texts, truncation=True, padding=True)
val_encodings = tokenizer(val_texts, truncation=True, padding=True)
test_encodings = tokenizer(test_texts, truncation=True, padding=True)

我们已经实现了 MyDataset 类。该类继承自抽象的 Dataset 类,并重写了 __getitem__ 和 __len__() 方法,分别用于返回数据项和数据集的大小:

train_dataset = MyDataset(train_encodings, train_labels)
val_dataset = MyDataset(val_encodings, val_labels)
test_dataset = MyDataset(test_encodings, test_labels)

由于数据集相对较小,我们将批量大小保持为 16。请注意,TrainingArguments 的其他参数与之前的情感分析实验几乎相同:

from transformers import TrainingArguments, Trainer
training_args = TrainingArguments(
    output_dir='./TTC4900Model',
    do_train=True,
    do_eval=True,
    num_train_epochs=3,
    per_device_train_batch_size=16,
    per_device_eval_batch_size=32,
    warmup_steps=100,
    weight_decay=0.01,
    logging_strategy='steps',
    logging_dir='./multi-class-logs',
    logging_steps=50,
    evaluation_strategy="epoch",
    eval_steps=50,
    save_strategy="epoch",
    fp16=True,
    load_best_model_at_end=True
)

情感分析和文本分类使用相同的评估指标,即宏平均 F1、精确度和召回率。因此,我们不再重新定义 compute_metrics() 函数。下面是实例化 Trainer 对象的代码:

trainer = Trainer(
    model=model,
    args=training_args,
    train_dataset=train_dataset,
    eval_dataset=val_dataset,
    compute_metrics=compute_metrics
)

最后,让我们开始训练过程:

trainer.train()

输出结果如下:

在这里插入图片描述

要检查训练后的模型,我们需要在三个数据集划分上评估微调后的模型,具体如下。我们最佳的模型在第 300 步时微调完成,损失为 0.28012:

q = [trainer.evaluate(eval_dataset=data) for data in [train_dataset, val_dataset, test_dataset]]
pd.DataFrame(q, index=["train", "val", "test"]).iloc[:, :5]

输出结果如下:

在这里插入图片描述

分类准确率约为 92.6%,而 F1 宏平均约为 92.5%。在文献中,许多方法已在这个土耳其基准数据集上进行了测试。这些方法主要采用 TF-IDF 和线性分类器、word2vec 嵌入或基于 LSTM 的分类器,最好的 F1 值也仅约为 90.0。与这些方法相比,除了 Transformer 模型外,微调后的 BERT 模型表现更为优越。

与其他实验一样,我们可以通过 TensorBoard 跟踪实验进程:

%load_ext tensorboard
%tensorboard --logdir multi-class-logs/

让我们设计一个函数来运行模型进行推断。如果你想看到实际的标签而不是 ID,可以使用模型的配置对象,如下所示的预测函数:

def predict(text):
    inputs = tokenizer(text, padding=True, truncation=True,
        max_length=512, return_tensors="pt").to("cuda")
    outputs = model(**inputs)
    probs = outputs[0].softmax(1)
    return (probs,
        probs.argmax(),
        model.config.id2label[probs.argmax().item()])

现在,我们准备调用预测函数进行文本分类推断。以下代码对关于足球队的句子进行分类:

text = "Fenerbahçeli futbolcular kısa paslarla hazırlık çalışması yaptılar"
predict(text)

输出:

(tensor([[5.6183e-04, 4.9046e-04, 5.1385e-04,
    9.94e-04, 3.44e-04, 9.96e-01, 4.061e-04]],
    device='cuda:0',
    grad_fn=<SoftmaxBackward>),
tensor(5, device='cuda:0'),
'spor')

如我们所见,模型正确地将句子预测为体育(spor)。现在,是时候保存模型并使用 from_pre-trained() 函数重新加载它了。以下是代码:

model_path = "turkish-text-classification-model"
trainer.save_model(model_path)
tokenizer.save_pretrained(model_path)

现在,我们可以重新加载保存的模型,并使用 pipeline 类进行推断:

model_path = "turkish-text-classification-model"
from transformers import (pipeline,
    BertForSequenceClassification,
    BertTokenizerFast)
model = BertForSequenceClassification.from_pretrained(model_path)
tokenizer = BertTokenizerFast.from_pretrained(model_path)
nlp = pipeline("sentiment-analysis",
                model=model, tokenizer=tokenizer)

你可能注意到任务名称是 sentiment-analysis。这个术语可能会让人困惑,但这个参数最终会返回 TextClassificationPipeline。让我们运行管道:

nlp("Sinemada hangi filmler oynuyor bugün")

输出:

[{'label': 'kultur', 'score': 0.9930670261383057}]

nlp("Dolar ve Euro bugün yurtiçi piyasalarda yükseldi")

输出:

[{'label': 'ekonomi', 'score': 0.9927696585655212}]

nlp("Bayern Münih ile Barcelona bugün karşı karşıya geliyor. \
    Maçı İngiliz hakem James Watts yönetecek!")

输出:

[{'label': 'spor', 'score': 0.9975664019584656}]

模型已经成功预测。

到目前为止,我们已经实现了两个单句任务——情感分析和多类别分类。在下一节中,我们将学习如何处理句子对输入以及如何设计 BERT 的回归模型。

微调 BERT 模型以进行句子对回归

回归模型通常用于分类任务,但在这种情况下,最后一层仅包含一个单元。与通过 softmax 逻辑回归处理不同,它会被归一化。要定义模型并在顶部添加一个单单元头层,有两个选项:直接在 BERT.from_pretrained() 方法中包括 num_labels=1 参数,或通过配置对象传递此信息。最初,需要从预训练模型的配置对象中复制这个配置,如下所示:

from transformers import (
    DistilBertConfig, DistilBertTokenizerFast,
    DistilBertForSequenceClassification)
model_path = 'distilbert-base-uncased'
config = DistilBertConfig.from_pretrained(model_path, num_labels=1)
tokenizer = DistilBertTokenizerFast.from_pretrained(model_path)
model = DistilBertForSequenceClassification.from_pretrained(
    model_path, config=config)

通过 num_labels=1 参数,我们的预训练模型拥有了一个单单元头层。现在,我们准备使用我们的数据集来微调模型。我们将使用语义文本相似度基准(STS-B),这是一个包含句子对的数据集,这些句子对来源于各种内容,如新闻标题。每对句子都被标注了一个从 1 到 5 的相似度评分。我们的任务是微调 BERT 模型以预测这些评分。我们将使用 Pearson/Spearman 相关系数来评估模型,遵循文献中的做法。让我们开始吧。

以下代码加载数据。原始数据被拆分为三部分。然而,测试集没有标签,因此我们可以将验证数据分为两部分,如下所示:

import datasets
from datasets import load_dataset
stsb_train = load_dataset('glue', 'stsb', split="train")
stsb_validation = load_dataset('glue', 'stsb', split="validation")
stsb_validation = stsb_validation.shuffle(seed=42)
stsb_val = datasets.Dataset.from_dict(stsb_validation[:750])
stsb_test = datasets.Dataset.from_dict(stsb_validation[750:])

让我们通过 Pandas 包装 stsb_train 训练数据,使其更加整洁:

pd.DataFrame(stsb_train)

这就是训练数据的样子:

在这里插入图片描述

运行以下代码以检查三个数据集的形状:

stsb_train.shape, stsb_val.shape, stsb_test.shape

输出结果是:

((5749, 4), (750, 4), (750, 4))

运行以下代码以对数据集进行分词:

enc_train = stsb_train.map(lambda e: tokenizer(
        e['sentence1'], e['sentence2'], padding=True,
        truncation=True),
    batched=True, batch_size=1000)
enc_val = stsb_val.map(lambda e: tokenizer(
        e['sentence1'], e['sentence2'], padding=True, truncation=True),
    batched=True, batch_size=1000)
enc_test = stsb_test.map(lambda e: tokenizer(
        e['sentence1'], e['sentence2'], padding=True,
        truncation=True),
    batched=True, batch_size=1000)

分词器将两个句子用 [SEP] 分隔符合并,并生成一个句子对的 input_ids 和 attention_mask,如下所示:

pd.DataFrame(enc_train)

输出结果如下:

在这里插入图片描述

与其他实验类似,我们在 TrainingArguments 和 Trainer 类中的配置几乎相同。以下是代码:

from transformers import TrainingArguments, Trainer

training_args = TrainingArguments(
    output_dir='./stsb-model',
    do_train=True,
    do_eval=True,
    num_train_epochs=3,
    per_device_train_batch_size=32,
    per_device_eval_batch_size=64,
    warmup_steps=100,
    weight_decay=0.01,
    logging_strategy='steps',
    logging_dir='./logs',
    logging_steps=50,
    evaluation_strategy="steps",
    save_strategy="epoch",
    fp16=True,
    load_best_model_at_end=True
)

当前回归任务与之前的分类任务之间的另一个重要区别是 compute_metrics 的设计。在这里,我们的评估指标将基于 Pearson 相关系数和 Spearman 秩相关系数,这符合文献中的常见做法。我们还提供了均方误差(MSE)、均方根误差(RMSE)和平均绝对误差(MAE)指标,这些指标通常用于回归模型:

import numpy as np
from scipy.stats import pearsonr
from scipy.stats import spearmanr

def compute_metrics(pred):
    preds = np.squeeze(pred.predictions)
    return {
        "MSE": ((preds - pred.label_ids) ** 2).mean().item(),
        "RMSE": np.sqrt(((preds - pred.label_ids) ** 2).mean()).item(),
        "MAE": np.abs(preds - pred.label_ids).mean().item(),
        "Pearson": pearsonr(preds, pred.label_ids)[0],
        "Spearman": spearmanr(preds, pred.label_ids)[0]
    }

现在,让我们实例化 Trainer 对象:

trainer = Trainer(
    model=model,
    args=training_args,
    train_dataset=enc_train,
    eval_dataset=enc_val,
    compute_metrics=compute_metrics,
    tokenizer=tokenizer
)

然后,运行训练:

train_result = trainer.train()

输出结果如下:

在这里插入图片描述

最佳的验证损失是在第 450 步计算得出的,为 0.544973。让我们对在该步骤获得的最佳检查点模型进行评估,代码如下:

q = [trainer.evaluate(eval_dataset=data) for data in [enc_train, enc_val, enc_test]]
pd.DataFrame(q, index=["train", "val", "test"]).iloc[:, :5]

输出结果如下:

在这里插入图片描述

皮尔逊和斯皮尔曼相关系数在测试数据集上的得分分别为 87.54 和 87.28。虽然我们没有获得最先进的结果,但根据 GLUE 基准排行榜,我们得到了一个可比的 STS-B 任务结果。

现在我们准备进行模型推理。让我们使用以下两个含义相同的句子,并将其传递给模型:

s1, s2 = "A plane is taking off.", "An air plane is taking off."
encoding = tokenizer(s1, s2, return_tensors='pt', padding=True, truncation=True, max_length=512)
input_ids = encoding['input_ids'].to(device)
attention_mask = encoding['attention_mask'].to(device)
outputs = model(input_ids, attention_mask=attention_mask)
outputs.logits.item()

输出结果为:4.033723831176758

接下来,我们处理负面的句子对,这意味着这些句子在语义上是不同的:

s1, s2 = "The men are playing soccer.", "A man is riding a motorcycle."
encoding = tokenizer("hey how are you there", "hey how are you", return_tensors='pt', padding=True, truncation=True, max_length=512)
input_ids = encoding['input_ids'].to(device)
attention_mask = encoding['attention_mask'].to(device)
outputs = model(input_ids, attention_mask=attention_mask)
outputs.logits.item()

输出结果为:2.3579328060150146

最后,我们将模型保存起来,代码如下:

model_path = "sentence-pair-regression-model"
trainer.save_model(model_path)
tokenizer.save_pretrained(model_path)

干得好!我们已经成功完成了三个任务:情感分析、多类分类和句子对回归。所有这些任务都基于单标签。接下来,我们将学习如何解决多标签分类问题。

多标签文本分类

在本章中,我们已经解决了多类别文本分类问题,其中每个文本只分配一个标签。现在,我们将讨论多标签分类,其中一个文本可以有多个标签。这在自然语言处理应用中很常见,例如新闻分类。例如,一条新闻可能同时与体育和健康相关。下图展示了多标签分类的示例:

在这里插入图片描述

现在,我们将深入探讨如何开发一个多标签分类的流程。为此,我们将使用PubMed数据集,该数据集包含约50,000篇研究文章。这些文章被生物医学专家手动标注了MeSH标签,每篇文章根据14个MeSH标签的组合进行描述。

首先,我们需要导入相关库:

import torch
import numpy as np
import pandas as pd
from datasets import Dataset, load_dataset
from transformers import (AutoTokenizer, AutoModelForSequenceClassification, TrainingArguments, Trainer)

数据集已经由Hugging Face Hub提供托管。我们从Hub下载数据集,如下所示。为了快速训练,我们仅选择训练数据集的10%。如果你希望获得更好的性能,可以使用整个数据集:

path = "owaiskha9654/PubMed_MultiLabel_Text_Classification_Dataset_MeSH"
dataset = load_dataset(path, split="train[:10%]")
train_dataset = pd.DataFrame(dataset)
text_column = 'abstractText'  # 文本字段
label_names = list(train_dataset.columns[6:])
num_labels = len(label_names)
print('Number of Labels:', num_labels)
train_dataset[[text_column] + label_names]

输出结果如下:

Number of Labels: 14

如下面的表格所示,我们有一个abstractText字段和14个可能的标签,其中1和0分别表示标签的存在和不存在。

在这里插入图片描述

现在,让我们计算标签分布并进行分析,使用以下代码:

train_dataset[label_names].apply(lambda x: sum(x), axis=0).plot(kind="bar", figsize=(10, 6))

这将绘制以下图表:

在这里插入图片描述

从不平衡的分布中可以看出,我们有一些较小的标签,如 F、H、I、J、L 和 Z。对整个数据集进行分析时,也会得到类似的分布!

我们需要将标签列转换为一个列表,如下所示:

train_dataset["labels"] = train_dataset.apply(
    lambda x: x[label_names].to_numpy(), axis=1)
train_dataset[[text_column, "labels"]]

现在,我们得到了以下形状(abstractText -> labels),这是后续管道所需要的:

在这里插入图片描述

我们将微调 distilbert-base-uncased 模型。由于需要对文本进行标记化,我们首先加载 DistilBert 分词器,如下所示:

model_path = "distilbert-base-uncased"
tokenizer = AutoTokenizer.from_pretrained(model_path)
def tokenize(batch):
    return tokenizer(batch[text_column],
        padding=True,
        truncation=True)

现在,我们将数据集拆分为三个子集(50% 训练集、25% 验证集和 25% 测试集),并相应地对其进行标记化:

q = train_dataset[[text_column, "labels"]].copy()
CUT = int((q.shape)[0] * 0.5)
CUT2 = int((q.shape)[0] * 0.75)
train_df = q[:CUT] # 训练集
val_df = q[CUT:CUT2] # 验证集
test_df = q[CUT2:]  # 测试集
train = Dataset.from_pandas(train_df) # 转换为 Dataset 对象
val = Dataset.from_pandas(val_df)
test = Dataset.from_pandas(test_df)
train_encoded = train.map(tokenize, batched=True,
    batch_size=None)
val_encoded = val.map(tokenize, batched=True,
    batch_size=None)
test_encoded = test.map(tokenize, batched=True,
    batch_size=None)

我们现在有三个子集的数据集,这些数据集已经通过分词器进行了编码,并准备好由 Transformer 模型处理。

接下来,我们将定义一个函数来处理 Transformer 模型最后一层的激活(logits),以生成预测向量。如果我们进行的是单标签分类,softmax 将是最合适的公式,因为我们有一个输出。然而,由于许多标签可以是正确的标签且它们不是互斥的,我们将通过 sigmoid 函数独立地传递所有标签,而不是使用 softmax。通过这样做,我们将有机会同时选择所有标签作为预测或没有任何标签。我们通过将 sigmoid 函数的输出通过简单的 >0.5 阈值来做出决定。

现在,我们将定义 compute_metrics() 函数,以在训练期间监控模型性能。以下函数利用 sklearn 库给出标签存在的精确度、召回率和 F1 分数。请注意,在 f1_score() 函数中,我们设置 pos_label=1,因为我们只关注标签的存在。如果考虑标签的存在和缺失,你可能会得到人为的高结果,并且很难监控模型性能,尤其是对于标签稀疏模式!

让我们定义 compute_metrics 函数:

from sklearn.metrics import (f1_score, precision_score, recall_score)
def compute_metrics(eval_pred):
    y_pred, y_true = eval_pred
    y_pred = torch.from_numpy(y_pred)
    y_true = torch.from_numpy(y_true)
    y_pred = y_pred.sigmoid() > 0.5
    y_true = y_true.bool()
    r = recall_score(y_true, y_pred,
    average='micro', pos_label=1)
    p = precision_score(y_true, y_pred,
    average='micro', pos_label=1)
    f1 = f1_score(y_true, y_pred,
    average='micro', pos_label=1)
    result = {"Recall": r, "Precision": p, "F1": f1}
    return result

对于单标签多分类任务,我们使用 softmax 激活函数加上交叉熵损失函数。然而,对于多标签模式,我们需要使用不同的激活函数和损失函数。在实现过程中,我们保留原始 Trainer 的所有其他功能,但必须调整损失函数。具体来说,我们将 Trainer 类原始损失函数中的 torch.nn.CrossEntropyLoss() 函数替换为 torch.nn.BCEWithLogitsLoss()。

如下所示,在 MultilabelTrainer 类定义中,torch.nn.BCEWithLogitsLoss() 函数计算真实标签和原始 logits 之间的损失。损失函数首先通过 sigmoid 函数生成预测,然后计算损失:

class MultilabelTrainer(Trainer):
    def compute_loss(self, model, inputs, return_outputs=False):
        labels = inputs.pop("labels")
        outputs = model(**inputs)
        logits = outputs.logits
        loss_fct = torch.nn.BCEWithLogitsLoss()
        preds_ = logits.view(-1, self.model.config.num_labels)
        labels_ = labels.float().view(-1, self.model.config.num_labels)
        loss = loss_fct(preds_, labels_)
        return (loss, outputs) if return_outputs else loss

此时,Trainer 实例和 TrainingArguments 实例与之前的多分类模式大致相同。以下是参数:

batch_size = 16
num_epoch = 3
args = TrainingArguments(
    output_dir="/tmp",
    per_device_train_batch_size=batch_size,
    per_device_eval_batch_size=batch_size,
    num_train_epochs=num_epoch,
    do_train=True,
    do_eval=True,
    load_best_model_at_end=True,
    save_steps=100,
    eval_steps=100,
    save_strategy="steps",
    evaluation_strategy="steps")

我们将加载 DistilBert 模型。注意,我们将模型的输出层大小设置为 14(与 num_labels 一致):

model = AutoModelForSequenceClassification.from_pretrained(
    model_path, num_labels=num_labels)

好了!我们准备开始训练。开始吧!

multi_trainer = MultilabelTrainer(model, args,
    train_dataset=train_encoded,
    eval_dataset=val_encoded,
    compute_metrics=compute_metrics,
    tokenizer=tokenizer)
multi_trainer.train()

如果一切顺利,我们可以在测试数据集上测试我们的模型,如下所示:

res = multi_trainer.predict(test_encoded)
pd.Series(compute_metrics(res[:2])).to_frame()

以下是输出结果:

在这里插入图片描述

完成了!我们已经用一个采样的数据集训练了一个多标签分类模型,进行了快速的实验。请注意,使用完整的数据集进行训练会得到更好的F1得分!请你自己试试看吧!接下来,我们将使用一个脚本来简化整个过程。

利用 run_glue.py 进行模型微调

到目前为止,我们已经使用原生PyTorch和Trainer类从头设计了一个微调架构。Hugging Face社区还提供了一个强大的脚本 run_glue.py,用于GLUE基准测试和类似GLUE的分类下游任务。这个脚本可以处理和组织整个训练/验证过程。如果你想进行快速原型开发,应该使用这个脚本。它可以微调任何在Hugging Face Hub上预训练的模型。我们也可以将自己的数据以任何格式输入给它。

请访问以下链接获取脚本并了解更多信息:GitHub链接。

这个脚本可以执行九种不同的GLUE任务。使用这个脚本,我们可以完成到目前为止使用Trainer类所做的所有操作。任务名称可以是以下GLUE任务中的一种:cola、sst2、mrpc、stsb、qqp、mnli、qnli、rte或wnli。

以下是微调模型的脚本示例:

export TASK_NAME="My-Task-Name"
python run_glue.py \
--model_name_or_path bert-base-cased \
--task_name $TASK_NAME \
--do_train \
--do_eval \
--max_seq_length 128 \
--per_device_train_batch_size 32 \
--learning_rate 2e-5 \
--num_train_epochs 3 \
--output_dir /tmp/$TASK_NAME/

社区还提供了另一个脚本 run_glue_no_trainer.py。与原始脚本的主要区别是,这个 no_trainer 脚本给了我们更多的机会来更改优化器的选项或添加我们想要的自定义内容。

总结

在这一章中,我们讨论了如何对任何文本分类下游任务微调预训练模型。我们使用情感分析、多类别分类和句子对分类(具体来说是句子对回归和多标签分类)来微调模型。我们使用了一个知名的IMDb数据集和我们自己的自定义数据集来训练模型。虽然我们利用了Trainer类来应对训练和微调过程中的复杂性,但我们也学习了如何使用原生库从头开始训练,以理解transformers库中的前向传播和反向传播。总结来说,我们讨论并进行了一些微调工作,包括使用Trainer进行单句分类,使用原生PyTorch进行情感分类,单句多类别分类,多标签分类,以及句子对回归的微调。
​

如何学习大模型

现在社会上大模型越来越普及了,已经有很多人都想往这里面扎,但是却找不到适合的方法去学习。

作为一名资深码农,初入大模型时也吃了很多亏,踩了无数坑。现在我想把我的经验和知识分享给你们,帮助你们学习AI大模型,能够解决你们学习中的困难。

我已将重要的AI大模型资料包括市面上AI大模型各大白皮书、AGI大模型系统学习路线、AI大模型视频教程、实战学习,等录播视频免费分享出来,需要的小伙伴可以扫取。

一、AGI大模型系统学习路线

很多人学习大模型的时候没有方向,东学一点西学一点,像只无头苍蝇乱撞,我下面分享的这个学习路线希望能够帮助到你们学习AI大模型。

在这里插入图片描述

二、AI大模型视频教程

在这里插入图片描述

三、AI大模型各大学习书籍

在这里插入图片描述

四、AI大模型各大场景实战案例

在这里插入图片描述

五、结束语

学习AI大模型是当前科技发展的趋势,它不仅能够为我们提供更多的机会和挑战,还能够让我们更好地理解和应用人工智能技术。通过学习AI大模型,我们可以深入了解深度学习、神经网络等核心概念,并将其应用于自然语言处理、计算机视觉、语音识别等领域。同时,掌握AI大模型还能够为我们的职业发展增添竞争力,成为未来技术领域的领导者。

再者,学习AI大模型也能为我们自己创造更多的价值,提供更多的岗位以及副业创收,让自己的生活更上一层楼。

因此,学习AI大模型是一项有前景且值得投入的时间和精力的重要选择。

解析Transformer模型微调:算法、工程实践与高效数据策略 本文分析了Transformer架构及其在NLP中的应用,包括BERT的双向理解、GPT的文本生成和标准Transformer的序列转换能力。我们讨论了这些模型的算法特点、工程实现挑战和针对性微调数据集构建的策略。强调了微调时数据质量、多样性及平衡的重要性,并通过案例展示了实际应用中的数据集准备。文章指出,有效的微调关键在于精心设计的数据集,并展望了自动化增强和质量评估的未来趋势。 阅读详情

相关推荐

如何训练和微调Transformer模型?

可以选择使用预训练的Transformer模型(如BERT、GPT等)作为基础模型,也可以从头开始构建自定义的Transformer模型。在训练和微调Transformer模型时,需要关注参数初始化、损失函数、优化器的选择,合理设置超参数,并根据实际情况进行验证和调参。此外,数据的质量和数量、训练的时间和计算资源等因素也会影响模型的训练和微调效果。模型评估:使用测试数据集对训练好的模型进行评估,评估模型在未见过的数据上的性能表现。优化器:选择合适的优化器,如Adam、SGD等,用于优化模型的参数。

njhhuuuby的博客 1672

6. 文本分类——transformer模型

文章目录一、简介二、transformer结构三、用于文本分类的transformer1. embedding layer(嵌入层)2. positional encoding(位置编码)3. Scaled dot-product attention(缩放的点乘注意力机制)4. Multi-head attention(多头注意力)5. Padding mask6. 残差连接7. Layer No...

qq_38293297的博客 1万+

NLP 中的语言模型预训练&微调

1 引言 语言模型(Language Model),语言模型简单来说就是一串词序列的概率分布。具体来说,语言模型的作用是为一个长度为m的文本确定一个概率分布P,表示这段文本存在的可能性。在实践中,如果文本的长度较长,P(wi | w1, w2, . . . , wi−1)的估算会非常困难。因此,研究者们提出使用一个简化模型:n元模型(n-gram model)。在 n 元模型中估算条件概率...

CLOUD 1万+

transformer上手(6)—— 微调预训练模型

与 Pytorch 类似,Transformers 库同样实现了很多的优化器,并且相比 Pytorch 固定学习率,Transformers 库的优化器会随着训练过程逐步减小学习率(通常会产生更好的效果)。函数来加载模型参数。最后,我们加载验证集上最优的模型权重,汇报其在测试集上的性能。注意:前面我们只保存了模型的权重,因此如果要单独调用上面的代码,需要首先实例化一个结构完全一样的模型,再通过。最终在测试集(这里用了验证集)上的准确率为 74.1%,与前面汇报的一致,也验证了模型参数的加载过程是正确的。

哦豁灬 1万+

Transformer实战(17)——微调Transformer语言模型进行多标签文本分类

本节针对多标签文本分类任务,介绍了如何使用 DistilBERT 在 PubMed 数据集上微调完成标签预测。为了适应多标签场景,模型输出层激活函数采用 sigmoid,损失函数采用 BCEWithLogitsLoss,并通过自定义 MultilabelTrainer 类将其集成到 Trainer 流程中。在评估阶段,采用微平均方式计算 Precision、Recall 和 F1 分数,最终在测试集上实现了约 0.836 的 F1 分数。

盼小辉丶的博客 4567

Transformer实战(14)——微调Transformer语言模型用于文本分类

本文介绍了基于 Transformer 架构的文本分类技术,重点介绍了如何使用 Hugging Face 的 transformers 库进行情感分析任务,使用 Trainer 类对 IMDb 数据集进行了情感预测模型的微调。训练后保存最佳模型权重,通过 Pipeline API 实现便捷的预测功能,自动输出标签及置信度。

盼小辉丶的博客 1万+

向Transformer投降!《精通Transformer》神书来了(附PDF)

当下红得发紫的chatGPT,给了我小小的危机感,因为我是写文案的企宣,未来可能会被机器人替代吧。现在更可怕了,chatGPT背后真正的大佬 Transformer来了,会带来什么伟大的变革呢?

DEVELOPERAA的博客 1162

Transformer实战(16)——微调Transformer语言模型用于多类别文本分类

本节介绍了如何在少量样本下高效微调多分类 Transformer 模型,使用微调 BERTurk 模型在土耳其语新闻数据集上取得了约 93.0% 的测试准确率和 92.99% 的宏平均 F1 分数,详细介绍了数据划分、自定义 MyDataset 实现、训练循环与 Trainer 用法,以及如何使用 pipeline 快速进行推理。

盼小辉丶的博客 4229

微调BERT模型实现文本分类

模型微调只是针对某种下游任务,针对性的强化模型的能力,但是微调之后的模型在泛化能力上有所下降。

大模型研究中心 4299

Transformer实战(20)——微调Transformer语言模型进行问答任务

问答 (Question Answering, QA) 是一种自然语言处理 (Natural Language Processing, NPL) 任务,其目标是在给定上下文文本的前提下,自动定位并生成对用户提问的准确回答。与视觉问答 (Visual Question Answering, VQA) 需要结合图像信息不同,纯文本 QA 完全依赖于文本上下文。本文将使用 SQuAD v2 数据集,详细讲解如何使用 DistilBERT 完成从数据预处理、模型微调,到模型保存的完整流程。

盼小辉丶的博客 6822

Transformer实战(15)——使用PyTorch微调Transformer语言模型

本节通过 DistilBert 的微调,介绍了使用 PyToch 从加载预训练模型、手动构建优化器,到实现前向与反向传播、管理梯度,展示了使用 PyTorch 微调 Transformer 语言模型的完整流程。我们演示了如何定义 Dataset 与 DataLoader,并利用 SST-2 数据集完成多轮训练与评估,最终取得约 90.94% 的验证准确率。

盼小辉丶的博客 3633

微调较小的 Transformer 模型:文本分类

原文:towardsdatascience.com/fine-tune-smaller-transformer-models-text-classification-77cbbd3bf02b。

龙哥盟 633

Transformer实战——微调多语言Transformer模型

在本节中,我们验证微调后的多语言模型的性能,是否确实比单语言模型差。以土耳其语文本分类(七个类别)为例,我们已经学习了如何微调了一个专门的土耳其语单语言模型,并取得了良好的结果,接下来,我们将重复相同的步骤,保持其他条件不变,仅将土耳其语单语言模型分别替换为 mBERT 和 XLM-R 模型。

盼小辉丶的博客 2906

BERT模型微调与文本分类深度学习实战指南

htmltable {th, td {th {pre {简介:本实战资源关注BERT模型在文本分类任务中的微调应用。BERT是一个预训练语言模型,通过Transformer架构实现双向理解,预训练包含MLM和NSP两个任务,微调阶段需要加载模型、数据预处理、配置参数、训练评估和模型保存等步骤。本项目包含实现BERT微调的代码、数据集和实践指南,帮助用户掌握BERT在实际问题中的应用,并提升深度学习和自然语言处理技能。

weixin_36303305的博客 863

Transformer实战(19)——微调Transformer语言模型进行词元分类

在本节中,我们将学习如何对语言模型进行微调,以适应词元分类任务。我们将探索命名实体识别 (NER)、词性标注 (POS) 和问答 (QA) 等任务,并了解如何针对这些任务微调特定的语言模型。我们将重点介绍 BERT 模型,学习如何微调 BERT 应用于 POS、NER 和 QA 任务,并熟悉这些任务的实现细节,包括所用数据集及执行过程。通过本节的学习,将能够使用 transformers 库执行各种词元分类任务。

盼小辉丶的博客 4388

Transformer实战(18)——微调Transformer语言模型进行回归分析

本节介绍了如何基于预训练 DistilBert 架构完成语义相似度回归分析。首先,通过修改配置或传参的方式,为模型顶层添加单神经元回归头;随后,借助 STS-B 数据集构建训练、验证与测试集,并应用分词器生成模型输入。接着,使用 Trainer 框架与自定义的 compute_metrics 函数,对模型在 MSE、RMSE、MAE 及 Pearson 和 Spearman 相关性等多维度指标上进行评估,验证了微调方法在回归任务中的有效性。

盼小辉丶的博客 3325

《精通Transformer》?ChatGPT:放弃战斗吧,向Transformer投降!

当下红得发紫的chatGPT,给了我小小的危机感,因为我是写文案的企宣,未来可能会被机器人替代吧。现在更可怕了,chatGPT背后真正的大佬 Transformer来了,会带来什么伟大的变革呢?

2401_85325557的博客 729

OpenCV学习笔记(25)基于MFC和OpenCV的摄像机定标与立体匹配测试程序(20140505更新)

最近整理了一下这两年一直在用的摄像机定标与立体匹配测试程序,将代码进行了重构,界面也做了调整,分享出来方便有需要的朋友使用。当然我的编程能力有限,程序可能还有各种bug,请大家多多包涵。相关问题欢迎留言或email联系讨论,谢谢! ==================================================================================源码

晨宇思远 5万+
上一篇: Transformer直接预测完整数学表达式,推理速度提高多个数量级
下一篇: 这本真绝!《自然语言处理新范式:基于预训练模型的方法》真的不要太强(附PDF)
AI_小站
博客等级 码龄3年 6255粉丝 1152原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值