Вычисление градиентов нового состояния (RNN) относительно параметров модели (включая CNN для входных данных) в тензорном потоке;tf.gradient return None - PullRequest
0 голосов
/ 08 февраля 2019

Резюме:

У меня есть 1d CNN, который извлекает функции из входов.Затем CNN следует за RNN.Я ищу способ обратного распространения градиентов от new_state RNN к параметрам CNN.Также мы можем рассмотреть извилистый слой с размером ядра [1, 1, input_num_features, output_num_features].Код ниже:

импортировать тензор потока как tf

mseed = 123
tf.set_random_seed(mseed)
kernel_initializer = tf.glorot_normal_initializer(seed=mseed)

# Graph Hyperparameters
cell_size = 64
num_classes = 2
m_dtype = tf.float32
num_features = 30

inputs_train_ph = tf.placeholder(dtype=m_dtype, shape=[None, 75, num_features], name="inputs_train_ph")
inputs_devel_ph = tf.placeholder(dtype=m_dtype, shape=[None, 75, num_features], name="inputs_devel_ph")

labels_train_ph = tf.placeholder(dtype=m_dtype, shape=[None, 75, num_classes], name="labels_train_ph")
labels_devel_ph = tf.placeholder(dtype=m_dtype, shape=[None, 75, num_classes], name="labels_devel_ph")

def return_inputs_train(): return inputs_train_ph
def return_inputs_devel(): return inputs_devel_ph
def return_labels_train(): return labels_train_ph
def return_labels_devel(): return labels_devel_ph

phase_train = tf.placeholder(tf.bool, shape=())
dropout = tf.placeholder(dtype=m_dtype, shape=())
initial_state = tf.placeholder(shape=[None, cell_size], dtype=m_dtype, name="initial_state")

inputs = tf.cond(phase_train, return_inputs_train, return_inputs_devel)
labels = tf.cond(phase_train, return_labels_train, return_labels_devel)

# Graph
def model(inputs):
    used = tf.sign(tf.reduce_max(tf.abs(inputs), 2))

    length = tf.reduce_sum(used, 1)
    length = tf.cast(length, tf.int32)

    with tf.variable_scope('layer_cell'):
        inputs = tf.layers.conv1d(inputs, filters=100, kernel_size=3, padding="same",
                                  kernel_initializer=tf.glorot_normal_initializer(seed=mseed))
        inputs = tf.layers.batch_normalization(inputs, training=phase_train, name="bn")
        inputs = tf.nn.relu(inputs)

    with tf.variable_scope('lstm_model'):

        cell = tf.nn.rnn_cell.GRUCell(cell_size, kernel_initializer=kernel_initializer)
        cell = tf.nn.rnn_cell.DropoutWrapper(cell, input_keep_prob=1.0 - dropout, state_keep_prob=1.0 - dropout)
        output, new_state = tf.nn.dynamic_rnn(cell, inputs, dtype=m_dtype, sequence_length=length,
                                              initial_state=initial_state)

    with tf.variable_scope("output"):
        output = tf.reshape(output, shape=[-1, cell_size])
        output = tf.layers.dense(output, units=num_classes,
                                 kernel_initializer=kernel_initializer)

        output = tf.reshape(output, shape=[5, -1, num_classes])
        used = tf.expand_dims(used, 2)

        output = output * used

    return output, new_state


output, new_state = model(inputs)

grads_new_state_wrt_vars = tf.gradients(new_state, tf.trainable_variables())
for g in grads_new_state_wrt_vars:
    print('**', g)

init_op = tf.global_variables_initializer()

with tf.Session() as sess:
    sess.run(init_op)

Обратите внимание, что когда я распечатывал тензоры градиентов, я получил следующее:

for g in grads_new_state_wrt_vars:
    print('**', g)

** None
** None
** None
** None
** Tensor("gradients/model/lstm_model/rnn/while/gru_cell/MatMul/Enter_grad/b_acc_3:0", shape=(220, 240), dtype=float64)
** Tensor("gradients/model/lstm_model/rnn/while/gru_cell/BiasAdd/Enter_grad/b_acc_3:0", shape=(240,), dtype=float64)
** Tensor("gradients/model/lstm_model/rnn/while/gru_cell/MatMul_1/Enter_grad/b_acc_3:0", shape=(220, 120), dtype=float64)
** Tensor("gradients/model/lstm_model/rnn/while/gru_cell/BiasAdd_1/Enter_grad/b_acc_3:0", shape=(120,), dtype=float64)
** None
** None

Наконецвесовые коэффициенты в сети указаны ниже:

for v in tf.trainable_variables():
    print(v.name)

