Medidas e pontuação de similaridade vetorial

Explore as medidas de similaridade vetorial e a pontuação no Elasticsearch, incluindo distância L1 e L2, similaridade de cosseno, similaridade de produto escalar e similaridade de produto interno máximo.

De busca vetorial a poderosas APIs REST, o Elasticsearch oferece aos desenvolvedores o kit de ferramentas de busca mais completo. Confira nossos notebooks de amostra no repositório Elasticsearch Labs para experimentar algo novo. Você também pode começar uma avaliação gratuita ou executar o Elasticsearch localmente hoje mesmo.

Quando surge a necessidade de pesquisar texto livre e Ctrl+F / Cmd+F não são mais suficientes, usar um mecanismo de busca lexical geralmente é a próxima escolha lógica que vem à mente. Os mecanismos de busca lexical são excelentes em analisar e tokenizar o texto a ser pesquisado em termos que podem ser correspondidos no momento da pesquisa, mas geralmente falham quando se trata de entender e dar sentido ao verdadeiro significado do texto que está sendo indexado e pesquisado.

É exatamente aí que os mecanismos de busca de vetores brilham. Eles podem indexar o mesmo texto de forma que ele possa ser pesquisado com base no significado que ele representa e em suas relações com outros conceitos que tenham significado semelhante ou relacionado.

Neste blog, abordaremos brevemente como os vetores são um ótimo conceito matemático para transmitir o significado do texto. Em seguida, nos aprofundaremos nas diferentes técnicas de similaridade suportadas pelo Elasticsearch quando se trata de pesquisar vetores vizinhos, ou seja, pesquisar vetores com significado semelhante, e como pontuá-los.

O que são embeddings vetoriais?

Este artigo não se aprofunda nas complexidades das incorporações de vetores. Se você quiser explorar mais esse tópico ou precisar de uma introdução antes de continuar, recomendamos conferir o guia a seguir.

Em poucas palavras, os embeddings vetoriais são obtidos por meio de um processo de aprendizado de máquina (por exemplo, redes neurais de aprendizado profundo) que transformam qualquer tipo de dado de entrada não estruturado (por exemplo, texto bruto, imagem, vídeo, som, etc.) em dados numéricos que carregam seu significado e relacionamentos. Diferentes tipos de dados não estruturados exigem diferentes tipos de modelos de aprendizado de máquina que foram treinados para "entender" cada tipo de dado.

Cada vetor localiza um dado específico como um ponto em um espaço multidimensional e essa localização representa um conjunto de características que o modelo usa para caracterizar os dados. O número de dimensões depende do modelo de aprendizado de máquina, mas geralmente varia de algumas centenas a alguns milhares. Por exemplo, os modelos OpenAI Embeddings possuem 1536 dimensões, enquanto os modelos Cohere Embeddings podem variar de 382 a 4096 dimensões. O tipo de campo dense_vector do Elasticsearch suporta até 4.096 dimensões na versão mais recente.

O verdadeiro feito das incorporações vetoriais é que os pontos de dados que compartilham significados semelhantes ficam próximos no espaço. Outro aspecto interessante é que as incorporações vetoriais também ajudam a capturar relacionamentos entre pontos de dados.

Como comparamos vetores?

Sabendo que dados não estruturados são fatiados e divididos por modelos de aprendizado de máquina em incorporações vetoriais que capturam a similaridade dos dados ao longo de um grande número de dimensões, agora precisamos entender como funciona a correspondência desses vetores. Acontece que a resposta é bem simples.

Incorporações de vetores que estão próximas umas das outras representam partes de dados semanticamente semelhantes . Então, quando consultamos um banco de dados vetorial, a entrada da pesquisa (imagem, texto, etc.) é primeiro transformada em embeddings vetoriais usando o mesmo modelo de aprendizado de máquina que foi usado para indexar todos os dados não estruturados, e o objetivo final é encontrar os vetores vizinhos mais próximos daquele vetor de consulta. Portanto, tudo o que precisamos fazer é descobrir como medir a "distância" ou "similaridade" entre o vetor de consulta e todos os vetores existentes indexados no banco de dados - é simples assim.

