web-dev-qa-db-ja.com

TensorFlowでdynamic_rnnの最後の出力を取得します

形状の3Dテンソル[batch, None, dim]ここで、2番目の次元、つまりタイムステップは不明です。私が使う dynamic_rnn次のスニペットのように、このような入力を処理します。

import numpy as np
import tensorflow as tf

batch = 2
dim = 3
hidden = 4

lengths = tf.placeholder(dtype=tf.int32, shape=[batch])
inputs = tf.placeholder(dtype=tf.float32, shape=[batch, None, dim])
cell = tf.nn.rnn_cell.GRUCell(hidden)
cell_state = cell.zero_state(batch, tf.float32)
output, _ = tf.nn.dynamic_rnn(cell, inputs, lengths, initial_state=cell_state)

実際、これをいくつかの実際の数値で省略して実行すると、合理的な結果が得られます。

inputs_ = np.asarray([[[0, 0, 0], [1, 1, 1], [2, 2, 2], [3, 3, 3]],
                    [[6, 6, 6], [7, 7, 7], [8, 8, 8], [9, 9, 9]]],
                    dtype=np.int32)
lengths_ = np.asarray([3, 1], dtype=np.int32)

with tf.Session() as sess:
    sess.run(tf.global_variables_initializer())
    output_ = sess.run(output, {inputs: inputs_, lengths: lengths_})
    print(output_)

そして出力は:

[[[ 0.          0.          0.          0.        ]
  [ 0.02188676 -0.01294564  0.05340237 -0.47148666]
  [ 0.0343586  -0.02243731  0.0870839  -0.89869428]
  [ 0.          0.          0.          0.        ]]

 [[ 0.00284752 -0.00315077  0.00108094 -0.99883419]
  [ 0.          0.          0.          0.        ]
  [ 0.          0.          0.          0.        ]
  [ 0.          0.          0.          0.        ]]]

形状の3Dテンソルを取得する方法はありますか[batch, 1, hidden] ---動的RNNの最後の関連出力を使用しますか?ありがとう!

16
petrux

これが gather_nd の目的です!

def extract_axis_1(data, ind):
    """
    Get specified elements along the first axis of tensor.
    :param data: Tensorflow tensor that will be subsetted.
    :param ind: Indices to take (one for each element along axis 0 of data).
    :return: Subsetted tensor.
    """

    batch_range = tf.range(tf.shape(data)[0])
    indices = tf.stack([batch_range, ind], axis=1)
    res = tf.gather_nd(data, indices)

    return res

あなたの場合:

output = extract_axis_1(output, lengths - 1)

現在、outputは次元[batch_size, num_cells]のテンソルです。

14
Alex

次の2つのソースから、

http://www.wildml.com/2016/08/rnns-in-tensorflow-a-practical-guide-and-undocumented-features/

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

または https://github.com/ageron/handson-ml/blob/master/14_recurrent_neural_networks.ipynb

Last_statesをdynamic_rnn呼び出しの2番目の出力から直接抽出できることは明らかです。 allレイヤー全体でlast_statesを提供します(LSTMでは、LSTMStateTupleから構成されます)一方で、出力にはlastレイヤー。

8
Shao Tang

わかりました—なので、実際にあるように見えます です より簡単な解決策。 @Shao Tangと@Rahulが述べたように、これを行う好ましい方法は、最終的なセルの状態にアクセスすることです。その理由は次のとおりです。

  • GRUCellソースコード(下記)を見ると、セルが保持する「状態」が実際には非表示の重みそのものであることがわかります。したがって、tf.nn.dynamic_rnnは最終的な状態を返します。実際には、関心のある最終的な非表示の重みが返されます。これを証明するために、設定を微調整して結果を得ました。

GRUCell呼び出し(rnn_cell_impl.py):

def call(self, inputs, state):
"""Gated recurrent unit (GRU) with nunits cells."""
if self._gate_linear is None:
      bias_ones = self._bias_initializer
if self._bias_initializer is None:
        bias_ones = init_ops.constant_initializer(1.0, dtype=inputs.dtype)
with vs.variable_scope("gates"):  # Reset gate and update gate.
self._gate_linear = _Linear(
            [inputs, state],
2 * self._num_units,
True,
bias_initializer=bias_ones,
kernel_initializer=self._kernel_initializer)
    value = math_ops.sigmoid(self._gate_linear([inputs, state]))
    r, u = array_ops.split(value=value, num_or_size_splits=2, axis=1)
    r_state = r * state
if self._candidate_linear is None:
with vs.variable_scope("candidate"):
self._candidate_linear = _Linear(
            [inputs, r_state],
self._num_units,
True,
bias_initializer=self._bias_initializer,
kernel_initializer=self._kernel_initializer)
    c = self._activation(self._candidate_linear([inputs, r_state]))
    new_h = u * state + (1 - u) * c
return new_h, new_h

解決:

import numpy as np
import tensorflow as tf

batch = 2
dim = 3
hidden = 4

