跳转至

快速开始

MindNLP为train提供了强大的功能,并使用AI模型来完成各种任务。 首先,本教程将指导您加载预贴模型并进行微调以满足您的特定需求。

使用预训练模型有很大的好处:它可以节省计算时间和资源。通过微调,您可以调整这些模型,以增强独特数据集的性能。现在您已经准备好了,让我们开始吧!

我们将使用 BERT 模型为示例,然后对其进行微调以在 大型电影评论数据集.

为了执行微调,MindNLP 提供了两种方法:一种方法是通过 MindNLP 的用户友好型 Trainer API,它支持基本的训练功能;要有更多的自定义控制,可以通过原生MindSpore使用另一种方式。在本教程中,我们将指导您完成这两种方法。

对于这两个例子,您首先需要通过运行本教程的 Prepare a dataset 部分来准备数据集。

数据集准备好后,从下面选择一个策略并开始您的旅程!

*使用 MindNLP Trainer 微调预训练模型。

*在原生MindSpore中微调预训练模型。

准备数据集

在您可以微调验证的模型之前,请下载数据集并准备train。

Mindnlp包括 load_dataset 从拥抱脸部数据集存储库中加载任何数据集的API。 在这里让我们加载 大型电影评论数据集 数据集,名为 'imdb',并将其分为train,验证和测试数据集。

from mindnlp import load_dataset

imdb_ds = load_dataset('imdb', split=['train', 'test'])
imdb_train = imdb_ds['train']
imdb_test = imdb_ds['test']

# Split train dataset further into training and validation datasets
imdb_train, imdb_val = imdb_train.split([0.7, 0.3])

接下来,为模型加载令牌。 Tokenization的过程将原始文本转换为机器学习模型可以处理的格式,这对于自然语言处理任务至关重要。

在Mindnlp中 AutoTokenizer 帮助自动获取并实例化适当的令牌以作为预训练的模型。

from mindnlp.transformers import AutoTokenizer
tokenizer = AutoTokenizer.from_pretrained('bert-base-cased')

一旦数据集和令牌准备就绪,我们就可以处理数据集。

这包括 *将文本引用。 *铸造以纠正数据类型。 *用填充或截断处理可变序列长度。 *洗净条目的顺序。 *批量数据集。

数据预处理 教程,这些步骤将被详细阐述。

在这里,我们定义以下 process_dataset 功能以准备数据集。

import mindspore
import numpy as np
from mindspore.dataset import transforms

def process_dataset(dataset, tokenizer, max_seq_len=256, batch_size=32, shuffle=False, take_len=None):
    # The tokenize function
    def tokenize(text):
        tokenized = tokenizer(text, truncation=True, max_length=max_seq_len)
        return tokenized['input_ids'], tokenized['token_type_ids'], tokenized['attention_mask']

    # Shuffle the order of the dataset
    if shuffle:
        dataset = dataset.shuffle(buffer_size=batch_size)

    # Select the first several entries of the dataset
    if take_len:
        dataset = dataset.take(take_len)

    # Apply the tokenize function, transforming the 'text' column into the three output columns generated by the tokenizer.
    dataset = dataset.map(operations=[tokenize], input_columns="text", output_columns=['input_ids', 'token_type_ids', 'attention_mask'])
    # Cast the datatype of the 'label' column to int32 and rename the column to 'labels'
    dataset = dataset.map(operations=transforms.TypeCast(mindspore.int32), input_columns="label", output_columns="labels")
    # Batch the dataset with padding.
    dataset = dataset.padded_batch(batch_size, pad_info={'input_ids': (None, tokenizer.pad_token_id),
                                                         'token_type_ids': (None, 0),
                                                         'attention_mask': (None, 0)})
    return dataset

现在处理数据集的所有拆分,并创建较小的数据集子集以缩短微调的过程:

batch_size = 4
take_len = batch_size * 200
small_dataset_train = process_dataset(imdb_train, tokenizer, batch_size=batch_size, shuffle=True, take_len=take_len)
small_dataset_val = process_dataset(imdb_val, tokenizer, batch_size=batch_size, shuffle=True, take_len=take_len)
small_dataset_test = process_dataset(imdb_test, tokenizer, batch_size=batch_size, shuffle=True, take_len=take_len)

这里 take_len 是一个可选的参数,有助于创建较小的数据集子集以缩短微调过程。

但是,在实际的微调工作中,通常使用完整的数据集。

火车

在此阶段,您可以选择 MindNLP trainer API原生MindSpore 微调模型的方法。

让我们从 trainer API方法开始。

与MindNLPtrainer一起训练

Mindnlp带有 Trainer 旨在简化模型train的课程。 和 Trainer,您可以避免需要手动编写自己的训练循环。

Trainer 支持广泛的train选项,将在 使用 trainer 教程。

初始化模型

在这里的示例中,我们将首先实例化验证的BERT模型。

为此,我们使用 AutoModelForSequenceClassification。 提供验证模型的名称,即 'bert-base-cased'AutoModelForSequenceClassification。 它将自动推断模型体系结构,对模型进行了启动并加载验证的参数。 这里加载的模型是专门用于分类任务的BERT模型,BertForSequenceClassification.

