Ter uma questão? Conecte-se com a comunidade no Fórum TensorFlow Visite o Fórum

Word2Vec

Ver no TensorFlow.org Executar no Google Colab Ver fonte no GitHubBaixar caderno

Word2Vec não é um algoritmo singular, ao contrário, é uma família de arquiteturas de modelo e otimizações que podem ser usadas para aprender embeddings de palavras a partir de grandes conjuntos de dados. Embeddings aprendidos por meio do Word2Vec provaram ser bem-sucedidos em uma variedade de tarefas downstream de processamento de linguagem natural.

Esses artigos propuseram dois métodos para aprender representações de palavras:

  • Modelo Contínuo de Bag-of-Words que prevê a palavra do meio com base nas palavras do contexto circundante. O contexto consiste em algumas palavras antes e depois da palavra atual (do meio). Essa arquitetura é chamada de modelo de saco de palavras, pois a ordem das palavras no contexto não é importante.
  • Modelo de Skip-gram contínuo que prevê palavras dentro de um determinado intervalo antes e depois da palavra atual na mesma frase. Um exemplo prático disso é fornecido abaixo.

Você usará a abordagem skip-gram neste tutorial. Primeiro, você explorará gramas de salto e outros conceitos usando uma única frase para ilustração. A seguir, você treinará seu próprio modelo Word2Vec em um pequeno conjunto de dados. Este tutorial também contém código para exportar os embeddings treinados e visualizá-los no Projetor de Embedding TensorFlow .

Skip-gram e amostragem negativa

Enquanto um modelo de saco de palavras prediz uma palavra dado o contexto vizinho, um modelo skip gram prediz o contexto (ou vizinhos) de uma palavra, dado a própria palavra. O modelo é treinado para ignorar gramas, que são n-gramas que permitem que os tokens sejam ignorados (consulte o diagrama abaixo para obter um exemplo). O contexto de uma palavra pode ser representado por meio de um conjunto de pares de skip-gram de (target_word, context_word) onde context_word aparece no contexto vizinho de target_word .

Considere a seguinte frase de 8 palavras.

A estrada larga tremeluziu ao sol quente.

As palavras de contexto para cada uma das 8 palavras desta frase são definidas por um tamanho de janela. O tamanho da janela determina a extensão das palavras em cada lado de uma target_word que pode ser considerada uma context word . Dê uma olhada nesta tabela de gramas de salto para palavras-alvo baseadas em tamanhos de janela diferentes.

word2vec_skipgrams

O objetivo de treinamento do modelo skip-gram é maximizar a probabilidade de prever palavras de contexto dadas a palavra-alvo. Para uma sequência de palavras w 1 , w 2 , ... w T , o objetivo pode ser escrito como o log de probabilidade médio

word2vec_skipgram_objective

onde c é o tamanho do contexto de treinamento. A formulação básica do skip-gram define essa probabilidade usando a função softmax.

word2vec_full_softmax

onde v e v ' são representações vetoriais de palavras-alvo e contexto e W é o tamanho do vocabulário.

Calcular o denominador desta formulação envolve realizar um softmax completo sobre todas as palavras do vocabulário, o que geralmente é grande (10 5 -10 7 ) termos.

A função de perda de estimativa de ruído contrastante é uma aproximação eficiente para um softmax completo. Com o objetivo de aprender embeddings de palavras em vez de modelar a distribuição de palavras, a perda de NCE pode ser simplificada para usar amostragem negativa.

O objetivo simplificado da amostragem negativa para uma palavra-alvo é distinguir a palavra de contexto das amostras negativas num_ns retiradas da distribuição de ruído P n (w) de palavras. Mais precisamente, uma aproximação eficiente de softmax total sobre o vocabulário é, para um par skip-gram, representar a perda de uma palavra-alvo como um problema de classificação entre a palavra de contexto e as amostras negativas num_ns .

Uma amostra negativa é definida como um par (target_word, context_word) de forma que context_word não apareça na vizinhança window_size de target_word. Para a frase de exemplo, essas são algumas amostras negativas em potencial (quando window_size é 2).

