RNN,具有记忆功能神经网络的理解与实现

我们当前掌握的网络类型,统称为feed forward网络。这种网络的特点是,当我们把很多条数据输入网络进行训练时,网络没有“记忆性”,也就是网络认为前一条输入的数据与下一条输入的数据之间没有任何联系。然而在实际运用中,输入的数据间往往存在着强联系,特别是在自然语言处理中。

假设我们给网络输入“中华人民共和国”一词,我们第一次传给网络“中华”,第二次传给“人民”,第三次传入”共和国“,显然这三次输入数据存在着非常紧密的联系,但是我们现在的网络对数据处理方式并没有考虑到前后数据间可能存在着相关性,而这种相关性往往能极大的提高网络对数据的处理效率以及准确率,因此我们在本节将引入一种具备新特性的神经网络叫recurrent neural network,这种网络能够将前后输入数据关联起来,从而大大提升网络对数据模式的识别。

RNN的基本结构如下:

数据输入网络,网络对数据进行处理,然后网络使用一组叫做”state”的参数来记录下当前数据的特性,等到下一组数据输入网络时,网络对数据的处理,会结合上一次留下来的”state”参数组一同对数据进行处理,每次对数据进行处理后,“state”对应的参数组都会进行相应更新,然后参与下一次网络对新输入数据的处理。我们可以用一组伪码来表示RNN网络的运行逻辑:

state_t = 0  #状态参数在初始时为0
for input_t in input_sequences:  #不断的将数据输入网络
    #W对应网络链路参数,  U是一个参数矩阵,用于与状态变量state_t相互作用,b是一维向量
    output_t = activation(dot(W, input_t) + dot(U, state_t)+b)  
    state_t = output_t  #更新state_t参数,以便参与下一条数据处理

我们可以再将上面伪码展开,以便加深对RNN结构和处理流程的理解:

import numpy as np

timesteps = 100  #总共100条训练数据
input_features = 32 #每条数据有32个参数
output_features = 64 #网络读取数据后输出含有64个参数的向量

inputs = np.random.random((timestep, input_features))
state_t = np.zeros((output_features))  #先把状态参数初始化为0

W = np.random.random((input_features, output_features))
U = np.random.random((output_features, output_features))
b = np.random.random((output_features,))

successive_outputs = []
for input_t in inputs:
    #处理输入数据
    output_t = np.tanh(np.dot(W, input_t) + np.dot(U, state_t) + b)
    #记录当前数据处理结果
    successive_outputs.append(output_t)
    #更新状态变量以便参与下次数据处理
    state_t = output_t

final_output_sequence = np.concatenate(successive_outputs, axis = 0)

RNN本质上就是一个for循环,每次循环在处理输入数据时,利用当前数据去更新一个状态变量,这个状态变量相当于对当前数据的“记忆”,它将把当前数据携带的信息代入到下一次的数据处理过程中,我们可以从下面的结构图来理解RNN:

接下来我们看看keras是如何支持CNN的,keras框架提供一种简单的RNN网络层,如下代码所示:

from keras.layers import SimpleRNN

上面导入的SimpleRNN网络层有一个特点是,他必须同时接收一批输入,而不能像我们以为那样一条条的把数据传入网络,而是要一下子把一批数据传进去。也就是我们在使用SimpleRNN层时,需要把数据集合成一个3维向量(batch_size, timesteps, inputput_features),当数据处理完毕后,它可以一下子输出一批结果例如(batch_size, timesteps, output_features),要不然就输出最后一条结果(batch_size, output_features)。我们看一个具体例子,下面代码使得网络输出最后一条结果:

from keras.models import Sequential
from keras.layers import Embedding, SimpleRNN
model = Sequential()
model.add(Embedding(10000, 32))
model.add(SimpleRNN(32))
model.summary()

而下面代码使得网络一下子输出一批结果:

from keras.models import Sequential
from keras.layers import Embedding, SimpleRNN
model = Sequential()
model.add(Embedding(10000, 32))
model.add(SimpleRNN(32, return_sequences=True))
model.summary()

上一节我们使用预处理单词向量在影评的情绪分析中出现了严重的过度拟合,现在我们使用RNN到影评情绪分析上看看效果如何,首先我们先加载数据。

from keras.datasets import imdb
from keras.preprocessing import sequence

max_features = 10000 #只考虑最常使用的前一万个单词
maxlen = 500 #一篇文章只考虑最多500个单词
batch_size = 32
print("Loading data....")
(input_train, y_train), (input_test, y_test) = imdb.load_data(num_words=max_features)
print(len(input_train), 'train sequence')
print(len(input_test), 'test sequence')

