keras 入门——电影评论二分类问题(from python深度学习)

时间:2024-05-19 13:50:04

一、IMDB数据集的介绍    

  电影评论IMDB数据集,包含来自电影数据库(IMDB)的50000两级分化的评论。我们在深度学习中采用其中的25000条评论作为训练集,剩下的25000条评论作为测试集。两个测试集都包含各50%的正面与负面评论,其中0代表负面,1代表正面。数据集已经内置于keras库,并且做过了预处理,其中的评论单词已经被转化为了整数序列,每个整数就映射到字典里的某个单词。每一条

首先看看IMDB数据集里的内容。在python中输入 

from keras.datasets import imdb
(train_data,train_labels),(test_data,test_labels) = imdb.load_data(num_words = 10000)

首次加载需要几分钟的时间,其中num_words = 10000的含义是,我们只采用单词索引序列前10000个高频单词,以免将数据搞得过于庞大。加载完毕之后我们来看看里面的数据结构。keras 入门——电影评论二分类问题(from python深度学习)

输入train_data[0]后发现显示的是一个整数list,查看他的长度,有218个数字,也就意味着这是一条有218个单词的评论。如果继续查询其他的评论字数,会发现数目不是相同的。

然后查看labels的内容。输入

train_labels[0]

在屏幕上显示 1,意味着第一条评论是正面评论。

二、数据的准备

   数据输入的准备

   要将数据输入到神经网络就要将数据做预先的处理,在这里,我们不能将输入层的节点数简简单单的定义为每条评论的单词个数,然后将单词索引作为输入。首先,每条评论的单词数目就不相同,很难做到节点数目上的确定,其次,每个单词的索引最大可为9999,如果将这些巨大的整数不做处理直接输入的话会大大降低神经网络的学习能力。因此我们考虑采用神经网络中常用的one-hot编码。

  one-hot编码与普通的二进制编码有所区别,比如我们用4位二进制来编码3,二进制表示为0011,one-hot表示为0001。二进制不做解释,one-hot编码就是每一个数字就把从最左边开始(0)到最右边(3)一位置1其他的都置0。简单来说,数据最大为多少我们就用多少维的one-hot向量。

  在这里我们用python代码来实现对所有数据的编码,输入

def vectorize_sequences(sequences,dimention = 10000):
    results = np.zeros((len(sequences),dimention))#创建一个大小为(25000,10000)的全零矩阵
    for i,sequence in enumerate(sequences):
        results[i,sequence] = 1.
    return results

这里函数enmerate是枚举函数,其作用如下:

a = [9,1,3]

enmerate(a)

>>0:9  1:1  2:3

在本实例中,i就是第i条评论,sequence就是每个单词索引,只要sequence有哪个值就把对应维one-hot,这里注意,在每一次操作都要全部完成i才会到下一个。比如说某个评论在第n个有3个数字,分别为[1,5,7]那么矩阵的第n行就是[0 1 0 0 0 1 0 1 ....].

label数据准备

因为labels数据是list为了统一要将其转化为向量,输入

y_train = np.asarray(y_train).astype('float32')
y_test = np.asarray(y_test).astype('float32')

三、构建与训练网络

结构模型的定义

代码如下

model = Sequential() 
model.add(Dense(500,input_shape=(10000,))) 
model.add(Activation('relu'))
model.add(Dropout(0.5)) 
 
model.add(Dense(500))
model.add(Activation('relu'))
model.add(Dropout(0.5))

model.add(Dense(100)) 
model.add(Activation('relu'))
model.add(Dropout(0.3))

model.add(Dense(16)) 
model.add(Activation('relu'))
model.add(Dropout(0.1))
 
model.add(Dense(1)) 
model.add(Activation('sigmoid'))
model.summary()

  采用sequential结构,输入节点10000个,设置3个隐藏层,**函数均采用relu,为了减少过度拟合,在每一层都设置一定的dropout,输出层一个节点,**函数为sigmoid。

编译模型

代码如下

model.compile(loss='binary_crossentropy', optimizer=optimizers.RMSprop(lr = 0.001),metrics=['acc'])

这里因为我们是0,1二分情况所以采用binary_crossentropy,优化算法采用rmsprop,这里对他的lr做设定为0.001。

