Точная настройка универсального кодировщика предложений с помощью LSTM

#python #tensorflow #keras #lstm

Вопрос:

Входные данные:

 string_1_A, string_2_A, string_3_A, label_A
string_1_B, string_2_B, string_3_B, label_B
...
string_1_Z, string_2_Z, string_3_Z, label_Z
 

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

 import tensorflow_hub as hub
import tensorflow as tf
import tensorflow.keras.backend as K
from tensorflow.keras.layers import LSTM


module_url = "../resources/embeddings/use-4"

def get_lstm_model():
    embedding_layer = hub.KerasLayer(module_url)

    inputs = tf.keras.layers.Input(shape=(3, ), dtype=tf.string)
    x = tf.keras.layers.Lambda(lambda y: tf.expand_dims(embedding_layer(tf.squeeze(y)), 1))(inputs)
    x = LSTM(128, return_sequences=False)(x)
    outputs = tf.keras.layers.Dense(1, activation="sigmoid")(x)

    model = tf.keras.Model(inputs=inputs, outputs=outputs)
    model.compile("adam",  K.binary_crossentropy)
    model.summary()
    return model


if __name__ == '__main__':
    model = get_lstm_model()
    print(model.predict([[["a"], ["b"], ["c"]]]))
 

проблема в том, что размер ввода/вывода определенных слоев не совпадает, как я ожидал (вместо 1 я ожидал бы 3):

 input_1 (InputLayer)         [(None, 3)]               0         
_________________________________________________________________
lambda (Lambda)              (None, ***1***, 512)            0       
 

Любое предложение — я думаю, что мне нужно лучше справляться с сжатием и без вопросов.

Ответ №1:

Самое простое решение-передать каждую строку/предложение отдельно в Универсальный кодировщик предложений. Это создает вложение для каждой строки/предложения формы 512, которое может быть объединено для формирования тензора формы (Нет, n_sentences, 512).

Это код модели:

 n_sentences = 50
module_url = "https://tfhub.dev/google/universal-sentence-encoder/4"

def get_lstm_model():
    embedding_layer = hub.KerasLayer(module_url, trainable=True)

    input = Input(shape=(n_sentences,), dtype=tf.string)
    x = [Reshape((1,512))(embedding_layer(input[:, s])) for s in range(n_sentences)]
    x = Concatenate(axis=1)(x)
    x = LSTM(128, return_sequences=False)(x)
    output = Dense(1, activation="sigmoid")(x)

    model = Model(inputs=input, outputs=output)
    model.compile("adam", "binary_crossentropy")
    model.summary()
    return model
 

Во время вывода:

 sentences = [str(i) for i in range(n_sentences)]
X = [sentences] # 1 sample
print(model.predict(X).shape)

X = [sentences, sentences[::-1]] # 2 samples
print(model.predict(X).shape)
 

Вот бегущая тетрадь

Комментарии:

1. @United121 смотрите мои обновления, где я привел пример, чтобы разобраться с 50 предложениями

2. Меня немного беспокоили предупреждения (о том, что в Лямбде не используется кераслой), поэтому я изменил его на эту ссылку на версию. Считаете ли вы, что это правильно из — за изменения формы-я не уверен, что измерение будет действительным в конце и что я не смешиваю все векторы вместе?

3. и это также кажется довольно медленным решением

4. Вы можете заменить Lambda expand_dim на Reshape, чтобы подавить предупреждения (см. Изменения). чем больше предложений, тем медленнее вычисление. Это нормально. Но вам следует проверить это в более сложном случае. Тем не менее, я думаю, что это правильный путь