深度学习入门系列21:项目:用LSTM+CNN对电影评论分类

大家好,我技术人Howzit,这是深度学习入门系列第二十一篇,欢迎大家一起交流!

深度学习入门系列1:多层感知器概述
深度学习入门系列2:用TensorFlow构建你的第一个神经网络
深度学习入门系列3:深度学习模型的性能评价方法
深度学习入门系列4:用scikit-learn找到最好的模型
深度学习入门系列5项目实战:用深度学习识别鸢尾花种类
深度学习入门系列6项目实战:声纳回声识别
深度学习入门系列7项目实战:波士顿房屋价格回归
深度学习入门系列8:用序列化保存模型便于继续训练
深度学习入门系列9:用检查点保存训练期间最好的模型
深度学习入门系列10:从绘制记录中理解训练期间的模型行为
深度学习入门系列11:用Dropout正则减少过拟合
深度学习入门系列12:使用学习规划来提升性能
深度学习入门系列13:卷积神经网络概述
深度学习入门系列14:项目实战:基于CNN的手写数字识别
深度学习入门系列15:用图像增强改善模型性能
深度学习入门系列16:项目实战:图像中目标识别
深度学习入门系列17:项目实战:从电影评论预测情感
深度学习入门系列18:循环神经网络概述
深度学习入门系列19:基于窗口(window)的多层感知器解决时序问题
深度学习入门系列20:LSTM循环神经网络解决国际航空乘客预测问题
深度学习入门系列21:项目:用LSTM+CNN对电影评论分类
深度学习入门系列22:从猜字母游戏中理解有状态的LSTM递归神经网络
深度学习入门系列23:项目:用爱丽丝梦游仙境生成文本


序列分类是个预测建模问题,它输入序列有空间或者时间属性,其任务是预测序列的类别。这个问题变得如此难的因为序列长度不断变化的,由大量的词汇组成的字符,可能还需要模型学习序列中的字符之间的长期上下文或者依赖关系。在这个项目中,你将学习如何用 Keras 深度学习库构建LSTM循环神经网络模型用于序列分类问题。完成这个项目后,你将了解:

  • 如何构建LSTM模型用于序列分类问题。
  • 如何通过使用Dropout技术减少LSTM过拟合。
  • 如何将LSTM和擅长空间结构的卷积神经网(CNN)络结合起来。

让我们开始吧!

1 用极简LSTM模型解决序列分类

在本节课中描述的序列学习的问题是 IMDB 电影评论情感分析问题,在第十七章 项目:从电影评论中预测情感用的数据集。我们能够快速的为IMDB问题构建一个简单的LSTM网络,而且还获得不错的准确率。让我先从导入模型必要的类和函数开始,并初始化随机生成器为常数,确保结果的可复制性。

import numpy 
from keras.datasets import imdb 
from keras.models import Sequential 
from keras.layers import Dense 
from keras.layers import LSTM 
from keras.layers.embeddings import Embedding 
from keras.preprocessing import sequence 

# fix random seed for reproducibility 
numpy.random.seed(7)

我们需要加载IMDB数据集,我们限制了数据集中的单词在前5000个。我们也将数据集分为训练集(50%)和测试集(50%)。

# load the dataset but only keep the top n words, zero the rest 
top_words = 5000 
(X_train, y_train), (X_test, y_test) = imdb.load_data(num_words=top_words)

接下来,我们需要裁减和平铺输入序列,目的是用同样的输入长度进行建模。学了0值模型是不携带任何信息的,因此就内容而言其序列的内容并不是一样的长,但是在Keras中计算的话还是需要同样长度的向量。

# truncate and pad input sequences 
max_review_length = 500 
X_train = sequence.pad_sequences(X_train, maxlen=max_review_length) 
X_test = sequence.pad_sequences(X_test, maxlen=max_review_length)

现在,我们定义,编译和拟合我们LSTM模型,第一层是用长度为32的向量代表单词的embedding层。接下来层是有100个记忆单元(小神经元)的LSTM层,最后,因为这是个分类问题,在这个问题上,我们使用一个神经元的Dense层和并使用sigmoid激活函数做0或者1预测(好或者坏)。因为它是个二分类问题,对数损失我使用损失函数(Keras中的binary_crossentropy),使用有效的ADAM优化算法。因为在这个问题上很快过拟合,模型仅仅拟合3个迭代周期。一个更大批处理尺寸64用于分隔权重更新。

