Ошибка при добавлении встраиваемого слоя в автоэнкодер lstm - PullRequest
3 голосов
/ 03 июня 2019

У меня есть модель seq2seq, которая работает нормально. Я хочу добавить слой встраивания в эту сеть, с которым я столкнулся с ошибкой.

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

LATENT_SIZE = 20

inputs = Input(shape=(SEQUENCE_LEN, EMBED_SIZE), name="input")

encoded = Bidirectional(LSTM(LATENT_SIZE), merge_mode="sum", name="encoder_lstm")(inputs)
encoded = Lambda(rev_ent)(encoded)
decoded = RepeatVector(SEQUENCE_LEN, name="repeater")(encoded)
decoded = Bidirectional(LSTM(EMBED_SIZE, return_sequences=True), merge_mode="sum", name="decoder_lstm")(decoded)
autoencoder = Model(inputs, decoded)
autoencoder.compile(optimizer="sgd", loss='mse')
autoencoder.summary()
NUM_EPOCHS = 1

num_train_steps = len(Xtrain) // BATCH_SIZE
num_test_steps = len(Xtest) // BATCH_SIZE

checkpoint = ModelCheckpoint(filepath=os.path.join('Data/', "simple_ae_to_compare"), save_best_only=True)
history = autoencoder.fit_generator(train_gen, steps_per_epoch=num_train_steps, epochs=NUM_EPOCHS, validation_data=test_gen, validation_steps=num_test_steps, callbacks=[checkpoint])

Это резюме:

Layer (type)                 Output Shape              Param #   
=================================================================
input (InputLayer)           (None, 45, 50)            0         
_________________________________________________________________
encoder_lstm (Bidirectional) (None, 20)                11360     
_________________________________________________________________
lambda_1 (Lambda)            (512, 20)                 0         
_________________________________________________________________
repeater (RepeatVector)      (512, 45, 20)             0         
_________________________________________________________________
decoder_lstm (Bidirectional) (512, 45, 50)             28400  

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

inputs = Input(shape=(SEQUENCE_LEN,), name="input")

embedding = Embedding(output_dim=EMBED_SIZE, input_dim=VOCAB_SIZE, input_length=SEQUENCE_LEN, trainable=True)(inputs)
encoded = Bidirectional(LSTM(LATENT_SIZE), merge_mode="sum", name="encoder_lstm")(embedding)

Я получил эту ошибку:

expected decoder_lstm to have 3 dimensions, but got array with shape (512, 45)

Итак, мой вопрос, что не так с моей моделью?

Обновление

Итак, эта ошибка возникает на этапе обучения. Я также проверил размер данных, подаваемых в модель, это (61598, 45), которые явно не имеют количества признаков или здесь, Embed_dim.

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

Теперь возникает вопрос, почему это не происходит в подобном коде? это мое мнение, поправьте меня, если я ошибаюсь. потому что Seq2Seq код обычно используется для перевода, обобщения. и в этих кодах, в части декодера также есть ввод (в случае перевода, есть другой язык, вводимый в декодер, поэтому идея иметь встраивание в часть декодера имеет смысл). Наконец, здесь у меня нет отдельного ввода, поэтому мне не нужно отдельное встраивание в часть декодера. Однако я не знаю, как решить проблему, я просто знаю, почему это происходит: |

Update2

это мои данные, поступающие в модель:

   sent_wids = np.zeros((len(parsed_sentences),SEQUENCE_LEN),'int32')
sample_seq_weights = np.zeros((len(parsed_sentences),SEQUENCE_LEN),'float')
for index_sentence in range(len(parsed_sentences)):
    temp_sentence = parsed_sentences[index_sentence]
    temp_words = nltk.word_tokenize(temp_sentence)
    for index_word in range(SEQUENCE_LEN):
        if index_word < sent_lens[index_sentence]:
            sent_wids[index_sentence,index_word] = lookup_word2id(temp_words[index_word])
        else:
            sent_wids[index_sentence, index_word] = lookup_word2id('PAD')