Distância, similaridade e pontuação

Felizmente para nós, medir a distância ou similaridade entre dois vetores é um problema fácil de resolver graças à aritmética vetorial. Então, vamos dar uma olhada nas funções de distância e similaridade mais populares suportadas pelo Elasticsearch. Atenção, matemática à frente!

Antes de começarmos, vamos dar uma olhada rápida na pontuação. Na verdade, o Lucene só permite que as pontuações sejam positivas. Todas as funções de distância e similaridade que apresentaremos em breve fornecem uma medida de quão próximos ou similares dois vetores são, mas esses números brutos raramente são adequados para serem usados como pontuação, pois podem ser negativos. Por esse motivo, a pontuação final precisa ser derivada do valor de distância ou similaridade de uma forma que garanta que a pontuação será positiva e uma pontuação maior corresponde a uma classificação mais alta (ou seja, para vetores mais próximos).

Distância L1

A distância L1, também chamada de distância de Manhattan, de dois vetores A\vec{A} e B\vec{B} é medida pela soma da diferença absoluta em pares de todos os seus elementos. Obviamente, quanto menor a distância δL1\delta_{L1}, mais próximos os dois vetores estarão. A fórmula da distância L1 (1) é bastante simples, como pode ser visto abaixo:

δL1(A,B)=1inAiBi(1)\tag{1} \delta_{L1}(\vec{A}, \vec{B}) = \sum_{\mathclap{1\le i\le n}} \vert A_i-B_i \vert

Visualmente, a distância L1 pode ser ilustrada conforme mostrado na imagem abaixo (em vermelho):

O cálculo da distância L1 dos dois vetores a seguir A=(12)\vec{A} = \binom{1}{2} e B=(20.5)\vec{B} = \binom{2}{0.5} resultaria em 12+20,5=2,5\vert 1–2 \vert + \vert 2–0,5 \vert = 2,5

Importante: Vale ressaltar que a função de distância L1 só é suportada para pesquisa vetorial exata (também conhecida como pesquisa de força bruta) usando a consulta DSL script_score , mas não para pesquisa kNN aproximada usando a opção de pesquisa knnou a consulta DSL knn .

Distância L2

A distância L2, também chamada de distância euclidiana, de dois vetores A\vec{A} e B\vec{B} é medida primeiro somando o quadrado da diferença de pares de todos os seus elementos e depois tirando a raiz quadrada do resultado. É basicamente o caminho mais curto entre dois pontos. Similarmente a L1, quanto menor a distância δL2\delta_{L2}, mais próximos os dois vetores estão:

δL2(A,B)=1in(AiBi)2(2)\tag{2} \delta_{L2}(\vec{A},\vec{B}) = \sqrt{\sum_{\mathclap{1\le i\le n}} ( A_i-B_i )^2 }

A distância L2 é mostrada em vermelho na imagem abaixo:

Vamos reutilizar os mesmos dois vetores de amostra A\vec{A} e B\vec{B} que usamos para a distância δL1\delta_{L1} , e agora podemos calcular a distância δL2\delta_{L2} como (12)2+(20.5)2=3.251.803\sqrt{(1-2)^2 + (2-0.5)^2} = \sqrt{3.25} \approxeq 1.803.

Em termos de pontuação, quanto menor a distância entre dois vetores, mais próximos (ou seja, mais semelhantes) eles são. Então, para derivar uma pontuação, precisamos inverter a medida de distância, de modo que a menor distância produza a maior pontuação. A maneira como a pontuação é calculada ao usar a distância L2 é mostrada na fórmula (3) abaixo:

_scoreL2(A,B)=11+δL2(A,B)2(3)\tag{3} \_score_{L2}(\vec{A},\vec{B}) = \frac{1}{1 + \delta_{L2}(\vec{A}, \vec{B})^2}

