第一个深度学习实战案例:电影评论分类

公众号:机器学习杂货店
作者:Peter
编辑:Peter

大家好,我是Peter~

这里是机器学习杂货店 Machine Learning Grocery~

本文的案例讲解的是机器学习中一个重要问题:分类问题。

本文是《Python深度学习》一书中的实战案例:电影评论的二分类问题

训练集和测试集

这是一个典型的二分类问题。使用的是IMDB数据集,训练集是25000条,测试也是25000条

In [1]:

import pandas as pd
import numpy as npfrom keras.datasets import imdb

In [2]:

# 10000:仅保留训练数据中前10000个最常见的词语(train_data, train_labels),(test_data, test_labels) = imdb.load_data(num_words=10000)
  • train_data、test_data:评论组成的列表
  • train_labels、test_lables:0-1组成的列表。其中0-负面 1-正面

In [3]:

train_data.shape

Out[3]:

(25000,)

In [4]:

type(train_data)

Out[4]:

numpy.ndarray

In [5]:

# train_data[3]

In [6]:

test_labels[1]  # 标签值都是0或者1

Out[6]:

1

单词的最大索引不超过10000:

In [7]:

# [max(i) for i in train_data]:每组数据的max([max(i) for i in train_data])

Out[7]:

9999

数据还原

将数值还原到对应的评论中

In [8]:

# 步骤1:单词和数值组成的字典word_index = imdb.get_word_index()

In [9]:

# 步骤2: key-value翻转
reverse_word_index = dict([(value, key) for (key, value) in word_index.items()])
reverse_word_index

准备数据

不能将整数序列直接输入到神经网络,必须先转成张量;提供两种转换方法:

  • 填充列表,使其具有相同的长度,再将列表转成(samples,word_indices)的整数张量;再使用Embedding层进行处理(后续介绍)
  • 对列表进行one-hot编码,转成0-1组成的向量。网络第一层可以Dense层,处理浮点数向量数据

one-hot编码

In [10]:

# one-hot编码实现import numpy as npdef vectorize_sequences(sequences, dimension=10000):results = np.zeros((len(sequences), dimension)) # 创建全0矩阵for i, sequence in enumerate(sequences):  results[i, sequence] = 1.  # 指定位置填充1return results# 训练数据和测试数据向量化
x_train = vectorize_sequences(train_data)
x_test = vectorize_sequences(test_data)

In [11]:

x_train[0]

Out[11]:

array([0., 1., 1., ..., 0., 0., 0.])

标签向量化

In [12]:

y_train = np.asarray(train_labels).astype("float32")
y_test = np.asarray(test_labels).astype("float32")

构建神经网络

输入数据是向量,标签是标量(0或者1)。在该类问题上表现好的神经网络:带有relu激活函数的全连接Dense层网络

Dense(16,activation='relu')
  • 16:表示隐藏单元的个数;一个隐藏单元表示空间的一个维度
  • 每层都对应一个表示空间,数据经过层层变换,最终映射到解

中间层使用relu函数作为激活函数,使用的主要运算:

output = relu(dot(W,input) + b)

最后一层使用sigmod激活,输出一个0-1之间的概率值作为样本的目标值等于1的可能性,即正面的可能性

  1. relu函数:将全部负值归0
  2. sigmoid函数:将数据压缩到0-1之间

模型定义(修改)

In [13]:

import tensorflow as tf  # add
import keras as models
import keras as layersmodel = models.Sequential()# 原文model.add(layers.Dense(16, activation="relu", input_shape=(10000, )))# 统一修改3处内容:layers.Dense 变成 tf.keras.layers.Dense# 输入层
model.add(tf.keras.layers.Dense(16,activation="relu",input_shape=(10000, )))
# 隐藏层1
model.add(tf.keras.layers.Dense(16,activation="relu"))
# 隐藏层2
model.add(tf.keras.layers.Dense(1,activation="sigmoid"))