model/conv1d/kernel:0
model/conv1d/bias:0
model/bn/gamma:0
model/bn/beta:0
model/lstm_model/rnn/gru_cell/gates/kernel:0
model/lstm_model/rnn/gru_cell/gates/bias:0
model/lstm_model/rnn/gru_cell/candidate/kernel:0
model/lstm_model/rnn/gru_cell/candidate/bias:0
model/output/dense/kernel:0
model/output/dense/bias:0

Следовательно, как получается, что градиенты не могут быть вычислены по отношению к весам слоев первого контура и пакетной нормы в сети?

Обратите внимание, что у меня нет той же проблемы при замене new_state на output в tf.gradients(new_state, tf.trainable_variables())

Любая помощь очень ценится !!

Редактировать

Я обнаружил, что если я изменю None на placeholders, определенный выше, проблема будет решена.И я получил градиенты new_state по сравнению со слоями конвона.Это будет работать до тех пор, пока определенный размер партии будет одинаковым как для поезда, так и для уровня placeholders, например:

inputs_train_ph = tf.placeholder(dtype=m_dtype, shape=[34, 75, num_features], name="inputs_train_ph")
inputs_devel_ph = tf.placeholder(dtype=m_dtype, shape=[34, 75, num_features], name="inputs_devel_ph")

labels_train_ph = tf.placeholder(dtype=m_dtype, shape=[34, 75, num_classes], name="labels_train_ph")
labels_devel_ph = tf.placeholder(dtype=m_dtype, shape=[34, 75, num_classes], name="labels_devel_ph")

В противном случае я снова столкнусь с ошибкой.

Пожалуйстаобратите внимание, что на градиенты выходного слоя wvt conv не влияет None для размера пакета в placeholders, определенном выше.

Теперь я хотел бы знать, почему я получаю эту ошибкуесли бы я не изменил None на batch_size?

1 Ответ

0 голосов
/ 12 февраля 2019

Я не уверен, является ли это точным ответом на ваш вопрос, но это может быть хорошим началом, так как кажется, что вашей проблеме не уделяется много внимания (и, ну, я не удивлен этимколичество путаницы).

Кроме того, есть тонны вопросов (слишком много для комментариев), которые могут возникнуть и у других, поэтому я приведу их здесь (и постараюсь дать ответ на имеющуюся ситуацию).

Версия Tensorflow: 1.12

1.Нет градиентов

Эта проблема не существует ни для output, ни для new_state , когда batch_size не указан .

  • Градиенты относительно new_state, например, grads_new_state_wrt_vars = tf.gradients(new_state, tf.trainable_variables()) возврат:

    ** Tensor("gradients/layer_cell/conv1d/BiasAdd_grad/BiasAddGrad:0", shape=(100,), dtype=float32)
    ** Tensor("gradients/layer_cell/bn/batchnorm/mul_grad/Mul_1:0", shape=(100,), dtype=float32)
    ** Tensor("gradients/layer_cell/bn/batchnorm/add_1_grad/Reshape_1:0", shape=(100,), dtype=float32)
    ** Tensor("gradients/lstm_model/rnn/while/gru_cell/MatMul/Enter_grad/b_acc_3:0", shape=(164, 128), dtype=float32)
    ** Tensor("gradients/lstm_model/rnn/while/gru_cell/BiasAdd/Enter_grad/b_acc_3:0", shape=(128,), dtype=float32)
    ** Tensor("gradients/lstm_model/rnn/while/gru_cell/MatMul_1/Enter_grad/b_acc_3:0", shape=(164, 64), dtype=float32)
    ** Tensor("gradients/lstm_model/rnn/while/gru_cell/BiasAdd_1/Enter_grad/b_acc_3:0", shape=(64,), dtype=float32)
    ** None
    ** None
    

    как ожидается (поскольку он не проходит через Dense часть вашей сети).

  • Градиенты относительно output_state, например, grads_new_state_wrt_vars = tf.gradients(output_state, tf.trainable_variables()) возврат:

    ** Tensor("gradients/layer_cell/conv1d/BiasAdd_grad/BiasAddGrad:0", shape=(100,), dtype=float32)                                                                                           
    ** Tensor("gradients/layer_cell/bn/batchnorm/mul_grad/Mul_1:0", shape=(100,), dtype=float32)
    ** Tensor("gradients/layer_cell/bn/batchnorm/add_1_grad/Reshape_1:0", shape=(100,), dtype=float32)                                                                                         
    ** Tensor("gradients/lstm_model/rnn/while/gru_cell/MatMul/Enter_grad/b_acc_3:0", shape=(164, 128), dtype=float32)                                                                          
    ** Tensor("gradients/lstm_model/rnn/while/gru_cell/BiasAdd/Enter_grad/b_acc_3:0", shape=(128,), dtype=float32)                                                                             
    ** Tensor("gradients/lstm_model/rnn/while/gru_cell/MatMul_1/Enter_grad/b_acc_3:0", shape=(164, 64), dtype=float32)                                                                         
    ** Tensor("gradients/lstm_model/rnn/while/gru_cell/BiasAdd_1/Enter_grad/b_acc_3:0", shape=(64,), dtype=float32)                                                                            
    ** Tensor("gradients/output/dense/MatMul_grad/MatMul_1:0", shape=(64, 2), dtype=float32)
    ** Tensor("gradients/output/dense/BiasAdd_grad/BiasAddGrad:0", shape=(2,), dtype=float32)
    

    Еще раз, все в порядке.