Reutilizando os vetores de amostra do exemplo anterior, sua pontuação seria 14.250,2352\frac{1}{4.25} \approxeq 0,2352. Dois vetores muito próximos um do outro tenderão a uma pontuação de 1, enquanto a pontuação de dois vetores muito distantes um do outro tenderá a 0.

Concluindo as funções de distância L1 e L2, uma boa analogia para compará-las é pensar em A e B como dois edifícios em Manhattan, Nova York. Um táxi indo de A para B teria que dirigir pelo caminho L1 (ruas e avenidas), enquanto um pássaro provavelmente usaria o caminho L2 (linha reta).

Similaridade de cosseno

Ao contrário de L1 e L2, a similaridade do cosseno não mede a distância entre dois vetores A\vec{A} e B\vec{B}, mas sim seu ângulo relativo, ou seja, se ambos estão apontando aproximadamente na mesma direção. Quanto maior a similaridade scoss_{cos}, menor o ângulo α\alpha entre os dois vetores e, portanto, mais "próximos" eles são e mais "semelhantes" são seus significados transmitidos.

Para ilustrar isso, vamos pensar em duas pessoas em uma área selvagem olhando em direções diferentes. Na figura abaixo, a pessoa de azul olha na direção simbolizada pelo vetor A\vec{A} e a pessoa de vermelho na direção do vetor B\vec{B}. Quanto mais eles direcionarem sua visão na mesma direção (ou seja, quanto mais próximos seus vetores estiverem), mais seu campo de visão simbolizado pelas áreas azul e vermelha se sobreporá. O quanto seus campos de visão se sobrepõem é a similaridade de seus cossenos. Entretanto, observe que a pessoa B parece mais distante do que a pessoa A (ou seja, o vetor B\vec{B} é maior). A pessoa B pode estar olhando para uma montanha distante no horizonte, enquanto a pessoa A pode estar olhando para uma árvore próxima. Para similaridade de cosseno, isso não desempenha nenhum papel, pois é apenas uma questão de ângulo.

Agora vamos calcular essa similaridade de cosseno. A fórmula (4) é bastante simples, onde o numerador consiste no produto escalar de ambos os vetores e o denominador contém o produto de sua magnitude (ou seja, seu comprimento):

scos(A,B)=ABA×B(4)\tag{4} s_{cos}(\vec{A}, \vec{B}) = \frac{\vec{A} \cdot \vec{B}}{\Vert \vec{A} \Vert \times \Vert \vec{B} \Vert}

A similaridade do cosseno entre A\vec{A} e B\vec{B} é mostrada na imagem abaixo como uma medida do ângulo entre eles (em vermelho):

Vamos fazer um rápido desvio para explicar o que esses valores de similaridade de cosseno significam concretamente. Como pode ser visto na imagem abaixo representando a função cosseno, os valores sempre oscilam no intervalo [1,1][-1, 1] .

Lembre-se de que, para que dois vetores sejam considerados semelhantes, seu ângulo deve ser o mais agudo possível, idealmente próximo de um ângulo de0°de 0° , o que se resumiria a uma semelhança perfeita de 11. Em outras palavras, quando os vetores são...

  1. ...próximos um do outro, o cosseno do seu ângulo se aproxima de1de 1 (ou seja, próximo de 0°)
  1. ...não relacionados, o cosseno do seu ângulo se aproxima de0de 0 (ou seja, próximo de 90°90°)
  1. ...oposto, o cosseno do seu ângulo se aproxima de1de -1 (ou seja, próximo de 180°180°)

Agora que sabemos como calcular a similaridade do cosseno entre dois vetores e temos uma boa ideia de como interpretar o valor resultante, podemos reutilizar os mesmos vetores de amostra A\vec{A} e B\vec{B} e calcular sua similaridade do cosseno usando a fórmula (4) que vimos anteriormente.

scos(A,B)=(12)+(20.5)(12+22)×(22+0.52)34.6090.650791s_{cos}(\vec{A}, \vec{B}) = \frac{(1 \cdot 2) + (2 \cdot 0.5)}{\sqrt{(1^2 + 2^2)} \times \sqrt{(2^2 + 0.5^2)}} \approxeq \frac{3}{4.609} \approxeq 0.650791

