Demonstrações interativas da aula de modelos encoder-only e sentence embeddings
Quatro visualizações que acompanham os slides: o padrão de atenção bidirecional do encoder contra o causal do decoder, o pré-treino com Masked Language Modeling e a regra 80/10/10 (ℒMLM = −(1/|M|)·Σi∈M log p(wi | w∖M)), a classificação de sentença sobre h[CLS] comparando feature extraction e fine-tuning, e o aprendizado contrastivo com InfoNCE (sim(f(xi), f(xj+))/τ) que dá origem aos sentence embeddings do SBERT.
A diferença estrutural entre as famílias está na máscara de atenção. No encoder (BERT, RoBERTa) cada token atende a todos os outros, o que produz representações ricas em contexto dos dois lados. No decoder (GPT) a máscara causal zera as posições futuras (j > i): cada token só vê o passado, condição necessária para gerar texto. Abaixo, a mesma frase passa pelas duas máscaras com os mesmos Q e K de brinquedo. Posições de [PAD] recebem −∞ nos logits e são ignoradas nas duas famílias, exatamente como a attention mask vista em aula.
Encoder (bidirecional): linha i = pesos da consulta qi (clique numa linha)
Decoder (causal): células vermelhas recebem −∞ antes do softmax
💡 Clique na linha de "gato": no encoder ele recebe peso de "tapete", que vem depois dele na frase; no decoder esse peso é zero. Aumente [PAD] para 3 e veja que as colunas de padding somem nas duas máscaras, a soma de cada linha continua 1 porque o softmax renormaliza sobre as posições reais. Use 🎲 para sortear novas projeções e confirmar que o padrão da máscara não muda, só os pesos.
O pré-treino do BERT esconde 15% dos tokens e pede que o modelo os recupere usando o contexto dos dois lados, com perda ℒMLM = −(1/|M|)·Σi∈M log p(wi | w∖M). Dos tokens selecionados, 80% viram [MASK], 10% são trocados por uma palavra aleatória e 10% ficam intactos (em todos os casos o alvo é a palavra original). Aqui um modelinho de coocorrência treinado num corpus de frases em português faz o papel do BERT: clique numa palavra para mascará-la e veja a distribuição prevista sobre o vocabulário.
Frase de entrada: clique numa palavra para mascarar/desmascarar (alvo original em cinza)
p(w | contexto) na posição selecionada (verde: palavra original)
💡 Mascare só "sentou" e observe a distribuição: o contexto bidirecional ("o gato" à esquerda, "no tapete" à direita) concentra a probabilidade em verbos plausíveis. Agora mascare também "tapete" e veja a perda subir: com menos contexto visível a previsão piora, que é o motivo de a taxa ficar em 15% e não em 50%. Use o botão 🎲 várias vezes com taxa 15% e repare nos casos raros de troca aleatória (laranja) e de token mantido (verde): o modelo precisa prever a palavra original mesmo assim.
O token [CLS] é prefixado a toda sequência e, ao longo das camadas, acumula informação da frase inteira via self-attention. Seu estado final h[CLS](L) alimenta uma cabeça linear W ∈ ℝd×C para classificação. Abaixo, 20 resenhas de filme têm seu h[CLS] projetado em 2D e uma cabeça logística é treinada ao vivo. Compare as duas estratégias da aula: em feature extraction o encoder fica congelado (os pontos não se movem, só a fronteira), em fine-tuning o gradiente também flui para o encoder (os embeddings se reorganizam para facilitar a separação).
h[CLS] em 2D e a fronteira da cabeça (clique num ponto para ler a frase)
Perda (ciano) e acurácia (laranja) por passo de treino
💡 Treine no modo congelado: a fronteira linear estaciona com alguns pontos do lado errado, a acurácia satura porque os embeddings não mudam. Reinicie, mude para fine-tuning e treine de novo: além da fronteira, os próprios pontos migram e as duas nuvens se afastam, a acurácia chega a 100%. Clique nos pontos perto da fronteira para ler as frases ambíguas. Com η = 2 o fine-tuning distorce o espaço rapidamente, lembrando por que na prática se usa learning rate pequena (na aula, 2×10−5).
Como visto em aula, o h[CLS] do BERT vanilla é ruim para similaridade: é preciso um novo objetivo de treino. No InfoNCE, um batch de N pares (qi, di) gera a matriz Sij = sim(f(qi), f(dj))/τ; o softmax em cada linha deve apontar para a diagonal, e os outros N−1 documentos do batch são negativos "grátis". Aqui os embeddings são vetores unitários em 2D (pontos num círculo, cosseno = ângulo entre eles): rode o treino e veja cada consulta ser puxada para seu documento e empurrada dos demais, a receita siamesa do SBERT.
Embeddings unitários: ● consulta qi, □ documento di (arraste qualquer ponto)
Softmax por linha de Sij/τ: o alvo é a diagonal (contorno verde)
💡 Treine com τ = 0.10 e observe a matriz virar uma diagonal: além de cada par se alinhar, os pares se espalham pelo círculo para fugir uns dos outros (uniformidade). Compare com τ = 1: a softmax fica achatada e os negativos difíceis pesam pouco. Depois de convergir, arraste um documento para cima de outro par e veja a linha correspondente da matriz se confundir, é o papel do negativo difícil. Com N = 10 há mais negativos por linha e o espaçamento final fica mais apertado, como nos batches grandes da aula.