Слой ELMo Embedding с Keras

Я использовал встраиваемый слой Keras по умолчанию со встраиваемыми словами в своей архитектуре. Архитектура выглядит так -

left_input = Input(shape=(max_seq_length,), dtype='int32')
right_input = Input(shape=(max_seq_length,), dtype='int32')

embedding_layer = Embedding(len(embeddings), embedding_dim, weights=[embeddings], input_length=max_seq_length,
                            trainable=False)

# Since this is a siamese network, both sides share the same LSTM
shared_lstm = LSTM(n_hidden, name="lstm")

left_output = shared_lstm(encoded_left)
right_output = shared_lstm(encoded_right)

Я хочу заменить слой внедрения на вложения ELMo. Поэтому я использовал настраиваемый слой встраивания - найденный в этом репозитории - https://github.com/strongio/keras-elmo/blob/master/Elmo%20Keras.ipynb. Встраиваемый слой выглядит так -

class ElmoEmbeddingLayer(Layer):
def __init__(self, **kwargs):
    self.dimensions = 1024
    self.trainable=True
    super(ElmoEmbeddingLayer, self).__init__(**kwargs)

def build(self, input_shape):
    self.elmo = hub.Module('https://tfhub.dev/google/elmo/2', trainable=self.trainable,
                           name="{}_module".format(self.name))

    self.trainable_weights += K.tf.trainable_variables(scope="^{}_module/.*".format(self.name))
    super(ElmoEmbeddingLayer, self).build(input_shape)

def call(self, x, mask=None):
    result = self.elmo(K.squeeze(K.cast(x, tf.string), axis=1),
                  as_dict=True,
                  signature='default',
                  )['default']
    return result

def compute_mask(self, inputs, mask=None):
    return K.not_equal(inputs, '--PAD--')

def compute_output_shape(self, input_shape):
    return (input_shape[0], self.dimensions)

Я изменил архитектуру нового слоя встраивания.

 # The visible layer
left_input = Input(shape=(1,), dtype="string")
right_input = Input(shape=(1,), dtype="string")

embedding_layer = ElmoEmbeddingLayer()

# Embedded version of the inputs
encoded_left = embedding_layer(left_input)
encoded_right = embedding_layer(right_input)

# Since this is a siamese network, both sides share the same LSTM
shared_lstm = LSTM(n_hidden, name="lstm")

left_output = shared_gru(encoded_left)
right_output = shared_gru(encoded_right)

Но я получаю ошибку -

ValueError: вход 0 несовместим со слоем lstm: ожидалось ndim = 3, найдено ndim = 2

Что я здесь делаю не так?


person Tharindu    schedule 11.02.2019    source источник
comment
Были ли у вас ошибки с k.tf.trainable_variables?   -  person El Sheikh    schedule 24.08.2019
comment
Я получаю сообщение об ошибке @ElSheikh, не могли бы вы найти решение?   -  person Celius Stingher    schedule 25.11.2019
comment
Да, ivan, пожалуйста self._trainable_weights += tf.trainable_variables(scope=f"^{self.name}_module/.*")   -  person El Sheikh    schedule 25.11.2019
comment
Вам это помогло? @IvanLibedinsky   -  person El Sheikh    schedule 25.11.2019
comment
Спасибо за вашу помощь, у меня есть с tensorflow и trainable_variables, не могли бы вы указать, какие версии tensforflow и keras вы использовали, когда вам удалось запустить это?   -  person Celius Stingher    schedule 29.11.2019
comment
Решено, мне нужно было сменить drowngrade на версию 1.13. Я использовал 2.0.0, спасибо!   -  person Celius Stingher    schedule 29.11.2019


Ответы (2)


Я также использовал этот репозиторий в качестве руководства для создания модели CustomELMo + BiLSTM + CRF, и мне нужно было изменить поиск dict на elmo вместо default. Как отметила Анна Крогагер, когда поиск dict является «по умолчанию», вывод будет (batch_size, dim), что недостаточно для размеров LSTM. Однако, когда поиск dict равен ['elmo'], слой возвращает тензор правильных размеров, а именно формы (batch_size, max_length, 1024).

Пользовательский слой ELMo:

class ElmoEmbeddingLayer(Layer):
def __init__(self, **kwargs):
    self.dimensions = 1024
    self.trainable = True
    super(ElmoEmbeddingLayer, self).__init__(**kwargs)

def build(self, input_shape):
    self.elmo = hub.Module('https://tfhub.dev/google/elmo/2', trainable=self.trainable,
                           name="{}_module".format(self.name))

    self.trainable_weights += K.tf.trainable_variables(scope="^{}_module/.*".format(self.name))
    super(ElmoEmbeddingLayer, self).build(input_shape)

def call(self, x, mask=None):
    result = self.elmo(K.squeeze(K.cast(x, tf.string), axis=1),
                       as_dict=True,
                       signature='default',
                       )['elmo']
    print(result)
    return result

# def compute_mask(self, inputs, mask=None):
#   return K.not_equal(inputs, '__PAD__')

def compute_output_shape(self, input_shape):
    return input_shape[0], 48, self.dimensions

Модель построена следующим образом:

def build_model(): # uses crf from keras_contrib
    input = layers.Input(shape=(1,), dtype=tf.string)
    model = ElmoEmbeddingLayer(name='ElmoEmbeddingLayer')(input)
    model = Bidirectional(LSTM(units=512, return_sequences=True))(model)
    crf = CRF(num_tags)
    out = crf(model)
    model = Model(input, out)
    model.compile(optimizer="rmsprop", loss=crf_loss, metrics=[crf_accuracy, categorical_accuracy, mean_squared_error])
    model.summary()
    return model

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

InvalidArgumentError: Incompatible shapes: [32,47] vs. [32,0]    [[{{node loss/crf_1_loss/mul_6}}]]

где 32 - размер пакета, а 47 - на единицу меньше, чем указанная мной max_length (предположительно, это означает, что он учитывает сам токен панели). Я еще не выяснил причину этой ошибки, так что это может подойти вам и вашей модели. Однако я заметил, что вы используете ГРУ, и в репозитории есть нерешенная проблема с добавлением ГРУ. Так что мне любопытно, понимаете ли вы это тоже.

person KMunro    schedule 17.07.2019
comment
Почему размер ввода (1,)? Как это сработает? input = layers.Input(shape=(1,), dtype=tf.string) - person Deshwal; 17.01.2021

Слой встраивания Elmo выводит одно вложение для каждого входа (таким образом, форма вывода равна (batch_size, dim)), тогда как ваш LSTM ожидает последовательность (т.е. форму (batch_size, seq_length, dim)). Я не думаю, что имеет смысл иметь слой LSTM после слоя внедрения Elmo, поскольку Elmo уже использует LSTM для встраивания последовательности слов.

person Anna Krogager    schedule 12.02.2019
comment
Что мне нужно изменить в слое внедрения ELMo, чтобы получить ожидаемую последовательность LSTM? - person Tharindu; 12.02.2019
comment
Что вы хотите получить от своего уровня LSTM? Ваш ввод - это просто строка, а не последовательность, поэтому я не понимаю, какова цель вашего слоя LSTM. Но если у вас каким-то образом будет последовательность строк в качестве входных данных, вы можете применить слой ELMo к каждому элементу последовательности (обернув ELMo в слой TimeDistributed), а затем передать полученную последовательность вложений в LSTM - person Anna Krogager; 12.02.2019
comment
Да, на самом деле мой вклад - это предложение - person Tharindu; 12.02.2019