In [1]:
import tensorflow as tf
import numpy as np
from show import show_graph
In [2]:
# 显存管理
import os
os.environ["CUDA_VISIBLE_DEVICES"] = '0'    # 指定第一块GPU可用
config = tf.ConfigProto()
config.gpu_options.per_process_gpu_memory_fraction = 0.5    # 最多允许占用50%显存
config.gpu_options.allow_growth = True      # 按需申请显存

相关参数设定

In [3]:
n_inputs = 3
n_neurons = 5

静态展开

为每一步创建一个RNNCell
创建和14.1一样的网络
……Session运行部分略……

In [4]:
# 占位符
X0 = tf.placeholder(tf.float32, [None, n_inputs])
X1 = tf.placeholder(tf.float32, [None, n_inputs])
In [5]:
# BasicRNNCell产生一个生成器,用于生成神经元数为num_units的RNNCell
basic_cell = tf.contrib.rnn.BasicRNNCell(num_units=n_neurons)

# static_rnn组建RNN网络
# ... 第一个参数指定一个RNNCell的生成器
# ... 第二个参数是输入列表
# ... dtype参数为输入的数据类型
# ... 第一个返回值是网络的输出
# ... 第二个返回值是网络的最终状态(如果用的是BasicRNNCell,则等同于网络的输出)
output_seqs, states = tf.contrib.rnn.static_rnn(
                            basic_cell, [X0, X1], dtype=tf.float32)

# 从RNN输出中分离出不同帧的输出
Y0, Y1 = output_seqs

但是,如果用这种方式创建输入步数很多的RNN时代码会变得十分臃肿;
接下来简化代码,使其可以用简短的代码接受大量的步数

In [9]:
tf.reset_default_graph()

n_steps = 2
In [10]:
# 把步数的序号作为输入占位符的一部分
X = tf.placeholder(tf.float32, [None, n_steps, n_inputs])

# tf.transpose调换了头两维的维序
# ... 此时第一维为步序,第二维为mini-batch的序号,第三维还是某batch某步下的输入
# tf.unstack把数组按第一维展开成列表
# ... 也就是说,X_seqs是一个包含每一步的Tensor列表,每个Tensor的大小为[None, n_inputs]
X_seqs = tf.unstack(tf.transpose(X, perm=[1, 0, 2]))
In [11]:
# 同先前的创建代码,[X0, X1]由X_seqs代替
basic_cell = tf.contrib.rnn.BasicRNNCell(num_units=n_neurons)
output_seqs, states = tf.contrib.rnn.static_rnn(
                            basic_cell, X_seqs, dtype=tf.float32)
In [12]:
# 最后的输出又需要用tf.transpose把头两维倒回来
# ... 此时,第一维是batch序号,第二维是步序,第三维是某batch某步下的输入
outputs = tf.transpose(tf.stack(output_seqs), perm=[1, 0, 2])

静态展开构成的计算图随着步数增加将变得十分臃肿;
而且在反向传播时会占用大量的显存,因为它需要保存所有Tensor的值

动态展开

dynamic_rnn() 使用 while_loop() 操作在cell上运行若干次;
可以指定参数 swap_memory=True,让它在显存不足时交换到内存上;
而且不再需要繁琐的stack和unstack等操作;
……Session运行部分略……

In [14]:
tf.reset_default_graph()

X = tf.placeholder(tf.float32, [None, n_steps, n_inputs])

basic_cell = tf.contrib.rnn.BasicRNNCell(num_units=n_neurons)
outputs, states = tf.nn.dynamic_rnn(basic_cell, X, dtype=tf.float32)