(hot, shimmered)
(wide, hot)
(wide, sun)

Na próxima seção, você gerará gramas de salto e amostras negativas para uma única frase. Você também aprenderá sobre técnicas de subamostragem e treinará um modelo de classificação para exemplos de treinamento positivos e negativos posteriormente no tutorial.

Configurar

import io
import re
import string
import tensorflow as tf
import tqdm

from tensorflow.keras import Model
from tensorflow.keras.layers import Dot, Embedding, Flatten
from tensorflow.keras.layers.experimental.preprocessing import TextVectorization
# Load the TensorBoard notebook extension
%load_ext tensorboard
SEED = 42
AUTOTUNE = tf.data.AUTOTUNE

Vectorize uma frase de exemplo

Considere a seguinte frase:
The wide road shimmered in the hot sun.

Tokenize a frase:

sentence = "The wide road shimmered in the hot sun"
tokens = list(sentence.lower().split())
print(len(tokens))
8

Crie um vocabulário para salvar mapeamentos de tokens para índices inteiros.

vocab, index = {}, 1  # start indexing from 1
vocab['<pad>'] = 0  # add a padding token
for token in tokens:
  if token not in vocab:
    vocab[token] = index
    index += 1
vocab_size = len(vocab)
print(vocab)
{'<pad>': 0, 'the': 1, 'wide': 2, 'road': 3, 'shimmered': 4, 'in': 5, 'hot': 6, 'sun': 7}

Crie um vocabulário inverso para salvar mapeamentos de índices inteiros para tokens.

inverse_vocab = {index: token for token, index in vocab.items()}
print(inverse_vocab)
{0: '<pad>', 1: 'the', 2: 'wide', 3: 'road', 4: 'shimmered', 5: 'in', 6: 'hot', 7: 'sun'}

Vectorize sua frase.

example_sequence = [vocab[word] for word in tokens]
print(example_sequence)
[1, 2, 3, 4, 5, 1, 6, 7]

Gere pula-gramas de uma frase

O módulo tf.keras.preprocessing.sequence fornece funções úteis que simplificam a preparação de dados para Word2Vec. Você pode usar tf.keras.preprocessing.sequence.skipgrams para gerar pares skip-gram de example_sequence com um determinado window_size de tokens no intervalo [0, vocab_size) .

window_size = 2
positive_skip_grams, _ = tf.keras.preprocessing.sequence.skipgrams(
      example_sequence,
      vocabulary_size=vocab_size,
      window_size=window_size,
      negative_samples=0)
print(len(positive_skip_grams))
26

Dê uma olhada em alguns gramas de salto positivos.

for target, context in positive_skip_grams[:5]:
  print(f"({target}, {context}): ({inverse_vocab[target]}, {inverse_vocab[context]})")
(1, 4): (the, shimmered)
(4, 3): (shimmered, road)
(4, 5): (shimmered, in)
(3, 2): (road, wide)
(1, 7): (the, sun)

Amostragem negativa para um grama de salto

A função skipgrams retorna todos os pares positivos de skip-gram deslizando sobre um determinado intervalo de janela. Para produzir pares de pular-grama adicionais que serviriam como amostras negativas para o treinamento, você precisa obter uma amostra de palavras aleatórias do vocabulário. Use a função tf.random.log_uniform_candidate_sampler para amostrar num_ns número de amostras negativas para uma determinada palavra-alvo em uma janela. Você pode chamar a função em uma palavra-alvo de skip-gram e passar a palavra de contexto como classe verdadeira para excluí-la da amostragem.

# Get target and context words for one positive skip-gram.
target_word, context_word = positive_skip_grams[0]

# Set the number of negative samples per positive context.
num_ns = 4