print('Pad sequences (samples x time)')
input_train = sequence.pad_sequences(input_train, maxlen = maxlen)
input_test = sequence.pad_sequences(input_test, maxlen=maxlen)
print('input_train shape:', input_train.shape)
print('input_test shape: ', input_test.shape)

接着我们构造一个RNN网络,把数据输入网络进行训练:

from keras.layers import Dense
model = Sequential()
model.add(Embedding(max_features, 32))
model.add(SimpleRNN(32))
model.add(Dense(1, activation='sigmoid'))

model.compile(optimizer='rmsprop', loss='binary_crossentropy', metrics=['acc'])
history = model.fit(input_train, y_train, epochs = 10, batch_size = 128, validation_split=0.2)

上面代码运行后,我们把网络训练的结果绘制出来:

import matplotlib.pyplot as plt

acc = history.history['acc']
val_acc = history.history['val_acc']
loss = history.history['loss']
val_loss = history.history['val_loss']

epochs = range(1, len(acc) + 1)
plt.plot(epochs, acc, 'bo', label = 'Training acc')
plt.plot(epochs, val_acc, 'b', label='Validation acc')
plt.legend()
plt.figure()

plt.plot(epochs, loss, 'bo', label='Training loss')
plt.plot(epochs, val_loss, 'b', label='Validation loss')
plt.title('Training and Validation loss')
plt.legend()

plt.show()

上面代码运行后,得到结果如下:

从第一幅图我们看到,网络对校验数据的准确率与对训练数据的准确率并没有分叉,因此相比于上一节,过度拟合得到了比较好的处理。对校验数据的检测中,最高准确率为85%,比我们以前采用的普通网络模型效果还要差一些。其中原因在于,我们只考虑影评前500个单词,这个量太小,但我们又不能简单的把这个限制增大,因为SimpleRNN无法记忆过长的单词串,下一节我们将引入新类型的记忆性网络以便处理我们现在遇到的问题。

原文发布于微信公众号 - Coding迪斯尼(gh_c9f933e7765d)

原文发表时间:2018-09-05

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏ATYUN订阅号

正则化贪心森林(RGF)的入门简介,含案例研究

作为曾参与机器学习竞赛的数据科学家,我一直在寻找“非主流”的算法。使用这些算法可能不会成为竞争的赢家。但是他们有独特的预测方式。这些算法可以在集成模型中使用,以...

5176
来自专栏ATYUN订阅号

不怕学不会 使用TensorFlow从零开始构建卷积神经网络

人们可以使用TensorFlow的所有高级工具如tf.contrib.learn和Keras,能够用少量代码轻易的建立一个卷积神经网络。但是通常在这种高级应用中...

4076
来自专栏杨熹的专栏

Ensemble Learners

Udacity Ensemble Learners ---- Boosting Algorithm 不需要绞尽脑汁去想很复杂的 Rules,只需要一些简单的 ...

3647
来自专栏人工智能LeadAI

简易的深度学习框架Keras代码解析与应用

总体来讲keras这个深度学习框架真的很“简易”,它体现在可参考的文档写的比较详细,不像caffe,装完以后都得靠技术博客,keras有它自己的官方文档(不过是...

7067
来自专栏码洞

人工不智能之sklearn聚类

线性回归是一种有监督算法,提供了输入数据x和参考目标值y,参考目标提供了一种纠错机制,是对预测结果y_的监督,如果y和y_相差过大,说明拟合的模型可能存在问题。...

661
来自专栏PPV课数据科学社区

K-means 在 Python 中的实现

K-means算法简介 K-means是机器学习中一个比较常用的算法,属于无监督学习算法,其常被用于数据的聚类,只需为它指定簇的数量即可自动将数据聚合到多类中,...

3689
来自专栏PaddlePaddle

【文本分类】基于DNN/CNN的情感分类

导语 PaddlePaddle提供了丰富的运算单元,帮助大家以模块化的方式构建起千变万化的深度学习模型来解决不同的应用问题。这里,我们针对常见的机器学习任务,提...

4934
来自专栏Python小屋

Python使用tensorflow中梯度下降算法求解变量最优值

TensorFlow是一个用于人工智能的开源神器,是一个采用数据流图(data flow graphs)用于数值计算的开源软件库。数据流图使用节点(nodes)...

3588
来自专栏机器之心

资源 | 一个Python特征选择工具,助力实现高效机器学习

项目地址:https://github.com/WillKoehrsen/feature-selector

1872
来自专栏AI科技大本营的专栏

用AI给黑白照片上色,复现记忆中的旧时光

【导读】我们知道,深度学习几乎已经应用在每一个领域,但如果我们能够构建一个基于深度学习的模型,让它能够给老照片着色,重现我们童年的旧回忆,这该多么令人激动啊!那...

5563

扫码关注云+社区

领取腾讯云代金券