【TensorFlow】什么是循环神经网络(RNN)?(第五课)

                                     循环神经网络--理解

1、循环神经网络(RNN)简介

为什么用RNN?什么是RNN?与DNN的区别是什么?

(1)循环神经网络的优势在于解决与时间序列相关的问题

(2)以下是一个典型的RNN:

         

 输入x1和模型上一时刻的状态h_{t-1},模型A产生一个此时刻的状态h_{t},然后输出a1.

展开后:

(3)与DNN的区别,就是RNN会加入一个输入量(模型上一时刻的状态),来得到输出。

代码案例:

import numpy as np
 
X = [1, 2]
state = [0.0, 0.0]
 
# 分开定义不同输入部分的权重
w_cell_state = np.asarray([[0.1, 0.2], [0.3, 0.4]])
w_cell_input = np.asarray([0.5, 0.6])
b_cell = np.asarray([0.1, -0.1])
 
# 定义用于输出的全连接层参数
w_output = np.asarray([1.0, 2.0])
b_output = 0.1
 
# 按照时间顺序执行循环神经网络的前向传播过程
for i in range(len(X)):
    before_activation = np.dot(state, w_cell_state) + X[i] * w_cell_input + b_cell
    state = np.tanh(before_activation)
 
    # 根据当前时刻状态计算最终输出
    final_output = np.dot(state, w_output) + b_output
 
    # 输出每个时刻的信息
    print("before activation: ", before_activation)
    print("state: ", state)
    print("output: ", final_output)

 

2、长短时记忆网络(LSTM)结构

LSTM的用途?

在复杂的语言场景中,有用信息的间隔有大有小、长短不一,这些情况会影响循环神经网络的性能。LSTM就是为了解决这个问题。

LSTM的结构?这里的c和h的区别?‘门’是什么?

结构如下图:

详细:

c、h的区别?

在LSTM中,c_{t}是状态,而ht是输出,ht由ct和输出门得到。

门:

‘门’的结构,就是先用一个按位乘法,然后把结果输入sigmoid。

以下是LSTM各个门的定义:

“遗忘门”的作用是让循环神经网络“忘记”之前没有用的信息。

“输入门”需要从当前的输入补充最新的记忆。

LSTM结构在计算得到新的状态 ctct 后需要产生当前时刻的输出,这个过程是通过“输出门”完成的。“输出门”会根据最新的状态 ct 、上一时刻的输出 ht−1 和当前的输入 xt 来决定该时刻的输出 ht 。

LSTM前向传播代码:

 #定义一个LSTM结构。在TensorFlow中通过一句简单的命令就可以实现一个完整LSTM结构。
# LSTM中使用的变量也会在该函数中自动被声明。
lstm = rnn_cell.BasicLSTMCell(lstm_hidden_size)
 
# 将LSTM中的状态初始化为全0数组。和其他神经网络类似,在优化循环神经网络时,每次也
# 会使用一个batch的训练样本。以下代码中,batch_size给出了一个batch的大小。
# BasicLSTMCell类提供了zero_state函数来生成全领的初始状态。
state = lstm.zero_state(batch_size, tf.float32)
 
# 定义损失函数。
loss = 0.0
# 在8.1节中介绍过,虽然理论上循环神经网络可以处理任意长度的序列,但是在训练时为了
# 避免梯度消散的问题,会规定一个最大的序列长度。在以下代码中,用num_steps
# 来表示这个长度。
for i in range(num_steps):
# 在第一个时刻声明LSTM结构中使用的变量,在之后的时刻都需要复用之前定义好的变量。   
if i > 0: tf.get_variable_scope().reuse_variables()
 
     # 每一步处理时间序列中的一个时刻。将当前输入(current_input)和前一时刻状态
     # (state)传入定义的LSTM结构可以得到当前LSTM结构的输出lstm_output和更新后
      # 的状态state。
    lstm_output, state = lstm(current_input, state)
   # 将当前时刻LSTM结构的输出传入一个全连接层得到最后的输出。
    final_output = fully_connected(lstm_output)
   # 计算当前时刻输出的损失。
    loss += calc_loss(final_output, expected_output)

