Простой пример реализации RNN на основе CuDnnGRU в Tensorflow

Я использую следующий код для стандартной реализации GRU:

def BiRNN_deep_dynamic_FAST_FULL_autolength(x,batch_size,dropout,hidden_dim):

seq_len=length_rnn(x)

with tf.variable_scope('forward'):
    lstm_cell_fwd =tf.contrib.rnn.GRUCell(hidden_dim,kernel_initializer=tf.contrib.layers.xavier_initializer(),bias_initializer=tf.contrib.layers.xavier_initializer())
    lstm_cell_fwd = tf.contrib.rnn.DropoutWrapper(lstm_cell_fwd, output_keep_prob=dropout)
with tf.variable_scope('backward'):
    lstm_cell_back =tf.contrib.rnn.GRUCell(hidden_dim,kernel_initializer=tf.contrib.layers.xavier_initializer(),bias_initializer=tf.contrib.layers.xavier_initializer())
    lstm_cell_back = tf.contrib.rnn.DropoutWrapper(lstm_cell_back, output_keep_prob=dropout)

outputs,_= tf.nn.bidirectional_dynamic_rnn(cell_fw=lstm_cell_fwd,cell_bw= lstm_cell_back,inputs=x,sequence_length=seq_len,dtype=tf.float32,time_major=False)
outputs_fwd,outputs_bck=outputs

### fwd matrix is the matrix that keeps all the last [-1] vectors
fwd_matrix=tf.gather_nd(outputs_fwd, tf.stack([tf.range(batch_size), seq_len-1], axis=1))       ###  99,64

outputs_fwd=tf.transpose(outputs_fwd,[1,0,2])
outputs_bck=tf.transpose(outputs_bck,[1,0,2])

return outputs_fwd,outputs_bck,fwd_matrix

Может ли кто-нибудь предоставить простой пример использования ячейки tf.contrib.cudnn_rnn.CudnnGRU аналогичным образом? Просто поменять местами ячейки не получится.

Первая проблема заключается в том, что для ячейки CuDnnGRU нет обертки отсева, и это нормально. Во-вторых, похоже, что он не работает с tf.nn.bidirectional_dynamic_rnn. Любая помощь приветствуется.


person Thrabbit    schedule 08.03.2018    source источник


Ответы (1)


CudnnGRU не является экземпляром RNNCell. Это больше похоже на dynamic_rnn.

Приведенные ниже манипуляции с тензором эквивалентны, где input_tensor - главный тензор времени, то есть формы [max_sequence_length, batch_size, embedding_size]. CudnnGRU ожидает, что входной тензор будет мажорным по времени (в отличие от более стандартного пакетного мажорного формата, то есть формы [batch_size, max_sequence_length, embedding_size]), и в любом случае рекомендуется использовать мажорные по времени тензоры с операциями RNN, поскольку они несколько быстрее.

CudnnGRU:

rnn = tf.contrib.cudnn_rnn.CudnnGRU(
  num_rnn_layers, hidden_size, direction='bidirectional')

rnn_output = rnn(input_tensor)

CudnnCompatibleGRUCell:

rnn_output = input_tensor
sequence_length = tf.reduce_sum(
  tf.sign(inputs),
  reduction_indices=0)  # 1 if `input_tensor` is batch-major.

  for _ in range(num_rnn_layers):
    fw_cell = tf.contrib.cudnn_rnn.CudnnCompatibleGRUCell(hidden_size)
    bw_cell = tf.contrib.cudnn_rnn.CudnnCompatibleGRUCell(hidden_size)
    rnn_output = tf.nn.bidirectional_dynamic_rnn(
      fw_cell, bw_cell, rnn_output, sequence_length=sequence_length,
      dtype=tf.float32, time_major=True)[1]  # Set `time_major` accordingly

Обратите внимание на следующее:

  1. Если вы использовали LSTM, вам не нужно использовать CudnnCompatibleLSTMCell; можно использовать стандартный LSTMCell. Но с GRU реализация Cudnn по своей сути имеет другие математические операции и, в частности, больше весов (см. документацию).
  2. В отличие от dynamic_rnn, CudnnGRU не позволяет указывать длину последовательности. Тем не менее, это более чем на порядок быстрее, но вы должны быть осторожны с тем, как вы извлекаете свои выходные данные (например, если вас интересует окончательное скрытое состояние каждой последовательности, которая дополнена и имеет разную длину, вам понадобится длина каждой последовательности).
  3. rnn_output, вероятно, в обоих случаях представляет собой кортеж с большим количеством (разных) вещей. Обратитесь к документации или просто распечатайте ее, чтобы проверить, какие части вывода вам нужны.
person Daniel Watson    schedule 03.07.2018