使用LSTM进行情感分析
原理见https://mp.csdn.net/console/editor/html/108697113
数据集见下文https://pan.baidu.com/s/1SctPmfFlq6ilY2bxcXHIFA
使用keras实现LSTM 情感分析见https://blog.csdn.net/ghj786110/article/details/89669783
案例流程
1) 制作词向量,可以使用gensim这个库,也可以直接用现成的
2) 词和ID的映射,常规套路了
3) 构建RNN网络架构
4) 训练我们的模型
数据集
IMDB数据集下载地址为:http://ai.stanford.edu/~amaas/data/sentiment/数据集应用于影评情绪的分类。另提一句,该数据集也集成在tensorflow的keras模块中,可以通过以下语句导入。
from keras.datasets import imdb
# num_words参数为保留训练集出现频率在前10000的词。
(train_data,train_labels),(test_data,test_labels) = imdb.load_data(num_words=10000)使用Keras首次导入时要下载 链接如下
导入数据
首先,我们需要去创建词向量。为了简单起见,我们使用训练好的模型来创建。
作为该领域的一个最大玩家,Google 已经帮助我们在大规模数据集上训练出来了 Word2Vec 模型,包括 1000 亿个不同的词!在这个模型中,谷歌能创建 300 万个词向量,每个向量维度为 300。
在理想情况下,我们将使用这些向量来构建模型,但是因为这个单词向量矩阵相当大(3.6G),我们用另外一个现成的小一些的,该矩阵由 GloVe 进行训练得到。矩阵将包含 400000 个词向量,每个向量的维数为 50。
我们将导入两个不同的数据结构,一个是包含 400000 个单词的 Python 列表,一个是包含所有单词向量值得 400000*50 维的嵌入矩阵。
import tensorflow as tf
import numpy as np
from random import randint
import time
import re
from os import listdir
from os.path import isfile, join
import matplotlib.pyplot as plt
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
if __name__ == "__main__":
maxSeqLength = 250
batchSize = 24#批处理大小
numDimensions = 250
lstmUnits = 64#LSTM的单元个数
numClasses = 2#分类类别
iterations = 50000#和训练次数
wordsList = np.load(r'.\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] # 进行解码,这一步很重要,不然回报word not in vocab错误
wordVectors = np.load(r'.\training_data\wordVectors.npy')
print('Loaded the word vectors!')
print(len(wordsList))
print(wordVectors.shape)
ids = np.load(r'.\LSTM\training_data\idsMatrix.npy')
tf.reset_default_graph()
input_data = tf.placeholder(tf.int32, shape=[batchSize, maxSeqLength]) # 占位符,必不可少
labels = tf.placeholder(tf.int32, shape=[batchSize, numClasses]) # 根据其格式来写
data = tf.Variable(tf.zeros([batchSize, maxSeqLength, numDimensions]), dtype=tf.float32)
data = tf.nn.embedding_lookup(wordVectors, input_data) # 按照索引来找相应的词向量
data = tf.cast(data, tf.float32) # 由于版本的问题,这一步必不可少,将x的数据格式转化成dtype,有的版本可以不写
# LSTM网络的构建
lstmCell = tf.contrib.rnn.BasicLSTMCell(lstmUnits) # lstmUnits为cell中隐藏层神经元的个数
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]) # value的输出为[batchsize,length,hidden_size]
# 也可以写成 value, states = tf.nn.dynamic_rnn(lstmCell, data, dtype=tf.float32),vale=states[-1],可以先打印出states的shape再进行判断
last = tf.gather(value, int(value.get_shape()[0]) - 1) # 上述对value做这种变化与注释中states[-1]结果相似
prediction = (tf.matmul(last, weight) + bias) # 可以再加上softmax层
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) # 随机梯度下降最小化loss
with tf.Session() as sess:
saver = tf.train.Saver() # 保存模型
sess.run(tf.global_variables_initializer()) # 初始化变量
for i in range(iterations):
# Next Batch of reviews
nextBatch, nextBatchLabels = getTrainBatch()
sess.run(optimizer, {input_data: nextBatch, labels: nextBatchLabels})
if (i % 1000 == 0 and i != 0):
loss_ = sess.run(loss, {input_data: nextBatch, labels: nextBatchLabels})
accuracy_ = sess.run(accuracy, {input_data: nextBatch, labels: nextBatchLabels})
print("iteration {}/{}...".format(i + 1, iterations),
"loss {}...".format(loss_),
"accuracy {}...".format(accuracy_))
# 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)
iterations = 10
for i in range(iterations):
nextBatch, nextBatchLabels = getTestBatch();
print("Accuracy for this batch:", (sess.run(accuracy, {input_data: nextBatch, labels: nextBatchLabels})) * 100)