Keras深度学习实战——使用长短时记忆网络构建情感分析模型

0. 前言

我们已经学习了如何使用循环神经网络 (Recurrent neural networks, RNN) 构建情感分析模型,为了将循环神经网络与长短时记忆网络 (Long Short Term Memory, LSTM) 的性能进行对比,同时也为了加深对 LSTM 的了解,在节中,我们将使用 LSTM 来完成同样的情感分类任务。

1. 构建 LSTM 模型进行情感分类

1.1 数据集分析

接下来,我们将实现 LSTM 构建情感分析模型,所用的数据集与在《从零开始构建单词向量》一节中使用的数据集相同,即航空公司 Twitter 数据集,模型的目标是预测用户对于航空公司的评价属于正面、负面或者中立。

1.2 模型构建

(1) 据加载与预处理。本节所用数据加载与预处理过程与使用 RNN 进行情感分类任务中使用的方法完全相同:

from keras.layers import Dense
from keras.layers.recurrent import LSTM
from keras.models import Sequential
from keras.layers.embeddings import Embedding
from sklearn.model_selection import train_test_split
import numpy as np
import nltk
from nltk.corpus import stopwords
import re
import pandas as pd

data=pd.read_csv('archive/Tweets.csv')
print(data.head())

stop = nltk.corpus.stopwords.words('english')
def preprocess(text):
    text=text.lower()
    text=re.sub('[^0-9a-zA-Z]+',' ',text)
    words = text.split()
    words2=[w for w in words if (w not in stop)]
    #words3=[ps.stem(w) for w in words]
    words4=' '.join(words2)
    return(words4)
data['text'] = data['text'].apply(preprocess)

from collections import Counter
counts = Counter()
for i,review in enumerate(data['text']):
    counts.update(review.split())
words = sorted(counts, key=counts.get, reverse=True)

nb_chars = len(words)
print(nb_chars)
word_to_int = {
    
    word: i for i, word in enumerate(words, 1)}
int_to_word = {
    
    i: word for i, word in enumerate(words, 1)}

mapped_reviews = []
for review in data['text']:
    mapped_reviews.append([word_to_int[word] for word in review.split()])

print('Original text:',data.loc[0]['text'])
print('Mapped text:',mapped_reviews[0])

length_sent = []
for i in range(len(mapped_reviews)):
    length_sent.append(len(mapped_reviews[i]))
sequence_length = max(length_sent)

from keras.preprocessing.sequence import pad_sequences
x = pad_sequences(maxlen=sequence_length, sequences=mapped_reviews, padding="post", value=0)

y = data['airline_sentiment'].values
y = np.array(pd.get_dummies(y))
x_train, x_test, y_train, y_test = train_test_split(x, y, test_size=0.2)

(2) 定义模型。嵌入层的输入是数据集中不同单词的总数,使用 output_dim 参数指定每个单词需要转换的预期维度,此外,我们还需要指定输入句子的长度 input_length

embedding_vecor_length=32
max_review_length=26
model = Sequential()
model.add(Embedding(input_dim=nb_chars+1, output_dim=32, input_length = 26))

model.add(LSTM(40, return_sequences=False))
model.add(Dense(3, activation='softmax'))
model.compile(loss='categorical_crossentropy', optimizer='adam', metrics=['acc'])
print(model.summary())

该模型的简要结构信息如下:

Model: "sequential"
_________________________________________________________________
Layer (type)                 Output Shape              Param #   
=================================================================
embedding (Embedding)        (None, 26, 32)            477920    
_________________________________________________________________
lstm (LSTM)                  (None, 40)                11680     
_________________________________________________________________
dense (Dense)                (None, 3)                 123       
=================================================================
Total params: 489,723
Trainable params: 489,723
Non-trainable params: 0
_________________________________________________________________

可以看到嵌入层和最后一层中的参数与使用 RNN 进行情感分类所用的模型参数相同,仅 LSTM 层具有不同数量的参数。

(3) 获取 LSTM 层中的 11680 个参数:

W = model.layers[1].get_weights()[0]
U = model.layers[1].get_weights()[1]
b = model.layers[1].get_weights()[2]
print(W.shape,U.shape,b.shape)

输出的参数形状如下所示:

(32, 160) (40, 160) (160,)

因此,LSTM 权重的总数为 ( 32 ∗ 160 ) + ( 40 ∗ 160 ) + 160 = 11680 (32 * 160)+(40 * 160)+ 160 = 11680 (32160)+(40160)+160=11680W 表示将输入连接到四个 LSTM 单元 (i, f, c, o) 的权重,U 表示网络中间状态间的连接,b 表示每个单元中的偏置。

