Ajuda a proteger a Grande Barreira de Corais com TensorFlow em Kaggle Junte Desafio

Word2Vec

Ver no TensorFlow.org Executar no Google Colab Ver fonte no GitHub Baixar 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:

  • Continuous modelo saco-de-palavras que prediz a palavra do meio baseado em torno palavras de contexto. 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.
  • Contínuo Pular gramas Modelo que prever palavras dentro de um determinado intervalo antes e depois da palavra atual na mesma frase. Um exemplo prático disso é dado 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 o código para exportar os embeddings treinados e visualizá-los na incorporação Projector 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 salto gramas de (target_word, context_word) onde context_word aparece no contexto vizinha de target_word .

Considere a seguinte frase de 8 palavras.

A estrada larga tremeluzia 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 de palavras de cada lado de um target_word que pode ser considerado 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 a probabilidade log média

word2vec_skipgram_objective

onde c é o tamanho do contexto de formação. 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 alvo e vector contexto representações de palavras e W é o tamanho do vocabulário.

Calcular o denominador desta formulação envolve a execução de uma softmax sobre toda as palavras do vocabulário que muitas vezes é grande (10 5 -10 7) termos.

O Contrastive Estimativa Noise função de perda é uma aproximação eficiente para um softmax completo. Com o objetivo de aprender embeddings palavra em vez de modelar a distribuição palavra, perda NCE pode ser simplificada para utilizar a amostragem negativo.

O negativo simplificado amostragem objectiva para uma palavra de destino é para distinguir a palavra de contexto a partir de amostras negativas num_ns extraídas distribuição de ruído P n (w) de palavras. Mais precisamente, uma aproximação eficaz de softmax total sobre o vocabulário é, por um par de salto gramas, para representar a perda de uma palavra-alvo como um problema de classificação entre a palavra e contexto num_ns amostras negativas.

