训练与评估
我们根据情感分析任务来进行详细的介绍,使用 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.LSTM , mindspore.nn.Dense , mindspore.nn.Sigmoid , mindspore.nn.Dropout ,和MindNLP的 Seq2vecModel, RNNEncoder 来构建我们的模型。并应用MindSpore的 mindspore.common.initializer.Uniform 和 mindspore.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)