[深度学习]-基于tensorflow的CNN和RNN-LSTM文本情感分析对比

基于tensorflow的CNN和LSTM文本情感分析对比

    • 1. 背景介绍
    • 2. 数据集介绍
      • 2.0 wordsList.npy
      • 2.1 wordVectors.npy
      • 2.2 idsMatrix.npy
        • 2.2.0 文本预处理
        • 2.2.0 为什么把词转化为词向量
      • 2.3 Helper Functions
    • 3. RNN网络训练
    • 4. CNN网络训练
    • 5. CNN与RNN训练结果对比
    • 6. 循环神经网络系列
    • 参考文献

1. 背景介绍

如今科技日益发展、网络技术不断深入到大众生活中,贴吧、网站、电子邮件,用户评论等使得人们有更多的便捷方式在网络中发表自己的意见和看法。这些数量庞大的文本中的情感信息有着极大的研究价值和实用价值。而如何能够从众多文本信息和数据中准确而高效地分析出文本中所蕴含的情感,并判断情感极性,对情感做出分类,是目前自然语言处理中的一个热门研究课题。关于文本情感分析,在此之前国内外专家和学者们都已经做了大量的研究,其中运用深度学习来对文本进行情感分析是常用的文本情感分析方法。神经网络模型通过学习和训练后,能有效地模拟人脑的学习方式,对大量的输入文本信息进行高效的分析,并对文本中的情感进行判断,非常适合用于文本情感分析的研究中。

2. 数据集介绍

Google 已经帮助我们在大规模数据集上训练出来了 Word2Vec 模型,它包括 1000 亿个不同的词,在这个模型中,谷歌能创建300万个词向量,每个向量维度为 300。在理想情况下,我们将使用这些向量来构建模型,但是因为这个单词向量矩阵太大了**(3.6G**),因此在此次研究中我们将使用一个更加易于管理的矩阵,该矩阵由 GloVe 进行训练得到。矩阵将包含 400000 个词向量,每个向量的维数为 50

我们将导入两个不同的数据结构,一个是包含 400000 个单词的 Python 列表(wordsList.npy),一个是包含所有单词向量值的 400000*50 维的嵌入矩阵 (wordVectors.npy)。

数据和代码可以从下面连接中下载
https://github.com/adeshpande3/LSTM-Sentiment-Analysis
[深度学习]-基于tensorflow的CNN和RNN-LSTM文本情感分析对比_第1张图片
如果上面数据集无法下载,可以通过下面我的百度网盘下载
链接:https://pan.baidu.com/s/1O-tGXFt4z9-CbzzJ0CTRkA
提取码:lj20

2.0 wordsList.npy

一个是包含 400000 个单词的 Python 列表,它里面每个单词对应的位置就是 wordVectors里相应词向量的位置
例子:如果我们要查找baseball这个词的相应词向量

import numpy as np
import tensorflow as tf
import os as os
import matplotlib.pyplot as plt
from os import listdir
wordsList = np.load('./training_data/wordsList.npy')
print('Loaded the word list!')

wordsList = wordsList.tolist()  # Originally loaded as numpy array
wordsList = [word.decode('UTF-8') for word in wordsList]  # Encode words as UTF-8
wordVectors = np.load('./training_data/wordVectors.npy')
print('Loaded the word vectors!')

print(len(wordsList))
# print(wordsList)
print(wordVectors.shape)

baseballIndex = wordsList.index('baseball')
print(baseballIndex)
print(wordVectors[baseballIndex])

执行结果

Loaded the word list!
Loaded the word vectors!
400000
(400000, 50)
1444
[-1.9327    1.0421   -0.78515   0.91033   0.22711  -0.62158  -1.6493
  0.07686  -0.5868    0.058831  0.35628   0.68916  -0.50598   0.70473
  1.2664   -0.40031  -0.020687  0.80863  -0.90566  -0.074054 -0.87675
 -0.6291   -0.12685   0.11524  -0.55685  -1.6826   -0.26291   0.22632
  0.713    -1.0828    2.1231    0.49869   0.066711 -0.48226  -0.17897
  0.47699   0.16384   0.16537  -0.11506  -0.15962  -0.94926  -0.42833
 -0.59457   1.3566   -0.27506   0.19918  -0.36008   0.55667  -0.70315
  0.17157 ]