LSTM与RNN的区别?

(1)RNN能够处理一定的短期依赖,但无法处理长期依赖问题。

(2)LSTM的网络结构相比于RNN复杂了很多。从微观上看,LSTM引入了细胞状态,并使用输入门、遗忘门、输出门三种门来保持和控制信息。

 

 

 

3、循环神经网络的变种

3.1、双向循环神经网络(bidirectional RNN)

应用情境:

在经典的循环神经网络中,状态的输入是单向的。然后,在有些问题中,输出不仅跟之前的状态有关,也和之后的状态有关。这时就需要使用双向循环神经网络。

结构:

3.2、深层循环神经网络(Deep RNN)

应用情境:

为了增强模型的表达能力,可以在网络中设置多个循环层(经典的RNN只有一层),将每层循环神经网络输出传给下一层进行处理。

结构:

3.3、循环神经网络的dropout

dropout是什么?与loss的区别?

dropout是指在训练一个大的神经网络的时候,随机“关闭”一些神经元,即把这些神经元从网络中“抹去”,这相当于在本次训练中,这些被“抹去”的神经元不参与本次训练,英文即是“dropout”的意思。

(loss是损失函数,完全没有联系!)

为什么dropout可以防止过拟合?

       我们知道“随机森林”是一种不容易发生过拟合的算法,其采用的方法是“bagging”,即通过对多个树的输出结果加权平均,得出最后的结果。而每棵树都是在不同的训练集上、设置不同的参数得到的,因此是一种典型的通过多个不同参数,甚至不同类型的模型来降低方差的一种方法。这种方法对传统的机器学习算法、或者小型的NN模型可行,但是当数据量很大、模型很复杂的时候,我们不能训练多个不同的模型出来做”bagging”,因为深度神经网络的训练是一个很耗时的过程,需要大量的计算资源和时间。
       dropout则为这种思想提供了一种“廉价”的解决方案,因为每一次迭代的过程中,我们会随机dropout掉一些神经元(至于在那一层做dropout,需要看不通的情况),如果设置的dropout的值为0.5,则表示每个神经元有50%的概率被留下来,50%的概率被”抹去“。这就相当于我们从原来的神经网络中随机采样了50%的节点,组成了一个新的神经网络,这个是原来的神经网络的一个子网络,但是规模要比原来的神经网络小很多,并且训练代价也比较小, 这个新的子网络就相当于是”随即森林“中的一个子树(sub-tree)了。我们多次迭代优化,每次迭代优化都会做这样的”随机采样“,从原来的网络中构造一个子网络(sub-network),而每次构造的网络也都不尽相同,这就使得学习到的sub-network在结果上差异性,最后再对这些每个迭代学习到的不同的sub-network做一个”bagging“来得到最终的输出结果。
 

4、循环神经网络的应用

什么时候应用?举一些例子。

拟合sin(x),代码:

"""
Created on Wed Dec  5 09:27:45 2018
tensorflow rnn 预测正弦函数
@author: lingtwave wang
"""
 
import numpy as np
import tensorflow as tf
import matplotlib as mpl
from matplotlib import pyplot as plt
from tensorflow.contrib.learn.python.learn.estimators.estimator import SKCompat
 
# TensorFlow的高层封装TFLearn
learn = tf.contrib.learn
 
# 神经网络参数
HIDDEN_SIZE = 30  # LSTM隐藏节点个数
NUM_LAYERS = 2    # LSTM层数
TIMESTEPS = 10    # 循环神经网络截断长度
BATCH_SIZE = 32   # batch大小
 
