• 关于基本的RNNLSTM的概念和BPTT算法可以查看这里
  • 参考文章:
    • https://r2rt.com/recurrent-neural-networks-in-tensorflow-i.html
    • https://r2rt.com/styles-of-truncated-backpropagation.html

一、源代码实现一个binary例子

1、例子描述

(1) 数据描述

  • 输入数据X是二进制的一串序列, 在t时刻,有50%的概率是150%的概率是0,比如:X=[1,1,0,0,1,0.....]
  • 输出数据Y

    • 在时刻t50%的概率是150%的概率是0
    • 如果Xt−3Xt−3是1,则YtYt 100%1(增加50%);
    • 如果Xt−8Xt−8是1,则YtYt 25%1(减少25%);
      • 所以如果Xt−3Xt−3和Xt−8Xt−8都是1,则YtYt 50%+50%-25%=75%的概率是1
  • 所以,输出数据是有两个依赖关系的

(2) 损失函数

  • 使用cross-entropy损失函数进行训练
  • 这里例子很简单,根据数据生成的规则,我们可以简单的计算一下不同情况下的cross-entropy
  • [1] 如果rnn没有学到两个依赖关系, 则最终预测正确的概率是62.5%cross entropy值为0.66计算如下
    • Xt−3={1→Xt−8={1→0.5+0.5−0.25=0.750→0.5+0.5=10→Xt−8={1→0.5−0.25=0.250→0.5Xt−3={1→Xt−8={1→0.5+0.5−0.25=0.750→0.5+0.5=10→Xt−8={1→0.5−0.25=0.250→0.5
    • 所以正确预测1的概率为:(0.75+1+0.25+0.5)/4=0.625
    • 所以cross entropy值为:-[plog(p)+(1-p)log(1-p)]=0.66
  • [2] 如果rnn学到第一个依赖关系,50%的情况下预测准确度为87.5%50%的情况下预测准确度为62.5%cross entropy值为0.52
    • 因为X是随机生成,0/1各占50%,想象生成了很多的数,根据大数定律,50%的情况是1,对应到 [1] 中的上面的情况就是:(0.75+1)/2=0.875的概率预测正确,其余的50%就和[1]中一样了(去除学到的一个依赖,其余就是没有学到依赖)62.5%
    • 损失值:-0.5 * (0.875 * .log(0.875) + 0.125 * log(0.125))-0.5 * (0.625 * np.log(0.625) + 0.375 * log(0.375)))=0.52
  • [3] 如果rnn两个依赖都学到了,则25%的情况下100%预测正确,25%的情况下50%预测正确,50%的情况向75%预测正确,cross entropy值为0.45
    • 1/4的情况就是Xt−3=1和Xt−8=0Xt−3=1和Xt−8=0 100%预测正确
    • 1/4的情况就是Xt−3=0和Xt−8=0Xt−3=0和Xt−8=0 50%预测正确
    • 1/2的情况75%预测正确(0.5+0.5-0.25)
    • 损失值:-0.50 * (0.75 * np.log(0.75) + 0.25 * np.log(0.25)) - 0.25 * (2 * 0.50 * np.log (0.50)) - 0.25 * (0) = 0.45

2、网络结构

  • 根据时刻t的输入向量XtXt和时刻t-1的状态向量state St−1St−1计算得出当前的状态向量StSt和输出的结果概率向量PtPt
  • Label数据是Y
  • 所以有:

    St=tanh(W(Xt⨁St−1))+bsSt=tanh(W(Xt⨁St−1))+bs
    Pt=softmax(USt+bp)Pt=softmax(USt+bp)
    • 这里⨁⨁表示向量的拼接
    • W∈Rd×(2+d),bs∈Rd,U∈R2×d,bp∈R2W∈Rd×(2+d),bs∈Rd,U∈R2×d,bp∈R2

      • d是 state 向量的长度
      • W是二维的矩阵,因为是将Xt和St−1Xt和St−1拼接起来和W运算的,2对应输入的X one-hot之后,所以是2
      • U是最后输出预测的权值
    • 初始化state S−1S−1 为0向量

  • 需要注意的是 cell 并不一定是只有一个neuron unit,而是有n个hidden units

    • 下图的state size=4

3、Tensorflow中RNN BPTT实现方式

1) 截断反向传播(TRUNCATED BACKPROPAGATION)

  • 假设我们训练含有1000000个数据的序列,如果全部训练的话,整个的序列都feed进RNN中,容易造成梯度消失或爆炸的问题
  • 所以解决的方法就是truncated backpropagation,我们将序列截断来进行训练(num_steps)

2) tensorflow中的BPTT算法实现

  • 一般截断的反向传播是:在当前时间t,往前反向传播num_steps步即可

    • 如下图,长度为6的序列,截断步数是3

  • 但是Tensorflow中的实现并不是这样(如下图)

    • 它是将长度为6的序列分为了两部分,每一部分长度为3
    • 前一部分计算得到的final state用于下一部分计算的initial state

  • 所以tensorflow风格的反向传播并没有有效的反向传播num_steps步(对比一般的方式,依赖关系变的弱一些)

    • 所以比如想要学习有8依赖关系的序列(我们的例子中就是),一般要设置的大于8
  • 另外,有人做实验比较了两种方式here,发现一般的实现方式中的n步和Tensorflow中截断设置为2n的结果相似

3) 关于这个例子,tensorflow风格的实现

  • 如下图,num_steps=5, state_size=4,就是截断反向传播的步数truncated backprop steps是5步,state_size就是cell中的神经元的个数
  • 如果需要截断的步数增多,可以适当增加state_size来记录更多的信息
    • 好比传统的神经网络,就是增加隐藏层的神经元个数
  • 途中的注释是下面的列子代码中定义变量的shape, 可以对照参考

4、自己实现例子中的RNN

  • 全部代码:https://github.com/lawlite19/Blog-Back-Up/blob/master/code/rnn/rnn_implement.py

1) 实现过程

  • 导入包:
1
2
3
4
import numpy as np
import tensorflow as tf
from tensorflow.python import debug as tf_debug
import matplotlib.pyplot as plt
  • 超参数

    • 这里num_steps=5就是只能记忆5步, 所以只能学习到一个依赖(因为至少8步才能学到第二个依赖),我们看结果最后的cross entropy是否在0.52左右

      1
      2
      3
      4
      5
      6
      '''超参数'''
      num_steps = 5
      batch_size = 200
      num_classes = 2
      state_size = 4
      learning_rate = 0.1
  • 生成数据

    • 就是按照我们描述的规则
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
'''生成数据
就是按照文章中提到的规则,这里生成1000000个
'''
def gen_data(size=1000000):
X = np.array(np.random.choice(2, size=(size,)))
Y = []
'''根据规则生成Y'''
for i in range(size):
threshold = 0.5
if X[i-3] == 1:
threshold += 0.5
if X[i-8] == 1:
threshold -=0.25
if np.random.rand() > threshold:
Y.append(0)
else:
Y.append(1)
return X, np.array(Y)
  • 生成batch数据,因为我们使用sgd训练
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
'''生成batch数据'''
def gen_batch(raw_data, batch_size, num_step):
raw_x, raw_y = raw_data
data_length = len(raw_x)
batch_patition_length = data_length // batch_size # ->5000
data_x = np.zeros([batch_size, batch_patition_length], dtype=np.int32) # ->(200, 5000)
data_y = np.zeros([batch_size, batch_patition_length], dtype=np.int32) # ->(200, 5000)
'''填到矩阵的对应位置'''
for i in range(batch_size):
data_x[i] = raw_x[batch_patition_length*i:batch_patition_length*(i+1)]# 每一行取batch_patition_length个数,即5000
data_y[i] = raw_y[batch_patition_length*i:batch_patition_length*(i+1)]
epoch_size = batch_patition_length // num_steps # ->5000/5=1000 就是每一轮的大小
for i in range(epoch_size): # 抽取 epoch_size 个数据
x = data_x[:, i * num_steps:(i + 1) * num_steps] # ->(200, 5)
y = data_y[:, i * num_steps:(i + 1) * num_steps]
yield (x, y) # yield 是生成器,生成器函数在生成值后会自动挂起并暂停他们的执行和状态(最后就是for循环结束后的结果,共有1000个(x, y))
def gen_epochs(n, num_steps):
for i in range(n):
yield gen_batch(gen_data(), batch_size, num_steps)
  • 定义RNN的输入

    • 这里每个数需要one-hot处理
    • unstack方法就是将n维的数据拆成若开个n-1的数据,axis指定根据哪个维度拆的,比如(200,5,2)三维数据,按axis=1会有5(200,2)的二维数据
      1
      2
      3
      4
      5
      6
      7
      '''定义placeholder'''
      x = tf.placeholder(tf.int32, [batch_size, num_steps], name="x")
      y = tf.placeholder(tf.int32, [batch_size, num_steps], name='y')
      init_state = tf.zeros([batch_size, state_size])
      '''RNN输入'''
      x_one_hot = tf.one_hot(x, num_classes)
      rnn_inputs = tf.unstack(x_one_hot, axis=1)
  • 定义RNNcell(关键步骤)

    • 这里关于name_scopevariable_scope的用法可以查看这里

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      '''定义RNN cell'''
      with tf.variable_scope('rnn_cell'):
      W = tf.get_variable('W', [num_classes + state_size, state_size])
      b = tf.get_variable('b', [state_size], initializer=tf.constant_initializer(0.0))
      def rnn_cell(rnn_input, state):
      with tf.variable_scope('rnn_cell', reuse=True):
      W = tf.get_variable('W', [num_classes+state_size, state_size])
      b = tf.get_variable('b', [state_size], initializer=tf.constant_initializer(0.0))
      return tf.tanh(tf.matmul(tf.concat([rnn_input, state],1),W) + b)
  • cell添加到计算图中

1
2
3
4
5
6
7
'''将rnn cell添加到计算图中'''
state = init_state
rnn_outputs = []
for rnn_input in rnn_inputs:
state = rnn_cell(rnn_input, state) # state会重复使用,循环
rnn_outputs.append(state)
final_state = rnn_outputs[-1] # 得到最后的state
  • 定义预测,损失函数,和优化方法

    • sparse_softmax_cross_entropy_with_logits会自动one-hot

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      '''预测,损失,优化'''
      with tf.variable_scope('softmax'):
      W = tf.get_variable('W', [state_size, num_classes])
      b = tf.get_variable('b', [num_classes], initializer=tf.constant_initializer(0.0))
      logits = [tf.matmul(rnn_output, W) + b for rnn_output in rnn_outputs]
      predictions = [tf.nn.softmax(logit) for logit in logits]
      y_as_list = tf.unstack(y, num=num_steps, axis=1)
      losses = [tf.nn.sparse_softmax_cross_entropy_with_logits(labels=label,logits=logit) for logit, label in zip(logits, y_as_list)]
      total_loss = tf.reduce_mean(losses)
      train_step = tf.train.AdagradOptimizer(learning_rate).minimize(total_loss)
  • 训练网络

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
'''训练网络'''
def train_rnn(num_epochs, num_steps, state_size=4, verbose=True):
with tf.Session() as sess:
sess.run(tf.global_variables_initializer())
#sess = tf_debug.LocalCLIDebugWrapperSession(sess)
training_losses = []
for idx, epoch in enumerate(gen_epochs(num_epochs, num_steps)):
training_loss = 0
training_state = np.zeros((batch_size, state_size)) # ->(200, 4)
if verbose:
print('\nepoch', idx)
for step, (X, Y) in enumerate(epoch):
tr_losses, training_loss_, training_state, _ = \
sess.run([losses, total_loss, final_state, train_step], feed_dict={x:X, y:Y, init_state:training_state})
training_loss += training_loss_
if step % 100 == 0 and step > 0:
if verbose:
print('第 {0} 步的平均损失 {1}'.format(step, training_loss/100))
training_losses.append(training_loss/100)
training_loss = 0
return training_losses
  • 显示结果
1
2
3
4
training_losses = train_rnn(num_epochs=1, num_steps=num_steps, state_size=state_size)
print(training_losses[0])
plt.plot(training_losses)
plt.show()

2) 实验结果

  • num_steps=5, state=4

    • 可以看到初试的损失值大约0.66, 最后学到一个依赖关系,最终损失值0.52左右

  • num_step=10, state=16

    • 学到了两个依赖,最终损失值接近0.45