# create the model 
embedding_vecor_length = 32 
model = Sequential() 
model.add(Embedding(top_words, embedding_vecor_length, input_length=max_review_length)) 
model.add(LSTM(100)) model.add(Dense(1, activation='sigmoid')) 
model.compile(loss='binary_crossentropy', optimizer='adam', metrics=['accuracy']) 
model.summary() m
odel.fit(X_train, y_train, validation_data=(X_test, y_test), epochs=3, batch_size=64)

一旦拟合,我们在位置评审上估计模型的性能。

# Final evaluation of the model 
scores = model.evaluate(X_test, y_test, verbose=0)
print("Accuracy: %.2f%%" % (scores[1]*100))

为了完整性,下面列出了在IMDB数据集上LSTM网络。

# LSTM for sequence classification in the IMDB dataset  
import numpy  
from keras.datasets import imdb  
from keras.layers import Dense  
from keras.layers import LSTM  
from keras.layers.embeddings import Embedding  
from keras.models import Sequential  
from keras.preprocessing import sequence  
  
# fix random seed for reproducibility  
numpy.random.seed(7)  
# load the dataset but only keep the top n words, zero the rest  
top_words = 5000  
(X_train, y_train), (X_test, y_test) = imdb.load_data(num_words=top_words)  
# truncate and pad input sequences  
max_review_length = 500  
X_train = sequence.pad_sequences(X_train, maxlen=max_review_length)  
X_test = sequence.pad_sequences(X_test, maxlen=max_review_length)  
# create the model  
embedding_vecor_length = 32  
model = Sequential()  
model.add(Embedding(top_words, embedding_vecor_length, input_length=max_review_length))  
model.add(LSTM(100))  
model.add(Dense(1, activation='sigmoid'))  
model.compile(loss='binary_crossentropy', optimizer='adam', metrics=['accuracy'])  
model.summary()  
model.fit(X_train, y_train, epochs=3, batch_size=64)  
# Final evaluation of the model  
scores = model.evaluate(X_test, y_test, verbose=0)  
print("Accuracy: %.2f%%" % (scores[1] * 100))

运行上面的例子得到下面结果。注意,如果你使用TensorFlow作为后端,那么你可能看到一些和PoolAllocator相关的警告信息,你直接忽略即可。

Epoch 1/3 
16750/16750 [==============================] - 107s - loss: 0.5570 - acc: 0.7149 
Epoch 2/3 
16750/16750 [==============================] - 107s - loss: 0.3530 - acc: 0.8577 
Epoch 3/3 
16750/16750 [==============================] - 107s - loss: 0.2559 - acc: 0.9019 
Accuracy: 86.79%

你能够看到,这个简单的LSTM模型,做了稍微调参就在IMDB问题上获得不错的结果。重要的是,你使用的模板也能将LSTM应用自己的序列分类问题上。现在,让我们一起看看在这个模型上的扩展,也可以应用于自己的问题上。

2 使用Dropout的LSTM模型解决序列分类问题

循环神经网络(RNN)像** LSTM ** 一般都会有过拟合的问题。在层之间用Keras Dropout层实现丢弃。我们很方便在EmbeddingLSTM 层以及LSTM and Dense 输出层之间添加Dropout层。例如:

model = Sequential() 
model.add(Embedding(top_words, embedding_vecor_length, input_length=max_review_length)) 
model.add(Dropout(0.2)) 
model.add(LSTM(100)) 
model.add(Dropout(0.2)) 
model.add(Dense(1, activation='sigmoid'))

下面是加了Dropout层的完整代码:

# LSTM with Dropout for sequence classification in the IMDB dataset  
import numpy  
from keras.datasets import imdb  
from keras.layers import Dense  
from keras.layers import Dropout  
from keras.layers import LSTM  
from keras.layers.embeddings import Embedding  
from keras.models import Sequential  
from keras.preprocessing import sequence  
  
