tf.nn.dynamic_rnn的输出outputs和state含义

一、 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
)

 

 tf.nn.dynamic_rnn的返回值有两个:outputs和state

为了描述输出的形状,先介绍几个变量,batch_size是输入的这批数据的数量,max_time就是这批数据中序列的最长长度,如果输入的三个句子,那max_time对应的就是最长句子的单词数量,cell.output_size其实就是rnn cell中神经元的个数。

  • outputs. outputs是一个tensor
    • 如果time_major==True,outputs形状为 [max_time, batch_size, cell.output_size ](要求rnn输入与rnn输出形状保持一致)
    • 如果time_major==False(默认),outputs形状为 [ batch_size, max_time, cell.output_size ]
  • state. state是一个tensor。state是最终的状态,也就是序列中最后一个cell输出的状态。一般情况下state的形状为 [batch_size, cell.output_size ],但当输入的cell为BasicLSTMCell时,state的形状为[2,batch_size, cell.output_size ],其中2也对应着LSTM中的cell state和hidden state

那为什么state输出形状会有变化呢?state和output又有什么关系呢?

二、state含义

对于第一问题“state”形状为什么会发生变化呢?

我们以LSTM和GRU分别为tf.nn.dynamic_rnn的输入cell类型为例,当cell为LSTM,state形状为[2,batch_size, cell.output_size ];当cell为GRU时,state形状为[batch_size, cell.output_size ]。其原因是因为LSTM和GRU的结构本身不同,如下面两个图所示,这是LSTM的cell结构,每个cell会有两个输出:Ct 和 ht,上面这个图是输出Ct,代表哪些信息应该被记住哪些应该被遗忘; 下面这个图是输出ht,代表这个cell的最终输出,LSTM的state是由Ct 和 ht组成的。

tf.nn.dynamic_rnn的输出outputs和state含义_第1张图片

tf.nn.dynamic_rnn的输出outputs和state含义_第2张图片

当cell为GRU时,state就只有一个了,原因是GRU将Ct 和 ht进行了简化,将其合并成了ht,如下图所示,GRU将遗忘门和输入门合并成了更新门,另外cell不在有细胞状态cell state,只有hidden state。

tf.nn.dynamic_rnn的输出outputs和state含义_第3张图片

对于第二个问题outputs和state有什么关系?

结论上来说,如果cell为LSTM,那 state是个tuple,分别代表Ct 和 ht,其中 ht与outputs中的对应的最后一个时刻的输出相等,假设state形状为[ 2,batch_size, cell.output_size ],outputs形状为 [ batch_size, max_time, cell.output_size ],那么state[ 1, batch_size, : ] == outputs[ batch_size, -1, : ];如果cell为GRU,那么同理,state其实就是 ht,state ==outputs[ -1 ]

 

三、实验

我们写点代码来具体感觉下outputs和state是什么,代码如下

import tensorflow as tf
import numpy as np

def dynamic_rnn(rnn_type='lstm'):
    # 创建输入数据,3代表batch size,6代表输入序列的最大步长(max time),8代表每个序列的维度
    X = np.random.randn(3, 6, 4)

    # 第二个输入的实际长度为4
    X[1, 4:] = 0

    #记录三个输入的实际步长
    X_lengths = [6, 4, 6]

    rnn_hidden_size = 5
    if rnn_type == 'lstm':
        cell = tf.contrib.rnn.BasicLSTMCell(num_units=rnn_hidden_size, state_is_tuple=True)
    else:
        cell = tf.contrib.rnn.GRUCell(num_units=rnn_hidden_size)

    outputs, last_states = tf.nn.dynamic_rnn(
        cell=cell,
        dtype=tf.float64,
        sequence_length=X_lengths,
        inputs=X)

    with tf.Session() as session:
        session.run(tf.global_variables_initializer())
        o1, s1 = session.run([outputs, last_states])
        print(np.shape(o1))
        print(o1)
        print(np.shape(s1))
        print(s1)


if __name__ == '__main__':
    dynamic_rnn(rnn_type='lstm')

实验一:cell类型为LSTM,我们看看输出是什么样子,如下图所示,输入的形状为 [ 3, 6, 4 ],经过tf.nn.dynamic_rnn后outputs的形状为 [ 3, 6, 5 ],state形状为 [ 2, 3, 5 ],其中state第一部分为c,代表cell state;第二部分为h,代表hidden state。可以看到hidden state 与 对应的outputs的最后一行是相等的。另外需要注意的是输入一共有三个序列,但第二个序列的长度只有4,可以看到outputs中对应的两行值都为0,所以hidden state对应的是最后一个不为0的部分。tf.nn.dynamic_rnn通过设置sequence_length来实现这一逻辑。