损失函数和优化器(修改)

这个问题属于二分类问题,网络输出的是一个概率值。

最后一层使用sigmoid函数作为激活函数,最好使用binary_crossentropy(二元交叉熵)作为损失。

温馨提示:对于输出是概率值的模型,最好使用交叉熵crossentropy(用于衡量概率值分布之间的距离)。

下面的优化过程是使用:

  • 优化器:rmsprop
  • 损失函数:binary_crossentropy

In [14]:

# 编译模型
model.compile(optimizer="rmsprop",  # 优化器loss="binary_crossentropy",  # 损失metrics=["accuracy"]  # 指标函数)

自定义优化器、损失函数、指标函数等:

In [15]:

# 配置优化器from keras import optimizers# 原文:optimizer = optimizers.RMSprop(lr=0.001)
# 修改地方:optimizers --->  tf.keras.optimizers
model.compile(optimizer=tf.keras.optimizers.RMSprop(lr=0.001),loss="binary_crossentropy",metrics=["accuracy"])

In [16]:

# 自定义损失函数和指标from keras import losses
from keras import metrics# 原文:optimizer = optimizers.RMSprop(lr=0.001)
# 修改地方:optimizers --->  tf.keras.optimizersmodel.compile(optimizer=tf.keras.optimizers.RMSprop(lr=0.001),loss=losses.binary_crossentropy,  # 自定义损失metrics=[metrics.binary_accuracy]  # 自定义指标函数)

验证模型

在原始训练数据集中留出10000个样本作为验证集

In [17]:

# 留出验证集x_val = x_train[:10000]
partial_x_train = x_train[10000:]y_val = y_train[:10000]
partial_y_train = y_train[10000:]

分批次进行迭代:

  • 使用512个样本组成小批量
  • 10000个样本将模型训练20次

同时监控模型在10000个样本上精度和损失

训练模型

In [18]:

model.compile(optimizer="rmsprop",loss="binary_crossentropy",metrics=["acc"])  # 使用acc作为评判指标history = model.fit(partial_x_train, # 验证集partial_y_train, epochs=20, # 批次batch_size=512,  # 每个批次的样本数validation_data=[x_val,y_val]  # 验证数据)
Epoch 1/20
30/30 [==============================] - 5s 142ms/step - loss: 0.5198 - acc: 0.7864 - val_loss: 0.4005 - val_acc: 0.8677
Epoch 2/20
30/30 [==============================] - 1s 31ms/step - loss: 0.3109 - acc: 0.9039 - val_loss: 0.3070 - val_acc: 0.8853
Epoch 3/20
30/30 [==============================] - 1s 31ms/step - loss: 0.2274 - acc: 0.9269 - val_loss: 0.2794 - val_acc: 0.8893
Epoch 4/20
30/30 [==============================] - 1s 33ms/step - loss: 0.1799 - acc: 0.9411 - val_loss: 0.2829 - val_acc: 0.8854
Epoch 5/20
30/30 [==============================] - 1s 32ms/step - loss: 0.1452 - acc: 0.9542 - val_loss: 0.2846 - val_acc: 0.8867
Epoch 6/20
30/30 [==============================] - 1s 32ms/step - loss: 0.1209 - acc: 0.9619 - val_loss: 0.3057 - val_acc: 0.8825
Epoch 7/20
30/30 [==============================] - 1s 34ms/step - loss: 0.1001 - acc: 0.9693 - val_loss: 0.3122 - val_acc: 0.8826
Epoch 8/20
30/30 [==============================] - 1s 36ms/step - loss: 0.0818 - acc: 0.9767 - val_loss: 0.3412 - val_acc: 0.8807
Epoch 9/20
30/30 [==============================] - 1s 32ms/step - loss: 0.0661 - acc: 0.9821 - val_loss: 0.3739 - val_acc: 0.8741
Epoch 10/20
30/30 [==============================] - 1s 31ms/step - loss: 0.0564 - acc: 0.9857 - val_loss: 0.3854 - val_acc: 0.8750
Epoch 11/20
30/30 [==============================] - 1s 31ms/step - loss: 0.0442 - acc: 0.9896 - val_loss: 0.4420 - val_acc: 0.8675
Epoch 12/20
30/30 [==============================] - 1s 31ms/step - loss: 0.0352 - acc: 0.9926 - val_loss: 0.4520 - val_acc: 0.8722
Epoch 13/20
30/30 [==============================] - 1s 32ms/step - loss: 0.0307 - acc: 0.9935 - val_loss: 0.4773 - val_acc: 0.8714
Epoch 14/20
30/30 [==============================] - 1s 32ms/step - loss: 0.0220 - acc: 0.9971 - val_loss: 0.5152 - val_acc: 0.8688
Epoch 15/20
30/30 [==============================] - 1s 30ms/step - loss: 0.0190 - acc: 0.9968 - val_loss: 0.5547 - val_acc: 0.8677
Epoch 16/20
30/30 [==============================] - 1s 33ms/step - loss: 0.0160 - acc: 0.9974 - val_loss: 0.5821 - val_acc: 0.8684
Epoch 17/20
30/30 [==============================] - 1s 34ms/step - loss: 0.0090 - acc: 0.9994 - val_loss: 0.6170 - val_acc: 0.8668
Epoch 18/20
30/30 [==============================] - 1s 32ms/step - loss: 0.0098 - acc: 0.9985 - val_loss: 0.6487 - val_acc: 0.8658
Epoch 19/20
30/30 [==============================] - 1s 32ms/step - loss: 0.0091 - acc: 0.9985 - val_loss: 0.6858 - val_acc: 0.8648
Epoch 20/20
30/30 [==============================] - 1s 26ms/step - loss: 0.0041 - acc: 0.9999 - val_loss: 0.7136 - val_acc: 0.8661

调用模型model.fit方法会返回一个history对象。这个对象有一个history成员,它是一个字典,包含训练过程中的所有数据:

In [19]:

history_dict = history.history
history_dict

查看不同的key

In [20]:

history_dict.keys()  # 训练过程和验证过程的两组指标

Out[20]:

dict_keys(['loss', 'acc', 'val_loss', 'val_acc'])

绘图可视化

In [25]:

# 损失绘图
import matplotlib.pyplot as plthistory_dict = history.history
loss_values = history_dict["loss"]
val_loss_values = history_dict["val_loss"]epochs = range(1,len(loss_values) + 1)  # 训练
plt.plot(epochs,  #  横坐标loss_values,  # 纵坐标"r",  # 颜色和形状,默认是实线label="Training_Loss"  # 标签名)
# 验证
plt.plot(epochs,val_loss_values,"b",label="Validation_Loss")plt.title("Training and Validation Loss")
plt.xlabel("Epochs")
plt.ylabel("Loss")
plt.legend()plt.show()

# 精度绘图
import matplotlib.pyplot as plthistory_dict = history.history
acc_values = history_dict["acc"]
val_acc_values = history_dict["val_acc"]epochs = range(1,len(loss_values) + 1)plt.plot(epochs,acc_values,"r",label="Training_ACC")plt.plot(epochs,val_acc_values,"b",label="Validation_ACC")plt.title("Training and Validation ACC")
plt.xlabel("Epochs")
plt.ylabel("acc")
plt.legend()plt.show()

结论:

  1. 训练的损失每轮都在降低;训练的精度每轮都在提升(红色)
  2. 验证集的损失和精度似乎都在第4轮达到最优值

也就是:模型在训练集上表现良好,但是在验证集上表现的不好,这种现象就是过拟合

重新训练模型

通过上面的观察,第四轮的效果是比较好的:

In [23]:

import tensorflow as tf  # add
import keras as models
import keras as layersmodel = models.Sequential()# 原文model.add(layers.Dense(16, activation="relu", input_shape=(10000, )))
# 统一修改3处内容:layers.Dense 变成 tf.keras.layers.Dense# 输入层
model.add(tf.keras.layers.Dense(16,activation="relu",input_shape=(10000, )))
# 隐藏层1
model.add(tf.keras.layers.Dense(16,activation="relu"))
# 隐藏层2
model.add(tf.keras.layers.Dense(1,activation="sigmoid"))# 编译模型
model.compile(optimizer="rmsprop",loss="binary_crossentropy",metrics=["accuracy"])# fit过程
model.fit(x_train,y_train,epochs=4,   # 修改了这里,改成只循环4次batch_size=512)
# 模型评价
results = model.evaluate(x_test, y_test)
results
Epoch 1/4
49/49 [==============================] - 3s 29ms/step - loss: 0.4518 - accuracy: 0.8211
Epoch 2/4
49/49 [==============================] - 1s 23ms/step - loss: 0.2593 - accuracy: 0.9100
Epoch 3/4
49/49 [==============================] - 1s 22ms/step - loss: 0.1992 - accuracy: 0.9298
Epoch 4/4
49/49 [==============================] - 1s 26ms/step - loss: 0.1669 - accuracy: 0.9412
782/782 [==============================] - 4s 5ms/step - loss: 0.3053 - accuracy: 0.8800

Out[23]:

[0.30533847212791443, 0.8800399899482727]

可以看到在这种最简单的方法下,精度居然达到了88.54%! 奈斯~

对测试集进行预测

训练好的网络对测试集进行预测:

In [24]:

model.predict(x_test)

Out[24]:

array([[0.23233771],[0.99984634],[0.94041836],...,[0.17830989],[0.10676837],[0.7466589 ]], dtype=float32)

模型对某些样本的预测结果还是可信的,比如0.999和0.10等,有些效果不理想:出现0.56的概率值,导致无法判断

进一步实验

  • 前面的案例使用的是两个隐藏层:可以尝试使用1个或者3个
  • 尝试使用更多或更少的隐藏单元,比如32或者64个
  • 尝试使用mse损失函数代替binary_crossentropy
  • 尝试使用tanh函数(早期流行的激活函数)代替relu激活函数

小结

  1. 对原始数据进行大量地预处理工作
  2. 带有relu激活函数的Dense堆叠层,可以解决多种问题(包含情感分类)
  3. 对于二分类问题:
    • 网络的最后一层使用带有sigmoid激活的Dense层,输出是0-1之间的概率值;
    • 同时建议使用binary_crossentropy作为损失函数
  4. 优化器的最佳选择:rmsprop
  5. 过拟合现象是常见的,因此一定要监控模型在训练数据集之外的数据集上的性能

深度学习实战案例:电影评论二分类相关推荐

  1. 【深度学习框架简单梳理】电影评论二分类问题

    文章目录 0x00 前言 0x01 整体概述 0x02 细节展开 2.1 数据预处理 2.1.1 获取数据 2.1.2 处理数据 2.2 神经网络模型搭建 2.2.1 模型架构 2.2.2 层 全连接 ...

  2. 【第 07 章 基于主成分分析的人脸二维码识别MATLAB深度学习实战案例】

    基于主成分分析的人脸二维码识别MATLAB深度学习实战案例 人脸库 全套文件资料目录下载链接–>传送门 本文全文源码下载[链接–>传送门] 如下分析: 主文件 function varar ...

  3. Python深度学习实战:声呐返回值分类

    Python深度学习实战:声呐返回值分类 声呐物体分类数据 简单的神经网络 预处理数据以增加性能 调整模型的拓扑和神经元 缩小网络 扩大网络 总结 本章我们使用Keras开发一个二分类网络.本章包括: ...

  4. TF2.0深度学习实战(一):分类问题之手写数字识别

    前言: 本专栏将分享从零开始搭建神经网络的学习过程,力争打造最易上手的小白教程.在这过程中,我将使用谷歌TensorFlow2 框架逐一复现经典的卷积神经网络:LeNet-5.AlexNet.VGG系 ...

  5. 深度学习 实验三 logistic回归预测二分类

    文章目录 深度学习 实验三 logistic回归预测二分类 一.问题描述 二.设计简要描述 三.程序清单 深度学习 实验三 logistic回归预测二分类 一.问题描述   学会使用学习到的逻辑回归的 ...

  6. AI:神经网络IMDB电影评论二分类模型训练和评估

    AI:Keras神经网络IMDB电影评论二分类模型训练和评估,python import keras from keras.layers import Dense from keras import ...

  7. Python深度学习实战:多类花朵分类

    Python深度学习实战:多类花朵分类 鸢尾花分类数据集 导入库和函数 指定随机数种子 导入数据 输出变量编码 设计神经网络 用K折交叉检验测试模型 总结 本章我们使用Keras为多类分类开发并验证一 ...

  8. 第 09 章 基于特征匹配的英文印刷字符识别 MATLAB深度学习实战案例

    基于特征匹配的英文印刷字符识别 MATLAB深度学习实战 话不多讲,直接开撸代码 MainForm函数 function MainForm global bw; global bl; global b ...

  9. 深度学习实战案例:基于LSTM的四种方法进行电影评论情感分类预测(附完整代码)

    序列分类是一个预测建模问题,你有一些输入序列,任务是预测序列的类别. 这个问题很困难,因为序列的长度可能不同,包含非常大的输入符号词汇表,并且可能需要模型学习输入序列中符号之间的长期上下文或依赖关系. ...

最新文章

  1. 贝尔实验室发布6G通信白皮书
  2. 伟人必须回答的(二十道问题)
  3. MySQL读写分离一主多从实现
  4. mybatis新增时将主键值返回(注解方式)
  5. Flask之flask-script
  6. 模型堆叠(Stacking)和模型融合的原理与实现以及一个库heamy的介绍
  7. ubuntu-安装qt+gdb-imagewatch
  8. Python调试工具——ipdb
  9. 统信UOS使用wine安装“方正ApabiReader_4.5.2.1790(ceb阅读器)”并解决安装过程中文显示成方块问题
  10. 百度坐标拾取html,百度地图API获取地址拾取坐标代码
  11. 单核CPU使用多线程能否提高效率?
  12. 卷积神经网络结构图绘制,卷积神经网络图怎么画
  13. 英语复数名词的变化规则
  14. 科技战疫志愿精神如何延续?腾讯的答案是……
  15. __I、 __O 、__IO是什么意思?怎么用?
  16. 流水线-流水线相关计算
  17. GPS北斗模块串口助手输出测试
  18. 非递归的归并排序(详细解析)
  19. php发邮件 环境,PHP使用Pear发送邮件(Windows环境)
  20. LG G3升级Android 6.0 Marshmallow方法亲测!界面渲染精美,拒绝卡顿,提升续航!

热门文章

  1. 基于MFC的Media Player播放器的制作(4---功能实现代码)
  2. 2021年全球飞行娱乐(IFE)收入大约6325.9百万美元,预计2028年达到14810百万美元,2022至2028期间,年复合增长率CAGR为14.0%
  3. LPC177x/8x勘误手册
  4. Shell小技巧(一百一十贰)特殊字符“\”-转义小结
  5. 32位ARM嵌入式处理器的调试技术
  6. c 语言matrix函数,R语言矩阵matrix函数
  7. xposed微信插件大全
  8. 文章标题warning: could not load any Objective-C class information. This will significantly reduce the qu
  9. MATLAB工具箱(功能型工具箱和领域型工具箱)
  10. ipad越狱后怎么还原?