Embeddings de frases de BERT de transformadores
Estou tentando obter vetores de frase de estados ocultos em um modelo de BERT. Olhando para as instruções do BertModel abraçando aqui , que dizem:
from transformers import BertTokenizer, BertModel
tokenizer = BertTokenizer.from_pretrained('bert-base-multilingual-cased')
model = BertModel.from_pretrained("bert-base-multilingual-cased")
text = "Replace me by any text you'd like."
encoded_input = tokenizer(text, return_tensors='pt')
output = model(**encoded_input)
Portanto, primeiro observe, como está no site, isso / não / funciona. Você obtém:
>>> Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: 'BertTokenizer' object is not callable
Mas parece que uma pequena alteração corrige isso, pois você não chama o tokenizer diretamente, mas pede que ele codifique a entrada:
encoded_input = tokenizer.encode(text, return_tensors="pt")
output = model(encoded_input)
OK, deixando isso de lado, os tensores que obtenho, no entanto, têm uma forma diferente do que eu esperava:
>>> output[0].shape
torch.Size([1,11,768])
São muitas camadas. Qual é a camada correta a ser usada para embeddings de frases? [0]
? [-1]
? Em média vários? Eu tenho o objetivo de ser capaz de fazer similaridade de cosseno com eles, então eu preciso de um vetor 1xN adequado em vez de um tensor NxK.
Vejo que o popular projeto bert-as-a-service parece usar[0]
Isso está correto? Existe documentação para cada uma das camadas?
Respostas
Não acho que haja uma única documentação oficial dizendo o que usar e quando. Você precisa experimentar e medir o que é melhor para sua tarefa. Observações recentes sobre o BERT estão bem resumidas neste artigo:https://arxiv.org/pdf/2002.12327.pdf.
Acho que a regra é:
Use a última camada se for ajustar o modelo para sua tarefa específica. E sempre que puder, várias centenas ou até dezenas de exemplos de treinamento são suficientes.
Use algumas das camadas intermediárias (7ª ou 8ª) se você não conseguir ajustar o modelo. A intuição por trás disso é que as camadas primeiro desenvolvem uma representação cada vez mais abstrata e geral da entrada. Em algum momento, a representação passa a ser mais direcionada para a tarefa de pré-treinamento.
Bert-as-services usa a última camada por padrão (mas é configurável). Aqui, seria [:, -1]
. No entanto, ele sempre retorna uma lista de vetores para todos os tokens de entrada. O vetor correspondente ao primeiro [CLS]
token especial (assim chamado ) é considerado a incorporação da frase. É [0]
daí que vem o snipper ao qual você se refere.
Embora a resposta existente de Jindrich seja geralmente correta, ela não aborda a questão inteiramente. O OP perguntou qual camada ele deveria usar para calcular a similaridade de cosseno entre embeddings de sentenças e a resposta curta para esta pergunta é nenhuma . Uma métrica como a similaridade do cosseno requer que as dimensões do vetor contribuam igualmente e de forma significativa, mas este não é o caso do BERT. Jacob Devlin (um dos autores do artigo do BERT) escreveu :
Não tenho certeza do que são esses vetores, uma vez que o BERT não gera vetores de frase significativos. Parece que isso está fazendo um agrupamento médio dos tokens de palavras para obter um vetor de sentença, mas nunca sugerimos que isso geraria representações de sentenças significativas. E mesmo que sejam representações decentes quando alimentadas em um DNN treinado para uma tarefa downstream, isso não significa que serão significativas em termos de distância cosseno. (Uma vez que a distância do cosseno é um espaço linear onde todas as dimensões são ponderadas igualmente).
No entanto, isso não significa que você não pode usar o BERT para tal tarefa. Significa apenas que você não pode usar os pesos pré-treinados prontos para uso. Você pode treinar um classificador em cima do BERT que aprende quais sentenças são semelhantes (usando o [CLS]
token) ou você pode usar transformadores de sentenças que podem ser usados em um cenário não supervisionado porque foram treinados para produzir representações de sentenças significativas.