为了向模型初始化提供其他参数,您可以添加更多的键字参数。 在这里,由于分类任务涉及确定电影审查是表达积极还是负面情绪,因此我们提供 num_labels=2 到BERT模型。

对于不同类型的任务,MindNLP具有多种多样 AutoModel 从中选择的课程。

from mindnlp.transformers import AutoModelForSequenceClassification

model = AutoModelForSequenceClassification.from_pretrained('bert-base-cased', num_labels=2)
print(type(model))

train超参数

接下来,创建一个 TrainingArguments 您可以在其中定义用于train的超参数的课程。

from mindnlp.engine import TrainingArguments
training_args = TrainingArguments(
     "../../output",
    per_device_train_batch_size=1,
    per_device_eval_batch_size=1,
    learning_rate=2e-5,
    num_train_epochs=3,
    logging_steps=200,
    evaluation_strategy='epoch',
    save_strategy='epoch'
)

为了全面了解更多参数 TrainingArguments,请参考 使用 trainer 教程。 在这里,我们指定了以下参数。 *output_dir :这是所有输出(例如模型检查点和预测)的目录。 在此示例中,它设置为 "../../output". * per_device_train_batch_size: This controls the batch size used for training on each device. Since we already batched our dataset, here the batch size is set to 1. If you want to use trainer's batch functionality, you can set your own batch size here. * per_device_eval_batch_size :类似于训练批量的大小,但在验证数据的评估阶段使用。 由于我们已经将数据集批量化,因此批处理大小设置为1。 *learning_rate :模型学习的速度。 较小的值意味着学习速度较慢,但​​它们可能会导致更好的模型进行微调。 *num_train_epochs :定义训练环将在整个train数据集上运行多少次。 *evaluation_strategy :确定执行评估的策略。 将其设置为“时期”意味着该模型在每个训练时期结束时进行评估。 *logging_steps :此设置控制多久将训练损耗和其他指标记录到控制台中的频率。 它有助于监视train进度。 *save_strategy :确定保存模型检查点的策略。 将其设置为“时期”可确保在每个时期的结尾保存模型。

评价

评估对于理解模型的性能和对新的,看不见的数据的概括性至关重要。

为了在train期间评估模型的性能,有必要提供指标汇编的功能 Trainer.

在这里,我们写了 compute_metrics 功能,将采用 EvalPrediction 对象作为输入,并计算预测标签和地面真实标签之间的评估指标。

import evaluate
import numpy as np
from mindnlp.engine.utils import EvalPrediction

metric = evaluate.load("accuracy")

def compute_metrics(eval_pred: EvalPrediction):
    logits, labels = eval_pred
    predictions = np.argmax(logits, axis=-1)
    return metric.compute(predictions=predictions, references=labels)

初始化 trainer

一旦 TrainingArguments 实例已配置,您可以将其传递给 Trainer 与您的模型和数据集一起上课。 此设置允许 Trainer 在整个train和评估阶段中利用这些论点。

from mindnlp.engine import Trainer
trainer = Trainer(
    model=model,
    train_dataset=small_dataset_train,
    eval_dataset=small_dataset_val,
    compute_metrics=compute_metrics,
    args=training_args,
)

开始训练

现在我们都准备好了,让我们开始train!

trainer.train()

使用训练有素的模型

现在,您可以使用训练有素的模型在一个简单的示例中进行预测。 我们定义文本,将其定义并将其用作模型输入。

import numpy as np
from mindspore import Tensor, ops

text = "What an amusing movie!" 

# Tokenize the text
inputs = tokenizer(text, padding=True, truncation=True, max_length=256)
ts_inputs = {key: Tensor(val).expand_dims(0) for key, val in inputs.items()}

# Predict
model.set_train(False)
outputs = model(**ts_inputs)
print(outputs)

输出是逻辑,可以将其转换为给定文本属于每个类别的概率。

# Convert predictions to probabilities
predictions = ops.softmax(outputs.logits)
probabilities = predictions.numpy().flatten()

# Here first class is 'negative' and the second is 'positive'
print(f "Negative sentiment: {probabilities[0]:.4f}")
print(f "Positive sentiment: {probabilities[1]:.4f}")

训练原生MindSpore

如果您希望对train过程进行更自定义的控制,则也可以在本地思维螺旋中微调A。

如果你去了 与MindNLPtrainer一起训练 部分,您可能需要重新启动笔记本并重新运行 准备数据集 部分,或执行以下代码以释放一些内存:

# Free up memory by deleting model and trainer used in the Train with MindNLP Trainer step
del model
del trainer

加载模型

加载模型的预期标签数:

from mindnlp.transformers import AutoModelForSequenceClassification

model = AutoModelForSequenceClassification.from_pretrained("bert-base-cased", num_labels=2)

优化器和损失功能

设置优化器,该优化器更新模型参数,以最大程度地减少基于计算梯度的损耗函数。 让我们使用 AdamWeightDeday mindspore的优化器:

from mindspore.experimental.optim import AdamW

optimizer = AdamW(model.trainable_params(), lr=5e-5)

定义损耗函数,该函数量化了模型的预测与实际目标值之间的差异。 在这里,我们使用横向渗透损失函数:

from mindspore import ops
loss_fn = ops.cross_entropy

向前和梯度功能

定义向前功能 forward_fn 管理模型的正向通行证并计算损失。

然后利用Mindspore的 value_and_grad 并定义梯度函数 grad_fn 自动计算相对于模型参数的损失和梯度的梯度。

from mindspore import value_and_grad
from tqdm import tqdm

def forward_fn(data, labels):
    logits = model(**data).logits
    loss = loss_fn(logits, labels)
    return loss

grad_fn = value_and_grad(forward_fn, None, optimizer.parameters)

训练步骤

实施 train_step 在train的每个步骤中都会有理会的功能。

此功能处理一批数据,计算损失和梯度,并更新模型参数。

def train_step(batch):
    labels = batch.pop('labels')
    loss, grads = grad_fn(batch, labels)
    optimizer(grads)
    return loss

一个epochs的训练循环

实施 train_one_epoch 通过在数据集中的所有批次上迭代来训练模型的功能:

from tqdm import tqdm

def train_one_epoch(model, train_dataset, epoch=0):
    model.set_train(True)
    total = train_dataset.get_dataset_size()
    loss_total = 0
    step_total = 0
    with tqdm(total=total) as progress_bar:
        progress_bar.set_description('Epoch %i' % epoch)
        for batch in train_dataset.create_dict_iterator():
            loss = train_step(batch)
            loss_total += loss.asnumpy()
            step_total += 1
            progress_bar.set_postfix(loss=loss_total/step_total)
            progress_bar.update(1)

在训练循环开始之前,train_one_epoch 通过将模型设置为训练模式 model.set_train(True).

在每次迭代中,函数调用 train_step 在当前的数据批次上。

为了跟踪训练的进度,它还积累并显示进度栏中批处理的平均损失,从而为训练进度提供了时期的实时视图。

评估

创建一个函数来计算模型预测的准确性。 与在Trainer API的train中一样,我们利用了拥抱脸的评估包。

import evaluate
import numpy as np

metric = evaluate.load("accuracy")

def compute_accuracy(logits, labels):
    predictions = np.argmax(logits, axis=-1)
    return metric.compute(predictions=predictions, references=labels)

实现功能 evaluate_fn 在验证数据集上评估模型。

def evaluate_fn(model, test_dataset, criterion, epoch=0):
    total = test_dataset.get_dataset_size()
    epoch_loss = 0
    epoch_acc = 0
    step_total = 0
    model.set_train(False)

    with tqdm(total=total) as progress_bar:
        progress_bar.set_description('Epoch %i' % epoch)
        for batch in test_dataset.create_dict_iterator():
            label = batch.pop('labels')
            logits = model(**batch).logits
            loss = criterion(logits, label)
            epoch_loss += loss.asnumpy()

            acc = compute_accuracy(logits, label)['accuracy']
            epoch_acc += acc

            step_total += 1
            progress_bar.set_postfix(loss=epoch_loss/step_total, acc=epoch_acc/step_total)
            progress_bar.update(1)

    return epoch_loss / total

在评估开始时,evaluate_fn 通过 model.set_train(False)

然后,该功能在所有测试批次上迭代。 对于每个批次,它计算逻辑,计算损失并评估准确性。 这些指标的积累是为了提供平均损失和准确性,该时期显示在进度栏上。

所有epochs的训练循环

最后,我们可以彰显训练在每个时期和每个时期结束时循环的训练,评估模型的性能。

当验证性能优于所有以前的时期时,模型参数将作为检查点文件保存,以备将来使用。

import mindspore as ms
num_epochs = 3
best_valid_loss = float('inf')

for epoch in range(num_epochs):
    train_one_epoch(model, small_dataset_train, epoch)
    valid_loss = evaluate_fn(model, small_dataset_val, loss_fn, epoch)

    if valid_loss < best_valid_loss:
        best_valid_loss = valid_loss
        ms.save_checkpoint(model, '../../sentiment_analysis.ckpt')

使用训练有素的模型

如果您对训练有素的模型实际将文本分类为其情感类别感到好奇,请尝试以下代码:

# Predict on example
import numpy as np
from mindspore import Tensor, ops

text = "I am pretty convinced that the movie depicted the future of AI in an elegant way." 

# Encode the text to input IDs and attention masks
inputs = tokenizer(text, padding=True, truncation=True, max_length=256)
ts_inputs = {key: Tensor(val).expand_dims(0) for key, val in inputs.items()}

# Predict
model.set_train(False)
outputs = model(**ts_inputs)
print(outputs)

# Convert predictions to probabilities
predictions = ops.softmax(outputs.logits)
probabilities = predictions.numpy().flatten()

# Here first class is 'negative' and the second is 'positive'
print(f "Negative sentiment: {probabilities[0]:.4f}")
print(f "Positive sentiment: {probabilities[1]:.4f}")