You've successfully subscribed to edrone Blog
Great! Next, complete checkout for full access to edrone Blog
Welcome back! You've successfully signed in.
Success! Your account is fully activated, you now have access to all content.
Success! Your billing info is updated.
Billing info update failed.

Word2vec: Modelo Skip-Gram

Podemos fazer os computadores entenderem palavras ao transformá-las em números – ou melhor, vetores. Mas como fazer os computadores entenderem relações entre as palavras? Uma das formas é o Modelo Skip-Gram.

Marcin Lewek
Marcin Lewek

Na primeira parte, aprendemos a transformar palavras em "códigos" (vetores) que as máquinas possam entender – ou melhor, que possam processar de uma forma útil. Esta transposição de palavras para vetores é denominada word embedding, pois estamos "embutindo" ou "fixando" as palavras em um espaço multidimensional.


O que é Word2Vec - Modelo de Linguagem baseado em Deep Learning
Word2Vec é um método de Aprendizado de Máquina para construir um modelo de linguagem baseado em ideias de Aprendizado Profundo. No entanto, a rede neural usada aqui é um tanto superficial (tem apenas uma camada escondida).
Leia a primeira parte!

Nesta parte, vamos discutir o processo de como o computador pode encontrar relações entre as palavras (agora vetores) e medir suas afinidades.

Encontrando pares

Relembrando o corpus de texto com o qual estávamos trabalhando:

'edrone is awesome'
'The First CRM for eCommerce and AI fueled marketing machine'

Cada vetor extraído deste corpus consiste em uma sequência de 11 números composta por apenas um '"1.0" e dez "0.0", e cada um destes números representa uma dimensão em um espaço de 11 dimensões. Isso significa que cada vetor específico (vetor one-hot) aponta exclusivamente para uma dimensão (a sua própria).

Relembrando como ficaram os vetores do nosso corpus de texto:

{'ai': 
 [0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0],

 'and': 
 [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0],
 
 'awesome': 
 [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0],
 
 'crm': 
 [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0],
 
 'ecommerce': 
 [0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0],
 
 'edrone': 
 [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0],
 
 'first': 
 [0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0],
 
 'for': 
 [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0],
 
 'fueled': 
 [0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0],
 
 'is': 
 [1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0],
 
 'machine': 
 [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0],
 
 'marketing': 
 [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0],
 
 'the': 
 [0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]}

Colocando o Modelo Skip-Gram em prática

Quanto mais vezes duas palavras aparecerem no mesmo contexto, mais próximos serão seus significados. Para fazer esta análise, usamos uma definição precisa, um contexto de determinado tamanho. O tamanho do trecho depende do critério do analista, então vamos usar um tamanho de dois – isso significa que vamos analisar cada palavra no corpus em relação às duas palavras que aparecerem imediatamente antes e depois dela, conforme o esquema abaixo:

exemplo de corpus de texto para aplicação do modelo skip-gram

Na primeira linha temos:

  • (edrone, is)
  • (edrone, awesome)

Na segunda, temos:

  • (is, edrone)
  • (is, awesome)
  • (is, the)

Na terceira:

  • (awesome, edrone)
  • (awesome, is)
  • (awesome, the)
  • (awesome, first)

Estes pares, traduzidos em linguagem de máquina, ficam assim:

(edrone, is) -> 
-> ([0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0],
    [1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0])

...e assim por diante.

Usando o modelo Skip-Gram, a tarefa da nossa rede neural será aprender a relação entre uma palavra específica, usada como dado de entrada, e a palavra que está em seu entorno, que será fornecida como dado de saída.

Camada de entrada, camada oculta e camada de saída

Se você já teve algum contato com Aprendizado de Máquinas (Machine Learning) ou Aprendizado Profundo (Deep Learning), talvez reconheça o gráfico abaixo.

exemplo de rede neural para aprendizado profundo

Vamos deixar o nosso corpus e vetores originais de lado por enquanto. Para explicar melhor os mecanismos por trás de uma Rede Neural, vamos usar como exemplo um corpus menor, de apenas seis palavras originais. Assim será mais fácil compreender como o processo funciona.

Como temos seis palavras originais, isso significa que seus vetores, cada um composto por uma sequência numérica única de cinco "0.0" e um "1.0", serão embutidos (lembra do word embedding?) em seis dimensões. No lado esquerdo do gráfico temos a camada de entrada (input layer), no meio a camada oculta (hidden layer) e à direita, a camada de saída (output layer). Neste exemplo, decidimos usar três nódulos, ou neurônios, na camada oculta. Assim como o tamanho do contexto, o número de nódulos também é uma escolha do analista.