训练模型

history = model.fit(X_train, y_train, batch_size=tBatchSize, epochs=Epochs, verbose=2,shuffle=True, validation_split=0.3)

score = model.evaluate(X_test,y_test, batch_size=tBatchSize)
print("The score:",score[0])
print("Tne accuracy:",score[1])

在训练集中采用30%的数据做validation,shuffle = True的含义是将数据打乱,增加随机性减少过拟合程度。将损失与准确性打印下来。

四、绘图,参数调整

接下来进行编译,在最后将loss画出来,以便直观的看出准确性与迭代次数的关系,对参数做出调整。

编译结果如下keras 入门——电影评论二分类问题(from python深度学习)

在验证集上的正确率达到87%,再看看损失图。

keras 入门——电影评论二分类问题(from python深度学习)

可以清晰的看到在训练集上的损失越来越小,这符合梯度下降的作用,但是在Validation上的损失却基本呈现一种上升趋势,说明数据过度拟合了。我们采用一个折中的epchs次数5次,试试看学习效果。

keras 入门——电影评论二分类问题(from python深度学习)

可以看到,在验证集上的正确率有所上升,在优化器不变的情况下,再尝试修改其他参数正确率均不会有显著上升,因此,如果想进一步提高正确率只能从优化器着手。

 

 

附全部代码:

from keras.models import Sequential  
from keras.layers import Input, Dense, Dropout, Activation
from keras.models import Model
from keras import optimizers
from keras.optimizers import SGD
from keras.datasets import imdb
import numpy as np
import matplotlib.pyplot as plt

tBatchSize = 512
Epochs = 20

model = Sequential() 
model.add(Dense(500,input_shape=(10000,))) 
model.add(Activation('relu'))
model.add(Dropout(0.5)) 
 
model.add(Dense(500))
model.add(Activation('relu'))
model.add(Dropout(0.5))

model.add(Dense(100)) 
model.add(Activation('relu'))
model.add(Dropout(0.3))

model.add(Dense(16)) 
model.add(Activation('relu'))
model.add(Dropout(0.1))
 
model.add(Dense(1)) 
model.add(Activation('sigmoid'))
model.summary()

model.compile(loss='binary_crossentropy', optimizer=optimizers.RMSprop(lr = 0.001),metrics=['acc'])
 
def vectorize_sequences(sequences,dimention = 10000):
    results = np.zeros((len(sequences),dimention))
    for i,sequence in enumerate(sequences):
        results[i,sequence] = 1.
    return results

 #load data
(X_train, y_train), (X_test, y_test) = imdb.load_data(num_words = 10000)



X_train = vectorize_sequences(X_train)
X_test = vectorize_sequences(X_test)

y_train = np.asarray(y_train).astype('float32')
y_test = np.asarray(y_test).astype('float32')

history = model.fit(X_train, y_train, batch_size=tBatchSize, epochs=Epochs, verbose=2,shuffle=True, validation_split=0.3)

score = model.evaluate(X_test,y_test, batch_size=tBatchSize)
print("The score:",score[0])
print("Tne accuracy:",score[1])

history_dic = history.history
loss_values = history_dic['loss']
val_loss_values = history_dic['val_loss']
acc = history_dic['acc']
val_acc = history_dic['val_acc']

epochs = range(1,len(loss_values)+1)
fig = plt.figure()

ax1 = fig.add_subplot(111)
ax1.plot(epochs,loss_values,'bo',label = 'Training loss')
ax1.plot(epochs,val_loss_values,'b',label = 'Validation loss')
plt.title("Training and validstion loss")
plt.xlabel("Epochs")
plt.ylabel("Loss")
plt.legend(bbox_to_anchor=(1,0),loc = 3,borderaxespad = 0)
plt.show()
'''
ax2 = fig.add_subplot(111)
ax2.plot(epochs,acc,'bo',label = 'Training acc')
ax2.plot(epochs,val_acc,'b',label = 'Validation acc')
plt.title("Training and validstion accuracy")
plt.xlabel("Epochs")
plt.ylabel("Accuracy")
plt.legend(bbox_to_anchor=(1,0),loc = 3,borderaxespad = 0)

plt.show()
'''