RNN循环神经网络(过程解析)

Posted 月疯

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了RNN循环神经网络(过程解析)相关的知识,希望对你有一定的参考价值。

RNN的引出:时间序列如何表达?

 

卷积神经网络是位置上上进行提取特征,比如语音和翻译都是在时间上缠身的,如何提取时间序列的特征。

对于序列问题的研究:咋么把文字编程一个数据类型或者数值,这个研究方案就是embedding。

 

 

单个股票价格的表示方法,每个时间点上都是一个对应的价格值。

 

多个股票价格的表示方法。

这个思想使用到图片上也是这样,按照行读取数值,作为序列的特征

 

 

 

one-hot表示方法。

 

 

 


通过具体问题来分析一下,判断一下评价是积极的还是消极的这样一个工作,当我们输入是I hate this boring movie,可以看出来一个Embedding就是一个单词。

每一个单词是一个输入,有多少单词就有多少全连接层,每个全连接层处理一个单词,通过全连接层把每个单词当前的语义信息给提取出来,然后做一个分类就知道,当前评价是好评还是差评。这种方法比较直观,但是存在一个问题,如果一个比较长的评语,100个单词需要引进100个全连接层,更关键的是我们只是获取到每个单词的语义信息,对于100个单词,我们没有整体的语义相关性。如果我们把100个单词打乱,也不会影响结果,但是结果打乱会影响的整体的语义相关性。 

我们需要把整体综合起来,整体分析,要处理这个问题?
参数量大在卷积网络是如何解决的,我们用一个卷积核,卷积核大小不变,内部值发生变化,得到解决。我们只使用一个神经网络来解决,不断的输入和输出。我们的参数量只有w和b。解决参数量过大的问题。

如何解决语义信息的整体分析呢?
我们加入一个memory层或者state状态层,就是每经过一次全连接层,后面的都会记录前面的信息。这样我们得到整个语句的最后一个memory,是记录了全体的信息的,我们只对最后一次得到的信息做处理就能获取所有的语义信息。 

时间轴上有多少个采样就需要走多少次,采样和时间相关。我们对时间周做一个折叠,初始状态h0,然后对信息不断聚合,当前的输入就是上一次的语境信息。 这样通过不断的聚合,最后一个就包含了所有的语境信息。这就是最简单的RNN循环网络的原理。综合起来就是一个神经网络不断聚合的结果。

这是RNN的数学表达:代码演示

# _*_ coding =utf-8 _*_

import tensorflow as tf
from tensorflow.keras import layers,optimizers,datasets,Sequential
import os
#Xt@Wxh + ht@Whh
cell =layers.SimpleRNNCell(3)
#[b,embeding]4输入的维度
cell.build(input_shape=(None,4))
#打印cell的参数
print(cell.trainable_variables)

#kernel:0表示Wxh,recurrent_kernel:0表示Whh
# [<tf.Variable 'kernel:0' shape=(4, 3) dtype=float32, numpy=
# array([[ 0.87822306,  0.8071407 , -0.20742077],
#        [-0.5177747 , -0.0864749 ,  0.87705004],
#        [-0.8141298 ,  0.32291627, -0.329014  ],
#        [-0.05522245, -0.5882717 ,  0.74687743]], dtype=float32)>, <tf.Variable 'recurrent_kernel:0' shape=(3, 3) dtype=float32, numpy=
# array([[ 0.29745793,  0.9037314 ,  0.30787772],
#        [-0.9194169 ,  0.35804993, -0.16270511],
#        [-0.25727728, -0.23467004,  0.9374105 ]], dtype=float32)>, <tf.Variable 'bias:0' shape=(3,) dtype=float32, numpy=array([0., 0., 0.], dtype=float32)>]

Wxh是上一次的权值,Whh是本次的权值,会产生下一个新的Yt,Ht是对上一次语境信息激活,计算梯度的时候保证连续可导。

如果输出是[b,64],那么[b,100]@[100,64] +[b,64]@[64,64]=[b,64] 

Xt@Wxh + ht@Whh 这就是一个SampleRNNCell (要和LSTM和GRU不一样)

