Разница между этими реализациями LSTM Autoencoder?
В частности, этот вопрос вызвал 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?
Ответы
Не существует официального или правильного способа разработки архитектуры автокодировщика на основе 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, равное входной форме.
- В этом случае форма ввода не такая,
В конце концов, вы выбираете архитектуру своей модели в зависимости от данных, которые вы хотите использовать для обучения, а именно: природы (текст, аудио, изображения), формы ввода, количества имеющихся данных и так далее ...