5、使用Tensorflow的cell实现

1) 使用static rnn方式

  • 将我们之前自己实现的cell和添加到计算图中步骤改为如下即可
1
2
3
cell = tf.contrib.rnn.BasicRNNCell(num_units=state_size)
rnn_outputs, final_state = tf.contrib.rnn.static_rnn(cell=cell, inputs=rnn_inputs,
initial_state=init_state)

2) 使用dynamic_rnn方式

  • 这里仅仅替换cell就不行了,RNN输入

    • 直接就是三维的形式

      1
      2
      '''RNN输入'''
      rnn_inputs = tf.one_hot(x, num_classes)
  • 使用dynamic_rnn

1
2
cell = tf.contrib.rnn.BasicRNNCell(num_units=state_size)
rnn_outputs, final_state = tf.nn.dynamic_rnn(cell, rnn_inputs, initial_state=init_state)
  • 预测,损失

    • 由于rnn_inputs是三维的,所以先转成二维的,计算结束后再转换回三维[batch_size, num_steps, num_classes]

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      '''因为rnn_outputs是三维的,这里需要将其转成2维的,
      矩阵运算后再转换回来[batch_size, num_steps, num_classes]'''
      logits = tf.reshape(tf.matmul(tf.reshape(rnn_outputs, [-1, state_size]), W) +b, \
      shape=[batch_size, num_steps, num_classes])
      predictions = tf.nn.softmax(logits)
      y_as_list = tf.unstack(y, num=num_steps, axis=1)
      losses = tf.nn.sparse_softmax_cross_entropy_with_logits(labels=y,logits=logits)
      total_loss = tf.reduce_mean(losses)
      train_step = tf.train.AdagradOptimizer(learning_rate).minimize(total_loss)

