[Deep-Learning-with-Python]基于Keras的imdb数据集电影评论情感二分类

IMDB数据集下载速度慢,可以在我的repo库中找到下载,下载后放到~/.keras/datasets/目录下,即可正常运行。

电影评论分类:二分类

二分类可能是机器学习最常解决的问题。我们将基于评论的内容将电影评论分类:正类和负类。

IMDB数据集

IMDB数据集有5万条来自网络电影数据库的评论;其中2万5千条用来训练,2万5千条用来测试,每个部分正负评论各占50%.
划分训练集、测试集的必要性:不能在相同的数据集上对机器学习模型进行测试。因为在训练集上模型表现好并不意味着泛化能力好(在没有见过的数据上仍然表现良好),而我们关心的是模型的泛化能力.
和MNIST数据集类似,IMDB数据集也集成在Keras中,同时经过了预处理:电影评论转换成了一系列数字,每个数字代表字典中的一个单词。

加载数据集

from keras.datasets import imdb

(train_data,train_labels),(test_data,test_labels) = imdb.load_data(num_words=10000)

num_words=10000意味着只保留训练集中最常出现的前10000个词,不经常出现的单词被抛弃---最终所有评论的维度保持相同。
变量train_data,test_data是电影评论的列表,每条评论由数字(对应单词在词典中出现的位置下标)列表组成。train_labels,test_labels是0,1列表,0负面评论,1表示正面评论。

>>> train_data[0]
[1, 14, 22, 16, ... 178, 32]
>>> train_labels[0]
1

预处理数据

不能直接将list类型的数据送到神经网络中训练,必须将list类型转换为tensor张量类型。有两种转换方式:

  • 填充列表使每个列表长度都相同,然后转换为整数类型的张量,形状为(samples, word_indices),使用张量作为神经网络的第一层(Embedding层,能处理这样的整数类型张量);
  • 将列表进行one-hot编码,转换成0、 1向量。然后用Dense网络层作为神经网络的第一层,处理浮点类型向量数据。
import numpy as np

def vectorize_sequences(sequences, dimension=10000):
    results = np.zeros((len(sequences), dimension)) #数据集长度,每个评论维度10000
    for i, sequence in enumerate(sequences):
        results[i, sequences] = 1 # one-hot
    return results

x_train = vectorize_sequences(train_data)
x_test = vectorize_sequences(test_data)

y_train = np.asarray(train_labels).astype('float32') # 向量化标签数据
y_test = np.asarray(test_labels).astype('float32')

构建网络模型

现在输入数据是向量类型,对应标签数据为标量(0, 1):最容易处理的数据格式。处理这类问题最常见的网络模型是Dense网络层的线性堆叠,Dense(16, activation='relu')。

Dense网络层接收的参数16表示网络层神经元数目。一个神经元单元表示网络层表示空间的一个维度。16个神经元表示网络层权重系数形状为(input_dimensions, 16);dot点积运算将会把输出张量转换为16维度的表示张量。越多的神经元数目表示神经网络可以学习到更加复杂的特征表示,相应的计算效率降低,也可能学到不必要的特征。
Dense网络层堆叠时回答两个关键的问题:

  • 有多少层网络?
  • 每个层网络有多少个神经元?

激活函数能给网络模型增加非线性表示。
使用的网络模型如下:


image
from keras import models
from keras import layers

model = models.Sequential()

model.add(layers.Dense(16, activation='relu',input_shape=(10000,)))
model.add(layers.Dense(16,activation='relu'))
model.add(layers.Dense(1,activation='sigmoid'))

最后,选择损失函数和优化算法。因为是二分类问题,网络模型的输出是一个概率,最好使用binary_crossentropy损失函数,也可以使用mean_squared_error均方误差损失函数。但是交叉熵是处理模型输出为概率时最佳选择。
配置使用rmsprop优化算法以及binary_crossentropy损失函数,选择监测的指标。

model.compile(optimizer='rmsprop',loss='binary_crossentropy',metrics=['accuracy'])

这里参数使用字符串传递,因为在keras中对应字符串已经定义好了。同时,可以传递函数类型给相应的参数。如:

from keras import losses
from keras import metrics

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