# #获取4个句子,每个句子80个单词,每个单子100位向量
# x = tf.random.normal([4,80,100])
# #获取第一个单词
# xt0 = x[:,0,:]
# #中间维度是64
# cell = tf.keras.layers.SimpleRNNCell(64)
# #初始状态xt0,返回俩个相同的状态[b,64] 输出
# out,xt1 = cell(xt0,[tf.zeros([4,64])])
#
# print(out.shape,xt1[0].shape)

梯度的弥散和梯度爆炸:

 

Whh的k次,如果Whh>1,那么结果会趋近于无穷大,会出现梯度爆炸
如果Whh<1的话,那么结果会趋近于0,会出现梯度弥散

 

 RNN情感分析实战:单层RNN

import os
import tensorflow as tf
import numpy as np
from tensorflow import keras
from tensorflow.keras import layers
from keras.preprocessing.sequence import pad_sequences

tf.random.set_seed(22)
np.random.seed(22)
os.environ['TF_CPP_MIN_LOG_LEVEL'] = '2'
assert tf.__version__.startswith('2.')
embedding_len=100#表示100个句子
batchsz = 128
#
total_words = 10000
max_review_len = 80 #80个单词
(x_train,y_train),(x_test,y_test) = keras.datasets.imdb.load_data(num_words=total_words)
# x_train[b,80] 每个句子80个单词
# x_test[b,80]
x_train = keras.preprocessing.sequence.pad_sequences(x_train,maxlen=max_review_len)
x_test = keras.preprocessing.sequence.pad_sequences(x_test,maxlen=max_review_len)

db_train = tf.data.Dataset.from_tensor_slices((x_train,y_train))
#最后一个bach给drop掉
db_train = db_train.shuffle(1000).batch(batchsz,drop_remainder=True)
db_test = tf.data.Dataset.from_tensor_slices((x_test,y_test))
db_test = db_test.batch(batchsz,drop_remainder=True)

print('x_train shape:',x_train.shape,tf.reduce_max(y_train),tf.reduce_min(y_train))
print('x_test:',x_test.shape)

class MyRNN(keras.Model):
    def __init__(self,units):
        super(MyRNN, self).__init__()
        #初始化状态[b,64],b个句子,每个句子64维的状态
        self.state0 = [tf.zeros([batchsz,units])]
        #网络总共三层,第一层就是把数字编码转换为embedding编码,b个句子,每个句子80个单词,每个单词100维向量来表示
        # [b,80] => [b,80,100]
        #total_words输入维度10000,embedding_len 输出是100维,input_length每个句子的长度是80
        self.embedding = layers.Embedding(total_words,embedding_len,input_length=max_review_len)

        #[b,80,100],h_dim:units(100维进行转换为64)
        #RNN:cell0,cell1,cell2
        #SimpleRNN
        #第二层是语义提取,就是利用SimapleRNN提取语义,dropout防止过拟合
        self.rnn_cell0 = layers.SimpleRNNCell(units,dropout=0.2)

        #fc,[b,80,100] => [b,64] => [b,1]
        self.outlayer = layers.Dense(1)

    def call(self,inputs,training=None):
        """
        net(x),net(x, training=True)
        :param inputs: [b,80]
        :param training:
        :return:
        """
        #[b,80]
        x = inputs
        #embedding:[b,80] => [b,80,100]
        x = self.embedding(x)
        #rnn cell compute
        # [b,80,100] =>[b,64]
        state0 = self.state0
        #x在第一维上进行展开
        for word in tf.unstack(x,axis=1):# word [b,100]
            # x*wxh + h*whh #上一个状态会获取下一个状态
            out,state1 = self.rnn_cell0(word,state0)
            #新的state赋值给上一个state
            state0 = state1

        # out: [b,64]=>[b,1]二分类转换为b和1
        x = self.outlayer(out)
        #p(y is pos|x) 计算概率
        prob = tf.sigmoid(x)

        return prob  #完成了前向计算的信息
def main():
    units =64
    epochs =4
    model =MyRNN(units)
    model.compile(optimizer = keras.optimizers.Adam(0.001),
                  loss = tf.losses.BinaryCrossentropy(),
                  metrics = ['accuracy'])
    model.fit(db_train,epochs=epochs,validation_data=db_test)

    model.evaluate(db_test)

if __name__ =='__main__':
    main()

多层RNN:

import os
import tensorflow as tf
import numpy as np
from tensorflow import keras
from tensorflow.keras import layers
from keras.preprocessing.sequence import pad_sequences

tf.random.set_seed(22)
np.random.seed(22)
os.environ['TF_CPP_MIN_LOG_LEVEL'] = '2'
assert tf.__version__.startswith('2.')
embedding_len=100#表示100个句子
batchsz = 128
#
total_words = 10000
max_review_len = 80 #80个单词
(x_train,y_train),(x_test,y_test) = keras.datasets.imdb.load_data(num_words=total_words)
# x_train[b,80] 每个句子80个单词
# x_test[b,80]
x_train = keras.preprocessing.sequence.pad_sequences(x_train,maxlen=max_review_len)
x_test = keras.preprocessing.sequence.pad_sequences(x_test,maxlen=max_review_len)

db_train = tf.data.Dataset.from_tensor_slices((x_train,y_train))
#最后一个bach给drop掉
db_train = db_train.shuffle(1000).batch(batchsz,drop_remainder=True)
db_test = tf.data.Dataset.from_tensor_slices((x_test,y_test))
db_test = db_test.batch(batchsz,drop_remainder=True)

print('x_train shape:',x_train.shape,tf.reduce_max(y_train),tf.reduce_min(y_train))
print('x_test:',x_test.shape)

#以单个层训练,现在再增加一个层,提高训练准确度

class MyRNN(keras.Model):
    def __init__(self,units):
        super(MyRNN, self).__init__()
        #初始化状态[b,64],b个句子,每个句子64维的状态
        self.state0 = [tf.zeros([batchsz,units])]
        self.state1 = [tf.zeros([batchsz,units])]
        #网络总共三层,第一层就是把数字编码转换为embedding编码,b个句子,每个句子80个单词,每个单词100维向量来表示
        # [b,80] => [b,80,100]
        #total_words输入维度10000,embedding_len 输出是100维,input_length每个句子的长度是80
        self.embedding = layers.Embedding(total_words,embedding_len,input_length=max_review_len)

        #[b,80,100],h_dim:units(100维进行转换为64)
        #RNN:cell0,cell1,cell2
        #SimpleRNN
        #第二层是语义提取,就是利用SimapleRNN提取语义,dropout防止过拟合
        self.rnn_cell0 = layers.SimpleRNNCell(units,dropout=0.2)
        self.rnn_cell1 = layers.SimpleRNNCell(units,dropout=0.2)

        #fc,[b,80,100] => [b,64] => [b,1]
        self.outlayer = layers.Dense(1)

    def call(self,inputs,training=None):
        """
        net(x),net(x, training=True)
        :param inputs: [b,80]
        :param training:
        :return:
        """
        #[b,80]
        x = inputs
        #embedding:[b,80] => [b,80,100]
        x = self.embedding(x)
        #rnn cell compute
        # [b,80,100] =>[b,64]
        state0 = self.state0
        state1 = self.state1
        #x在第一维上进行展开
        for word in tf.unstack(x,axis=1):# word [b,100]
            # x*wxh + h*whh #上一个状态会获取下一个状态
            out0,state0 = self.rnn_cell0(word,state0)
            out1,state1 = self.rnn_cell1(out0,state1)


        # out: [b,64]=>[b,1]二分类转换为b和1
        x = self.outlayer(out1)
        #p(y is pos|x) 计算概率
        prob = tf.sigmoid(x)

        return prob  #完成了前向计算的信息
def main():
    units =64
    epochs =4
    model =MyRNN(units)
    model.compile(optimizer = keras.optimizers.Adam(0.001),
                  loss = tf.losses.BinaryCrossentropy(),
                  metrics = ['accuracy'])
    model.fit(db_train,epochs=epochs,validation_data=db_test)

    model.evaluate(db_test)

if __name__ =='__main__':
    main()

 结果展示:

 

以上是关于RNN循环神经网络(过程解析)的主要内容,如果未能解决你的问题,请参考以下文章

RNN循环神经网络(过程解析)

RNN循环神经网络(过程解析)

吴恩达深度学习笔记(deeplearning.ai)之循环神经网络(RNN)

84. 双向循环神经网络

深度学习(06)_循环神经网络RNN和LSTM_01

强烈推荐RNN 架构解析(循环神经网络)