context_class = tf.reshape(tf.constant(context_word, dtype="int64"), (1, 1))
negative_sampling_candidates, _, _ = tf.random.log_uniform_candidate_sampler(
    true_classes=context_class,  # class that should be sampled as 'positive'
    num_true=1,  # each positive skip-gram has 1 positive context class
    num_sampled=num_ns,  # number of negative context words to sample
    unique=True,  # all the negative samples should be unique
    range_max=vocab_size,  # pick index of the samples from [0, vocab_size]
    seed=SEED,  # seed for reproducibility
    name="negative_sampling"  # name of this operation
)
print(negative_sampling_candidates)
print([inverse_vocab[index.numpy()] for index in negative_sampling_candidates])
tf.Tensor([2 1 4 3], shape=(4,), dtype=int64)
['wide', 'the', 'shimmered', 'road']

Construir um exemplo de treinamento

Para um determinado skip-gram positivo (target_word, context_word) , agora você também tem num_ns palavras de contexto de amostra negativa que não aparecem na vizinhança do tamanho da janela de target_word . context_word as 1 context_word positiva e num_ns palavras de contexto negativas em um tensor. Isso produz um conjunto de gramas de salto positivos (rotulados como 1 ) e amostras negativas (rotulados como 0 ) para cada palavra-alvo.

# Add a dimension so you can use concatenation (on the next step).
negative_sampling_candidates = tf.expand_dims(negative_sampling_candidates, 1)

# Concat positive context word with negative sampled words.
context = tf.concat([context_class, negative_sampling_candidates], 0)

# Label first context word as 1 (positive) followed by num_ns 0s (negative).
label = tf.constant([1] + [0]*num_ns, dtype="int64")

# Reshape target to shape (1,) and context and label to (num_ns+1,).
target = tf.squeeze(target_word)
context = tf.squeeze(context)
label = tf.squeeze(label)

Dê uma olhada no contexto e nos rótulos correspondentes para a palavra-alvo no exemplo de pular grama acima.

print(f"target_index    : {target}")
print(f"target_word     : {inverse_vocab[target_word]}")
print(f"context_indices : {context}")
print(f"context_words   : {[inverse_vocab[c.numpy()] for c in context]}")
print(f"label           : {label}")
target_index    : 1
target_word     : the
context_indices : [4 2 1 4 3]
context_words   : ['shimmered', 'wide', 'the', 'shimmered', 'road']
label           : [1 0 0 0 0]

Uma tupla de tensores (target, context, label) constitui um exemplo de treinamento para treinar seu modelo Word2Vec de amostragem negativa de gram de salto. Observe que o destino tem a forma (1,) enquanto o contexto e o rótulo são da forma (1+num_ns,)

print("target  :", target)
print("context :", context)
print("label   :", label)
target  : tf.Tensor(1, shape=(), dtype=int32)
context : tf.Tensor([4 2 1 4 3], shape=(5,), dtype=int64)
label   : tf.Tensor([1 0 0 0 0], shape=(5,), dtype=int64)

Resumo

Esta imagem resume o procedimento de geração de exemplo de treinamento a partir de uma frase.

word2vec_negative_sampling

Compilar todas as etapas em uma função

Tabela de amostragem de pulo-grama

Um grande conjunto de dados significa vocabulário maior com um número maior de palavras mais frequentes, como palavras irrelevantes. Exemplos de treinamento obtidos por uma amostragem palavras que ocorrem comumente (como the , is , on ) não acrescentam muita informação útil para o modelo para aprender. Mikolov et al. sugerir subamostragem de palavras frequentes como uma prática útil para melhorar a qualidade de incorporação.

A função tf.keras.preprocessing.sequence.skipgrams aceita um argumento de tabela de amostragem para codificar probabilidades de amostragem de qualquer token. Você pode usar tf.keras.preprocessing.sequence.make_sampling_table para gerar uma tabela de amostragem probabilística baseada em classificação de frequência de palavras e passá-la para a função skipgrams . Dê uma olhada nas probabilidades de amostragem para um vocab_size de 10.

sampling_table = tf.keras.preprocessing.sequence.make_sampling_table(size=10)
print(sampling_table)
[0.00315225 0.00315225 0.00547597 0.00741556 0.00912817 0.01068435
 0.01212381 0.01347162 0.01474487 0.0159558 ]