# 数据参数
TRAINING_STEPS = 3000      # 训练轮数
TRAINING_EXAMPLES = 10000  # 训练数据个数
TESTING_EXAMPLES = 1000    # 测试数据个数
SAMPLE_GAP = 0.01          # 采样间隔
 
 
def generate_data(seq):
    # 序列的第i项和后面的TIMESTEPS-1项合在一起作为输入,第i+TIMESTEPS项作为输出
    X = []
    y = []
    for i in range(len(seq) - TIMESTEPS - 1): #0-9989  #0-989
        X.append([seq[i:i + TIMESTEPS]])
        y.append([seq[i + TIMESTEPS]])
    return np.array(X, dtype=np.float32), np.array(y, dtype=np.float32)
    
 
# LSTM基本结构单元
def LstmCell():
    lstm_cell = tf.contrib.rnn.BasicLSTMCell(HIDDEN_SIZE)
    return lstm_cell
 
def lstm_model(X, y):
    # 使用多层LSTM,不能用lstm_cell*NUM_LAYERS的方法,会导致LSTM的tensor名字都一样
    cell = tf.contrib.rnn.MultiRNNCell([LstmCell() for i in range(NUM_LAYERS)])  
    # 将多层LSTM结构连接成RNN网络并计算前向传播结果
    
    #输入 cell,inputs,dtype
    #输出形如 [batch_size,max_time,cell.output.size]
    output, _ = tf.nn.dynamic_rnn(cell, X, dtype=tf.float32)
    #形如[? *30] -1表示自适应
    output = tf.reshape(output, [-1, HIDDEN_SIZE])
    # 通过无激活函数的全联接层计算线性回归,并将数据压缩成一维数组的结构
    # 输入,输出,激活函数
    predictions = tf.contrib.layers.fully_connected(output, 1, None) 
    # 将predictions和labels调整为统一的shape
    y = tf.reshape(y, [-1])
    predictions = tf.reshape(predictions, [-1])
    # 计算损失值
    loss = tf.losses.mean_squared_error(predictions, y)
    # 创建模型优化器并得到优化步骤
    train_op = tf.contrib.layers.optimize_loss(
        loss,
        tf.train.get_global_step(),
        optimizer='Adagrad',
        learning_rate=0.1
    )
    return predictions, loss, train_op
 
 
#用正弦函数生成训练和测试数据集合
#numpu.linspace函数可以创建一个等差序列的数组,它常用的参数有三个参数,第一个参数
#表示起始值,第二个参数表示终止值,第三个参数表示数列的长度。例如,linespace(1,10,10)
#产生的数组是array([1,2,3,4,5,6,7,8,9,10])
test_start = TRAINING_EXAMPLES * SAMPLE_GAP
test_end = (TRAINING_EXAMPLES + TESTING_EXAMPLES) * SAMPLE_GAP
train_X, train_y = generate_data(np.sin(np.linspace(0, test_start, TRAINING_EXAMPLES, dtype=np.float32)))
test_X, test_y = generate_data(np.sin(np.linspace(test_start, test_end, TESTING_EXAMPLES, dtype=np.float32)))
 
 
# 建立深层循环网络模型
regressor = SKCompat(learn.Estimator(model_fn=lstm_model, model_dir='model/'))
 
# 调用fit函数训练模型
regressor.fit(train_X, train_y, batch_size=BATCH_SIZE, steps=TRAINING_STEPS)
 
# 使用训练好的模型对测试集进行预测
predicted = [[pred] for pred in regressor.predict(test_X)]
# 计算rmse作为评价指标
rmse = np.sqrt(((predicted - test_y)**2).mean(axis=0))
print('Mean Square Error is: %f' % (rmse[0]))
 
# 对预测曲线绘图,并存储到sin.jpg
fig = plt.figure()
plot_test, = plt.plot(test_y, label='real_sin',c='blue')
plot_predicted, = plt.plot(predicted,label='predicted',c='red')
 
plt.legend([plot_predicted, plot_test], ['predicted', 'real_sin'])
plt.show()
fig.savefig('sin.png')

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值