2.Указание размера партии

Когда размер партии указан, как вы описали, например,

inputs_train_ph = tf.placeholder(dtype=m_dtype, shape=[34, 75, num_features], name="inputs_train_ph")
inputs_devel_ph = tf.placeholder(dtype=m_dtype, shape=[34, 75, num_features], name="inputs_devel_ph")

ваша сеть НЕ работает вообще, и это не страннотак как ваши фигуры не совпадают в выходном пространстве имен.

Кроме того, labels_devel_ph и labels_train_ph не имеют значения для рассматриваемого кода, зачем размещать их здесь, они просто загромождают вопрос еще дальше.См. Минимальный, полный и проверяемый пример , существует множество деталей, совершенно не необходимых для рассматриваемой задачи.

Далее, нет связи между партиямиформа inputs_train_ph и inputs_devel_ph, с чего бы это?Один не зависит от другого, и только один используется одновременно из-за tf.cond (который должен быть указан как значение при запуске сеанса, но это выходит за рамки этого вопроса).

Проблемный выводчасть, именно это:

output = tf.reshape(output, shape=[5, -1, num_classes])
used = tf.expand_dims(used, 2)

output = output * used

Тензорные формы, используя ваш подход:

Output shape: (5, 480, 2)                                                                                                                          
Used initial shape: (32, 75) 
Used after expand_dims: (32, 75, 1)

Очевидно, (5, 480, 2), умноженное на (32, 75, 1), не будет работать, я не вижу возможности этой работы когда-либо, даже с Tensorflow в пре-альфа-версии, что заставляет меня думать, что другие части вашего исходного кода заставляют его работать, и кто знает, что еще влияет на него, если честно.

Проблема с used может быть решенанесколькими способами, но я думаю, что вы хотели, чтобы сложить used в другое измерение и изменить его впоследствии ( это не будет работать без изменения ):

output = tf.reshape(output, shape=[5, -1, num_classes])
used = tf.stack((used, used), 2)
used = tf.reshape(used, shape=(5, -1, num_classes))

output = output * used

Используя этот подход, каждая форма партии проходит через сеть без проблем.

Кстати. Я не совсем уверен, чего вы пытаетесь достичь с помощью used в начале eЕще, но, возможно, у вас есть вариант использования, IMO намерение полностью нечитаемо по сравнению с конечным результатом (столбцы, содержащие нули, когда все объекты в последовательности равны нулю, и один в противном случае).

3.Версии Tensorflow

Протестировано с версией 1.8 версии Tensorflow (ток 1.12 и 2.0 за углом) и Мне удалось воспроизвести вашу проблему.

Тем не менее, выходные формы сбои, как описано выше, хотя.

На самом деле, версия 1.9 уже имеет эту проблему решена.

Почему существует эта проблемав 1.8?

Я пытался определить возможную причину, но я все еще не знаю.Некоторые идеи:

  • Использование tf.layers вместо tf.nn.Так как планируется для версии 2.0 , этот модуль будет устаревшим, и из-за большого количества ошибок в фреймворке, я предположил, что что-то может быть не так и в этом случае.Я изменил conv1d на tf.keras.layers аналог и нормализацию партии на tf.nn.batch_normalization, но безрезультатно, к сожалению, результаты все те же.

  • Согласно версии 1.9ноты Prevent tf.gradients() from backpropagating through integer tensors.Может быть, это как-то связано с вашей проблемой?Может быть, график обратного распространения как-то застрял в v1.8.0?

  • Проблемы с областью действия tf.variable_scope и tf.layers - как и ожидалось, ничего не изменилось после удаления пространств имен.

В целом: обновите ваши зависимости до версии 1.9 или выше, это решит все ваши проблемы (хотя почему они возникают, довольно сложно понять, как и этот фреймворк).

На самом деле, мне кажется, что такие изменения происходят между второстепенными версиями и не описаны более подробно в журнале изменений, но, возможно, я упускаю что-то большое ...

Немного-topic

Может быть, вам следует рассмотреть возможность использования tf.Estimator, tf.keras или другого фреймворка, такого как PyTorch?Этот код крайне нечитабелен, труден для отладки и уродлив, существуют новые методы, и они должны помочь вам и нам (если у вас есть другая проблема с нейронными сетями и вы решите обратиться в StackOverflow)

...