Правильный способ обеспечить BiLSTM подходящей маской

#tensorflow #keras #lstm #huggingface-transformers #encoder-decoder

Вопрос:

Я должен построить модель глубокого обучения для маркировки последовательностей в Keras, где кодер является моделью трансформатора, а декодер-BiLSTM. Дело в том, что кодировщик должен определить серию упоминаний в заданном входном тексте длиной 256 символов с усечением и заполнением, назначив соответствующие метки, в то время как кодировщик должен определить, в какой степени упоминания существуют (т. Е. Определить маркеры, участвующие в упоминании). Таким образом, конечным результатом должен быть список из 256 меток, по одной на маркер, которые равны 0, если они не содержат никакого упоминания или соответствующей закодированной метки, если иначе. Например:

 input_text = "This is a MENTION in a text"
tokens = ["[CLS]", "This", "is", "a", "MENTION", "in", "a", "text", "[SEP]", '''continues with padding until 255th position''']
input_ids = [101, 24918, 7821, 5983, 46106, 21905, 10789, 234, 102 '''continues with zeros until 255th position'''] # one input id per token
attention_mask = [1, 1, 1, 1, 1, 1, 1, 1, 1 '''continues with zeros until 255th position''']
labels = ["0", "0", "0", "0", "mention_type_1", "0", "0", "0", "0" '''continues with "0" until 255th position''']
 

Эти данные хранятся в фрейме данных pandas, столбцы которого называются так же, как и предыдущие переменные (т. Е. df[«input_ids»] и т. Д.). Поскольку целевые метки имеют строковый формат, а не являются целыми числами, я использовал кодировщик меток sklearn для преобразования их в целые числа. Следовательно, я загружаю данные:

 MAX_DOC_LENGTH = 256
BATCH_SIZE = 32

train_input_ids = train_df[INPUT_IDS_HEADER].values.tolist()
valid_input_ids = valid_df[INPUT_IDS_HEADER].values.tolist()
test_input_ids = test_df[INPUT_IDS_HEADER].values.tolist()
train_attention_mask = train_df[ATTENTION_MASK_HEADER].values.tolist()
valid_attention_mask = valid_df[ATTENTION_MASK_HEADER].values.tolist()
test_attention_mask = test_df[ATTENTION_MASK_HEADER].values.tolist()

label_encoder = LabelEncoder()
y_train = [label_encoder.fit_transform(code_list).astype('int32') for code_list in train_df[LABELS_HEADER].values]
y_valid = [label_encoder.fit_transform(code_list).astype('int32') for code_list in valid_df[LABELS_HEADER].values]
y_test = [np.zeros(MAX_DOC_LENGTH, dtype=np.int32) for test_row in test_input_ids]

train_dataset = (
    tf.data.Dataset
    .from_tensor_slices(((  tf.convert_to_tensor(train_input_ids), tf.convert_to_tensor(train_attention_mask)), y_train))
    .repeat()
    .shuffle(2048)
    .batch(BATCH_SIZE)
    .prefetch(BATCH_SIZE * 2)
)
valid_dataset = (
    tf.data.Dataset
    .from_tensor_slices(((tf.convert_to_tensor(valid_input_ids), tf.convert_to_tensor(valid_attention_mask)), y_valid))
    .batch(BATCH_SIZE)
    .prefetch(BATCH_SIZE * 2)
    )
test_dataset = (
    tf.data.Dataset
    .from_tensor_slices(((tf.convert_to_tensor(test_input_ids), tf.convert_to_tensor(test_attention_mask)), y_test))
    .batch(BATCH_SIZE)
    .prefetch(BATCH_SIZE * 2)
    )
 

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

 def get_sequence_input_from_code_list(code_list):
    return [1 if code == "0" else 0 for code in code_list]

def get_sequence_input_from_list_of_lists_of_codes(list_of_lists_of_codes):
    return [get_sequence_input_from_code_list(code_list) for code_list in list_of_lists_of_codes]

class MaskedBiLSTMLayer(layers.Layer):
    def __init__(self, max_len, **kwargs):
        super(MaskedBiLSTMLayer, self).__init__(**kwargs)
        self.bilstm = tf.keras.layers.Bidirectional(tf.keras.layers.LSTM(max_len, return_sequences=True))

    def __call__(self, inputs, labels)
        mask = tf.py_function(func=get_sequence_input_from_list_of_lists_of_codes, inp=[labels], Tout=tf.int32)
        output = self.bilstm(inputs, mask=mask)
        return output
 

The model:

 distilbert_model = TFAutoModel.from_pretrained("distilbert-base-multilingual-cased")
# Encoder
input_ids = tf.keras.layers.Input(shape=(MAX_DOC_LENGTH,), dtype=tf.int32) 
attention_mask = tf.keras.layers.Input(shape=(MAX_DOC_LENGTH,), dtype=tf.int32)
labels = tf.keras.layers.Input(shape=(MAX_DOC_LENGTH,), dtype=tf.int32)
distilbert = distilbert_model({"input_ids": input_ids, "attention_mask": attention_mask, "labels": labels})
# Decoder
bilstm_layer = MaskedBiLSTMLayer(MAX_DOC_LENGTH)
bilstm = bilstm_layer(distilbert.last_hidden_state, labels)
model = tf.keras.models.Model(inputs={"input_ids": input_ids, "attention_mask": attention_mask, "labels": labels}, outputs=bilstm)
model.compile(run_eagerly=True, optimizer=tf.keras.optimizers.Adam(learning_rate=5e-5), loss='categorical_crossentropy')
print(model.summary())
n_steps = train_input_ids.shape[0]
train_history = model.fit(train_dataset, epochs=EPOCHS, steps_per_epoch=n_steps, validation_data=valid_dataset)
 

However, I must be doing something wrong. With the current code, I get the following error:

 code.py:48 __call__  *
    output = self.bilstm(inputs, mask=mask)
    /home/users/user/.local/lib/python3.6/site-packages/tensorflow/python/framework/tensor_shape.py:829 __len__
        raise ValueError("Cannot take the length of shape with unknown rank.")

    ValueError: Cannot take the length of shape with unknown rank.
 

If add the line mask.set_shape((BATCH_SIZE, MAX_DOC_LENGTH)) in the __call__ method, I get this other error stemming from the same line:

 TypeError: Input 'y' of 'Equal' Op has type bool that does not match type int32 of argument 'x'
 

What am I doing wrong?