sampling_table[i] denota a probabilidade de amostragem da i-ésima palavra mais comum em um conjunto de dados. A função assume uma distribuição Zipf das frequências de palavras para amostragem.

Gerar dados de treinamento

Compile todas as etapas descritas acima em uma função que pode ser chamada em uma lista de frases vetorizadas obtidas de qualquer conjunto de dados de texto. Observe que a tabela de amostragem é construída antes da amostragem dos pares de palavras do grama ignorado. Você usará esta função nas seções posteriores.

# Generates skip-gram pairs with negative sampling for a list of sequences
# (int-encoded sentences) based on window size, number of negative samples
# and vocabulary size.
def generate_training_data(sequences, window_size, num_ns, vocab_size, seed):
  # Elements of each training example are appended to these lists.
  targets, contexts, labels = [], [], []

  # Build the sampling table for vocab_size tokens.
  sampling_table = tf.keras.preprocessing.sequence.make_sampling_table(vocab_size)

  # Iterate over all sequences (sentences) in dataset.
  for sequence in tqdm.tqdm(sequences):

    # Generate positive skip-gram pairs for a sequence (sentence).
    positive_skip_grams, _ = tf.keras.preprocessing.sequence.skipgrams(
          sequence,
          vocabulary_size=vocab_size,
          sampling_table=sampling_table,
          window_size=window_size,
          negative_samples=0)

    # Iterate over each positive skip-gram pair to produce training examples
    # with positive context word and negative samples.
    for target_word, context_word in positive_skip_grams:
      context_class = tf.expand_dims(
          tf.constant([context_word], dtype="int64"), 1)
      negative_sampling_candidates, _, _ = tf.random.log_uniform_candidate_sampler(
          true_classes=context_class,
          num_true=1,
          num_sampled=num_ns,
          unique=True,
          range_max=vocab_size,
          seed=SEED,
          name="negative_sampling")

      # Build context and label vectors (for one target word)
      negative_sampling_candidates = tf.expand_dims(
          negative_sampling_candidates, 1)

      context = tf.concat([context_class, negative_sampling_candidates], 0)
      label = tf.constant([1] + [0]*num_ns, dtype="int64")

      # Append each element from the training example to global lists.
      targets.append(target_word)
      contexts.append(context)
      labels.append(label)

  return targets, contexts, labels

Prepare dados de treinamento para Word2Vec

Com a compreensão de como trabalhar com uma frase para um modelo Word2Vec baseado em amostragem negativa de gram, você pode continuar a gerar exemplos de treinamento a partir de uma lista maior de frases!

Baixar corpus de texto

Você usará um arquivo de texto da escrita de Shakespeare para este tutorial. Altere a linha a seguir para executar este código em seus próprios dados.

path_to_file = tf.keras.utils.get_file('shakespeare.txt', 'https://storage.googleapis.com/download.tensorflow.org/data/shakespeare.txt')
Downloading data from https://storage.googleapis.com/download.tensorflow.org/data/shakespeare.txt
1122304/1115394 [==============================] - 0s 0us/step

Leia o texto do arquivo e observe as primeiras linhas.

with open(path_to_file) as f: 
  lines = f.read().splitlines()
for line in lines[:20]:
  print(line)
First Citizen:
Before we proceed any further, hear me speak.

All:
Speak, speak.

First Citizen:
You are all resolved rather to die than to famish?

All:
Resolved. resolved.

First Citizen:
First, you know Caius Marcius is chief enemy to the people.

All:
We know't, we know't.

First Citizen:
Let us kill him, and we'll have corn at our own price.

Use as linhas não vazias para construir um objeto tf.data.TextLineDataset para as próximas etapas.

text_ds = tf.data.TextLineDataset(path_to_file).filter(lambda x: tf.cast(tf.strings.length(x), bool))

Vectorize frases do corpus

Você pode usar a camada TextVectorization para vetorizar frases do corpus. Saiba mais sobre como usar essa camada neste tutorial de classificação de texto . Observe nas primeiras frases acima que o texto precisa estar em um caso e a pontuação precisa ser removida. Para fazer isso, defina uma custom_standardization function que pode ser usada na camada TextVectorization.