Quando treinamos esta rede com os pares de palavras, a entrada (input) é um vetor one-hot representando a palavra de entrada, e o dado de saída de treinamento (training output), que nós determinamos, também é um vetor one-hot representando a palavra de saída.

O dado de saída (output) de fato – não o de treinamento – será gerado pela rede neural após ela ser treinada. Agora, o dado de entrada continuará sendo um vetor one-hot representando uma palavra, mas o dado de saída será uma distribuição de probabilidade formada por diferentes valores de ponto flutuante (ou seja, não serão vetores one-hot). Mas voltaremos ao dado de saída mais tarde.

A primeira metade do gráfico pode ser representada pela seguinte equação:

\[  \begin{bmatrix} 0 & 0 & 1 & 0 & 0 & 0 \end{bmatrix} \times \begin{bmatrix} 1 & 2 & 2\\ -1 & 0 & -2\\ 1.2 & 1 & -1\\ -0.5 & -1 & 2\\ -1 & 0 & -1\\ 1 & 2 & -1 \end{bmatrix} =\begin{bmatrix} 1.2 & 1 & -1 \end{bmatrix} \]

A matriz representa as conexões entre os nodos, com diferentes pesos atribuídos a elas. Aqui, estes pesos foram determinados aleatoriamente a título de exemplo, mas à medida que a rede neural aprende (veremos como isso acontece na parte III), esta matriz é automaticamente atualizada.

Se você é bom em álgebra linear, talvez esteja pensando: "Espera um pouco... se o vetor é composto majoritariamente por zeros, eu consigo facilmente calcular esta matriz de cabeça." Qual é a pegadinha?

Quando você multiplica um vetor one-hot por uma matriz, está efetivamente selecionando apenas a linha da matriz que corresponde ao "1.0" no vetor. Em nosso exemplo, seria a terceira linha da matriz, que tem os valores (1.2, 1 e -1).

Ou seja, estamos usando o "1.0" do vetor one-hot como um indicador, e a camada oculta age como uma tabela de consulta (lookup table).

Porém, nós temos vetores de seis dimensões em ambos os lados. A segunda parte da equação é semelhante, e faremos um novo cálculo usando outra matriz.

Desta vez, o dado de saída (output) não está mais tão claro – e o mais importante, não aponta a uma direção específica, pois não é um vetor one-hot.

Para extrair um resultado útil deste dado de saída, usaremos a função de ativação softmax:

\[ {\frac{e^{x}}{\sum e^{x}}} \]

Ao aplicar a função softmax, nosso resultado será:

Note que a soma dos valores é igual a 1!

O resultado é uma lista de probabilidades para os vetores correspondentes no dicionário (lista de palavras com as quais começamos). Em outras palavras, cada linha representa a probabilidade daquela posição conter o número "1.0" no vetor one-hot  de saída. No exemplo abaixo, o resultado indica que a palavra de saída (output) com a maior probabilidade de estar certa é a representada pelo vetor [1.0, 0.0, 0.0, 0.0, 0.0, 0.0] em nosso dicionário.

modelo skip-gram: função softmax aplicada ao dado de saída (output)

A diferença entre o vetor de saída, baseado em probabilidade, e o vetor alvo (a palavra "correta") é crucial para que a rede neural possa aprender. Falaremos sobre isso na parte III.

Modelo Skip-Gram e CBOW: Duas abordagens ao Word2Vec

Este é um bom momento para mencionarmos que existem duas abordagens principais ao Word2Vec: o Modelo Skip-Gram e o Continuous Bag of Words (CBOW). Em poucas palavras:

  • Modelo Skip-Gram: indica o contexto (palavras ao redor) a partir de uma palavra específica que foi selecionada como input.
  • CBOW: prevê uma palavra central, com base nas palavras ao redor que foram usadas como input.

Como você pode perceber, uma abordagem é o inverso da outra. Neste exemplo, usamos o modelo Skip-Gram: tomamos uma palavra específica, e observamos as previsões de palavras de entorno fornecidas pela rede neural.

Qual técnica é melhor? Isso vai depender do seu objetivo. Independentemente de qual você usar, a arquitetura das redes neurais será mais ou menos parecida. A diferença é qual informação nós usaremos como dado de entrada.

E como aplicar este resultado? Como ensinar à rede se ela está acertando ou errando?

Faremos isso aplicando a Função de Perda (Loss Function), que veremos em detalhes na parte III!

Artificial intelligenceDeep learningMachine learningTutorials & GuidesPythonWord2vecNLP

Marcin Lewek

Digital marketer and copywriter specialized in AI, design, and digital marketing itself. Science, and holistic approach enthusiast, after-hours musician, and sometimes actor.