tf.nn.dynamic_rnn和tf.nn.static_rnn

2022-10-09 07:59:49

为什么会有tf.nn.dynamic_rnn和tf.nn.static_rnn,首先理解time_step是干什么的。

1. 首先理解time_step

举例说明:

  • 文字数据
    如果数据有1000段时序的句子,每句话有25个字,对每个字进行向量化,每个字的向量维度为300,那么batch_size=1000time_steps=25input_size=300
    解析:time_steps一般情况下就是等于句子的长度,input_size等于字量化后向量的长度。
  • 图片数据
    拿MNIST手写数字集来说,训练数据有6000个手写数字图像,每个数字图像大小为28*28,batch_size=6000time_steps=28input_size=28,我们可以理解为把图片图片分成28份,每份shape=(1, 28)。

2. 解释为什么出现dynamic_rnn和static_rnn

在tensorflow中,可以通过tf.nn.rnn_cell.BasicLSTMCell构建LSTM,最常使用的参数是num_units,表示的是LSTM中隐含状态的维度。

lstm_cell=tf.nn.rnn_cell.BasicLSTMCell(num_units=hidden_size)

LSTM的输入不仅有数据输入,还有前一个时刻的状态输入,因此需要初始化输入状态。

initial_state=lstm_cell.zero_state(batch_size,dtype=tf.float32)

构建多层LSTM,其中hidden_layer_num为LSTM的层数

cell = tf.nn.rnn_cell.MultiRNNCell([lstm_cell]*hidden_layer_num)

构建LSTM完整代码如下:

import tensorflowas tfimport numpyas np
 
batch_size=2
hidden_size=64
num_steps=10
input_dim=8input=np.random.randn(batch_size,num_steps,input_dim)input[1,6:]=0
x=tf.placeholder(dtype=tf.float32,shape=[batch_size,num_steps,input_dim],name='input_x')
lstm_cell=tf.nn.rnn_cell.BasicLSTMCell(num_units=hidden_size)
initial_state=lstm_cell.zero_state(batch_size,dtype=tf.float32)
 
outputs=[]with tf.variable_scope('RNN'):for iinrange(num_steps):if i>0:# print(tf.get_variable_scope())
            tf.get_variable_scope().reuse_variables()
 
        output=lstm_cell(x[:,i,:],initial_state)
        outputs.append(output)

从上面可以看出,要想获得num_steps后的output结果,需要for循环进行迭代。此时可以通过dynamic_rnn和static_rnn两个函数进行简化,让他们去做循环的工作。

tf.nn.static_rnn(
    cell,
    inputs,
    initial_state=None,
    dtype=None,
    sequence_length=None,
    scope=None
)
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
)

总结:基础的RNNCell有一个很明显的问题:对于单个的RNNCell,使用它的call函数进行运算时,只是在序列时间上前进了一个step。比如使用x1、h0得到h1,通过x2、h1得到h2等。这样的话,如果序列长度为10,就要调用10次call函数,比较麻烦。对此,TensorFlow提供了一个tf.nn.dynamic_rnn和tf.nn.static_rnn函数,使用该函数就相当于调用了n次call函数。即通过{h0,x1, x2, …., xn}直接得{h1,h2…,hn}。

3. dynamic_rnn和static_rnn对比

dynamic_rnnstatic_rnn
input shape【batch_size,time_step(序列长度),input-dim】【time_steps,batch_size,input_dim】
output shape【batch_size,n_steps,n_hidden】【n_steps,batch_size,n_hidden
time_step是否可以不同可以不可以

其中,需要注意

  1. tf.nn.dynamic_rnn对应最后的输出shape是【batch_size,n_steps,n_hidden】,因此若要输出对应最后的output,我们必须要进行转置,即tf.transpose(output,[1,0,2])。此时对应输出output[-1]才是对应最终的输出。
    特别注意:对应dyanmic_rnn里有个参数是time_major,如果设置对应为true,则我们对应输入为【time_step,batch_size,input_dim】,对应输出也是如此;而如果设置为false,则对应我们如下的代码不需要改动
#在此假设输入的mnist数据X_in对应为【batch_size,time_steps,input_dim】,则对应lstm的构建为
cell= tf.nn.rnn_cell.BasicLSTMCell(n_hidden_units,forget_bias=1.0,state_is_tuple=True)
init_state= cell.zero_state(batch_size,dtype=tf.float32)
outputs,final_state= tf.nn.dynamic_rnn(cell,X_in,initial_state=init_state,time_major=False)#对应若是要取最后的数据,则需要进行转置,将n_steps维度提到前面来
outputs= tf.transpose(outputs,[1,0,2])
last_output= outputs[-1]
  1. tf.nn.static_rnn的input输入需要是一个list,也就是说是一个【】形式,每个list对应的都是一个time_steps(序列)。输出shape对应为【n_steps,batch_size,n_hidden】,因此对应输出最后一个output[-1]即为我们需要的值。
'''还有一种方法,可以转换为list(忽略其中的加入输入层部分)
_X = tf.transpose(_X, [1, 0, 2])  # permute n_steps and batch_size   
_X = tf.reshape(_X, [-1, n_inputs])  # (n_steps*batch_size, n_input)   
_X = tf.matmul(_X, weights['in']) + biases['in']    
lstm_cell =tf.nn.rnn_cell.BasicLSTMCell(n_hidden_unis, forget_bias=1.0)    _init_state=lstm_cell.zero_state(batch_size,dtype=tf.float32)    
_X = tf.split(_X, n_step,0 )  # n_steps * (batch_size, n_hidden)   #得到我们对应想要的list
##上方的axis 默认是为0的 所以可写可不写
 outputs, states =tf.nn.static_rnn(lstm_cell, _X, initial_state=_init_state)
'''input=tf.unstack(x,time_steps,1)
lstm_layer=rnn.BasicLSTMCell(num_units,forget_bias=1)
outputs,_=rnn.static_rnn(lstm_layer,input,dtype="float32")
  • 作者:Blessy_Zhu
  • 原文链接:https://blog.csdn.net/weixin_42555080/article/details/121214607
    更新时间:2022-10-09 07:59:49