# Now, create a custom standardization function to lowercase the text and
# remove punctuation.
def custom_standardization(input_data):
  lowercase = tf.strings.lower(input_data)
  return tf.strings.regex_replace(lowercase,
                                  '[%s]' % re.escape(string.punctuation), '')


# Define the vocabulary size and number of words in a sequence.
vocab_size = 4096
sequence_length = 10

# Use the text vectorization layer to normalize, split, and map strings to
# integers. Set output_sequence_length length to pad all samples to same length.
vectorize_layer = TextVectorization(
    standardize=custom_standardization,
    max_tokens=vocab_size,
    output_mode='int',
    output_sequence_length=sequence_length)

Chame adapt no conjunto de dados de texto para criar vocabulário.

vectorize_layer.adapt(text_ds.batch(1024))

Uma vez que o estado da camada foi adaptado para representar o corpus do texto, o vocabulário pode ser acessado com get_vocabulary() . Esta função retorna uma lista de todos os tokens de vocabulário classificados (decrescente) por sua frequência.

# Save the created vocabulary for reference.
inverse_vocab = vectorize_layer.get_vocabulary()
print(inverse_vocab[:20])
['', '[UNK]', 'the', 'and', 'to', 'i', 'of', 'you', 'my', 'a', 'that', 'in', 'is', 'not', 'for', 'with', 'me', 'it', 'be', 'your']

O vectorize_layer agora pode ser usado para gerar vetores para cada elemento no text_ds .

# Vectorize the data in text_ds.
text_vector_ds = text_ds.batch(1024).prefetch(AUTOTUNE).map(vectorize_layer).unbatch()

Obtenha sequências do conjunto de dados

Agora você tem umtf.data.Dataset de frases codificadas por inteiros. Para preparar o conjunto de dados para treinar um modelo Word2Vec, achatar o conjunto de dados em uma lista de sequências de vetores de frases. Esta etapa é necessária, pois você iteraria cada frase no conjunto de dados para produzir exemplos positivos e negativos.

sequences = list(text_vector_ds.as_numpy_iterator())
print(len(sequences))
32777

Dê uma olhada em alguns exemplos de sequences .

for seq in sequences[:5]:
  print(f"{seq} => {[inverse_vocab[i] for i in seq]}")
[ 89 270   0   0   0   0   0   0   0   0] => ['first', 'citizen', '', '', '', '', '', '', '', '']
[138  36 982 144 673 125  16 106   0   0] => ['before', 'we', 'proceed', 'any', 'further', 'hear', 'me', 'speak', '', '']
[34  0  0  0  0  0  0  0  0  0] => ['all', '', '', '', '', '', '', '', '', '']
[106 106   0   0   0   0   0   0   0   0] => ['speak', 'speak', '', '', '', '', '', '', '', '']
[ 89 270   0   0   0   0   0   0   0   0] => ['first', 'citizen', '', '', '', '', '', '', '', '']

Gere exemplos de treinamento a partir de sequências

sequences agora é uma lista de sentenças codificadas int. Basta chamar a função generate_training_data() definida anteriormente para gerar exemplos de treinamento para o modelo Word2Vec. Para recapitular, a função itera sobre cada palavra de cada sequência para coletar palavras de contexto positivas e negativas. O comprimento do alvo, os contextos e os rótulos devem ser os mesmos, representando o número total de exemplos de treinamento.

targets, contexts, labels = generate_training_data(
    sequences=sequences,
    window_size=2,
    num_ns=4,
    vocab_size=vocab_size,
    seed=SEED)
print(len(targets), len(contexts), len(labels))
100%|██████████| 32777/32777 [00:25<00:00, 1267.26it/s]
64720 64720 64720

Configure o conjunto de dados para desempenho

Para executar lotes eficientes para o número potencialmente grande de exemplos de treinamento, use a APItf.data.Dataset . Após esta etapa, você teria um objetotf.data.Dataset de (target_word, context_word), (label) elementos para treinar seu modelo Word2Vec!