2.1 wordVectors.npy

一个是包含所有单词向量值的 400000*50 维的嵌入矩阵
假如我们有这么一句话“I thought the movie was incredible and inspiring” ,一个10个词,那么它们在wordVectors中的词向量是什么?
代码实现去查找它们相应的词向量

import numpy as np
import tensorflow as tf
import os as os
import matplotlib.pyplot as plt
from os import listdir
wordsList = np.load('./training_data/wordsList.npy')
print('Loaded the word list!')

wordsList = wordsList.tolist()  # Originally loaded as numpy array
wordsList = [word.decode('UTF-8') for word in wordsList]  # Encode words as UTF-8
wordVectors = np.load('./training_data/wordVectors.npy')
maxSeqLength = 10  # Maximum length of sentence
numDimensions = 300  # Dimensions for each word vector
firstSentence = np.zeros((maxSeqLength), dtype='int32')
firstSentence[0] = wordsList.index("i")
firstSentence[1] = wordsList.index("thought")
firstSentence[2] = wordsList.index("the")
firstSentence[3] = wordsList.index("movie")
firstSentence[4] = wordsList.index("was")
firstSentence[5] = wordsList.index("incredible")
firstSentence[6] = wordsList.index("and")
firstSentence[7] = wordsList.index("inspiring")
# firstSentence[8] and firstSentence[9] are going to be 0
print(firstSentence.shape)
print(firstSentence)  # Shows the row index for each word
with tf.Session() as sess:
    print(tf.nn.embedding_lookup(wordVectors, firstSentence).eval().shape)

执行结果

(10,)
[    41    804 201534   1005     15   7446      5  13767      0      0]
(10, 50)

2.2 idsMatrix.npy

IMDB(Internet Movie Database互联网电影数据库)数据集,我们在这个数据集上做的训练和测试。这个数据集包含 25000 条电影数据,其中 12500 条正向数据在positiveReviews目录下,12500 条负向数据在negativeReviews目录下。我们将25000个文本中的23000个文本评论作为训练集,将剩下的2000个文本评论作为测试集

下面代码是把positiveReviews和negativeReviews目录下电影评论数据转化为Numpy的数据集
25000 x 250, 一共25000条电影评论,最长的评论有250单词

import numpy as np
import tensorflow as tf
import os as os
import matplotlib.pyplot as plt
from os import listdir

file_path = 'D:/BaiduNetdiskDownload/'
positiveReviews_path = file_path+'positiveReviews/'
negativeReviews_path = file_path +'negativeReviews/'
positiveFiles = [positiveReviews_path + f for f in listdir(positiveReviews_path) if os.path.isfile(os.path.join(positiveReviews_path, f))]
negativeFiles = [negativeReviews_path + f for f in listdir(negativeReviews_path) if os.path.isfile(os.path.join(negativeReviews_path, f))]

wordsList = np.load('./training_data/wordsList.npy')
print('Loaded the word list!')

wordsList = wordsList.tolist()  # Originally loaded as numpy array
wordsList = [word.decode('UTF-8') for word in wordsList]  # Encode words as UTF-8

maxSeqLength = 250

ids = np.zeros((25000, maxSeqLength), dtype='int32')
fileCounter = 0
for pf in positiveFiles:
    with open(pf, "r", encoding='utf-8') as f:
        indexCounter = 0
        line=f.readline()
        cleanedLine = cleanSentences(line)
        split = cleanedLine.split()
        for word in split:
            try:
                ids[fileCounter][indexCounter] = wordsList.index(word)
            except ValueError:
                ids[fileCounter][indexCounter] = 399999 #Vector for unkown words
            indexCounter = indexCounter + 1
            if indexCounter >= maxSeqLength:
                break
    fileCounter = fileCounter + 1
for nf in negativeFiles:
    with open(nf, "r", encoding='utf-8') as f:
        indexCounter = 0
        line=f.readline()
        cleanedLine = cleanSentences(line)
        split = cleanedLine.split()
        for word in split:
            try:
                ids[fileCounter][indexCounter] = wordsList.index(word)
            except ValueError:
                ids[fileCounter][indexCounter] = 399999 #Vector for unkown words
            indexCounter = indexCounter + 1
            if indexCounter >= maxSeqLength:
                break
        fileCounter = fileCounter + 1

