Simple RNN模型

适用于:小规模数据集

如何对序列数据进行建模?-----> RNN(many to one/many to many)模型

我们知道,将一段文字整体输入逻辑斯蒂回归模型时,是属于一对一(one to one)模型,一个输入对应一个输出,这种一对一模型非常适合图片类数据,但不太适合文本数据

Simple RNN模型_第1张图片

RNN的输入和输出都不固定,非常适合文本、语音等持续序列的数据,它可以持续记忆不停输入的词,主要过程如下:

用状态向量ht来积累阅读过的信息

将输入的词通过word embedding变成一个个的词向量Xt

每输入一个词,ht就会更新状态并保存

Simple RNN的结构和原理

原理:

RNN实际上就是说,每个输出的状态都只由前一时刻的状态当前时刻的输入来决定

比如: h0中保存的是the这个词,那么h1中保存的就是the cat ........,ht中保存了the cat sat....mat,也就是说最后一个状态向量会保存整句话的信息,我们可以把ht看成是从这整句话中抽取的特征向量,每次更新状态ht时需要用到A这个参数矩阵,且整个RNN只会有一个A(从等式左边的一个环绕箭头就能明白参数是共享的,A随机初始化,然后利用训练数据来学习A

结构图:

Simple RNN模型_第2张图片

上一个状态记作h(t-1),新输入的x向量记作xt,将这两个向量做点积得到一个更高的向量,矩阵A是RNN的模型参数,A*(h(t-1)*xt)(矩阵与向量相乘得到一个向量),然后将向量的每一个元素代入激活函数tanh()中,

 Simple RNN模型_第3张图片

tanh()是一个双曲正切函数, 输出值在(-1,1)之间,把激活函数的输出更新为新的状态向量ht,ht \epsilon (-1,1)

Simple RNN模型_第4张图片

ht = h(t-1) * xt

新状态ht是上一个状态ht-1和新输入向量xt的乘积,神经网络的模型参数是矩阵A,所以新状态ht依赖于上一个状态ht-1、新输入向量xt、矩阵A三部分

 Simple RNN模型_第5张图片

激活函数为什么是tanh()函数,可以换成其他函数吗?

Simple RNN模型_第6张图片

假设输入的词向量全都是0,X0=X1... =X100=0,那么就相当于去掉了x,这样第100个向量h100=Ah99=A^2h98=....=A^100h0,当矩阵A最大的特征值\lambdamax(A)略小于1,假如为0.9时,那么0.9^100几乎接近0,那么矩阵A就变成一个几乎全为0的矩阵,h100也会是个全0的向量; 而假如矩阵A的最大特征值略大于1,假如为1.2时,那么1.2^100=非常大的一个数字,大概八千多万,在如此大数额的情况下,我们的状态向量就会爆炸,所以如果没有这个激活函数,我们的向量就会走向极端,要么低到0要么高到非常非常大,有了这个激活函数,每次更新状态后会让h恢复到(-1,1)之间

 Simple RNN 有多少个模型参数?

Simple RNN模型_第7张图片

Simple RNN的应用

搭建RNN神经网络

word embedding: 将一个词映射到词向量X中,词向量的维度自行设定,h和x的维度通常不一                                     样,这里是巧合

最后可以只输出ht,因为ht包含了整个句子信息,将ht送入分类器,输出一个0/1的概率值,0表示负面评价,1表示正面评价

Simple RNN模型_第8张图片

代码实现: 

from keras.models import Sequential
from keras.layers import SimpleRNN, Embedding, Dense
vocabulary = 10000   #一共有10000个词
embedding_dim = 32   #词向量X的维度
word_num = 500       #句子的长度,超过500会截断,不够的通过zero_padding补零
state_dim = 32       #状态向量h的维度

model = Sequential()  #建立一个Sequential模型,往里加层
model.add(Embedding(vocabulary, embedding_dim, input_length=word_num)) #首先第一层word embedding
model.add(SimpleRNN(state_dim, return_sequences=False))   #然后是SimpleRNN layer,return_sequences=False只输入最后一个状态ht,其余不输出
model.add(Dense(1,activation='sigmoid') ) #全连接层,输出一个0/1的数
model.summary()

Simple RNN模型_第9张图片

Embedding的输出:500×32维的矩阵,表示每条评论有500个单词,每个单词用32维的词向量表示

simple rnn层输出:最后一个状态向量是32维,一共有2080个参数,最后一个32是偏移量,rnn默                                 认用intercept=32(不重要)

                             Simple RNN模型_第10张图片

 编译模型:

from keras import optimizers 
epochs = 3  #迭代3轮
# 编译
model.compile(optimizer =optimizers.RMSprop(1r=0.001),  #指定算法RMSprop
              loss='binary_ crossentropy', metrics=['acc'])
history = model.fit(x_train,
                    y_train,
                    epochs=epochs ,
                    batch_size=32,
                    validation_data=(x_valid, y_valid))

Simple RNN模型_第11张图片

 模型评价

#模型评价
loss_and_acc = model.evaluate(x_test, labels_test)  #将测试数据作为输入
print( 'loss = ' + str(loss_and acc[0]))
print( 'acc = ' + str(loss_and acc[1]))

上述我们选择只输出最后一个状态向量,如果输出所有的状态向量的话,rnn会输出一个矩阵,矩阵的每一行是一个状态向量h,然后需要再加入flatten层,将这个矩阵变为向量送进分类器,从而判断电影评价是正面还是负面

 Simple RNN模型_第12张图片

如果你想输出所有的状态向量,则只需在上述代码中改动两处:

model.add(SimpleRNN(state_dim,return_sequences=True))
model.add(Flatten())

RNN缺陷:遗忘

如果我只给半句话,让你预测下一个词,如果是较短的句子,rnn可以预测成功,但如果句子很长很长,rnn就会预测失败,因为它只擅长短时记忆,对于之前太久的词语会忘记,如果我们把第100个状态向量h关于输入x1求导,结果会趋近于0,说明当我们改变x1的时候,h100不会发生任何变化,但是这是不合理的,我们改变x1,不可能对h100没有任何影响,说明h100已经把之前的步骤都忘记了

Simple RNN模型_第13张图片

 

PS:

RNN改进后有GRU、 LSTM,这里介绍只有一个参数矩阵A的简易版rnn,rnn 可能还会有一个参数截距向量B,后期介绍

你可能感兴趣的:(NLP,深度学习,自然语言处理,rnn)