# fix random seed for reproducibility  
numpy.random.seed(7)  
# load the dataset but only keep the top n words, zero the rest  
top_words = 5000  
(X_train, y_train), (X_test, y_test) = imdb.load_data(num_words=top_words)  
# truncate and pad input sequences  
max_review_length = 500  
X_train = sequence.pad_sequences(X_train, maxlen=max_review_length)  
X_test = sequence.pad_sequences(X_test, maxlen=max_review_length)  
# create the model  
embedding_vecor_length = 32  
model = Sequential()  
model.add(Embedding(top_words, embedding_vecor_length, input_length=max_review_length))  
model.add(Dropout(0.2))  
model.add(LSTM(100))  
model.add(Dropout(0.2))  
model.add(Dense(1, activation='sigmoid'))  
model.compile(loss='binary_crossentropy', optimizer='adam', metrics=['accuracy'])  
model.summary()  
model.fit(X_train, y_train, epochs=3, batch_size=64)  
# Final evaluation of the model  
scores = model.evaluate(X_test, y_test, verbose=0)  
print("Accuracy: %.2f%%" % (scores[1] * 100))

运行上面这个例子得到下面的结果:

Epoch 1/3 
16750/16750 [==============================] - 108s - loss: 0.5802 - acc: 0.6898 
Epoch 2/3 
16750/16750 [==============================] - 108s - loss: 0.4112 - acc: 0.8232
Epoch 3/3 
16750/16750 [==============================] - 108s - loss: 0.3825 - acc: 0.8365 
Accuracy: 85.56%

我们能够看到,dropout会导致训练的收敛速度稍慢,在这个例子最后的准确率更低了。模型可能需要使用更多的训练周期,可能获得更高的准确率(试试看)。或者,可以将dropout 准确而单独地应用于输入端和循环连接的记忆单元的LSTM上。KerasLSTM 层上提供参数,dropout用于配置输出端的丢弃,recurrent_dropout用于配置循环丢弃。举个例子,我们修改了第一个例子,增加dropout到输入端和循环连接上,如下:

model = Sequential() 
model.add(Embedding(top_words, embedding_vecor_length, input_length=max_review_length, dropout=0.2)) 
model.add(LSTM(100, dropout_W=0.2, dropout_U=0.2))
model.add(Dense(1, activation='sigmoid'))

为了完整性,下面列出了更加精准的 LSTM dropout 的完整代码。

# LSTM with dropout for sequence classification in the IMDB dataset  
import numpy  
from keras.datasets import imdb  
from keras.models import Sequential  
from keras.layers import Dense  
from keras.layers import LSTM  
from keras.layers.embeddings import Embedding  
from keras.preprocessing import sequence  
  
# fix random seed for reproducibility  
numpy.random.seed(7)  
# load the dataset but only keep the top n words, zero the rest  
top_words = 5000  
(X_train, y_train), (X_test, y_test) = imdb.load_data(num_words=top_words)  
# truncate and pad input sequences  
max_review_length = 500  
X_train = sequence.pad_sequences(X_train, maxlen=max_review_length)  
X_test = sequence.pad_sequences(X_test, maxlen=max_review_length)  
# create the model  
embedding_vecor_length = 32  
model = Sequential()  
model.add(Embedding(top_words, embedding_vecor_length, input_length=max_review_length))  
model.add(LSTM(100, dropout=0.2, recurrent_dropout=0.2))  
model.add(Dense(1, activation='sigmoid'))  
model.compile(loss='binary_crossentropy', optimizer='adam', metrics=['accuracy'])  
model.summary()  
model.fit(X_train, y_train, epochs=3, batch_size=64)  
# Final evaluation of the model  
scores = model.evaluate(X_test, y_test, verbose=0)  
print("Accuracy: %.2f%%" % (scores[1] * 100))

运行上面这个例子得到如下的结果:

Epoch 1/3 
16750/16750 [==============================] - 112s - loss: 0.6623 - acc: 0.5935 
Epoch 2/3 
16750/16750 [==============================] - 113s - loss: 0.5159 - acc: 0.7484 
Epoch 3/3 
16750/16750 [==============================] - 113s - loss: 0.4502 - acc: 0.7981 
Accuracy: 82.82%