Obtemos uma similaridade de cosseno de 0,6507910,650791, que é mais próxima de 11 do que de 00, o que significa que os dois vetores são um tanto similares, ou seja, não são perfeitamente similares, mas também não são completamente independentes e certamente não têm significados opostos.

Para derivar uma pontuação positiva de qualquer valor de similaridade de cosseno, precisamos usar a seguinte fórmula (5), que transforma os valores de similaridade de cosseno que oscilam dentro do intervalo [1,1][-1, 1] em pontuações no intervalo [0,1][0, 1] :

_scorecos(A,B)=1+scos(A,B)2(5)\tag{5} \_score_{cos}(\vec{A},\vec{B}) = \frac{1 + s_{cos}(\vec{A}, \vec{B})}{2}

A pontuação para os vetores de amostra A\vec{A} e B\vec{B} seria: 1+0.65079120,8253\frac{1 + 0.650791}{2} \approxeq 0,8253.

Similaridade do produto escalar

Uma desvantagem da similaridade de cosseno é que ela leva em conta apenas o ângulo entre dois vetores, mas não sua magnitude, o que significa que se dois vetores apontam aproximadamente na mesma direção, mas um é muito maior que o outro, ambos ainda serão considerados semelhantes. A similaridade do produto escalar, também chamada de similaridade escalar ou de produto interno, melhora isso ao levar em conta tanto o ângulo quanto a magnitude dos vetores, o que fornece uma métrica de similaridade mais precisa. Para tornar a magnitude dos vetores irrelevante, a similaridade do produto escalar exige que os vetores sejam normalizados primeiro, de modo que, em última análise, estamos apenas comparando vetores de comprimento unitário 1.

Vamos tentar ilustrar isso novamente com as mesmas duas pessoas de antes, mas, desta vez, as colocamos no meio de uma sala circular, de modo que seu alcance de visão seja exatamente o mesmo (ou seja, o raio da sala). De forma semelhante à similaridade do cosseno, quanto mais eles se voltam na mesma direção (ou seja, quanto mais próximos seus vetores ficam), mais seus campos de visão se sobrepõem. Entretanto, ao contrário da similaridade de cosseno, ambos os vetores têm o mesmo comprimento e ambas as áreas têm a mesma superfície, o que significa que as duas pessoas olham exatamente para a mesma imagem localizada à mesma distância. O quão bem essas duas áreas se sobrepõem denota sua similaridade de produto escalar.

Antes de introduzir a fórmula de similaridade do produto escalar, vamos ver rapidamente como um vetor pode ser normalizado. É bem simples e pode ser feito em duas etapas triviais:

  1. calcular a magnitude do vetor
  2. divida cada componente pela magnitude obtida em 1.

Como exemplo, vamos pegar o vetor A=(12)\vec{A} = \binom{1}{2}. Podemos calcular sua magnitude A\Vert \vec{A} \Vert como vimos anteriormente ao revisar a similaridade do cosseno, ou seja, 12+22=5\sqrt{1^2 + 2^2} = \sqrt{5}. Então, dividindo cada componente do vetor por sua magnitude, obtemos o seguinte vetor normalizado C\vec{C}:

Anorm=C=(1525)(0.440.89)\vec{A_{norm}} = \vec{C} = \dbinom{\frac{1}{\sqrt{5}}}{\frac{2}{\sqrt{5}}} \approxeq \dbinom{0.44}{0.89}

Passar pelo mesmo processo para o segundo vetor B=(20.5)\vec{B} = \binom{2}{0.5} produziria o seguinte vetor normalizado D\vec{D}:

Bnorm=D=(24.250.54.25)(0.970.24)\vec{B_{norm}} = \vec{D} = \dbinom{\frac{2}{\sqrt{4.25}}}{\frac{0.5}{\sqrt{4.25}}} \approxeq \dbinom{0.97}{0.24}

Para derivar a fórmula de similaridade do produto escalar, podemos calcular a similaridade do cosseno entre nossos vetores normalizados C\vec{C} e D\vec{D} usando a fórmula (4), conforme mostrado abaixo:

scos(C,D)=CD1×1s_{cos}(\vec{C}, \vec{D}) = \frac{\vec{C} \cdot \vec{D}}{1 \times 1}

E como a magnitude de ambos os vetores normalizados é agora 11, a fórmula de similaridade do produto escalar (6) simplesmente se torna... você adivinhou, um produto escalar de ambos os vetores normalizados:

sdot(C,D)=CD(6)\tag{6} s_{dot}(\vec{C}, \vec{D}) = \vec{C} \cdot \vec{D}

Na imagem abaixo, mostramos os vetores normalizados C\vec{C} e D\vec{D} e podemos ilustrar sua similaridade de produto escalar como a projeção de um vetor sobre o outro (em vermelho).

Usando nossa nova fórmula (6), podemos calcular a similaridade do produto escalar de nossos dois vetores normalizados, o que, sem surpresa, produz exatamente o mesmo valor de similaridade que o do cosseno:

sdot(C,D)=(1524.25)+(250.54.25)0.650791s_{dot}(\vec{C}, \vec{D}) = \Big(\frac{1}{\sqrt{5}} \cdot \frac{2}{\sqrt{4.25}}\Big) + \Big(\frac{2}{\sqrt{5}} \cdot \frac{0.5}{\sqrt{4.25}}\Big) \approxeq 0.650791

Ao aproveitar a similaridade do produto escalar, a pontuação é calculada de forma diferente dependendo se os vetores contêm valores flutuantes ou de bytes. No primeiro caso, a pontuação é calculada da mesma forma que para a similaridade do cosseno usando a fórmula (7) abaixo:

_scoredotfloat(C,D)=1+sdot(C,D)2(7)\tag{7} \_score_{dot-float}(\vec{C},\vec{D}) = \frac{1 + s_{dot}(\vec{C}, \vec{D})}{2}

Entretanto, quando o vetor é composto de valores de bytes, a pontuação é calculada de forma um pouco diferente, conforme mostrado na fórmula (8) abaixo, onde dimsdims é o número de dimensões do vetor:

_scoredotbyte(C,D)=0.5+sdot(C,D)32768×dims(8)\tag{8} \_score_{dot-byte}(\vec{C},\vec{D}) = \frac{0.5 + s_{dot}(\vec{C}, \vec{D})}{32768 \times dims}

Além disso, uma restrição para produzir pontuações precisas é que todos os vetores, incluindo o vetor de consulta, devem ter o mesmo comprimento, mas não necessariamente 1.

Similaridade máxima do produto interno

Desde a versão 8.11, há uma nova função de similaridade que é menos restrita do que a similaridade do produto escalar, pois os vetores não precisam ser normalizados. O principal motivo para isso é explicado detalhadamente no artigo a seguir, mas, para resumir muito brevemente, certos conjuntos de dados não são muito bem adaptados para ter seus vetores normalizados (por exemplo, incorporações Cohere) e isso pode causar problemas de relevância.

A fórmula para calcular a similaridade máxima do produto interno é exatamente a mesma que a do produto escalar (6). O que muda é a maneira como a pontuação é calculada, escalando a similaridade máxima do produto interno usando uma função por partes cuja fórmula depende se a similaridade é positiva ou negativa, conforme mostrado na fórmula (9) abaixo:

_scoremip(A,B)={11sdot(A,B)if sdot<01+sdot(A,B)if sdot0(9)\tag{9} \_score_{mip}(\vec{A},\vec{B}) = \begin{cases} \Large \frac{1}{1 - s_{dot}(\vec{A}, \vec{B})} &\text{if } s_{dot} < 0 1 + s_{dot}(\vec{A}, \vec{B}) &\text{if } s_{dot} \geqslant 0 \end{cases}

O que essa função por partes faz é dimensionar todos os valores negativos de similaridade do produto interno máximo no intervalo [0,1[[0, 1[ e todos os valores positivos no intervalo [1,[[1, \infty[ .

Resumindo

Foi uma jornada e tanto, matematicamente falando, mas aqui estão algumas lições que você pode achar úteis.

A função de similaridade que você pode usar depende, em última análise, se seus embeddings vetoriais são normalizados ou não. Se seus vetores já estiverem normalizados ou se seu conjunto de dados for independente da normalização vetorial (ou seja, a relevância não será afetada), você pode prosseguir e normalizar seus vetores e usar a similaridade do produto escalar, pois é muito mais rápido de calcular do que o cosseno, pois não há necessidade de calcular o comprimento de cada vetor. Ao comparar milhões de vetores, esses cálculos podem somar bastante.

Se seus vetores não estiverem normalizados, você tem duas opções:

  1. use similaridade de cosseno se normalizar seus vetores não for uma opção
  2. use a nova similaridade máxima do produto interno se quiser que a magnitude dos seus vetores contribua para a pontuação porque eles carregam significado (por exemplo, incorporações Cohere)

Neste ponto, calcular a distância ou similaridade entre incorporações vetoriais e como derivar suas pontuações deve fazer sentido para você. Esperamos que você tenha achado este artigo útil.

Perguntas frequentes

O que a similaridade de cosseno mede?

A similaridade de cosseno mede o ângulo relativo entre dois vetores, ou seja, se ambos estão apontando aproximadamente na mesma direção.

Como é medida a distância L1?

A distância L1 é medida somando-se a diferença absoluta entre todos os seus elementos, par a par.

Como a distância L2 é medida?

A distância L2, também chamada de distância euclidiana, de dois vetores é medida primeiro somando o quadrado da diferença entre pares de todos os seus elementos e depois tirando a raiz quadrada do resultado.

Qual a diferença entre as distâncias L1 e L2?

A diferença entre a distância L1 e a distância L2 reside na forma como se mede a distância entre dois vetores. A distância L1 é medida somando-se a diferença absoluta entre todos os seus elementos, par a par. Por outro lado, a distância L2 é medida somando-se primeiro o quadrado da diferença entre todos os seus elementos e, em seguida, extraindo-se a raiz quadrada do resultado.

Qual a diferença entre similaridade de cosseno e distância de cosseno?

A similaridade de cosseno mede o ângulo relativo entre dois vetores, ou seja, se ambos apontam aproximadamente na mesma direção. Por outro lado, a distância cosseno mede o quão diferentes são suas direções.

Qual a diferença entre produto escalar e similaridade de cosseno?

O produto escalar mede tanto o comprimento quanto o alinhamento dos vetores, enquanto a similaridade de cosseno mede apenas o grau de alinhamento de suas direções, ignorando o comprimento.

Quando usar o produto escalar em vez da similaridade de cosseno?

Se seus vetores estiverem normalizados (ou puderem ser normalizados sem afetar a relevância), use a similaridade do produto escalar — é mais rápido porque você não precisa calcular os comprimentos dos vetores. Se seus vetores não estiverem normalizados, use a similaridade de cosseno quando você se importa apenas com a direção, ou o produto escalar se a magnitude do vetor for significativa e deva influenciar a pontuação.

Como escolher a métrica de distância correta para busca vetorial?

Escolha uma métrica de distância com base nos seus vetores e no que é importante para a sua pesquisa: use L1 ou L2 para medir diferenças absolutas, similaridade de cosseno se apenas a direção importa, produto escalar se tanto a direção quanto a magnitude importam (e os vetores estão normalizados), ou produto interno máximo se os vetores não estão normalizados, mas a magnitude deve influenciar a relevância.

Conteúdo relacionado

Pronto para criar buscas de última geração?

Uma pesquisa suficientemente avançada não se consegue apenas com o esforço de uma só pessoa. O Elasticsearch é impulsionado por cientistas de dados, especialistas em operações de aprendizado de máquina, engenheiros e muitos outros que são tão apaixonados por buscas quanto você. Vamos nos conectar e trabalhar juntos para construir a experiência de busca mágica que lhe trará os resultados desejados.

Experimente você mesmo(a)