def sentence_generator(X,embeddings, batch_size, sample_weights):
    while True:
        # loop once per epoch
        num_recs = X.shape[0]
        indices = np.random.permutation(np.arange(num_recs))
        # print(embeddings.shape)
        num_batches = num_recs // batch_size
        for bid in range(num_batches):
            sids = indices[bid * batch_size : (bid + 1) * batch_size]
            temp_sents = X[sids, :]
            Xbatch = embeddings[temp_sents]
            weights = sample_weights[sids, :]
            yield Xbatch, Xbatch
LATENT_SIZE = 60

train_size = 0.95
split_index = int(math.ceil(len(sent_wids)*train_size))
Xtrain = sent_wids[0:split_index, :]
Xtest = sent_wids[split_index:, :]
train_w = sample_seq_weights[0: split_index, :]
test_w = sample_seq_weights[split_index:, :]
train_gen = sentence_generator(Xtrain, embeddings, BATCH_SIZE,train_w)
test_gen = sentence_generator(Xtest, embeddings , BATCH_SIZE,test_w)

и parsed_sentences - это 61598 предложений, которые дополняются.

Кроме того, это слой, который у меня есть в модели как лямбда-слой, я только что добавил его на случай, если он когда-либо повлияет:

def rev_entropy(x):
        def row_entropy(row):
            _, _, count = tf.unique_with_counts(row)
            count = tf.cast(count,tf.float32)
            prob = count / tf.reduce_sum(count)
            prob = tf.cast(prob,tf.float32)
            rev = -tf.reduce_sum(prob * tf.log(prob))
            return rev

        nw = tf.reduce_sum(x,axis=1)
        rev = tf.map_fn(row_entropy, x)
        rev = tf.where(tf.is_nan(rev), tf.zeros_like(rev), rev)
        rev = tf.cast(rev, tf.float32)
        max_entropy = tf.log(tf.clip_by_value(nw,2,LATENT_SIZE))
        concentration = (max_entropy/(1+rev))
        new_x = x * (tf.reshape(concentration, [BATCH_SIZE, 1]))
        return new_x

Любая помощь приветствуется:)

1 Ответ

1 голос
/ 07 июня 2019

Я попробовал следующий пример на Google colab (версия TensorFlow 1.13.1),

from tensorflow.python import keras
import numpy as np

SEQUENCE_LEN = 45
LATENT_SIZE = 20
EMBED_SIZE = 50
VOCAB_SIZE = 100

inputs = keras.layers.Input(shape=(SEQUENCE_LEN,), name="input")

embedding = keras.layers.Embedding(output_dim=EMBED_SIZE, input_dim=VOCAB_SIZE, input_length=SEQUENCE_LEN, trainable=True)(inputs)

encoded = keras.layers.Bidirectional(keras.layers.LSTM(LATENT_SIZE), merge_mode="sum", name="encoder_lstm")(embedding)
decoded = keras.layers.RepeatVector(SEQUENCE_LEN, name="repeater")(encoded)
decoded = keras.layers.Bidirectional(keras.layers.LSTM(EMBED_SIZE, return_sequences=True), merge_mode="sum", name="decoder_lstm")(decoded)
autoencoder = keras.models.Model(inputs, decoded)
autoencoder.compile(optimizer="sgd", loss='mse')
autoencoder.summary()

А затем обучил модель, используя некоторые случайные данные,


x = np.random.randint(0, 90, size=(10, 45))
y = np.random.normal(size=(10, 45, 50))
history = autoencoder.fit(x, y, epochs=NUM_EPOCHS)

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

Обновление

Контекст

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

Исправление вашего кода

Если вы выполните следующее, вы сможете получить работающий код. Здесь embeddings - предварительно обученный вектор GloVe numpy.ndarray.

def sentence_generator(X, embeddings, batch_size):
    while True:
        # loop once per epoch
        num_recs = X.shape[0]
        embed_size = embeddings.shape[1]
        indices = np.random.permutation(np.arange(num_recs))
        # print(embeddings.shape)
        num_batches = num_recs // batch_size
        for bid in range(num_batches):
            sids = indices[bid * batch_size : (bid + 1) * batch_size]
            # Xbatch is a [batch_size, seq_length] array
            Xbatch = X[sids, :] 

            # Creating the Y targets
            Xembed = embeddings[Xbatch.reshape(-1),:]
            # Ybatch will be [batch_size, seq_length, embed_size] array
            Ybatch = Xembed.reshape(batch_size, -1, embed_size)
            yield Xbatch, Ybatch
...