今天是参加昇思25天学习打卡营的第14天,今天打卡的课程是“RNN实现情感分类”,这里做一个简单的分享。
1.简介
情感分类任务在LLM原理及实践的部分已经学习过基于LLM进行实现的方法,今天要学习的是传统基于深度学习神经网络进行进行情感分类的方法。
本次所使用的数据集来自互联网电影资料库(Internet Movie Database,简称IMDb)的电影评论数据,目标是识别电影评论的情感类型:积极的或则消极的,用于训练的数据集标注了评论对应的情感类型。
本次需要使用预训练词向量对自然语言单词进行编码,以获取文本的语义特征,本节选取Glove词向量作为Embedding。
2.RNN模型构建过程
模型构建的基本步骤:
- 首先需要将输入文本(即序列化后的index id列表)通过查表转为向量化表示,此时需要使用
nn.Embedding
层加载Glove词向量 - 然后使用RNN循环神经网络做特征提取
- 最后将RNN连接至一个全连接层,即
nn.Dense
,将特征转化为与分类数量相同的size,用于后续进行模型优化训练
整体模型结构如下:
nn.Embedding -> nn.RNN -> nn.Dense
这里我们使用能够一定程度规避RNN梯度消失问题的变种LSTM(Long short-term memory)做特征提取层。
主要代码:
import math
import mindspore as ms
import mindspore.nn as nn
import mindspore.ops as ops
from mindspore.common.initializer import Uniform, HeUniform
class RNN(nn.Cell):
def __init__(self, embeddings, hidden_dim, output_dim, n_layers,
bidirectional, pad_idx):
super().__init__()
vocab_size, embedding_dim = embeddings.shape
self.embedding = nn.Embedding(vocab_size, embedding_dim, embedding_table=ms.Tensor(embeddings), padding_idx=pad_idx)
self.rnn = nn.LSTM(embedding_dim,
hidden_dim,
num_layers=n_layers,
bidirectional=bidirectional,
batch_first=True)
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)
def construct(self, inputs):
embedded = self.embedding(inputs)
_, (hidden, _) = self.rnn(embedded)
hidden = ops.concat((hidden[-2, :, :], hidden[-1, :, :]), axis=1)
output = self.fc(hidden)
return output
损失函数与优化器
完成模型主体构建后,首先根据指定的参数实例化网络;然后选择损失函数和优化器。针对本节情感分类问题的特性,即预测Positive或Negative的二分类问题,我们选择nn.BCEWithLogitsLoss
(二分类交叉熵损失函数)。
hidden_size = 256
output_size = 1
num_layers = 2
bidirectional = True
lr = 0.001
pad_idx = vocab.tokens_to_ids('<pad>')
model = RNN(embeddings, hidden_size, output_size, num_layers, bidirectional, pad_idx)
loss_fn = nn.BCEWithLogitsLoss(reduction='mean')
optimizer = nn.Adam(model.trainable_params(), learning_rate=lr)
训练逻辑
在完成模型构建,进行训练逻辑的设计。一般训练逻辑分为一下步骤:
- 读取一个Batch的数据;
- 送入网络,进行正向计算和反向传播,更新权重;
- 返回loss。
def forward_fn(data, label):
logits = model(data)
loss = loss_fn(logits, label)
return loss
grad_fn = ms.value_and_grad(forward_fn, None, optimizer.parameters)
def train_step(data, label):
loss, grads = grad_fn(data, label)
optimizer(grads)
return loss
def train_one_epoch(model, train_dataset, epoch=0):
model.set_train()
total = train_dataset.get_dataset_size()
loss_total = 0
step_total = 0
with tqdm(total=total) as t:
t.set_description('Epoch %i' % epoch)
for i in train_dataset.create_tuple_iterator():
loss = train_step(*i)
loss_total += loss.asnumpy()
step_total += 1
t.set_postfix(loss=loss_total/step_total)
t.update(1)
评估指标和逻辑
训练逻辑完成后,需要对模型进行评估。即使用模型的预测结果和测试集的正确标签进行对比,求出预测的准确率。由于IMDB的情感分类为二分类问题,对预测值直接进行四舍五入即可获得分类标签(0或1),然后判断是否与正确标签相等即可。下面为二分类准确率计算函数实现:
def binary_accuracy(preds, y):
"""
计算每个batch的准确率
"""
# 对预测值进行四舍五入
rounded_preds = np.around(ops.sigmoid(preds).asnumpy())
correct = (rounded_preds == y).astype(np.float32)
acc = correct.sum() / len(correct)
return acc
有了准确率计算函数后,类似于训练逻辑,对评估逻辑进行设计, 分别为以下步骤:
- 读取一个Batch的数据;
- 送入网络,进行正向计算,获得预测结果;
- 计算准确率。
同训练逻辑一样,使用tqdm
进行loss和过程的可视化。此外返回评估loss至供保存模型时作为模型优劣的判断依据。
在进行evaluate时,使用的模型是不包含损失函数和优化器的网络主体; 在进行evaluate前,需要通过
model.set_train(False)
将模型置为评估状态,此时Dropout不生效。def evaluate(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 t: t.set_description('Epoch %i' % epoch) for i in test_dataset.create_tuple_iterator(): predictions = model(i[0]) loss = criterion(predictions, i[1]) epoch_loss += loss.asnumpy() acc = binary_accuracy(predictions, i[1]) epoch_acc += acc step_total += 1 t.set_postfix(loss=epoch_loss/step_total, acc=epoch_acc/step_total) t.update(1) return epoch_loss / total
3.小结
今天学习了在Mindspore环境下,利于RNN模型来实现情感分析。基于LSTM的RNN模型利用记忆机制和门控设计,解决了传统方法在处理序列数据情感依赖性方面的不足。通过精心设计的数据预处理、词嵌入和模型结构,RNN能够精确捕捉文本的情感脉络,为情感分析任务提供了一种强大而灵活的深度学习解决方案。经过这几课的学习,陆续学习了RNN、BERT、GPT在的情感分类方面应用,对于传统深度学习模型、预训练大模型在自然语言处理方法的应用也有一个整体的认知。 当然,这里面包含的内容还有很多,还需要继续深入的就学习和总计。
以上是第14天的学习内容,附上今日打卡记录: