Генерация последовательностей из скрытого пространства [pytorch]

У меня есть несколько вопросов о наилучшей практике использования рекуррентных сетей в pytorch для генерации последовательностей.

Первый, если я хочу построить сеть декодера, я должен использовать nn.GRU (или же nn.LSTM) вместо nn.LSTMCell (nn.GRUCell)? Из моего опыта, если я работаю с LSTMCell скорость расчетов значительно ниже (до 100 раз), чем если бы я использовал nn.LSTM, Может быть, это связано с оптимизацией cudnn для LSTM (а также GRU) модуль? Есть ли способ ускорить LSTMCell расчеты?

Я пытаюсь построить автоэнкодер, который принимает последовательности переменной длины. Мой автоэнкодер выглядит так:

class SimpleAutoencoder(nn.Module):
    def init(self, input_size, hidden_size, n_layers=3):
    super(SimpleAutoencoder, self).init()
    self.n_layers = n_layers
    self.hidden_size = hidden_size
    self.gru_encoder = nn.GRU(input_size, hidden_size,n_layers,batch_first=True)
    self.gru_decoder = nn.GRU(input_size, hidden_size, n_layers, batch_first=True)
    self.h2o = nn.Linear(hidden_size,input_size) # Hidden to output

def encode(self, input):
    output, hidden = self.gru_encoder(input, None)
    return output, hidden

def decode(self, input, hidden):
    output,hidden = self.gru_decoder(input,hidden)
    return output,hidden
def h2o_apply(self,input):
    return self.h2o(input)

Мой цикл тренировок выглядит так:

one_hot_batch = list(map(lambda x:Variable(torch.FloatTensor(x)),one_hot_batch))

packed_one_hot_batch = pack_padded_sequence(pad_sequence(one_hot_batch,batch_first=True).cuda(),batch_lens, batch_first=True)

 _, latent = vae.encode(packed_one_hot_batch)
 outputs, = vae.decode(packed_one_hot_batch,latent)
 packed = pad_packed_sequence(outputs,batch_first=True)

 for string,length,index in zip(*packed,range(batch_size)):
        decoded_string_without_sos_symbol = vae.h2o_apply(string[1:length])
        loss += criterion(decoded_string_without_sos_symbol,real_strings_batch[index][1:])
 loss /= len(batch)

Обучение в такой манере, насколько я понимаю, - это сила учителя. Потому что на этапе декодирования сеть подает реальные входы (outputs,_ = vae.decode(packed_one_hot_batch,latent)). Но для моей задачи это приводит к ситуации, когда на этапе тестирования сеть может очень хорошо генерировать последовательности, только если я использую реальные символы (как в режиме обучения), но если я передаю результаты предыдущего шага, сеть генерирует мусор (просто бесконечное повторение одного конкретного символа).

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

one_hot_batch_fake = list(map(lambda x:torch.ones_like(x).cuda(),one_hot_batch))
packed_one_hot_batch_fake = pack_padded_sequence(pad_sequence(one_hot_batch_fake, batch_first=True).cuda(), batch_lens, batch_first=True)

_, latent = vae.encode(packed_one_hot_batch)
outputs, = vae.decode(packed_one_hot_batch_fake,latent)
packed = pad_packed_sequence(outputs,batch_first=True)

Работает, но очень неэффективно, качество реконструкции очень низкое. Итак, второй вопрос, как правильно генерировать последовательности из латентного представления?

Я полагаю, что хорошей идеей является применение принуждения учителя с некоторой вероятностью, но для этого, как можно использовать слой nn.GRU, чтобы выходные данные предыдущего шага были входными данными для следующего шага?

0 ответов

Другие вопросы по тегам