Uma amostra negativa é definida como uma (target_word, context_word) par de tal modo que o context_word não aparecer no window_size vizinhança do target_word. Para o exemplo frase, estes são algumas amostras potenciais negativos (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 tqdm

import numpy as np

import tensorflow as tf
from tensorflow.keras import layers
# 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 tf.keras.preprocessing.sequence módulo fornece funções úteis de preparação de dados que simplifique para Word2Vec. É possível utilizar os tf.keras.preprocessing.sequence.skipgrams para gerar pares Ir gramas do example_sequence com um dado window_size de fichas 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]})")
(3, 1): (road, the)
(6, 1): (hot, the)
(2, 1): (wide, the)
(6, 7): (hot, sun)
(6, 5): (hot, in)

Amostragem negativa para um grama de salto

Os skipgrams devolve todos os pares de Ir-gram positivas, deslizando ao longo de 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. Utilizar a tf.random.log_uniform_candidate_sampler função de amostra num_ns número de amostras negativas para uma dada 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 dado positivo (target_word, context_word) pular gramas, agora você também tem num_ns negativos palavras de contexto amostrados que não aparecem no bairro tamanho da janela de target_word . Lote os 1 positivos context_word e num_ns negativos palavras de contexto para um tensor. Isto produz um conjunto de SKIP-positivos gramas (rotulado como 1 ) e amostras negativas (rotulado 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    : 3
target_word     : road
context_indices : [1 2 1 4 3]
context_words   : ['the', 'wide', 'the', 'shimmered', 'road']
label           : [1 0 0 0 0]

Uma tupla de (target, context, label) tensores constitui exemplo de um treinamento para treinar seu negativo skip-gram amostragem modelo Word2Vec. Note-se que o alvo é de forma (1,) enquanto o contexto e o rótulo são de forma (1+num_ns,)

print("target  :", target)
print("context :", context)
print("label   :", label)
target  : tf.Tensor(3, shape=(), dtype=int32)
context : tf.Tensor([1 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.

O tf.keras.preprocessing.sequence.skipgrams função aceita um argumento mesa de amostragem para probabilidades codificar de amostragem qualquer token. Você pode usar o tf.keras.preprocessing.sequence.make_sampling_table para gerar uma tabela de amostragem probabilística classificação palavra-frequência baseada e passá-lo para skipgrams função. 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 o i-th palavra mais comum em um conjunto de dados. A função assume uma distribuição de Zipf das freqüências palavra por amostragem.

Gerar dados de treinamento

Compile todas as etapas descritas acima em uma função que pode ser chamada em uma lista de sentenças vetorizadas obtida 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
1130496/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 vazios para construir um tf.data.TextLineDataset objecto para os passos seguintes.

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 o TextVectorization camada para vetorizar frases do corpus. Saiba mais sobre como usar essa camada neste Classificação texto tutorial. Observe nas primeiras frases acima que o texto precisa estar em um caso e a pontuação precisa ser removida. Para fazer isso, definir uma custom_standardization function que pode ser usado 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 TextVectorization layer to normalize, split, and map strings to
# integers. Set output_sequence_length length to pad all samples to same length.
vectorize_layer = layers.TextVectorization(
    standardize=custom_standardization,
    max_tokens=vocab_size,
    output_mode='int',
    output_sequence_length=sequence_length)

Ligue para 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 adaptada para representar o corpo de texto, o vocabulário pode ser acedida 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 pode agora ser usado para gerar vectores para cada elemento nos 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 um tf.data.Dataset de inteiros codificado frases. 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 int codificado frases. Basta ligar para o generate_training_data() função 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)

targets = np.array(targets)
contexts = np.array(contexts)[:,:,0]
labels = np.array(labels)

print('\n')
print(f"targets.shape: {targets.shape}")
print(f"contexts.shape: {contexts.shape}")
print(f"labels.shape: {labels.shape}")
100%|██████████| 32777/32777 [00:33<00:00, 976.91it/s]
targets.shape: (64889,)
contexts.shape: (64889, 5)
labels.shape: (64889, 5)

Configure o conjunto de dados para desempenho

Para executar dosagem eficiente para o número potencialmente grande de exemplos de treinamento, use o tf.data.Dataset API. Após esta etapa, você teria um tf.data.Dataset objeto (target_word, context_word), (label) elementos para treinar o 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)), (1024, 5)), types: ((tf.int64, tf.int64), tf.int64)>

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