np.save('idsMatrix', ids)

2.2.0 文本预处理

文本预处理
[深度学习]-基于tensorflow的CNN和RNN-LSTM文本情感分析对比_第2张图片
输入文本,在将输入文本转化成向量之前,我们需要将标点符号、括号、问号等删去,只留下字母、数字和字符, 同时将大写字母转化为小写。

效果如下图
[深度学习]-基于tensorflow的CNN和RNN-LSTM文本情感分析对比_第3张图片

2.2.0 为什么把词转化为词向量

我们希望创建这种词向量的方式是可以表示单词及其在上下文中意义的。例如,我们希望单词 “love” 和 “adore” 这两个词在向量空间中是有一定的相关性的,因为他们的意思相似,而且都在类似的上下文中使用,因此他们的空间相距距离会相对较小。而“love”、“adore”这两个单词与单词“baseball”的意思有很大的不同,词性也不相同,那么“love”、“adore”这两个单词的向量与单词“baseball”的向量相距距离就会相对较大。单词的向量表示也被称之为词嵌入。

[深度学习]-基于tensorflow的CNN和RNN-LSTM文本情感分析对比_第4张图片
为了得到这些词嵌入,我们采用一个很著名的模型 “Word2Vec”。“Word2Vec”是近几年很火的算法,它通过神经网络机器学习算法来训练N-gram 语言模型,并在训练过程中求出word所对应的vector的方法。它是将词表征为实数值向量的一种高效的算法模型,其利用深度学习的思想,可以通过训练,把对文本内容的处理简化为 K 维向量空间中的向量运算,而向量空间上的相似度可以用来表示文本语义上的相似。在这个模型中,每个词的词向量是根据上下文的语境来进行推断的,如果两个词在上下文的语境中可以被互换,那么这就表示这两个词的意思相似,词性相似,那么他们的词向量中相距距离就非常近。在自然语言中,上下文的语境对分析词语的意义是非常重要的。

简单来说,Word2Vec这个模型的作用就是从一大堆句子(以 Wikipedia 为例)中为每个独一无二的单词进行建模,并且输出一个唯一的向量,Word2Vec 模型的输出被称为一个嵌入矩阵。该嵌入矩阵将包含训练语料库中每个不同单词的向量。 传统上,嵌入矩阵可以包含超过300万个单词向量。

Word2Vec模型是通过对数据集中的每个句子进行训练,在其上滑动一个固定大小的窗口,并试图预测窗口的中心词,给出其他词。使用损失函数和优化程序,该模型为每个唯一字生成向量。这个训练过程的细节可能会变得有点复杂,所以我们现在要跳过细节,但这里主要的一点是,任何深度学习方法对于NLP任务的输入可能都会有单词向量作为输入。

Google 已经帮助我们在大规模数据集上训练出来了 Word2Vec 模型,它包括 1000 亿个不同的词,在这个模型中,谷歌能创建300万个词向量,每个向量维度为 300。在理想情况下,我们将使用这些向量来构建模型,但是因为这个单词向量矩阵太大了(3.6G),因此在此次研究中我们将使用一个更加易于管理的矩阵,该矩阵由 GloVe 进行训练得到。矩阵将包含 400000 个词向量,每个向量的维数为 50

2.3 Helper Functions

from random import randint
import numpy as np

maxSeqLength = 250
batchSize = 24
ids = np.load('./training_data/idsMatrix.npy')

def getTrainBatch():
    labels = []
    arr = np.zeros([batchSize, maxSeqLength])
    for i in range(batchSize):
        if (i % 2 == 0):
            num = randint(1,11499)
            labels.append([1,0])
        else:
            num = randint(13499,24999)
            labels.append([0,1])
        arr[i] = ids[num-1:num]
    return arr, labels

def getTestBatch():
    labels = []
    arr = np.zeros([batchSize, maxSeqLength])
    for i in range(batchSize):
        num = randint(11499,13499)
        if (num <= 12499):
            labels.append([1,0])
        else:
            labels.append([0,1])
        arr[i] = ids[num-1:num]
    return arr, labels

