Tensorflow dynamic_rnn распространяет nans для размера пакета больше 1 - PullRequest
0 голосов
/ 06 июня 2018

Надеясь, что кто-то может помочь мне понять проблему, с которой я сталкивался при использовании LSTM с dynamic_rnn в Tensorflow.В соответствии с этим MWE, когда у меня есть размер пакета 1 с последовательностями, которые являются неполными (я добавляю короткие тензоры к Nan, а не к нулям, чтобы выделить), все работает как обычно, Nan в коротких последовательностях игнорируется, как и ожидалось..

import tensorflow as tf
import numpy as np

batch_1 = np.random.randn(1, 10, 8)
batch_2 = np.random.randn(1, 10, 8)

batch_1[6:] = np.nan # lets make a short batch in batch 1 second sample of length 6 by padding with nans

seq_lengths_batch_1 = [6]
seq_lengths_batch_2 = [10]

tf.reset_default_graph()

input_vals = tf.placeholder(shape=[1, 10, 8], dtype=tf.float32)
lengths = tf.placeholder(shape=[1], dtype=tf.int32)

cell = tf.nn.rnn_cell.LSTMCell(num_units=5)
outputs, states  = tf.nn.dynamic_rnn(cell=cell, dtype=tf.float32, sequence_length=lengths, inputs=input_vals)
last_relevant_value = states.h
fake_loss = tf.reduce_mean(last_relevant_value)
optimizer = tf.train.AdamOptimizer(learning_rate=0.001).minimize(fake_loss)

sess = tf.InteractiveSession()
sess.run(tf.global_variables_initializer())
_, fl, lrv = sess.run([optimizer, fake_loss, last_relevant_value], feed_dict={input_vals: batch_1, lengths: seq_lengths_batch_1})
print(fl, lrv)
_, fl, lrv = sess.run([optimizer, fake_loss, last_relevant_value], feed_dict={input_vals: batch_2, lengths: seq_lengths_batch_2})
print(fl, lrv)

sess.close()

, который выводит правильно заполненные значения ilk ....

0.00659429 [[ 0.11608966  0.08498846 -0.02892204 -0.01945034 -0.1197343 ]]
-0.080244 [[-0.03018401 -0.18946587 -0.19128899 -0.10388547  0.11360413]]

Однако тогда, когда я увеличиваю свой размер пакета, например, до размера 3, выполняется первый пакет.правильно, но потом как-то вторая партия заставляет nans начать распространять

import tensorflow as tf
import numpy as np

batch_1 = np.random.randn(3, 10, 8)
batch_2 = np.random.randn(3, 10, 8)

batch_1[1, 6:] = np.nan 
batch_2[0, 8:] = np.nan 

seq_lengths_batch_1 = [10, 6, 10]
seq_lengths_batch_2 = [8, 10, 10]

tf.reset_default_graph()

input_vals = tf.placeholder(shape=[3, 10, 8], dtype=tf.float32)
lengths = tf.placeholder(shape=[3], dtype=tf.int32)

cell = tf.nn.rnn_cell.LSTMCell(num_units=5)
outputs, states  = tf.nn.dynamic_rnn(cell=cell, dtype=tf.float32, sequence_length=lengths, inputs=input_vals)
last_relevant_value = states.h
fake_loss = tf.reduce_mean(last_relevant_value)
optimizer = tf.train.AdamOptimizer(learning_rate=0.001).minimize(fake_loss)

sess = tf.InteractiveSession()
sess.run(tf.global_variables_initializer())
_, fl, lrv = sess.run([optimizer, fake_loss, last_relevant_value], feed_dict={input_vals: batch_1, lengths: seq_lengths_batch_1})
print(fl, lrv)
_, fl, lrv = sess.run([optimizer, fake_loss, last_relevant_value], feed_dict={input_vals: batch_2, lengths: seq_lengths_batch_2})
print(fl, lrv)

sess.close()

, давая

0.0533635 [[ 0.33622459 -0.0284576   0.11914439  0.14402215 -0.20783389]
 [ 0.20805927  0.17591488 -0.24977767 -0.03432769  0.2944448 ]
 [-0.04508523  0.11878576  0.07287208  0.14114542 -0.24467923]]