lengths = tf.placeholder(dtype=tf.int32, shape=[batch])
inputs = tf.placeholder(dtype=tf.float32, shape=[batch, None, dim])
cell = tf.nn.rnn_cell.GRUCell(hidden)
cell_state = cell.zero_state(batch, tf.float32)
output, state = tf.nn.dynamic_rnn(cell, inputs, lengths, initial_state=cell_state)

inputs_ = np.asarray([[[0, 0, 0], [1, 1, 1], [2, 2, 2], [3, 3, 3]],
                    [[6, 6, 6], [7, 7, 7], [8, 8, 8], [9, 9, 9]]],
                    dtype=np.int32)
lengths_ = np.asarray([3, 1], dtype=np.int32)

with tf.Session() as sess:
    sess.run(tf.global_variables_initializer())
    output_, state_ = sess.run([output, state], {inputs: inputs_, lengths: lengths_})
    print (output_)
    print (state_)

出力:

[[[ 0.          0.          0.          0.        ]
  [-0.24305521 -0.15512943  0.06614969  0.16873555]
  [-0.62767833 -0.30741733  0.14819752  0.44313088]
  [ 0.          0.          0.          0.        ]]

 [[-0.99152333 -0.1006391   0.28767768  0.76360202]
  [ 0.          0.          0.          0.        ]
  [ 0.          0.          0.          0.        ]
  [ 0.          0.          0.          0.        ]]]
[[-0.62767833 -0.30741733  0.14819752  0.44313088]
 [-0.99152333 -0.1006391   0.28767768  0.76360202]]
  • LSTMCell(別の一般的なオプション)を使用している他の読者の場合、状況は少し異なります。 LSTMCellは、異なる方法で状態を維持します。セル状態は、タプルまたは実際のセル状態と非表示状態の連結バージョンです。したがって、最終的な非表示の重みにアクセスするには、(is_state_Tuple to True)はセルの初期化中に行われ、最終状態はタプルになります(最終的なセルの状態、最終的な非表示の重み)。したがって、この場合、

    _、(_、h)= tf.nn.dynamic_rnn(セル、入力、長さ、初期状態=セル状態)

最終的な重みを与えます。

参照: Tensorflow LSTMのc_stateおよびm_statehttps://github.com/tensorflow/tensorflow/blob/438604fc885208ee05f9eef2d0f2c630e1360a83/tensorflow/python/ops/rnn_cell_impl.py#L308 - https://github.com/tensorflow/tensorflow/blob/438604fc885208ee05f9eef2d0f2c630e1360a83/tensorflow/python/ops/rnn_cell_impl.py#L415

4
Sushant Kafle

実際、解決策はそれほど難しくありませんでした。次のコードを実装しました。

slices = []
for index, l in enumerate(tf.unstack(lengths)):
    slice = tf.slice(rnn_out, begin=[index, l - 1, 0], size=[1, 1, 3])
    slices.append(slice)
last = tf.concat(0, slices)

したがって、完全なスニペットは次のようになります。

import numpy as np
import tensorflow as tf

batch = 2
dim = 3
hidden = 4

lengths = tf.placeholder(dtype=tf.int32, shape=[batch])
inputs = tf.placeholder(dtype=tf.float32, shape=[batch, None, dim])
cell = tf.nn.rnn_cell.GRUCell(hidden)
cell_state = cell.zero_state(batch, tf.float32)
output, _ = tf.nn.dynamic_rnn(cell, inputs, lengths, initial_state=cell_state)

inputs_ = np.asarray([[[0, 0, 0], [1, 1, 1], [2, 2, 2], [3, 3, 3]],
                    [[6, 6, 6], [7, 7, 7], [8, 8, 8], [9, 9, 9]]],
                    dtype=np.int32)
lengths_ = np.asarray([3, 1], dtype=np.int32)

slices = []
for index, l in enumerate(tf.unstack(lengths)):
    slice = tf.slice(output, begin=[index, l - 1, 0], size=[1, 1, 3])
    slices.append(slice)
last = tf.concat(0, slices)

with tf.Session() as sess:
    sess.run(tf.global_variables_initializer())
    outputs = sess.run([output, last], {inputs: inputs_, lengths: lengths_})
    print 'RNN output:'
    print(outputs[0])
    print
    print 'last relevant output:'
    print(outputs[1])

そして出力:

RNN output:
[[[ 0.          0.          0.          0.        ]
 [-0.06667092 -0.09284072  0.01098599 -0.03676109]
 [-0.09101103 -0.19828682  0.03546784 -0.08721405]
 [ 0.          0.          0.          0.        ]]

[[-0.00025157 -0.05704876  0.05527233 -0.03741353]
 [ 0.          0.          0.          0.        ]
 [ 0.          0.          0.          0.        ]
 [ 0.          0.          0.          0.        ]]]

last relevant output:
[[[-0.09101103 -0.19828682  0.03546784]]

 [[-0.00025157 -0.05704876  0.05527233]]]
2
petrux