Выводим внимание на причал-цоколь-без кожуха с обтягивающим лицом / трансформаторами (фонариком)

Я читал статью о лексической подстановке на основе BERT (в частности, пытаясь реализовать уравнение (2) - если бы кто-то уже реализовал всю статью, тоже было бы здорово). Таким образом, я хотел получить как последние скрытые слои (единственное, в чем я не уверен, так это порядок слоев на выходе: последний первый или первый первый?), И внимание со стороны базовой модели BERT (bert-base-uncased).

Однако я немного не уверен, действительно ли библиотека huggingface / transformers привлекает внимание (я использовал torch , но я открыт для использования вместо этого TF) для bert-base-uncased?

От того, что я прочитал, я ожидал получить кортеж из (logits, hidden_states , внимание), но в приведенном ниже примере (выполняется, например, в Google Colab) вместо этого я получаю длину 2.

Я неверно истолковываю то, что я получаю, или делаю это неправильно? Я провел очевидный тест и использовал output_attention=False вместо output_attention=True (хотя output_hidden_states=True действительно, похоже, добавляет скрытые состояния, как и ожидалось), и ничего не изменилось в выводе, который я получил. Это явно плохой знак о моем понимании библиотеки или указывает на проблему.

import numpy as np
import torch
!pip install transformers

from transformers import (AutoModelWithLMHead, 
                          AutoTokenizer, 
                          BertConfig)

bert_tokenizer = AutoTokenizer.from_pretrained("bert-base-uncased")
config = BertConfig.from_pretrained('bert-base-uncased', output_hidden_states=True, output_attention=True) # Nothign changes, when I switch to output_attention=False
bert_model = AutoModelWithLMHead.from_config(config)

sequence = "We went to an ice cream cafe and had a chocolate ice cream."
bert_tokenized_sequence = bert_tokenizer.tokenize(sequence)

indexed_tokens = bert_tokenizer.encode(bert_tokenized_sequence, return_tensors='pt')

predictions = bert_model(indexed_tokens)

########## Now let's have a look at what the predictions look like #############
print(len(predictions)) # Length is 2, I expected 3: logits, hidden_layers, attention

print(predictions[0].shape) # torch.Size([1, 16, 30522]) - seems to be logits (shape is 1 x sequence length x vocabulary

print(len(predictions[1])) # Length is 13 - the hidden layers?! There are meant to be 12, right? Is one somehow the attention?

for k in range(len(predictions[1])):
  print(predictions[1][k].shape) # These all seem to be torch.Size([1, 16, 768]), so presumably the hidden layers?

Объяснение того, что в итоге сработало, на основе принятого ответа

import numpy as np
import torch
!pip install transformers

from transformers import BertModel, BertConfig, BertTokenizer

tokenizer = BertTokenizer.from_pretrained('bert-base-uncased')
config = BertConfig.from_pretrained('bert-base-uncased', output_hidden_states=True, output_attentions=True)
model = BertModel.from_pretrained('bert-base-uncased', config=config)
sequence = "We went to an ice cream cafe and had a chocolate ice cream."
tokenized_sequence = tokenizer.tokenize(sequence)
indexed_tokens = tokenizer.encode(tokenized_sequence, return_tensors='pt'
enter code here`outputs = model(indexed_tokens)
print( len(outputs) ) # 4 
print( outputs[0].shape ) #1, 16, 768 
print( outputs[1].shape ) # 1, 768
print( len(outputs[2]) ) # 13  = input embedding (index 0) + 12 hidden layers (indices 1 to 12)
print( outputs[2][0].shape ) # for each of these 13: 1,16,768 = input sequence, index of each input id in sequence, size of hidden layer
print( len(outputs[3]) ) # 12 (=attenion for each layer)
print( outputs[3][0].shape ) # 0 index = first layer, 1,12,16,16 = , layer, index of each input id in sequence, index of each input id in sequence

person Björn    schedule 07.02.2020    source источник
comment
Как вы разобрали последний тензор [1, 12, 16, 16]? В документации сказано, что он представляет batch_size, num_heads, sequence_length, sequence_length, но я не уверен, как интерпретировать последние два измерения. Есть ли у вас какие-либо идеи?   -  person stackoverflowuser2010    schedule 31.03.2020
comment
Внимание к каждому слою немного? Итак, вы привлекаете внимание к определенному слою, скажем, первому (индекс 0) как output [3] [0], тогда вы можете захотеть, например, внимание, которое глава № 3 (индекс 2) уделяет элементу 2 (индекс 1) при интерпретации элемента 15 (индекс 14). Чтобы получить это, вы берете выходы [3] [0] [0,2,1,14], или, возможно, выходы [3] [0] [0,2,14,1] - я забыл, в каком направлении этот последний бит . Я думаю, что github.com/jessevig/bertviz прекрасно это визуализирует.   -  person Björn    schedule 31.03.2020


Ответы (2)


Причина в том, что вы используете AutoModelWithLMHead, который является оболочкой для реальной модели. Он вызывает модель BERT (т.е. экземпляр BERTModel), а затем использует матрицу внедрения в качестве матрицы весов для предсказания слова. Между тем базовая модель действительно возвращает внимание, но оболочка не заботится и возвращает только логиты.

Вы можете получить модель BERT напрямую, вызвав AutoModel. Обратите внимание, что эта модель возвращает не логиты, а скрытые состояния.

bert_model = AutoModel.from_config(config)

Или вы можете получить его из объекта BertWithLMHead, позвонив:

wrapped_model = bert_model.base_model
person Jindřich    schedule 10.02.2020
comment
благодарю вас! Признаюсь, что меня смущало то, что я получил сейчас (после переключения на predictions = bert_model.base_model(indexed_tokens) в приведенном выше коде). Я получаю кортеж из 3 элементов (отлично!) С фигурами: [1, 16, 768] (предположительно, последний скрытый слой?), Следующий элемент - [1, 768], а последний - кортеж длиной 13, каждый элемент формируется [1, 16, 768]. Это может быть глупый вопрос, но что это? Разве не 12 скрытых слоев (n = 768) + 144 головы внимания (по 12 на каждый из 12 слоев)? Я ожидал 12 x [1, 16, 768] + 144 x [1, 16, 768] или около того ... Я явно что-то неправильно понял. - person Björn; 10.02.2020
comment
Разобрался сейчас сам. Добавил внизу вопросы. - person Björn; 12.02.2020

Я думаю, что уже слишком поздно отвечать здесь, но с обновлением от трансформаторов huggingface, я думаю, мы можем использовать это

config = BertConfig.from_pretrained('bert-base-uncased', 
output_hidden_states=True, output_attentions=True)  
bert_model = BertModel.from_pretrained('bert-base-uncased', 
config=config)

with torch.no_grad():
  out = bert_model(input_ids)
  last_hidden_states = out.last_hidden_state
  pooler_output = out.pooler_output
  hidden_states = out.hidden_states
  attentions = out.attentions
person Youngho    schedule 16.12.2020
comment
Пожалуйста, если у вас есть вопросы, опубликуйте их как вопрос со ссылкой на этот пост, не задавайте в рамках ответов. - person Ruli; 16.12.2020
comment
Спасибо ! Я здесь новичок, лол - person Youngho; 17.12.2020