dataset = dataset.cache().prefetch(buffer_size=AUTOTUNE)
print(dataset)
<PrefetchDataset shapes: (((1024,), (1024, 5)), (1024, 5)), types: ((tf.int64, 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 o seu modelo Word2Vec com as seguintes camadas:

  • target_embedding : Um tf.keras.layers.Embedding camada que olha para a incorporação de uma palavra quando aparece como uma palavra-alvo. O número de parâmetros nesta camada são (vocab_size * embedding_dim) .
  • context_embedding : Outra tf.keras.layers.Embedding camada que olha para a incorporação de uma palavra quando ele aparece como uma palavra de contexto. O número de parâmetros desta camada são os mesmos como aqueles em target_embedding , ou seja, (vocab_size * embedding_dim) .
  • dots : Um tf.keras.layers.Dot camada que calcula o produto escalar das incorporações alvo e de contexto a partir de um par de formação.
  • flatten : Um tf.keras.layers.Flatten camada para achatar os resultados de dots camada em logitos.

Com o modelo de subclasse, pode-se definir a call() a função que aceita (target, context) pares que podem então ser passados para a sua incorporação camada correspondente. Remodelar o context_embedding para realizar um produto escalar com target_embedding e retornar o resultado achatada.

class Word2Vec(tf.keras.Model):
  def __init__(self, vocab_size, embedding_dim):
    super(Word2Vec, self).__init__()
    self.target_embedding = layers.Embedding(vocab_size,
                                      embedding_dim,
                                      input_length=1,
                                      name="w2v_embedding")
    self.context_embedding = layers.Embedding(vocab_size,
                                       embedding_dim,
                                       input_length=num_ns+1)

  def call(self, pair):
    target, context = pair
    # target: (batch, dummy?)  # The dummy axis doesn't exist in TF2.7+
    # context: (batch, context)
    if len(target.shape) == 2:
      target = tf.squeeze(target, axis=1)
    # target: (batch,)
    word_emb = self.target_embedding(target)
    # word_emb: (batch, embed)
    context_emb = self.context_embedding(context)
    # context_emb: (batch, context, embed)
    dots = tf.einsum('be,bce->bc', word_emb, context_emb)
    # dots: (batch, context)
    return dots

Definir função de perda e modelo de compilação

Para simplificar, você pode usar tf.keras.losses.CategoricalCrossEntropy como uma alternativa para a perda de amostragem negativo. 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). Compilar o modelo com o tf.keras.optimizers.Adam otimizador.

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")

Treinar o modelo com dataset acima preparada por algum número de épocas.

word2vec.fit(dataset, epochs=20, callbacks=[tensorboard_callback])
Epoch 1/20
63/63 [==============================] - 1s 9ms/step - loss: 1.6083 - accuracy: 0.2309
Epoch 2/20
63/63 [==============================] - 0s 2ms/step - loss: 1.5890 - accuracy: 0.5520
Epoch 3/20
63/63 [==============================] - 0s 3ms/step - loss: 1.5413 - accuracy: 0.6021
Epoch 4/20
63/63 [==============================] - 0s 2ms/step - loss: 1.4584 - accuracy: 0.5789
Epoch 5/20
63/63 [==============================] - 0s 2ms/step - loss: 1.3598 - accuracy: 0.5857
Epoch 6/20
63/63 [==============================] - 0s 2ms/step - loss: 1.2622 - accuracy: 0.6127
Epoch 7/20
63/63 [==============================] - 0s 2ms/step - loss: 1.1710 - accuracy: 0.6456
Epoch 8/20
63/63 [==============================] - 0s 2ms/step - loss: 1.0867 - accuracy: 0.6804
Epoch 9/20
63/63 [==============================] - 0s 3ms/step - loss: 1.0085 - accuracy: 0.7123
Epoch 10/20
63/63 [==============================] - 0s 2ms/step - loss: 0.9361 - accuracy: 0.7418
Epoch 11/20
63/63 [==============================] - 0s 2ms/step - loss: 0.8690 - accuracy: 0.7669
Epoch 12/20
63/63 [==============================] - 0s 2ms/step - loss: 0.8070 - accuracy: 0.7891
Epoch 13/20
63/63 [==============================] - 0s 2ms/step - loss: 0.7500 - accuracy: 0.8082
Epoch 14/20
63/63 [==============================] - 0s 3ms/step - loss: 0.6977 - accuracy: 0.8249
Epoch 15/20
63/63 [==============================] - 0s 3ms/step - loss: 0.6498 - accuracy: 0.8393
Epoch 16/20
63/63 [==============================] - 0s 3ms/step - loss: 0.6061 - accuracy: 0.8528
Epoch 17/20
63/63 [==============================] - 0s 3ms/step - loss: 0.5663 - accuracy: 0.8651
Epoch 18/20
63/63 [==============================] - 0s 3ms/step - loss: 0.5300 - accuracy: 0.8762
Epoch 19/20
63/63 [==============================] - 0s 2ms/step - loss: 0.4970 - accuracy: 0.8858
Epoch 20/20
63/63 [==============================] - 0s 2ms/step - loss: 0.4670 - accuracy: 0.8947
<keras.callbacks.History at 0x7fbea4362490>

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

%tensorboard --logdir logs

Incorporação de pesquisa e análise

Obter os pesos do modelo usando get_layer() e get_weights() . O get_vocabulary() função fornece o vocabulário para construir um arquivo de metadados com um sinal 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 Projector Embedding .

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.