nan [[ nan  nan  nan  nan  nan]
 [ nan  nan  nan  nan  nan]
 [ nan  nan  nan  nan  nan]]

Я считаю это поведение довольно странным, так как я ожидала, что все значения после длин последовательности доигнорируется, как это происходит с размером пакета 1, но не работает с размером пакета 2 или более.

Очевидно, что nans не распространяется, если я использую 0 в качестве значения заполнения, но это не внушает мне уверенности в том, что dynamic_rnn функционирует так, как я ожидаю.

ТакжеЯ должен упомянуть, что если я удалю шаг оптимизации, проблема не возникнет, так что теперь я запутался и, после дня попыток многих различных перестановок, я не могу понять, почему размер партии будет иметь какое-то значение здесь

1 Ответ

0 голосов
/ 07 июня 2018

Я не проследил это до точной операции, но вот то, что, как я полагаю, имеет место.

Почему значения за пределами sequence_length не игнорируются? Они игнорируютсяв том смысле, что они умножаются на 0 (они маскируются) при выполнении некоторых операций.Математически результат всегда равен нулю, поэтому они не должны иметь никакого эффекта.К сожалению, nan * 0 = nan.Итак, если вы дадите nan значений в ваших примерах, они распространятся.Вы можете удивиться, почему TensorFlow не игнорирует их полностью, а только маскирует их.Причина в производительности на современном оборудовании.Гораздо проще выполнять операции с большой правильной формой с кучей нулей, чем с несколькими небольшими (что получается при разложении неправильной формы).

Почему это происходит только на второйbatch? В первом пакете потери и последнее скрытое состояние вычисляются с использованием исходных значений переменных.Они в порядке.Поскольку вы также выполняете обновление оптимизатора в sess.run(), переменные обновляются и становятся nan при первом вызове.Во втором вызове nan s из переменных распространяются на потери и скрытое состояние.

Как я могу быть уверен, что значения за пределами sequence_length действительно замаскированы? Я изменилВаш пример для воспроизведения проблемы, но также сделал ее детерминированной.

import tensorflow as tf
import numpy as np

batch_1 = np.ones((3, 10, 2))

batch_1[1, 7:] = np.nan

seq_lengths_batch_1 = [10, 7, 10]

tf.reset_default_graph()

input_vals = tf.placeholder(shape=[3, 10, 2], dtype=tf.float32)
lengths = tf.placeholder(shape=[3], dtype=tf.int32)

cell = tf.nn.rnn_cell.LSTMCell(num_units=3, initializer=tf.constant_initializer(1.0))
init_state = tf.nn.rnn_cell.LSTMStateTuple(*[tf.ones([3, c]) for c in cell.state_size])
outputs, states  = tf.nn.dynamic_rnn(cell=cell, dtype=tf.float32, sequence_length=lengths, inputs=input_vals,
        initial_state=init_state)
last_relevant_value = states.h
fake_loss = tf.reduce_mean(last_relevant_value)
optimizer = tf.train.AdamOptimizer(learning_rate=0.1).minimize(fake_loss)

with tf.Session() as sess:
    sess.run(tf.global_variables_initializer())
    for _ in range(1):
        _, fl, lrv = sess.run([optimizer, fake_loss, last_relevant_value],
                feed_dict={input_vals: batch_1, lengths: seq_lengths_batch_1})
        print "VARIABLES:", sess.run(tf.trainable_variables())
        print "LOSS and LAST HIDDEN:", fl, lrv

Если вы замените np.nan в batch_1[1, 7:] = np.nan на любое число (например, попробуйте -1M, 1M, 0), вы увидите, чтозначения, которые вы получаете, одинаковы.Вы также можете запустить цикл для большего количества итераций.В качестве дополнительной проверки работоспособности, если вы установите seq_lengths_batch_1 на что-то «неправильное», например, [10, 8, 10], вы увидите, что теперь значение, которое вы используете в batch_1[1, 7:] = np.nan, влияет на вывод.

...