BATCH_SIZE = 1024
BUFFER_SIZE = 10000
dataset = tf.data.Dataset.from_tensor_slices(((targets, contexts), labels))
dataset = dataset.shuffle(BUFFER_SIZE).batch(BATCH_SIZE, drop_remainder=True)
print(dataset)
<BatchDataset shapes: (((1024,), (1024, 5, 1)), (1024, 5)), types: ((tf.int32, tf.int64), tf.int64)>

Adicione cache() e prefetch() para melhorar o desempenho.

dataset = dataset.cache().prefetch(buffer_size=AUTOTUNE)
print(dataset)
<PrefetchDataset shapes: (((1024,), (1024, 5, 1)), (1024, 5)), types: ((tf.int32, tf.int64), tf.int64)>

Modelo e treinamento

O modelo Word2Vec pode ser implementado como um classificador para distinguir entre palavras de contexto verdadeiras de gramas de salto e palavras de contexto falsas obtidas por amostragem negativa. Você pode realizar um produto escalar entre os embeddings de palavras de destino e de contexto para obter previsões para rótulos e calcular a perda contra rótulos verdadeiros no conjunto de dados.

Modelo Word2Vec com subclasse

Use a API Keras Subclassing para definir seu modelo Word2Vec com as seguintes camadas:

  • target_embedding : Uma camada tf.keras.layers.Embedding que procura a incorporação de uma palavra quando ela aparece como uma palavra-alvo. O número de parâmetros nesta camada é (vocab_size * embedding_dim) .
  • context_embedding : Outra camada tf.keras.layers.Embedding que procura a incorporação de uma palavra quando ela aparece como uma palavra de contexto. O número de parâmetros nesta camada é igual ao de target_embedding , ou seja, (vocab_size * embedding_dim) .
  • dots : uma camada tf.keras.layers.Dot que calcula o produto escalar de embeddings de destino e contexto de um par de treinamento.
  • flatten : Uma camada tf.keras.layers.Flatten para achatar os resultados da camada de dots em logits.

Com o modelo de subclasse, você pode definir a função call() que aceita pares (target, context) que podem então ser passados ​​para sua camada de incorporação correspondente. Remodele o context_embedding para realizar um produto target_embedding com target_embedding e retornar o resultado nivelado.

class Word2Vec(Model):
  def __init__(self, vocab_size, embedding_dim):
    super(Word2Vec, self).__init__()
    self.target_embedding = Embedding(vocab_size,
                                      embedding_dim,
                                      input_length=1,
                                      name="w2v_embedding")
    self.context_embedding = Embedding(vocab_size,
                                       embedding_dim,
                                       input_length=num_ns+1)
    self.dots = Dot(axes=(3, 2))
    self.flatten = Flatten()

  def call(self, pair):
    target, context = pair
    word_emb = self.target_embedding(target)
    context_emb = self.context_embedding(context)
    dots = self.dots([context_emb, word_emb])
    return self.flatten(dots)

Definir a função de perda e compilar o modelo

Para simplificar, você pode usar tf.keras.losses.CategoricalCrossEntropy como uma alternativa para a perda de amostragem negativa. Se quiser escrever sua própria função de perda personalizada, você também pode fazer o seguinte:

def custom_loss(x_logit, y_true):
      return tf.nn.sigmoid_cross_entropy_with_logits(logits=x_logit, labels=y_true)

É hora de construir seu modelo! Instancie sua classe Word2Vec com uma dimensão de incorporação de 128 (você pode experimentar com valores diferentes). Compile o modelo com o otimizador tf.keras.optimizers.Adam .

embedding_dim = 128
word2vec = Word2Vec(vocab_size, embedding_dim)
word2vec.compile(optimizer='adam',
                 loss=tf.keras.losses.CategoricalCrossentropy(from_logits=True),
                 metrics=['accuracy'])

Defina também um retorno de chamada para registrar as estatísticas de treinamento do tensorboard.

tensorboard_callback = tf.keras.callbacks.TensorBoard(log_dir="logs")

