昇思25天打卡训练营第25天|RNN实现情感分类

1.概述
情感分类是自然语言处理中的经典任务,是典型的分类问题。本节使用MindSpore实现一个基于RNN网络的情感分类模型,实现如下的效果:

输入: This film is terrible
正确标签: Negative
预测标签: Negative

输入: This film is great
正确标签: Positive
预测标签: Positive


2.数据准备
本节使用情感分类的经典数据集IMDB影评数据集,数据集包含Positive和Negative两类,下面为其样例:

Review    Label
"Quitting" may be as much about exiting a pre-ordained identity as about drug withdrawal. As a rural guy coming to Beijing, class and success must have struck this young artist face on as an appeal to separate from his roots and far surpass his peasant parents' acting success. Troubles arise, however, when the new man is too new, when it demands too big a departure from family, history, nature, and personal identity. The ensuing splits, and confusion between the imaginary and the real and the dissonance between the ordinary and the heroic are the stuff of a gut check on the one hand or a complete escape from self on the other.    

Negative
This movie is amazing because the fact that the real people portray themselves and their real life experience and do such a good job it's like they're almost living the past over again. Jia Hongsheng plays himself an actor who quit everything except music and drugs struggling with depression and searching for the meaning of life while being angry at everyone especially the people who care for him most.    

Positive


使用预训练词向量对自然语言单词进行编码,以获取文本的语义特征。选取Glove词向量作为Embedding。


1).数据下载模块

数据下载模块,实现可视化下载流程,并保存数据集与预训练词向量至指定路径。

数据下载模块使用requests库进行http请求,并通过tqdm库对下载百分比进行可视化。

使用IO的方式下载临时文件,而后保存至指定的路径并返回,保证下载安全性。

tqdm和requests库需手动安装,命令如下:pip install tqdm requests

2)再使用下边URL(华为云镜像,也可使用其他镜像)下载IMDB数据集并保存到指定路径(文件路径+文件名):

3)加载IMDB数据集
下载好的IMDB数据集为tar.gz文件,我们使用Python的tarfile库对其进行读取,并将所有数据和标签分别进行存放。原始的IMDB数据集解压目录如下:

    ├── aclImdb
    │   ├── imdbEr.txt
    │   ├── imdb.vocab
    │   ├── README
    │   ├── test
    │   └── train
    │         ├── neg
    │         ├── pos
    ...
4)数据集已分割为train和test两部分,且每部分包含neg和pos两个分类的文件夹,需分别train和test进行读取并处理数据和标签。

3.加载训练数据集进行测试,输出数据集数量:

将IMDB数据集加载至内存并构造为迭代对象后,使用mindspore.dataset提供的Generatordataset

接口加载数据集迭代对象,并进行下一步的数据处理。下面函数将train和test分别使用

Generatordataset进行加载,数据集文本和标签的column_name分别为text和label:

加载IMDB数据集,可以看到imdb_train是一个GeneratorDataset对象

4.加载预训练词向量

预训练词向量是对输入单词的数值化表示,通过nn.Embedding层,采用查表的方式,输入单词对

应词表中的index,获得对应的表达向量。

进行模型构造前,需要将Embedding层所需的词向量和词表进行构造。此处使用Glove(Global

Vectors for Word Representation)这种经典的预训练词向量, 其数据格式如下:

Word    Vector
the    0.418 0.24968 -0.41242 0.1217 0.34527 -0.044457 -0.49688 -0.17862 -0.00066023 ...
,    0.013441 0.23682 -0.16899 0.40951 0.63812 0.47709 -0.42852 -0.55641 -0.364 ...


下边使用首列单词作为词表,使用dataset.text.Vocab将其按顺序加载;同时读取每一行

的Vector并转为numpy.array,用于nn.Embedding加载权重使用。具体实现如下:

<unk>标记数据集中存在但词表中没有的单词;<pad>标记符用于在打包为一个batch时填充短的文本。完成后的词表长度为原词表长度+2。

- 下载Glove词向量,并加载生成词表和词向量权重矩阵。

- 使用词表将the转换为index id,并查询词向量矩阵对应的词向量:

5. 数据集预处理

IMDB数据集分词处理不满足构造训练数据的需要,要进行额外的预处理如下:

使用mindspore.dataset中提供的接口进行预处理操作,接口均由MindSpore的高性能数据引擎设

计,每个接口对应操作视作数据流水线的一部分,详情请参考

高性能数据处理引擎 — MindSpore master 文档

- 针对token到index id的查表操作,使用text.Lookup接口加载前边构建的词表,并指定

unknown_token。

- 为文本序列统一长度操作,使用PadEnd接口(最大长度和补齐

值(pad_value)),这里取最大长度为500,补齐值为对应词表中<pad>的index id。

- 将label数据转为float32格式以适应模型处理需要。

- 完成预处理操作后,需将其加入到数据集处理流水线中,使用map接口对指定column添加操作。

- 手动将IMDB数据集分割为训练集和验证集两部分,比例取0.7, 0.3。

- 指定数据集的batch大小,通过batch接口指定,设置是否丢弃无法被batch size整除的剩余数据。

调用数据集的map、split、batch为数据集处理流水线增加对应操作,返回值为新的Dataset类型。

在执行时开始执行数据处理流水线,获取最终处理好的数据并送入模型进行训练。

6. 模型构建

完成数据集的处理后,设计用于情感分类的模型结构。

- 将输入文本(即序列化后的index id列表)通过查表转为向量化表示,此时需要使用nn.Embedding

层加载Glove词向量

- 然后使用RNN循环神经网络做特征提取

- 最后将RNN连接至一个全连接层,即nn.Dense,将特征转化为与分类数量相同的size,用于后续

进行模型优化训练

整体模型结构如下,特征提取层使用能够一定程度规避RNN梯度消失问题的变种LSTM(Long short-term memory):

nn.Embedding -> nn.RNN -> nn.Dense

- Embedding
Embedding层又可称为EmbeddingLookup层,使用index id对权重矩阵对应id的向量进行查找。

当输入为一个由index id组成的序列时,则查找并返回一个相同长度的矩阵,例如:

embedding = nn.Embedding(1000, 100) # 词表大小(index的取值范围)为1000,表示向量的size为100
input shape: (1, 16)                # 序列长度为16
output shape: (1, 16, 100)

这里我们使用前文处理好的Glove词向量矩阵,设置nn.Embedding的embedding_table为预训练词

向量矩阵。对应的vocab_size为词表大小400002,embedding_size为选用的glove.6B.100d向量大

小,即100。

- RNN(循环神经网络)


循环神经网络(Recurrent Neural Network, RNN)是一类以序列(sequence)数据为输入,在序

列的演进方向进行递归(recursion)且所有节点(循环单元)按链式连接的神经网络。下图为

RNN的一般结构:

图示左侧为一个RNN Cell循环,右侧为RNN的链式连接平铺。实际上不管是单个RNN Cell还是一

个RNN网络,都只有一个Cell的参数,在不断进行循环计算中更新。

由于RNN的循环特性和自然语言文本的序列特性(句子是由单词组成的序列)十分匹配,因此被大

量应用于自然语言处理研究中。下图为RNN的结构拆解:

RNN单个Cell的结构简单,但有梯度消失(Gradient Vanishing)问题,即RNN网络在序列较长时,

在序列尾部已经基本丢失了序列首部的信息。为了克服这一问题,LSTM(Long short-term、

memory)通过门控机制(Gating Mechanism)来控制信息流在每个循环步中的留存和丢弃。下图为

LSTM的结构拆解:

此处选择LSTM变种而不是经典的RNN做特征提取,来规避梯度消失问题,并获得更好的模型效

果。MindSpore中nn.LSTM对应的公式为:

 
这里nn.LSTM隐藏了整个循环神经网络在序列时间步(Time step)上的循环。由输入序列、初始状

态,即可获得每个时间步的隐状态(hidden state)拼接而成的矩阵,以及最后一个时间步对应的隐状

态。将最后的一个时间步的隐状态作为输入句子的编码特征送入下一层。

Time step:循环神经网络计算的每一次循环成为一个Time step。在送入文本序列时,一个Time

step对应一个单词。因此在本例中,LSTM的输出 ℎ0:𝑡对应每个单词的隐状态集合, ℎ𝑡对应最后一

个单词对应的隐状态。

- Dense

在经过LSTM编码获取句子特征后,将其送入一个全连接层,即nn.Dense,将特征维度变换为二分

类所需的维度1,经过Dense层后的输出即为模型预测结果。

7. 损失函数与优化器


根据指定的参数实例化网络,再选择损失函数和优化器。针对本节情感分类问题的特性,即预测

Positive或Negative的二分类问题,选择nn.BCEWithLogitsLoss(二分类交叉熵损失函数)。

8.训练逻辑

在完成模型构建后,进行训练逻辑的设计。一般训练逻辑分为下列步骤:

- 读取一个Batch的数据

- 送入网络,进行正向计算和反向传播,更新权重

- 返回loss

按照此逻辑,使用tqdm库,设计训练一个epoch的函数,用于训练过程和loss的可视化,代码如下:

9. 评估指标和逻辑


训练逻辑完成后,需要对模型进行评估。使用模型的预测结果和测试集的正确标签进行对比,求

出预测的准确率。由于IMDB的情感分类为二分类问题,对预测值直接进行四舍五入即可获得分类

标签(0或1),然后判断是否与正确标签相等即可。下面为二分类准确率计算函数实现:

类似于训练逻辑,按下边步骤设计评估逻辑:

- 读取一个Batch的数据

- 送入网络,进行正向计算,获得预测结果

- 计算准确率

同训练逻辑一样,使用tqdm进行loss和过程的可视化。此外返回评估loss至供保存模型时作为模型

优劣的判断依据。

在进行evaluate时,使用的模型是不包含损失函数和优化器的网络主体; 在进行evaluate前,需要

通过model.set_train(False)将模型置为评估状态,此时Dropout不生效。

10. 模型训练与保存

完成了模型构建和训练、评估逻辑的设计之后即可进行模型训练。我们设置训练轮数为5轮。同时

维护一个用于保存最优模型的变量best_valid_loss,根据每一轮评估的loss值,取loss值最小的轮

次,将模型进行保存。为节省用例运行时长,此处num_epochs设置为2,可根据需要自行修改。

可以看到每轮Loss逐步下降,在验证集上的准确率逐步提升。


11.模型加载与测试

模型训练完成后,一般需要对模型进行测试或部署上线,此时需要加载已保存的最优模型(即

checkpoint),供后续测试使用。这里我们直接使用MindSpore提供的Checkpoint加载和网络权重加

载接口:1.将保存的模型Checkpoint加载到内存中,2.将Checkpoint加载至模型。

load_param_into_net接口会返回模型中没有和Checkpoint匹配的权重名,正确匹配时返回空列表。

对测试集打batch,然后使用evaluate方法进行评估,得到模型在测试集上的效果。

自定义输入测试

最后我们设计一个预测函数,实现开头描述的效果,输入一句评价,获得评价的情感分类。具体包

含以下步骤:

将输入句子进行分词


使用词表获取对应的index id序列


index id序列转为Tensor


送入模型获得预测结果


打印输出预测结果


具体实现如下:

最后我们预测开头的样例,可以看到模型可以很好地将评价语句的情感进行分类。

  • 8
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
以下是使用RNN实现情感分类的代码示例: ``` import numpy as np import pandas as pd import tensorflow as tf from tensorflow.keras.preprocessing.text import Tokenizer from tensorflow.keras.preprocessing.sequence import pad_sequences from tensorflow.keras.models import Sequential from tensorflow.keras.layers import Dense, Embedding, LSTM, SpatialDropout1D from sklearn.model_selection import train_test_split # 读取数据集 data = pd.read_csv('sentiment_analysis.csv') data = data[['text', 'sentiment']] data = data[data.sentiment != "Neutral"] data['text'] = data['text'].apply(lambda x: x.lower()) data['text'] = data['text'].apply((lambda x: re.sub('[^a-zA-z0-9\s]', '', x))) # 获取文本和标签 texts = data['text'].values labels = pd.get_dummies(data['sentiment']).values # 对文本进行分词,并将每个词转换为数字 tokenizer = Tokenizer(num_words=2000, split=' ') tokenizer.fit_on_texts(texts) X = tokenizer.texts_to_sequences(texts) X = pad_sequences(X) # 划分数据集 X_train, X_test, Y_train, Y_test = train_test_split(X, labels, test_size=0.33, random_state=42) # 构建RNN模型 embed_dim = 128 lstm_out = 196 model = Sequential() model.add(Embedding(2000, embed_dim, input_length=X.shape[1])) model.add(SpatialDropout1D(0.4)) model.add(LSTM(lstm_out, dropout=0.2, recurrent_dropout=0.2)) model.add(Dense(3, activation='softmax')) model.compile(loss='categorical_crossentropy', optimizer='adam', metrics=['accuracy']) # 训练模型 batch_size = 32 model.fit(X_train, Y_train, epochs=10, batch_size=batch_size, verbose=2) # 评估模型 score, acc = model.evaluate(X_test, Y_test, verbose=2, batch_size=batch_size) print("score: %.2f" % (score)) print("acc: %.2f" % (acc)) ``` 在这个示例中,我们首先读取数据集并对文本进行预处理。然后,我们使用Tokenizer将文本转换为数字,并使用pad_sequences将每个序列填充到相同的长度。然后,我们将数据集划分为训练集和测试集。 接下来,我们构建RNN模型。我们使用Embedding层将每个数字转换为向量,然后添加SpatialDropout1D层和LSTM层。最后,我们添加一个Dense层,并使用softmax激活函数对输出进行分类。我们使用categorical_crossentropy作为损失函数,使用adam优化器进行训练,并使用accuracy作为评估指标。 最后,我们训练模型并评估其性能。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值