4. Attention Mechanisms
Mecanismos de Atenção e Auto-Atenção em Redes Neurais
Os mecanismos de atenção permitem que redes neurais focalizem partes específicas da entrada ao gerar cada parte da saída. Eles atribuem pesos diferentes a diferentes entradas, ajudando o modelo a decidir quais entradas são mais relevantes para a tarefa em questão. Isso é crucial em tarefas como tradução automática, onde entender o contexto de toda a frase é necessário para uma tradução precisa.
O objetivo desta quarta fase é muito simples: Aplicar alguns mecanismos de atenção. Estes serão muitos níveis repetidos que vão capturar a relação de uma palavra no vocabulário com seus vizinhos na frase atual sendo usada para treinar o LLM. Muitos níveis são usados para isso, então muitos parâmetros treináveis vão capturar essa informação.
Entendendo os Mecanismos de Atenção
Em modelos tradicionais de sequência para sequência usados para tradução de idiomas, o modelo codifica uma sequência de entrada em um vetor de contexto de tamanho fixo. No entanto, essa abordagem tem dificuldades com frases longas porque o vetor de contexto de tamanho fixo pode não capturar todas as informações necessárias. Os mecanismos de atenção abordam essa limitação permitindo que o modelo considere todos os tokens de entrada ao gerar cada token de saída.
Exemplo: Tradução Automática
Considere traduzir a frase em alemão "Kannst du mir helfen diesen Satz zu übersetzen" para o inglês. Uma tradução palavra por palavra não produziria uma frase em inglês gramaticalmente correta devido a diferenças nas estruturas gramaticais entre os idiomas. Um mecanismo de atenção permite que o modelo se concentre nas partes relevantes da frase de entrada ao gerar cada palavra da frase de saída, levando a uma tradução mais precisa e coerente.
Introdução à Auto-Atenção
A auto-atensão, ou intra-atensão, é um mecanismo onde a atenção é aplicada dentro de uma única sequência para calcular uma representação dessa sequência. Ela permite que cada token na sequência preste atenção a todos os outros tokens, ajudando o modelo a capturar dependências entre tokens, independentemente da distância na sequência.
Conceitos Chave
Tokens: Elementos individuais da sequência de entrada (por exemplo, palavras em uma frase).
Embeddings: Representações vetoriais de tokens, capturando informações semânticas.
Pesos de Atenção: Valores que determinam a importância de cada token em relação aos outros.
Calculando Pesos de Atenção: Um Exemplo Passo a Passo
Vamos considerar a frase "Hello shiny sun!" e representar cada palavra com um embedding de 3 dimensões:
Hello:
[0.34, 0.22, 0.54]
shiny:
[0.53, 0.34, 0.98]
sun:
[0.29, 0.54, 0.93]
Nosso objetivo é calcular o vetor de contexto para a palavra "shiny" usando auto-atensão.
Passo 1: Calcular Pontuações de Atenção
Basta multiplicar cada valor de dimensão da consulta pelo relevante de cada token e somar os resultados. Você obtém 1 valor por par de tokens.
Para cada palavra na frase, calcule a pontuação de atenção em relação a "shiny" calculando o produto escalar de seus embeddings.
Pontuação de Atenção entre "Hello" e "shiny"
Pontuação de Atenção entre "shiny" e "shiny"
Pontuação de Atenção entre "sun" e "shiny"
Passo 2: Normalizar Pontuações de Atenção para Obter Pesos de Atenção
Não se perca nos termos matemáticos, o objetivo desta função é simples, normalizar todos os pesos para que eles somem 1 no total.
Além disso, a função softmax é usada porque acentua diferenças devido à parte exponencial, facilitando a detecção de valores úteis.
Aplique a função softmax às pontuações de atenção para convertê-las em pesos de atenção que somam 1.
Calculando os exponenciais:
Calculando a soma:
Calculando pesos de atenção:
Passo 3: Calcular o Vetor de Contexto
Basta pegar cada peso de atenção e multiplicá-lo pelas dimensões do token relacionado e, em seguida, somar todas as dimensões para obter apenas 1 vetor (o vetor de contexto)
O vetor de contexto é calculado como a soma ponderada dos embeddings de todas as palavras, usando os pesos de atenção.
Calculando cada componente:
Embedding Ponderado de "Hello":
* **Embedding Ponderado de "shiny"**:
* **Embedding Ponderado de "sun"**:
Somando os embeddings ponderados:
context vector=[0.0779+0.2156+0.1057, 0.0504+0.1382+0.1972, 0.1237+0.3983+0.3390]=[0.3992,0.3858,0.8610]
Este vetor de contexto representa o embedding enriquecido para a palavra "shiny", incorporando informações de todas as palavras na frase.
Resumo do Processo
Calcular Pontuações de Atenção: Use o produto escalar entre o embedding da palavra-alvo e os embeddings de todas as palavras na sequência.
Normalizar Pontuações para Obter Pesos de Atenção: Aplique a função softmax às pontuações de atenção para obter pesos que somem 1.
Calcular o Vetor de Contexto: Multiplique o embedding de cada palavra pelo seu peso de atenção e some os resultados.
Auto-Atenção com Pesos Treináveis
Na prática, os mecanismos de auto-atensão usam pesos treináveis para aprender as melhores representações para consultas, chaves e valores. Isso envolve a introdução de três matrizes de peso:
A consulta é os dados a serem usados como antes, enquanto as matrizes de chaves e valores são apenas matrizes aleatórias treináveis.
Passo 1: Calcular Consultas, Chaves e Valores
Cada token terá sua própria matriz de consulta, chave e valor multiplicando seus valores de dimensão pelas matrizes definidas:
Essas matrizes transformam os embeddings originais em um novo espaço adequado para calcular a atenção.
Exemplo
Assumindo:
Dimensão de entrada
din=3
(tamanho do embedding)Dimensão de saída
dout=2
(dimensão desejada para consultas, chaves e valores)
Inicialize as matrizes de peso:
Calcule consultas, chaves e valores:
Passo 2: Calcular Atenção de Produto Escalonado
Calcular Pontuações de Atenção
Semelhante ao exemplo anterior, mas desta vez, em vez de usar os valores das dimensões dos tokens, usamos a matriz de chave do token (já calculada usando as dimensões):. Assim, para cada consulta qi
e chave kj
:
Escalonar as Pontuações
Para evitar que os produtos escalares se tornem muito grandes, escalone-os pela raiz quadrada da dimensão da chave dk
:
A pontuação é dividida pela raiz quadrada das dimensões porque os produtos escalares podem se tornar muito grandes e isso ajuda a regulá-los.
Aplicar Softmax para Obter Pesos de Atenção: Como no exemplo inicial, normalize todos os valores para que somem 1.
Passo 3: Calcular Vetores de Contexto
Como no exemplo inicial, basta somar todas as matrizes de valores multiplicando cada uma pelo seu peso de atenção:
Exemplo de Código
Pegando um exemplo de https://github.com/rasbt/LLMs-from-scratch/blob/main/ch03/01_main-chapter-code/ch03.ipynb você pode conferir esta classe que implementa a funcionalidade de auto-atenção que discutimos:
Observe que, em vez de inicializar as matrizes com valores aleatórios, nn.Linear
é usado para marcar todos os pesos como parâmetros a serem treinados.
Atenção Causal: Ocultando Palavras Futuras
Para LLMs, queremos que o modelo considere apenas os tokens que aparecem antes da posição atual para prever o próximo token. Atenção causal, também conhecida como atenção mascarada, alcança isso modificando o mecanismo de atenção para impedir o acesso a tokens futuros.
Aplicando uma Máscara de Atenção Causal
Para implementar a atenção causal, aplicamos uma máscara aos scores de atenção antes da operação softmax para que os restantes ainda somem 1. Essa máscara define os scores de atenção dos tokens futuros como negativo infinito, garantindo que, após o softmax, seus pesos de atenção sejam zero.
Passos
Calcular Scores de Atenção: Igual ao anterior.
Aplicar Máscara: Use uma matriz triangular superior preenchida com negativo infinito acima da diagonal.
Aplicar Softmax: Calcule os pesos de atenção usando os scores mascarados.
Mascarando Pesos de Atenção Adicionais com Dropout
Para prevenir overfitting, podemos aplicar dropout aos pesos de atenção após a operação softmax. O dropout zera aleatoriamente alguns dos pesos de atenção durante o treinamento.
Uma taxa de dropout regular é de cerca de 10-20%.
Code Example
Code example from https://github.com/rasbt/LLMs-from-scratch/blob/main/ch03/01_main-chapter-code/ch03.ipynb:
Estendendo a Atenção de Cabeça Única para Atenção de Múltiplas Cabeças
Atenção de múltiplas cabeças em termos práticos consiste em executar várias instâncias da função de autoatenção, cada uma com seus próprios pesos, de modo que vetores finais diferentes sejam calculados.
Exemplo de Código
Pode ser possível reutilizar o código anterior e apenas adicionar um wrapper que o execute várias vezes, mas esta é uma versão mais otimizada de https://github.com/rasbt/LLMs-from-scratch/blob/main/ch03/01_main-chapter-code/ch03.ipynb que processa todas as cabeças ao mesmo tempo (reduzindo o número de loops for caros). Como você pode ver no código, as dimensões de cada token são divididas em diferentes dimensões de acordo com o número de cabeças. Dessa forma, se o token tiver 8 dimensões e quisermos usar 3 cabeças, as dimensões serão divididas em 2 arrays de 4 dimensões e cada cabeça usará uma delas:
Para uma implementação compacta e eficiente, você pode usar a classe torch.nn.MultiheadAttention
no PyTorch.
Resposta curta do ChatGPT sobre por que é melhor dividir as dimensões dos tokens entre as cabeças em vez de fazer com que cada cabeça verifique todas as dimensões de todos os tokens:
Embora permitir que cada cabeça processe todas as dimensões de embedding possa parecer vantajoso porque cada cabeça teria acesso a todas as informações, a prática padrão é dividir as dimensões de embedding entre as cabeças. Essa abordagem equilibra a eficiência computacional com o desempenho do modelo e incentiva cada cabeça a aprender representações diversas. Portanto, dividir as dimensões de embedding é geralmente preferido em relação a fazer com que cada cabeça verifique todas as dimensões.
Referências
Last updated