(3, 6, 5)
[[[ 0.0146346  -0.04717453 -0.06930042 -0.06065602  0.02456717]
  [-0.05580321  0.08770171 -0.04574306 -0.01652854 -0.04319528]
  [ 0.09087799  0.03535907 -0.06974291 -0.03757408 -0.15553619]
  [ 0.10003044  0.10654698  0.21004055  0.13792148 -0.05587583]
  [ 0.13547596 -0.014292   -0.0211154  -0.10857875  0.04461256]
  [ 0.00417564 -0.01985144  0.00050634 -0.13238986  0.14323784]]

 [[ 0.04893576  0.14289175  0.17957205  0.09093887 -0.0507192 ]
  [ 0.17696126  0.09929577  0.21185635  0.20386451  0.11664373]
  [ 0.15658667  0.03952745 -0.03425637  0.00773833 -0.03546742]
  [-0.14002582 -0.18578786 -0.08373584 -0.25964601  0.04090167]
  [ 0.          0.          0.          0.          0.        ]
  [ 0.          0.          0.          0.          0.        ]]

 [[ 0.18564152  0.01531695  0.13752453  0.17188506  0.19555427]
  [ 0.13703949  0.14272294  0.21313036  0.07417354  0.0477547 ]
  [ 0.23021792  0.04455495  0.10204565  0.17159792  0.34148467]
  [ 0.0386402   0.0387848   0.02134559  0.00110381  0.08414687]
  [ 0.01386241 -0.02629686 -0.0733538  -0.03194245  0.13606553]
  [ 0.01859433 -0.00585316 -0.04007138  0.03811594  0.21708331]]]
(2, 3, 5)
LSTMStateTuple(c=array([[ 0.00909146, -0.03747076,  0.0008946 , -0.23459786,  0.29565899],
       [-0.18409266, -0.30463044, -0.28033809, -0.49032542,  0.12597639],
       [ 0.04494702, -0.01359631, -0.06706629,  0.06766361,  0.40794032]]), h=array([[ 0.00417564, -0.01985144,  0.00050634, -0.13238986,  0.14323784],
       [-0.14002582, -0.18578786, -0.08373584, -0.25964601,  0.04090167],
       [ 0.01859433, -0.00585316, -0.04007138,  0.03811594,  0.21708331]]))

实验二:cell类型为GRU,我们看看输出是什么样子,如下图所示,输入的形状为 [ 3, 6, 4 ],经过tf.nn.dynamic_rnn后outputs的形状为 [ 3, 6, 5 ],state形状为 [ 3, 5 ]。可以看到 state 与 对应的outputs的最后一行是相等的。

(3, 6, 5)
[[[-0.05190962 -0.13519617  0.02045928 -0.0821183   0.28337528]
  [ 0.0201574   0.03779418 -0.05092804  0.02958051  0.12232347]
  [ 0.14884441 -0.26075898  0.1821795  -0.03454954  0.18424161]
  [-0.13854156 -0.26565378  0.09567164 -0.03960079  0.14000589]
  [-0.2605973  -0.39901657  0.12495693 -0.19295695  0.52423598]
  [-0.21596414 -0.63051687  0.20837501 -0.31775378  0.77519457]]

 [[-0.1979659  -0.30253523  0.0248779  -0.17981144  0.41815343]
  [ 0.34481129 -0.05256187  0.1643036   0.00739746  0.27384158]
  [ 0.49703664  0.22241165  0.27344766  0.00093435  0.09854949]
  [ 0.23312444  0.156997    0.25482553  0.0138156  -0.02302272]
  [ 0.          0.          0.          0.          0.        ]
  [ 0.          0.          0.          0.          0.        ]]

 [[-0.06401732  0.08605342 -0.03936866 -0.02287695  0.16947652]
  [-0.1775206  -0.2801672  -0.0387468  -0.20264583  0.58125297]
  [ 0.39408762 -0.44066425  0.25826641 -0.18851604  0.36172166]
  [ 0.0536013  -0.29902928  0.08891931 -0.03930039  0.0743423 ]
  [ 0.02304702 -0.0612499   0.09113458 -0.05169013  0.29876455]
  [-0.06711324  0.014125   -0.05856332 -0.05632359 -0.00390189]]]
(3, 5)
[[-0.21596414 -0.63051687  0.20837501 -0.31775378  0.77519457]
 [ 0.23312444  0.156997    0.25482553  0.0138156  -0.02302272]
 [-0.06711324  0.014125   -0.05856332 -0.05632359 -0.00390189]]

 

Reference

http://colah.github.io/posts/2015-08-Understanding-LSTMs/

https://www.tensorflow.org/api_docs/python/tf/nn/dynamic_rnn

你可能感兴趣的:(深度学习)