Treine o modelo com o dataset preparado acima para algumas épocas.

word2vec.fit(dataset, epochs=20, callbacks=[tensorboard_callback])
Epoch 1/20
63/63 [==============================] - 2s 11ms/step - loss: 1.6082 - accuracy: 0.2308
Epoch 2/20
63/63 [==============================] - 0s 5ms/step - loss: 1.5889 - accuracy: 0.5539
Epoch 3/20
63/63 [==============================] - 0s 5ms/step - loss: 1.5412 - accuracy: 0.6001
Epoch 4/20
63/63 [==============================] - 0s 5ms/step - loss: 1.4585 - accuracy: 0.5751
Epoch 5/20
63/63 [==============================] - 0s 5ms/step - loss: 1.3600 - accuracy: 0.5834
Epoch 6/20
63/63 [==============================] - 0s 5ms/step - loss: 1.2628 - accuracy: 0.6110
Epoch 7/20
63/63 [==============================] - 0s 5ms/step - loss: 1.1719 - accuracy: 0.6456
Epoch 8/20
63/63 [==============================] - 0s 5ms/step - loss: 1.0875 - accuracy: 0.6791
Epoch 9/20
63/63 [==============================] - 0s 5ms/step - loss: 1.0092 - accuracy: 0.7101
Epoch 10/20
63/63 [==============================] - 0s 5ms/step - loss: 0.9366 - accuracy: 0.7379
Epoch 11/20
63/63 [==============================] - 0s 5ms/step - loss: 0.8695 - accuracy: 0.7622
Epoch 12/20
63/63 [==============================] - 0s 5ms/step - loss: 0.8076 - accuracy: 0.7848
Epoch 13/20
63/63 [==============================] - 0s 5ms/step - loss: 0.7507 - accuracy: 0.8050
Epoch 14/20
63/63 [==============================] - 0s 5ms/step - loss: 0.6985 - accuracy: 0.8217
Epoch 15/20
63/63 [==============================] - 0s 5ms/step - loss: 0.6507 - accuracy: 0.8368
Epoch 16/20
63/63 [==============================] - 0s 5ms/step - loss: 0.6071 - accuracy: 0.8506
Epoch 17/20
63/63 [==============================] - 0s 5ms/step - loss: 0.5673 - accuracy: 0.8633
Epoch 18/20
63/63 [==============================] - 0s 5ms/step - loss: 0.5311 - accuracy: 0.8741
Epoch 19/20
63/63 [==============================] - 0s 5ms/step - loss: 0.4981 - accuracy: 0.8842
Epoch 20/20
63/63 [==============================] - 0s 5ms/step - loss: 0.4681 - accuracy: 0.8936
<tensorflow.python.keras.callbacks.History at 0x7f120c5b5210>

O Tensorboard agora mostra a precisão e a perda do modelo Word2Vec.

%tensorboard --logdir logs

Incorporação de pesquisa e análise

Obtenha os pesos do modelo usando get_layer() e get_weights() . A função get_vocabulary() fornece o vocabulário para construir um arquivo de metadados com um token por linha.

weights = word2vec.get_layer('w2v_embedding').get_weights()[0]
vocab = vectorize_layer.get_vocabulary()

Crie e salve os vetores e o arquivo de metadados.

out_v = io.open('vectors.tsv', 'w', encoding='utf-8')
out_m = io.open('metadata.tsv', 'w', encoding='utf-8')

for index, word in enumerate(vocab):
  if index == 0:
    continue  # skip 0, it's padding.
  vec = weights[index]
  out_v.write('\t'.join([str(x) for x in vec]) + "\n")
  out_m.write(word + "\n")
out_v.close()
out_m.close()

Baixe o vectors.tsv e metadata.tsv para analisar os embeddings obtidos no Embedding Projector .

try:
  from google.colab import files
  files.download('vectors.tsv')
  files.download('metadata.tsv')
except Exception:
  pass

Próximos passos

Este tutorial mostrou como implementar um modelo Word2Vec skip-gram com amostragem negativa do zero e visualizar os embeddings de palavras obtidos.