3. RNN网络训练

import tensorflow as tf
import numpy as np
import datetime
from random import randint

maxSeqLength = 250
batchSize = 24
lstmUnits = 64
numClasses = 2
iterations = 100000
numDimensions = 50 #Dimensions for each word vector

maxSeqLength = 250
batchSize = 24
ids = np.load('./training_data/idsMatrix.npy')

def getTrainBatch():
    labels = []
    arr = np.zeros([batchSize, maxSeqLength])
    for i in range(batchSize):
        if (i % 2 == 0):
            num = randint(1,11499)
            labels.append([1,0])
        else:
            num = randint(13499,24999)
            labels.append([0,1])
        arr[i] = ids[num-1:num]
    return arr, labels


wordVectors = np.load('./training_data/wordVectors.npy')
print('Loaded the word vectors!')

tf.reset_default_graph()

labels = tf.placeholder(tf.float32, [batchSize, numClasses])
input_data = tf.placeholder(tf.int32, [batchSize, maxSeqLength])

data = tf.Variable(tf.zeros([batchSize, maxSeqLength, numDimensions]),dtype=tf.float32)
data = tf.nn.embedding_lookup(wordVectors, input_data)

lstmCell = tf.contrib.rnn.BasicLSTMCell(lstmUnits)
lstmCell = tf.contrib.rnn.DropoutWrapper(cell=lstmCell, output_keep_prob=0.75)
value, _ = tf.nn.dynamic_rnn(lstmCell, data, dtype=tf.float32)

weight = tf.Variable(tf.truncated_normal([lstmUnits, numClasses]))
bias = tf.Variable(tf.constant(0.1, shape=[numClasses]))
value = tf.transpose(value, [1, 0, 2])
last = tf.gather(value, int(value.get_shape()[0]) - 1)
prediction = (tf.matmul(last, weight) + bias)

correctPred = tf.equal(tf.argmax(prediction,1), tf.argmax(labels,1))
accuracy = tf.reduce_mean(tf.cast(correctPred, tf.float32))

loss = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(logits=prediction, labels=labels))
optimizer = tf.train.AdamOptimizer().minimize(loss)

tf.summary.scalar('Loss', loss)
tf.summary.scalar('Accuracy', accuracy)
merged = tf.summary.merge_all()
logdir = "tensorboard/" + datetime.datetime.now().strftime("%Y%m%d-%H%M%S") + "/"


sess = tf.InteractiveSession()
saver = tf.train.Saver()
sess.run(tf.global_variables_initializer())

writer = tf.summary.FileWriter(logdir, sess.graph)

for i in range(iterations):
    #Next Batch of reviews
    nextBatch, nextBatchLabels = getTrainBatch();
    sess.run(optimizer, {input_data: nextBatch, labels: nextBatchLabels})

    #Write summary to Tensorboard
    if (i % 50 == 0):
        summary = sess.run(merged, {input_data: nextBatch, labels: nextBatchLabels})
        writer.add_summary(summary, i)

    #Save the network every 10,000 training iterations
    if (i % 10000 == 0 and i != 0):
        save_path = saver.save(sess, "models/pretrained_lstm.ckpt", global_step=i)
        print("saved to %s" % save_path)
writer.close()

4. CNN网络训练

情感分析之卷积神经网络-TextCNN,包含代码

5. CNN与RNN训练结果对比

6. 循环神经网络系列

1. 循环神经网络系列之RNN与LSTM介绍
2. 循环神经网络系列之word2vector总结与理解
3. 循环神经网络系列之Imdb影评的数据集介绍与下载
4. 循环神经网络系列之文本情感分析包含(数据预处理-训练-预测)
5. 循环神经网络系列之基于tensorflow的CNN和RNN-LSTM文本情感分析对比
6. 情感分析之卷积神经网络-TextCNN,包含代码

参考文献

https://blog.csdn.net/qq_33547191/article/details/86075275
https://www.oreilly.com/content/perform-sentiment-analysis-with-lstms-using-tensorflow/

你可能感兴趣的:(tensorflow,深度学习,tensorflow)