我们能够看到,指定的dropoutLSTM要比面向层的dropout在网络收敛上影响更明显。正如上面,迭代周期不变和增加迭代周期两种情况能够看到模型的性能是否进一步提升。在你的LSTM模型中,Dropout一种抵抗过拟合的有效技术。最好的是两种方法你都试下,但是最好的结果是Keras中提供的制定门(gate)的。

3 用LSTM和CNN实现序列分类

卷积神经网络在学习输入数据的空间结构方便表现比较出色。IMDB评论数据中的单词序列具有一维空间结构,CNN能够提取好和坏情感的单变量特征。这种已学习的空间特征也有可能被LSTM层作为序列进行学习。我们能很方便在 Embedding层之后添加一个一维的 CNNmax pooling 层,而Embedding层将综合特征输入 LSTM。我们使用过滤器长为3的32个小特征集合,pooling层使用标准大小为2用于获取特征图的大小。例如,我们创建模型如下:

model = Sequential() 
model.add(Embedding(top_words, embedding_vecor_length, input_length=max_review_length)) 
model.add(Conv1D(filters=32, kernel_size=3, padding='same', activation='relu')) 
model.add(MaxPooling1D(pool_size=2)) 
model.add(LSTM(100)) 
model.add(Dense(1, activation='sigmoid'))

为了完整性,下面列出了 CNNLSTM 层的所有代码。

# LSTM and CNN for sequence classification in the IMDB dataset  
import numpy  
from keras.datasets import imdb  
from keras.layers import Dense  
from keras.layers import LSTM  
from keras.layers.convolutional import Conv1D  
from keras.layers.convolutional import MaxPooling1D  
from keras.layers.embeddings import Embedding  
from keras.models import Sequential  
from keras.preprocessing import sequence  
  
# fix random seed for reproducibility  
numpy.random.seed(7)  
# load the dataset but only keep the top n words, zero the rest  
top_words = 5000  
(X_train, y_train), (X_test, y_test) = imdb.load_data(num_words=top_words)  
  
# truncate and pad input sequences  
max_review_length = 500  
X_train = sequence.pad_sequences(X_train, maxlen=max_review_length)  
X_test = sequence.pad_sequences(X_test, maxlen=max_review_length)  
# create the model  
embedding_vecor_length = 32  
model = Sequential()  
model.add(Embedding(top_words, embedding_vecor_length, input_length=max_review_length))  
model.add(Conv1D(filters=32, kernel_size=3, padding='same', activation='relu'))  
model.add(MaxPooling1D(pool_size=2))  
model.add(LSTM(100))  
model.add(Dense(1, activation='sigmoid'))  
model.compile(loss='binary_crossentropy', optimizer='adam', metrics=['accuracy'])  
model.summary()  
model.fit(X_train, y_train, epochs=3, batch_size=64)  
# Final evaluation of the model  
scores = model.evaluate(X_test, y_test, verbose=0)  
print("Accuracy: %.2f%%" % (scores[1]*100))

运行提供的代码,得到如下结果:

Epoch 1/3 
16750/16750 [==============================] - 58s - loss: 0.5186 - acc: 0.7263 
Epoch 2/3 
16750/16750 [==============================] - 58s - loss: 0.2946 - acc: 0.8825 
Epoch 3/3 
16750/16750 [==============================] - 58s - loss: 0.2291 - acc: 0.9126 

Accuracy: 86.36%

我们能够看到,虽然我们使用更少的权重和更多的训练时间,但是我们获得和第一例子相似的结果。我期望,如果这个例子进一步扩展下,使用dropout,那么会获得更好的结果。

4总结

在这个项目中,你已经学习了如何构建LSTM网络模型用于序列分类预测建模问题,特别是,你已经学到:

  • 如何构建简单的单层 LSTM 模型用于 IMDB 电影评论的情感分类问题。
  • 如何用面向层和指定LSTM dropout扩展的LSTM模型来减少过拟合。
  • 如何将具有空间结构学习的卷积神经网络和具有序列学习的LSTM进行结合。

4.1 接下来

在即将完成的这个项目中,你已经学习了使用LSTM循环神经网络解决序列分类问题,在下节课,你将建立在LSTM网络立即之前,针对简单的序列预测问题,更好的理解Keras api如何维持状态。

  • 1
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

技术人Howzit

钱不钱的无所谓,这是一种鼓励!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值