模型验证

为了在训练过程中在没有见过数据上监测准确率变化,需要分出一个验证集。从训练集中分出10000条做验证集。

x_val = x_train[:10000]
partial_x_train = x_train[10000:]

y_val = y_train[:10000]
partial_y_train = y_train[10000:]

在512小批量,迭代20次进行模型训练,同时在验证集上监测准确率变化。

model.compile(optimizer='rmsprop',loss='binary_crossentropy',metrics=['acc'])

history = model.fit(partial_x_train,partial_y_train,epochs=20,batch_size=512,validation_data=(x_val, y_val))

通过调用model.fit()方法返回一个history对象,history对象有history属性---一个包含在训练过程中记录的数据的字典。

>>> history_dict = history.history
>>> history_dict.keys()
[u'acc', u'loss', u'val_acc', u'val_loss']

字典包括4个键--在训练、验证过程中被监测的指标。

在图中画出训练损失和验证损失的变化图:

import matplotlib.pyplot as plt

history_dict = history.history
loss_values = history_dict['loss']
val_loss_values = history_dict['val_loss']

epochs = range(1, len(acc) + 1)

plt.plot(epochs, loss_values, 'bo', label='Training loss')#bo:blue dot蓝点
plt.plot(epochs, val_loss_values, 'b', label='Validation loss')#b: blue蓝色
plt.title('Training and validation loss')
plt.xlabel('Epochs')
plt.ylabel('Loss')
plt.legend()

plt.show()
image

训练集和验证集上准确率变化:

plt.clf()

acc_values = history_dict['acc']
val_acc_values = history_dict['val_acc']
plt.plot(epochs, acc, 'bo', label='Training acc')
plt.plot(epochs, val_acc, 'b', label='Validation acc')
plt.title('Training and validation accuracy')
plt.xlabel('Epochs')
plt.ylabel('Loss')
plt.legend()

plt.show()
image

可以从上面的两张图中看到,训练损失逐渐降低,训练准确度逐渐提高--这正是使用梯度下降算法,我们所期望看到的。但是,验证损失和验证集上的准确率却在第4次迭代左右开始变差----模型在训练集上表现良好,在没有见过的数据上表现很差(泛化能力差)。用术语讲,模型发生了过拟合。在这里可以,使模型在第4次epoch时,训练结束,这样来尽可能避免过拟合现象的发生。

重新训练

model = models.Sequential()

model.add(layers.Dense(16,activation='relu',input_shape=(10000,)))
model.add(layers.Dense(16,activation='relu'))
model.add(layers.Dense(1,activation='sigmoid'))

model.compile(optimizer='rmsprop',loss='binary_crossentropy',metrics=['accuracy'])

model.fit(x_train,y_train,epochs=4,batch_size=512)
results = model.evaluate(x_test, y_test)
#[0.2929924130630493, 0.88327999999999995] 模型准确率为88%

使用训练好的模型在新数据上做预测

使用训练好的模型做预测----训练模型的目的.
可以使用predict函数对数据进行预测,给出为正面评论的概率。

>>> model.predict(x_test)
array([[ 0.98006207]
[ 0.99758697]
[ 0.99975556]
...,
[ 0.82167041]
[ 0.02885115]
[ 0.65371346]], dtype=float32)

小结

  • 在把数据送到模型训练之前,需要对原始数据进行预处理---将原始数据转换成tensor张量格式。
  • 使用relu为激活函数的Dense网络层的线性连接能解决很大一部分问题;
  • 在二分类问题中,网络模型应该以包含一个神经元,激活函数为sigmoid的Dense层结束;输出是介于0~1的标量,可以理解为概率。
  • 二分类问题,sigmoid标量输出,对应损失函数应该选择binary_crossentropy;
  • rmsprop优化算法大多数情况下是一个很好的选择,无论问题是什么。
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 158,736评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,167评论 1 291
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,442评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,902评论 0 204
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,302评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,573评论 1 216
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,847评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,562评论 0 197
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,260评论 1 241
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,531评论 2 245
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,021评论 1 258
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,367评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,016评论 3 235
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,068评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,827评论 0 194
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,610评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,514评论 2 269

推荐阅读更多精彩内容