训练与评估

我们根据情感分析任务来进行详细的介绍,使用 Trainer 来进行快速训练和评估。

加载和处理数据

加载数据

我们可以调用来自 dataset 模块的函数 load() 来加载IMDB数据集。该函数会返回IMDB数据集的训练集和测试集。

加载数据的代码如下所示:

from mindnlp.dataset import load

imdb_train, imdb_test = load('imdb', shuffle=True)

处理和划分数据

首先我们通过调用来自 Glove 的函数 from_pretrained() ,获取嵌入和词汇表:

from mindnlp.modules import Glove

embedding, vocab = Glove.from_pretrained('6B', 100, special_tokens=["<unk>", "<pad>"], dropout=drop)

然后我们通过实例化类 BasicTokenizer 来初始化分词器:

from mindnlp.dataset.transforms import BasicTokenizer

tokenizer = BasicTokenizer(True)

接着,我们将获取到的训练集、分词器和词汇表等传入方法 process() ,应用该方法获取处理过的训练集:

from mindnlp.dataset import process

imdb_train = process('imdb', imdb_train, tokenizer=tokenizer, vocab=vocab, \
                    bucket_boundaries=[400, 500], max_len=600, drop_remainder=True)

最后,我们使用方法 split() 来划分处理后的训练集,从而获取新的训练集和验证集:

imdb_train, imdb_valid = imdb_train.split([0.7, 0.3])

定义和训练模型

定义和初始化网络

我们引入了MindSpore和MindNLP预定义好的网络层来构建我们的网络。

使用MindSpore的 mindspore.nn.LSTMmindspore.nn.Densemindspore.nn.Sigmoidmindspore.nn.Dropout ,和MindNLP的 Seq2vecModelRNNEncoder 来构建我们的模型。并应用MindSpore的 mindspore.common.initializer.Uniformmindspore.common.initializer.HeUniform 来初始化我们构建的网络的权重和偏差。

定义和初始化网络的代码如下所示:

from mindspore import nn
from mindspore import ops
from mindspore.common.initializer import Uniform, HeUniform

from mindnlp.modules import RNNEncoder
from mindnlp.abc import Seq2vecModel

class Head(nn.Cell):
    """
    Head for Sentiment Classification model
    """
    def __init__(self, hidden_dim, output_dim, dropout):
        super().__init__()
        weight_init = HeUniform(math.sqrt(5))
        bias_init = Uniform(1 / math.sqrt(hidden_dim * 2))
        self.fc = nn.Dense(hidden_dim * 2, output_dim, weight_init=weight_init, bias_init=bias_init)
        self.sigmoid = nn.Sigmoid()
        self.dropout = nn.Dropout(1 - dropout)

    def construct(self, context):
        context = ops.concat((context[-2, :, :], context[-1, :, :]), axis=1)
        context = self.dropout(context)
        return self.sigmoid(self.fc(context))

class SentimentClassification(Seq2vecModel):
    """
    Sentiment Classification model
    """
    def __init__(self, encoder, head):
        super().__init__(encoder, head)
        self.encoder = encoder
        self.head = head

    def construct(self, text):
        _, (hidden, _), _ = self.encoder(text)
        output = self.head(hidden)
        return output

hidden_size = 256
output_size = 1
num_layers = 2
bidirectional = True
drop = 0.5

lstm_layer = nn.LSTM(100, hidden_size, num_layers=num_layers, batch_first=True,
                    dropout=drop, bidirectional=bidirectional)

sentiment_encoder = RNNEncoder(embedding, lstm_layer)

sentiment_head = Head(hidden_size, output_size, drop)

net = SentimentClassification(sentiment_encoder, sentiment_head)

定义损失函数和优化器

我们训练模型时需要损失函数,我们使用MindSpore提供的 mindspore.nn.BCELoss 来定义一个损失函数:

loss = nn.BCELoss(reduction='mean')

然后,调用 mindspore.nn.Adam ,并传入模型的可训练参数,从而定义运行模型所需要的优化器:

optimizer = nn.Adam(net.trainable_params(), learning_rate=lr)

定义回调函数

借助MindNLP进行模型训练时,定义回调函数非常重要。它帮助在训练过程中添加一些额外的操作。

例如,我们可以添加 BestModelCallback 用于保存和加载最好的模型。或者我们能够使用 CheckpointCallback 来保存checkpoint。除此之外,还有能用于早停和计时的回调函数。

当定义我们需要的回调函数时,我们首先需要初始化回调函数对应的类,然后声明一个由我们事先初始化的回调函数组成的列表,正如:

from mindnlp.engine.callbacks.timer_callback import TimerCallback
from mindnlp.engine.callbacks.earlystop_callback import EarlyStopCallback
from mindnlp.engine.callbacks.best_model_callback import BestModelCallback

timer_callback_epochs = TimerCallback(print_steps=2)
earlystop_callback = EarlyStopCallback(patience=2)
bestmodel_callback = BestModelCallback(save_path='save/callback/best_model', auto_load=True)

callbacks = [timer_callback_epochs, earlystop_callback, bestmodel_callback]

定义评价指标

使用一个或多个评价指标来评估模型是有必要的。我们选择 Accuracy 作为模型的评价指标:

from mindnlp.engine.metrics import Accuracy

metric = Accuracy()

训练与评估模型

定义好网络、损失函数、优化器、回调函数和评价指标后,我们应用 Trainer 来训练和评估前文定义好的模型。

具体地说,当我们训练模型时,我们应该将这些参数传入 Trainer

  • network:训练的网络。

  • train_dataset:用于训练模型的数据集。

  • eval_dataset:用于评估模型的数据集。

  • metrics:用于评估模型的评价指标。

  • epochs:训练数据的总迭代次数。

  • loss_fn:损失函数。

  • optimizer:用于更新训练参数的优化器。

  • callbacks:训练时执行的额外操作。

训练和评估模型的示例代码:

from mindnlp.engine.trainer import Trainer

trainer = Trainer(network=net, train_dataset=imdb_train, eval_dataset=imdb_valid, metrics=metric,
                    epochs=5, loss_fn=loss, optimizer=optimizer, callbacks=callbacks)

trainer.run(tgt_columns="label", jit=False)