(4) 输入、遗忘门、输入门和输出门的权重可以按以下方式获得:

units = 40
W_i = W[:, :units]
W_f = W[:, units: units * 2]
W_c = W[:, units * 2: units * 3]
W_o = W[:, units * 3:]

U_i = U[:, :units]
U_f = U[:, units: units * 2]
U_c = U[:, units * 2: units * 3]
U_o = U[:, units * 3:]

b_i = b[:units]
b_f = b[units: units * 2]
b_c = b[units * 2: units * 3]
b_o = b[units * 3:]

(5) 拟合模型编译后的 LSTM 模型:

history = model.fit(x_train, y_train,
            validation_data=(x_test, y_test),
            epochs=20,
            batch_size=64)

模型在训练和测试数据集中随着训练时间的增加,损失值和准确率的变化如下:

模型训练过程监测

使用 LSTM 层时的预测准确率约为 80%,比使用 simpleRNN 层时的预测精度更好一些。接下来,我们可以通过使用堆叠多个 LSTM 层来尝试进一步改善分类结果。

2. 构建多层 LSTM 进行情感分类

在上一节中,我们利用 Keras 中构建了 LSTM 模型实现了情感分类。在本节中,我们将堆叠多个 LSTM 层实现同样的情感分类任务。堆叠多个 LSTM 可能会捕获数据中的更多变化,从而有可能获得更高的准确性。

(1) 堆叠多层 LSTM 的实现如下,代码中需要将第 1LSTM 层中的 return_sequences 参数值更改为 true,这样可以确保第一个 LSTM 返回一个输出序列,然后将其传递给另一个 LSTM 层作为输入:

embedding_vecor_length=32
max_review_length=26
model = Sequential()
model.add(Embedding(input_dim=nb_chars+1, output_dim=32, input_length = 26))
model.add(LSTM(40, return_sequences=True))
model.add(LSTM(40, return_sequences=False))
model.add(Dense(3, activation='softmax'))
model.compile(loss='categorical_crossentropy', optimizer='adam', metrics=['acc'])
print(model.summary())

模型架构的简要信息输入如下:

Model: "sequential"
_________________________________________________________________
Layer (type)                 Output Shape              Param #   
=================================================================
embedding (Embedding)        (None, 26, 32)            477920    
_________________________________________________________________
lstm (LSTM)                  (None, 26, 40)            11680     
_________________________________________________________________
lstm_1 (LSTM)                (None, 40)                12960     
_________________________________________________________________
dense (Dense)                (None, 3)                 123       
=================================================================
Total params: 502,683
Trainable params: 502,683
Non-trainable params: 0
_________________________________________________________________

在此体系结构中,使用了 2 个叠加的 LSTM 层,第一个 LSTM 每个时间戳输出 40 个值,因此输出形状为(None, 26, 40),其中 None 表示 batch_size26 表示时间戳数,40 表示 LSTM 中神经元数,也就是每个时间戳输出值的维度。第二个 LSTM 中的参数数量如下所示:

W = model.layers[2].get_weights()[0]
U = model.layers[2].get_weights()[1]
b = model.layers[2].get_weights()[2]
print(W.shape,U.shape,b.shape)

得到的参数形状输出如下,从输出中可以看到,共有 12960 个参数:

(40, 160) (40, 160) (160,)

(2) 训练模型,如下所示:

history = model.fit(x_train, y_train,
            validation_data=(x_test, y_test),
            epochs=20, 
            batch_size=64)

随着训练时间的增加,在训练和测试数据集,损失值和准确率的变化如下:

模型训练过程监测

如上图所示,训练后的多层 LSTM 模型的测试准确率约为 78%。但是,可以看到模型出现了严重的过拟合,在使用更多的数据后,多层 LSTM 比单层 LSTM 能够捕获更多信息。

相关链接

Keras深度学习实战(1)——神经网络基础与模型训练过程详解
Keras深度学习实战(2)——使用Keras构建神经网络
Keras深度学习实战(7)——卷积神经网络详解与实现
Keras深度学习实战(24)——从零开始构建单词向量
Keras深度学习实战(25)——使用skip-gram和CBOW模型构建单词向量
Keras深度学习实战(26)——文档向量详解
Keras深度学习实战(27)——循环神经详解与实现
Keras深度学习实战(28)——利用单词向量构建情感分析模型
Keras深度学习实战(29)——长短时记忆网络详解与实现
Keras深度学习实战——使用循环神经网络构建情感分析模型

猜你喜欢

转载自blog.csdn.net/LOVEmy134611/article/details/126702803