提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
文章目录
前言
- 进阶RNN:学习一次执行多步以及堆叠RNN的构建
提示:以下是本篇文章正文内容,下面案例可供参考
1.任务描述
本关任务:学习如何一次执行得到 RNNCell 多步调用 call 方法得到的结果,其次掌握构建堆叠 RNNCell 的方法。
2.相关知识
为了完成本关任务,你需要掌握:
1.学习如何一次执行多步: tf.nn.dynamic_rnn ,
2.学习如何堆叠 RNNCell : MultiRNNCell 。
学习如何一次执行多步:tf.nn.dynamic_rnn
基础的 RNNCell 有一个很明显的问题:对于单个的 RNNCell ,我们使用它的 call 函数进行运算时,只是在序列时间上前进了一步。比如使用 x1 、 h0 得到 h1 ,通过 x2 、 h1 得到 h2 等。这样的话,如果我们的序列长度为 10 ,就要调用 10 次 call 函数,比较麻烦。对此, TensorFlow 提供了一个 tf.nn.dynamic_rnn 函数,使用该函数就相当于调用了 n 次 call 函数。即通过 { h 0 , x 1 , x 2 , … , x n } \{h0,x1, x2, \dots, xn\} {h0,x1,x2,…,xn} 直接得 { h 1 , h 2 … , h n } \{h1,h2\dots,hn\} {h1,h2…,hn}。
具体来说,设我们输入数据的格式为 (batch_size, time_steps, input_size) ,其中 time_steps 表示序列本身的长度,如在 Char RNN 这一开源项目中,长度为 10 的句子对应的 time_steps 就等于 10 。最后的 input_size 就表示输入数据单个序列单个时间维度上固有的长度。另外我们已经定义好了一个 RNNCell ,调用该 RNNCell 的 call 函数 time_steps 次,对应的代码就是:
# inputs: shape = (batch_size, time_steps, input_size)
# cell: RNNCell
# initial_state: shape = (batch_size, cell.state_size)。初始状态。一般可以取零矩阵
outputs, state = tf.nn.dynamic_rnn(cell, inputs, initial_state=initial_state)
此时,得到的 outputs 就是 time_steps 步里所有的输出。它的形状为 [batch_size, time_steps, cell_state_size] 。 state 是最后一步的隐状态,它的形状为 (batch_size, cell.state_size) 。
学习如何堆叠RNNCell:MultiRNNCell
很多时候,单层 RNN 的能力有限,我们需要多层的 RNN 。将 x 输入第一层 RNN 的后得到隐层状态 h ,这个隐层状态就相当于第二层 RNN 的输入,第二层 RNN 的隐层状态又相当于第三层 RNN 的输入,以此类推。在 TensorFlow 中,可以使用 tf.nn.rnn_cell.MultiRNNCell 函数对 RNNCell 进行堆叠,相应的示例程序如下:
import tensorflow as tf
import numpy as np
# 每调用一次这个函数就返回一个BasicRNNCell
def get_a_cell():
return tf.nn.rnn_cell.BasicRNNCell(num_units=128)
# 用tf.nn.rnn_cell MultiRNNCell创建3层RNN
cell = tf.nn.rnn_cell.MultiRNNCell([get_a_cell() for _ in range(3)]) # 3层RNN
# 得到的cell实际也是RNNCell的子类
# 它的state_size是(128, 128, 128)
# (128, 128, 128)并不是128x128x128的意思
# 而是表示共有3个隐层状态,每个隐层状态的大小为128
print(cell.state_size) # (128, 128, 128)
# 使用对应的call函数
inputs = tf.placeholder(np.float32, shape=(32, 100)) # 32 是 batch_size,100是input_size
h0 = cell.zero_state(32, np.float32) # 通过zero_state得到一个全0的初始状态
output, h1 = cell.call(inputs, h0)
print(h1) # 新的隐层状态中含有3个32x128的向量
通过 MultiRNNCell 得到的 cell 并不是什么新鲜事物,它实际也是 RNNCell 的子类,因此也有 call 方法、 state_size 和 output_size 属性。同样可以通过 tf.nn.dynamic_rnn 来一次运行多步。
3.编程要求
根据前面所学知识,在 begin-end 间
尝试构建一个 a 层的 RNN ,每一层由 state_size=b 的 RNNBasicCell 组成,初始化隐层状态为全零,输入一个 batch_size=c,time_steps=d,input_size=e 的输入序列,调用 tf.nn.dynamic_rnn 一次得到多步输入后的结果,并打印出最终的输出 output 的函数 MultiRNNCell_dynamic_call(a,b,c,d,e) 。
4.测试说明
平台会对你编写的代码进行测试:
测试输入: 4 , 91 , 51 , 2 , 32 ;
预期输出:
Tensor("rnn/transpose_1:0", shape=(51, 2, 91), dtype=float32)
测试输入: 5 , 1 , 151 , 12 , 22 ;
预期输出:
Tensor("rnn/transpose_1:0", shape=(151, 12, 1), dtype=float32)
提示:
def get_a_cell():
return tf.nn.rnn_cell.BasicRNNCell(num_units=128)
#用tf.nn.rnn_cell MultiRNNCell创建3层RNN
cell = tf.nn.rnn_cell.MultiRNNCell([get_a_cell() for _ in range(3)]) # 3层RNN
可以替换为
cell = tf.nn.rnn_cell.MultiRNNCell([tf.nn.rnn_cell.BasicRNNCell(num_units=128) for _ in range(3)])
5.笔者答案
#-*- coding: utf-8 -*-
import tensorflow as tf
import numpy as np
#参数 a 是RNN的层数, 参数 b 是每个BasicRNNCell包含的神经元数即state_size
#参数 c 是输入序列的批量大小即batch_size,参数 d 是时间序列的步长即time_steps,参数 e 是单个输入input的维数即input_size
def MultiRNNCell_dynamic_call(a,b,c,d,e):
# 用tf.nn.rnn_cell MultiRNNCell创建a层RNN,并调用tf.nn.dynamic_rnn
# 请在此添加代码 完成本关任务
# ********** Begin *********#
#构建 BasicRNNCell,含有 b 个神经元
def get_a_cell():
return tf.nn.rnn_cell.BasicRNNCell(num_units=b)
cell=tf.nn.rnn_cell.MultiRNNCell([get_a_cell() for _ in range(a)]) # a层RNN
inputs = tf.placeholder(np.float32, shape=(c,d,e))
h0 = cell.zero_state(c, np.float32) #通过zero_state得到一个全0的初始状态
outputs,state=tf.nn.dynamic_rnn(cell,inputs, initial_state=h0)
print(outputs)
# ********** End **********#
代码修改
去掉get_a_cell()函数
#-*- coding: utf-8 -*-
import tensorflow as tf
import numpy as np
#参数 a 是RNN的层数, 参数 b 是每个BasicRNNCell包含的神经元数即state_size
#参数 c 是输入序列的批量大小即batch_size,参数 d 是时间序列的步长即time_steps,参数 e 是单个输入input的维数即input_size
def MultiRNNCell_dynamic_call(a,b,c,d,e):
# 用tf.nn.rnn_cell MultiRNNCell创建a层RNN,并调用tf.nn.dynamic_rnn
# 请在此添加代码 完成本关任务
# ********** Begin *********#
cell=tf.nn.rnn_cell.MultiRNNCell([tf.nn.rnn_cell.BasicRNNCell(num_units=b) for _ in range(a)]) # a层RNN
inputs = tf.placeholder(np.float32, shape=(c,d,e))
h0 = cell.zero_state(c, np.float32) #通过zero_state得到一个全0的初始状态
outputs,state=tf.nn.dynamic_rnn(cell,inputs, initial_state=h0)
print(outputs)
# ********** End **********#
通过截图
总结
- 进阶RNN:学习一次执行多步以及堆叠RNN的构建