在构建LSTM网络,要用到很重要的一个函数tf.nn.dynamic_rnn,今天就来介绍一下该函数的参数和作用。
先来看一下tf.nn.dynamic_rnn的定义:
tf.nn.dynamic_rnn(
cell,
inputs,
sequence_length=None,
initial_state=None,
dtype=None,
parallel_iterations=None,
swap_memory=False,
time_major=False,
scope=None
)
下面解释一下各个参数的含义,其中必要的参数只有三个,分别是cell、inputs、dtype(下文已加粗标明)。
cell:即在写代码时在前面所定义到的lstm_cell,通常的定义语法是:
cell = tf.contrib.rnn.BasicLSTMCell(num_units=n_neurons)
inputs:LSTM的输入。默认格式是[batch_size,num_step,vector_size]
其中,batch_size是输入的这批数据的数量;
num_step是这批数据序列最长的长度,也就是样本的序列长度(时间步长);vector_size(也经常写作input_size)是cell中神经元的个数,也是输入向量的维度。
sequence_length:Int32/Int64矢量大小。用于在超过批处理元素的序列长度时复制通过状态和零输出,会将超过的部分置零。因此,它更多的是为了性能而不是正确性。
例如,令 sequence_length为[3,2],其表示第一个采样数据的有效长度是3,第二个有效长度是2,当我们传入这个参数的时候,对于第二个batch,TensorFlow对于2以后的padding就不计算了,outputs中超过第2步的结果将会被置零。
dtype:数据类型。
parallel_iterations:并行运行的迭代次数。那些不具有任何时间依赖性并且可以并行运行的操作将是。这个参数用时间来交换空间。值>>1使用更多的内存,但花费的时间更少,而较小的值使用更少的内存,但计算需要更长的时间。
time_major:输入和输出tensor的形状格式。如果为True,这些张量的形状必须是[max_time,batch_size,depth]。如果为False,这些张量的形状必须是[batch_size,max_time,depth]。使用time_major=true会更有效率,因为它可以避免在RNN计算的开始和结束时进行换位。但是,大多数TensorFlow数据都是批处理主数据,因此默认情况下,此函数为False。
scope:创建的子图的可变作用域;默认为“RNN”。
tf.nn.dynamic_rnn(单层)代码示例:
(这里为了普遍性,用的是RNN,可以很容易的换成LSTM的)
import tensorflow as tf
import numpy as np
n_steps = 2
n_inputs = 3
n_neurons = 5
X = tf.placeholder(tf.float32, [None, n_steps, n_inputs])
basic_cell = tf.contrib.rnn.BasicRNNCell(num_units=n_neurons)
seq_length = tf.placeholder(tf.int32, [None])
outputs, states = tf.nn.dynamic_rnn(basic_cell, X, dtype=tf.float32,
sequence_length=seq_length)
init = tf.global_variables_initializer()
X_batch = np.array([
# step 0 step 1
[[0, 1, 2], [9, 8, 7]], # instance 1
[[3, 4, 5], [0, 0, 0]], # instance 2 (padded with zero vectors)
[[6, 7, 8], [6, 5, 4]], # instance 3
[[9, 0, 1], [3, 2, 1]], # instance 4
])
seq_length_batch = np.array([2, 1, 2, 2])
with tf.Session() as sess:
init.run()
outputs_val, states_val = sess.run(
[outputs, states], feed_dict={X: X_batch, seq_length: seq_length_batch})
print("outputs_val.shape:", outputs_val.shape, "states_val.shape:", states_val.shape)
print("outputs_val:", outputs_val, "states_val:", states_val)
得到如下输出:
outputs_val.shape: (4, 2, 5) states_val.shape: (4, 5)
outputs_val:
[[[ 0.53073734 -0.61281306 -0.5437517 0.7320347 -0.6109526 ]
[ 0.99996936 0.99990636 -0.9867181 0.99726075 -0.99999976]]
[[ 0.9931584 0.5877845 -0.9100412 0.988892 -0.9982337 ]
[ 0. 0. 0. 0. 0. ]]
[[ 0.99992317 0.96815354 -0.985101 0.9995968 -0.9999936 ]
[ 0.99948144 0.9998127 -0.57493806 0.91015154 -0.99998355]]
[[ 0.99999255 0.9998929 0.26732785 0.36024097 -0.99991137]
[ 0.98875254 0.9922327 0.6505734 0.4732064 -0.9957567 ]]]
states_val:
[[ 0.99996936 0.99990636 -0.9867181 0.99726075 -0.99999976]
[ 0.9931584 0.5877845 -0.9100412 0.988892 -0.9982337 ]
[ 0.99948144 0.9998127 -0.57493806 0.91015154 -0.99998355]
[ 0.98875254 0.9922327 0.6505734 0.4732064 -0.9957567 ]]
输入X的shape是[batch_size = 4, n_step = 2, input_size = 3],
outputs是最后一层每个step的输出,它的结构是[batch_size,step,n_neurons] = [4,2,5],states是每一层的最后那个step的输出。
本例中,我们的循环网络只有一个隐藏层,所以它就代表这一层的最后那个step的输出,因此它和step的大小是没有关系的,我们的X有4个样本组成,输出神经元大小n_neurons是5,因此states的结构就是[batch_size,n_neurons] = [4,5],最后我们观察数据,states的每条数据正好就是outputs的最后一个step的输出。
参考:
https://blog.csdn.net/weixin_44791964/article/details/98480738
https://blog.csdn.net/junjun150013652/article/details/81331448
https://blog.csdn.net/qq_35203425/article/details/79572514