静态RNN和动态RNN的区别是什么

这篇“静态RNN和动态RNN的区别是什么”文章的知识点大部分人都不太理解,所以小编给大家总结了以下内容,内容详细,步骤清晰,具有一定的借鉴价值,希望大家阅读完这篇文章能有所收获,下面我们一起来看看这篇“静态RNN和动态RNN的区别是什么”文章吧。

创新互联专注于点军网站建设服务及定制,我们拥有丰富的企业做网站经验。 热诚为您提供点军营销型网站建设,点军网站制作、点军网页设计、点军网站官网定制、微信平台小程序开发服务,打造点军网络公司原创品牌,更为您提供点军网站排名全网营销落地服务。

1. 静态RNN

函数static_rnn()函数通过连接记忆单元创建一个展开的RNN网络,下面的代码创建了一个RNN网络,该网络和上期中我们创建的是完全一样的。

X0 = tf.placeholder(tf.float32, [None, n_inputs])
X1 = tf.placeholder(tf.float32, [None, n_inputs])
basic_cell = tf.contrib.rnn.BasicRNNCell(num_units=n_neurons)
output_seqs, states = tf.contrib.rnn.static_rnn(
                       basic_cell, [X0, X1], dtype=tf.float32)
Y0, Y1 = output_seqs

首先,和之前一样我们创建了两个用来输入数据的placeholder,接下来,我们创建了BasicRNNCell(可以把这个函数想象为一个创建记忆单元的一个工厂),用来构建展开的RNN网络。接下来调用static_rnn(),该函数输入为创建好的cell,输入的tensor以及tensor的类型。对于每一个输入,static_rnn()调用记忆单元的__call__()函数,创建两个记忆单元的两个copy,每一个copy中都包含着有5个循环神经元的一层网络,并且有着共享变量和偏置项,和之前做的一样,连在一起。
static_rnn()函数返回两个对象,其中一个是一个list,该list包含每一个时刻所输出的tensor,另一个对象是一个tensor包含着网络的最终状态。如果我们用最基本的记忆单元的话,那么最后状态和输出是一致的。
如果有50个时刻,那么这样定义50个输入的placeholder和50个输出的tensor就会显得比较麻烦。还有在执行的时候,还得传输50个placeholder和50个输出tensor,你说麻烦不麻烦?既然麻烦,那么就会有简单的办法,如下:

X = tf.placeholder(tf.float32, [None, n_steps, n_inputs])
X_seqs = tf.unstack(tf.transpose(X, perm=[1, 0, 2]))
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)
outputs = tf.transpose(tf.stack(output_seqs), perm=[1, 0, 2])

如上,这里我们只需要用1个placeholder就可以了,它的shape是[None, n_steps, n_inputs],其中第一维度None代表mini-batch的大小,第二个维度代表时间步长的个数,也就是有多少个时刻。第三个维度为每个时刻的输入大小。X_seqs是一个拥有n_steps个shape为[None, n_inputs]的tensor。为了转换成这种形式,我们得先通过transpose()函数,将前两个维度互换一下,转换之后时间步长就变成了第一个维度。然后我们可以通过unstack()函数根据第一个维度将它转换成一个python列表的形式。接下来的两行跟之前一样,创建静态RNN,最后我们通过stack()函数将所有的输出tensor合并成一个tensor,最后交换输出tensor的前两个维度,转换成[None, n_steps, n_inputs]形式。这样的话,我们就可以通过传输一个包含mini-batch序列的tensor来运行网络了。如下:

X_batch = np.array([
       # t = 0 t = 1
       [[0, 1, 2], [9, 8, 7]], # instance 0
       [[3, 4, 5], [0, 0, 0]], # instance 1
       [[6, 7, 8], [6, 5, 4]], # instance 2
       [[9, 0, 1], [3, 2, 1]], # instance 3
   ])
with tf.Session() as sess:
   init.run()
   outputs_val = outputs.eval(feed_dict={X: X_batch})

运行结束,我们得到一个tensor(outputs_val) 包含着每个样本在每个时刻每个神经元上的输出情况。如下:

>>> print(outputs_val)
[[[-0.2964572 0.82874775 -0.34216955 -0.75720584 0.19011548]
 [ 0.51955646 1. 0.99999022 -0.99984968 -0.24616946]]
[[-0.12842922 0.99981797 0.84704727 -0.99570125 0.38665548]
[-0.70553327 -0.11918639 0.48885304 0.08917919 -0.26579669]]
[[ 0.04731077 0.99999976 0.99330056 -0.999933 0.55339795]
[-0.32477224 0.99996376 0.99933046 -0.99711186 0.10981458]]
[[ 0.70323634 0.99309105 0.99909431 -0.85363263 0.7472108 ]
[-0.43738723 0.91517633 0.97817528 -0.91763324 0.11047263]]]

然而,通过这种方法创建的图会在每个时刻都创建一个单元,有50个时刻的话,看起来比较丑,有点像不用循环写了50次。Y0=f(0, X0); Y1=f(Y0, X1); Y2=f(Y1, X2); ...; Y50=f(Y49,X50)。这么大的一张图,一想就知道肯定会占用很大的内存空间,特别是在反向传播的时候,对于一个内存受限的GPU,简直就是要了老命。因为反向传播的时候需要用所有前向传播的权重值来计算梯度,这就不得不将前向传播的值都存下来。那么对于有限的内存来说,关机,洗洗睡吧。
兵来将挡水来土掩,幸运的是,我们可以用动态RNN来解决这个问题,那么什么是动态RNN呢?

2. 动态RNN

动态RNN的函数为dynamic_rnn(),这个函数内部用了一个while_loop()的操作,它会根据有多少时刻来动态调整参数运行网络。我们也可以通过设置swap_memory=True来避免在反向传输的时候内存耗尽。这个设置允许在反向传输的时候将CPU内存和GPU内存互换。
很方便的,动态RNN对于所有的输入也接收一个tensor,shape为[None, n_steps, n_inputs],并且和前面的一样,输出一个shape为[None, n_steps, n_inputs]的tensor。而且不用像前面一样要通过unstack,stack,transpose等函数转来转去的。下面的代码用dynamic_rnn()创建了和前面一样的RNN。比较漂亮!

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)

以上就是关于“静态RNN和动态RNN的区别是什么”这篇文章的内容,相信大家都有了一定的了解,希望小编分享的内容对大家有帮助,若想了解更多相关的知识内容,请关注创新互联行业资讯频道。


网页标题:静态RNN和动态RNN的区别是什么
本文链接:http://myzitong.com/article/gigeop.html