Разница между этими реализациями LSTM Autoencoder?

Dec 08 2020

В частности, этот вопрос вызвал return_sequenceаргумент версии TensorFlow уровня LSTM.

В документах говорится:

Логическое. Возвращать ли последний вывод. в выходной последовательности или в полной последовательности. По умолчанию: False.

Я видел некоторые реализации, особенно автокодеры, которые используют этот аргумент для удаления всего, кроме последнего элемента в выходной последовательности, в качестве выходных данных «кодировочной» половины автокодировщика.

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

Пример 1 (TensorFlow):

Эта реализация удаляет все выходные данные LSTM, кроме последнего элемента последовательности, а затем повторяет этот элемент несколько раз для восстановления последовательности:

model = Sequential()
model.add(LSTM(100, activation='relu', input_shape=(n_in,1)))
# Decoder below
model.add(RepeatVector(n_out))
model.add(LSTM(100, activation='relu', return_sequences=True))
model.add(TimeDistributed(Dense(1)))

Когда я смотрю на реализации автоэнкодеров в PyTorch, я не вижу, чтобы авторы этим занимались. Вместо этого они используют весь вывод LSTM для кодировщика (иногда за ним следует плотный слой, а иногда нет).

Пример 1 (PyTorch):

Эта реализация тренирует встраивание ДО того, как будет применен слой LSTM ... Кажется, это почти опровергает идею автокодировщика на основе LSTM ... Последовательность уже закодирована к тому моменту, когда она попадает на уровень LSTM.

class EncoderLSTM(nn.Module):
  def __init__(self, input_size, hidden_size, n_layers=1, drop_prob=0):
    super(EncoderLSTM, self).__init__()
    self.hidden_size = hidden_size
    self.n_layers = n_layers

    self.embedding = nn.Embedding(input_size, hidden_size)
    self.lstm = nn.LSTM(hidden_size, hidden_size, n_layers, dropout=drop_prob, batch_first=True)

  def forward(self, inputs, hidden):
    # Embed input words
    embedded = self.embedding(inputs)
    # Pass the embedded word vectors into LSTM and return all outputs
    output, hidden = self.lstm(embedded, hidden)
    return output, hidden

Пример 2 (PyTorch):

Этот пример кодировщика сначала расширяет ввод одним слоем LSTM, а затем выполняет его сжатие через второй слой LSTM с меньшим количеством скрытых узлов. Помимо расширения, это похоже на статью, которую я нашел:https://arxiv.org/pdf/1607.00148.pdf

Однако в декодере этой реализации нет окончательного плотного слоя. Декодирование происходит через второй слой lstm, который расширяет кодирование до того же размера, что и исходный ввод. Смотрите здесь . Это не соответствует статье (хотя я не знаю, авторитетна она или нет).

class Encoder(nn.Module):
  def __init__(self, seq_len, n_features, embedding_dim=64):
    super(Encoder, self).__init__()
    self.seq_len, self.n_features = seq_len, n_features
    self.embedding_dim, self.hidden_dim = embedding_dim, 2 * embedding_dim
    self.rnn1 = nn.LSTM(
      input_size=n_features,
      hidden_size=self.hidden_dim,
      num_layers=1,
      batch_first=True
    )
    self.rnn2 = nn.LSTM(
      input_size=self.hidden_dim,
      hidden_size=embedding_dim,
      num_layers=1,
      batch_first=True
    )
  def forward(self, x):
    x = x.reshape((1, self.seq_len, self.n_features))
    x, (_, _) = self.rnn1(x)
    x, (hidden_n, _) = self.rnn2(x)
    return hidden_n.reshape((self.n_features, self.embedding_dim))

Вопрос:

Меня интересует это расхождение в реализациях. Разница кажется довольно большой. Все ли эти действительные способы достичь одного и того же? Или некоторые из этих ошибочных попыток создать «настоящий» автокодировщик LSTM?

Ответы

2 LucaAngioloni Dec 08 2020 at 22:38

Не существует официального или правильного способа разработки архитектуры автокодировщика на основе LSTM ... Единственная особенность, которую дает название, - это то, что модель должна быть автокодировщиком и где-то должна использоваться слой LSTM.

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

Опишем их:

  • Реализация TF :

    • Предполагается, что вход имеет только один канал , а это означает, что каждый элемент в последовательности - это просто число и что он уже предварительно обработан .
    • Поведение по умолчанию LSTM layerв Keras / TF - выводить только последний вывод LSTM, вы можете настроить его на вывод всех шагов вывода с return_sequencesпараметром.
    • В этом случае входные данные были сокращены до (batch_size, LSTM_units)
    • Учтите, что последний выход LSTM, конечно же, является функцией предыдущих выходов (особенно, если это LSTM с отслеживанием состояния).
    • Он применяет Dense(1)к последнему слою, чтобы получить ту же форму, что и вход.
  • PyTorch 1 :

    • Они применяют вложение к входным данным до того, как они будут переданы в LSTM.
    • Это стандартная практика, которая помогает, например, преобразовать каждый элемент ввода в векторную форму (см. Word2vec, например, где в текстовой последовательности каждое слово, не являющееся вектором, отображается в векторном пространстве). Это всего лишь этап предварительной обработки, чтобы данные имели более значимую форму.
    • Это не противоречит идее автокодировщика LSTM, поскольку встраивание применяется независимо к каждому элементу входной последовательности, поэтому оно не кодируется при входе на уровень LSTM.
  • PyTorch 2 :

    • В этом случае форма ввода не такая, (seq_len, 1)как в первом примере TF, поэтому декодеру не требуется плотная последующая форма . Автор использовал количество единиц в слое LSTM, равное входной форме.

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