o problema
O BERT resolveu comparação de frases sendo um cross-encoder: as duas frases entram juntas na rede, separadas por [SEP], a atenção cruza uma na outra e uma camada de regressão cospe o score. Funciona muito bem e custa caro. Para achar o par mais parecido numa coleção de 10.000 frases são n·(n−1)/2 = 49.995.000 inferências, cerca de 65 horas numa V100. Para responder qual das mais de 40 milhões de perguntas do Quora é a mais próxima de uma pergunta nova, mais de 50 horas por consulta. Clustering, então, nem se cogita.
A saída óbvia é dar a cada frase um vetor fixo e comparar vetores. O que todo mundo fazia — inclusive o repositório bert-as-a-service, popular na época — era passar a frase sozinha pelo BERT e tirar a média da camada de saída, ou usar o vetor do token [CLS]. Ninguém tinha medido se isso presta. Reimers e Gurevych mediram: a média das saídas dá 54,81 de correlação de Spearman média nas sete tarefas STS, e o [CLS] dá 29,19. Média simples de embeddings GloVe dá 61,32. O BERT cru, usado assim, é pior que um saco de vetores de palavra de 2014.
a ideia
Não é que falte informação no BERT: é que ele nunca precisou que o vetor de uma frase isolada fosse comparável ao vetor de outra. O treinamento sempre deixou as duas frases no mesmo contexto. Cosseno pressupõe um espaço onde proximidade significa semelhança, e esse espaço nunca foi construído.
O SBERT constrói. Duas cópias do BERT com pesos amarrados — estrutura siamesa —, uma operação de pooling em cada saída, e uma perda que só melhora se os vetores independentes ficarem no lugar certo um em relação ao outro. Uma época de fine-tune em dados de inferência textual e o espaço se reorganiza. O modelo é o mesmo; o que muda é a exigência imposta a ele.
como funciona
O pooling tem três variantes — CLS, MEAN e MAX — e o padrão é MEAN. Sobre isso vão três funções objetivo, escolhidas pelo formato dos dados anotados:
- classificação: concatena
u,ve|u−v|, multiplica por um W treinável em R^(3n×k) e passa por softmax, com cross-entropy. É a usada no NLI, de três rótulos. - regressão: cosseno entre
uev, com erro quadrático médio. - triplet: dados âncora, positivo e negativo, minimiza
max(||sa−sp|| − ||sa−sn|| + ε, 0), com distância euclidiana e margem ε = 1.
O treino padrão usa SNLI (570.000 pares) mais MultiNLI (430.000), uma época, batch de 16, Adam com learning rate 2e-5 e warm-up linear sobre 10% dos dados. Na inferência nada disso sobrevive: sai o vetor, entra o cosseno.
A ablação mostra onde está o trabalho pesado. Com objetivo de classificação, a escolha de pooling muda pouco (80,78 no MEAN, 79,80 no CLS, 79,07 no MAX); a concatenação muda muito. Sem o |u−v|, só com (u,v), cai para 66,04. Somar u*v, como fazem InferSent e Universal Sentence Encoder, piorou um pouco. Com objetivo de regressão o quadro inverte: o MAX desaba para 69,92 contra 87,44 do MEAN.
Há ainda um detalhe de engenharia que rende mais que muita arquitetura: smart batching agrupa frases de comprimento parecido e faz padding só até o maior do mini-batch — 89% mais rápido na CPU, 48% na GPU.
o que isso custou
O bi-encoder é uma troca, não um upgrade. Quando dá para pagar as duas passagens, o cross-encoder ainda ganha: 88,77 contra 86,10 na STS benchmark, versão large. E quando a tarefa depende de comparar as frases palavra a palavra, a perda fica visível — no corpus AFS, avaliado cross-topic, o SBERT cai cerca de 7 pontos de Spearman em relação ao BERT, porque precisa posicionar num vetor argumentos de um tema que nunca viu.
Os embeddings também herdam os dados de origem. O SBERT foi pré-treinado só em Wikipedia, via BERT, e ajustado em NLI: perde para o Universal Sentence Encoder em SICK-R e em TREC, ambos favorecidos pelos dados de fórum e de perguntas com que o USE foi treinado. Na CPU, o InferSent é cerca de 65% mais rápido, e média de GloVe processa 6.469 frases por segundo contra 83 do SBERT com smart batching. Os autores ainda avisam que SentEval não é o propósito da coisa: para transfer learning, ajustar o BERT inteiro continua sendo o caminho.
onde isso aparece hoje
O desenho virou o padrão de busca semântica: codificar cada documento uma vez, guardar o vetor, comparar por cosseno em um índice aproximado. O próprio paper já aponta para essa combinação ao citar índices otimizados para reduzir a consulta do Quora a milissegundos — o lugar hoje ocupado por Faiss e HNSW. O mesmo bi-encoder sobre BERT reaparece em recuperação de passagens com DPR, e a tensão que o SBERT expõe — velocidade contra interação entre as frases — é exatamente o que o ColBERT tenta dividir ao meio com late interaction. Todo pipeline de RAG que embeda trechos e busca por similaridade está usando essa forma. O código saiu como sentence-transformers, e é por ele que a maioria das pessoas encontrou o paper.