Reference

  • https://r2rt.com/recurrent-neural-networks-in-tensorflow-i.html
  • https://r2rt.com/styles-of-truncated-backpropagation.html
  • https://web.stanford.edu/class/psych209a/ReadingsByDate/02_25/Williams%20Zipser95RecNets.pdf
原文地址: http://lawlite.me/2017/06/16/RNN-%E5%BE%AA%E7%8E%AF%E7%A5%9E%E7%BB%8F%E7%BD%91%E7%BB%9C-02Tensorflow%E4%B8%AD%E7%9A%84%E5%AE%9E%E7%8E%B0/

RNN-循环神经网络-02Tensorflow中的实现相关推荐

  1. 【机器学习】RNN循环神经网络

    循环神经网络归属: 领域:机器学习 方向:自然语言处理 贡献:自动文本生成 循环神经网络实际应用: 生活中因为原始数据都是序列化的,比如自然语言,语音处理,时间序列问题(股票价格)等问题, 这个时候需 ...

  2. [译] RNN 循环神经网络系列 2:文本分类

    原文地址:RECURRENT NEURAL NETWORKS (RNN) – PART 2: TEXT CLASSIFICATION 原文作者:GokuMohandas 译文出自:掘金翻译计划 本文永 ...

  3. 小白学深度之RNN循环神经网络

    不懂CNN的建议先看一下CNN 前言 我们先看一下普通的神经网络,只要训练的数据和次数足够,这种网络是可以拟合任意函数的. 但是这种最基本的网络肯定是有很多不足的,上面那种网络只能单独的处理每一个输入 ...

  4. RNN 循环神经网络系列 5: 自定义单元

    原文地址:RECURRENT NEURAL NETWORK (RNN) – PART 5: CUSTOM CELLS 原文作者:GokuMohandas 译文出自:掘金翻译计划 本文永久链接:gith ...

  5. Recurrent Neural Networks(RNN) 循环神经网络初探

    1. 针对机器学习/深度神经网络"记忆能力"的讨论 0x1:数据规律的本质是能代表此类数据的通用模式 - 数据挖掘的本质是在进行模式提取 数据的本质是存储信息的介质,而模式(pat ...

  6. rnn 循环神经网络

    rnn 循环神经网络 创建日期 星期四 10 一月 2019 rnn为 recurrent natural network, 递归神经网络 是一种基于序列的神经网络, 序列可以是时间,文本序列等,和普 ...

  7. PyTorch-09 循环神经网络RNNLSTM (时间序列表示、RNN循环神经网络、RNN Layer使用、时间序列预测案例、RNN训练难题、解决梯度离散LSTM、LSTM使用、情感分类问题实战)

    PyTorch-09 循环神经网络RNN&LSTM (时间序列表示.RNN循环神经网络.RNN Layer使用.时间序列预测案例(一层的预测点的案例).RNN训练难题(梯度爆炸和梯度离散)和解 ...

  8. LSTM -长短期记忆网络(RNN循环神经网络)

    文章目录 基本概念及其公式 输入门.输出门.遗忘门 候选记忆元 记忆元 隐状态 从零开始实现 LSTM 初始化模型参数 定义模型 训练和预测 简洁实现 小结 基本概念及其公式 LSTM,即(long ...

  9. RNN循环神经网络(recurrent neural network)

     自己开发了一个股票智能分析软件,功能很强大,需要的点击下面的链接获取: https://www.cnblogs.com/bclshuai/p/11380657.html 1.1  RNN循环神经网络 ...

  10. July深度学习之RNN循环神经网络

    RNN循环神经网络 一.简介 首先,为什么有BP神经网络和CNN,还要提出RNN? 因为传统的神经网络,包括CNN,它的输入和输出是互相独立的.但有些时候,后续的输出和前面的内容是相关的.比如,我是中 ...

最新文章

  1. 自动化测试的优势和局限性有哪些
  2. TensorFlow中的ResNet残差网络实战(2)
  3. Promise详解(一) ----基础用法
  4. KingPaper初探ThinkPHP3.1.2之扩展函数库和类库的使用(四)
  5. 使用JavaScript的图像识别游戏
  6. matlab安装好 启动总是闪退_在Ubuntu16.04下安装MATLAB2017b
  7. register关键字-1
  8. layer + ajax 弹出框
  9. 科比退役原因-数据分析
  10. windows访问Linux共享文件夹
  11. three.js教程和手册
  12. 20200725 PAT甲级 7-2 The Judger (25分)
  13. Linux on IBM Cloud - Port Knocking
  14. 图像处理------简单综合实例(大米计数)
  15. FL Studio 插件使用教程 —— 3x Osc(上)
  16. 万字好文!Redis 到底是怎么实现“附近的人”这个功能的呢?
  17. vue2.x版本+element-ui2.15+版本实现只能输入数字的ip输入框,功能样式借鉴windows,与父组件双向绑定
  18. a12处理器和骁龙855_骁龙855和苹果A12处理器对比实用评测
  19. Git之搭建Git服务器
  20. 管理平台|智慧工地将成为施工界的“扛把子”!

热门文章

  1. 快速查找无序数组中的第K大数?
  2. [导入]查询锁定表中非锁定记录。
  3. MPI 集合通信函数 MPI_Reduce(),MPI_Allreduce(),MPI_Bcast(),MPI_Scatter(),MPI_Gather(),MPI_Allgather(),MPI_S
  4. 计算天数java_Java,计算两个日期之间的天数
  5. 【算法】一个简单的k均值(k-means)原理
  6. [云炬创业基础笔记]第十一章创业计划书测试1
  7. Delphi中的各种路径
  8. delphi编码规范文档
  9. 使用DataSet对象添加记录
  10. bash-shell中使用的特殊字符总结