Вложение предложения BERT путем суммирования последних 4 слоев - PullRequest
1 голос
/ 09 октября 2019

Я использовал учебник Криса Маккормика по BERT, используя pytorch-pretained-bert, чтобы получить вложение предложения следующим образом:

tokenized_text = tokenizer.tokenize(marked_text)
indexed_tokens = tokenizer.convert_tokens_to_ids(tokenized_text)
segments_ids = [1] * len(tokenized_text)
tokens_tensor = torch.tensor([indexed_tokens])
segments_tensors = torch.tensor([segments_ids])
model = BertModel.from_pretrained('bert-base-uncased')
model.eval()

with torch.no_grad():
    encoded_layers, _ = model(tokens_tensor, segments_tensors)
    # Holds the list of 12 layer embeddings for each token
    # Will have the shape: [# tokens, # layers, # features]
    token_embeddings = []

    # For each token in the sentence...
    for token_i in range(len(tokenized_text)):
        # Holds 12 layers of hidden states for each token
        hidden_layers = []

        # For each of the 12 layers...
        for layer_i in range(len(encoded_layers)):

                # Lookup the vector for `token_i` in `layer_i`
                vec = encoded_layers[layer_i][batch_i][token_i]

                hidden_layers.append(vec)

        token_embeddings.append(hidden_layers)

Теперь я пытаюсь получить вложение окончательного предложения, суммируя последние 4 слоя следующим образом:

summed_last_4_layers = [torch.sum(torch.stack(layer)[-4:], 0) for layer in token_embeddings]

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

[tensor([-3.8930e+00, -3.2564e+00, -3.0373e-01,  2.6618e+00,  5.7803e-01,
-1.0007e+00, -2.3180e+00,  1.4215e+00,  2.6551e-01, -1.8784e+00,
-1.5268e+00,  3.6681e+00, ...., 3.9084e+00]), tensor([-2.0884e+00, -3.6244e-01,  ....2.5715e+00]), tensor([ 1.0816e+00,...-4.7801e+00]), tensor([ 1.2713e+00,.... 1.0275e+00]), tensor([-6.6105e+00,..., -2.9349e-01])]

Что я получил здесь? Как мне объединить сумму последних для слоев?

Спасибо!

1 Ответ

1 голос
/ 10 октября 2019

Вы создаете список, используя понимание списка, которое повторяется по token_embeddings. Это список, который содержит один тензор на каждый токен, а не один тензор на слой, как вы, вероятно, думали (судя по вашим for layer in token_embeddings). Таким образом, вы получите список с длиной, равной количеству токенов. Для каждого токена у вас есть вектор, который является суммой вложений BERT из последних 4 слоев.

Более эффективным было бы избегать явных циклов for и представлений списков:

summed_last_4_layers = torch.stack(encoded_layers[-4:]).sum(0)

Сейчаспеременная summed_last_4_layers содержит те же данные, но в форме одного тензора измерения: длина предложения × 768.

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

...