Pomoc chronić Wielkiej Rafy Koralowej z TensorFlow na Kaggle Dołącz Wyzwanie

Word2Vec

Zobacz na TensorFlow.org Uruchom w Google Colab Wyświetl źródło na GitHub Pobierz notatnik

Word2Vec nie jest pojedynczym algorytmem, a raczej rodziną architektur modeli i optymalizacji, których można używać do uczenia się osadzania słów z dużych zbiorów danych. Osadzania wyuczone za pomocą Word2Vec okazały się skuteczne w wielu dalszych zadaniach przetwarzania języka naturalnego.

Artykuły te proponowały dwie metody uczenia się reprezentacji słów:

  • Ciągły model Bag-of-Words , który przewiduje środkowe słowo na podstawie otaczających słów kontekstu. Kontekst składa się z kilku słów przed i po bieżącym (środkowym) słowie. Ta architektura nazywana jest modelem torby słów, ponieważ kolejność słów w kontekście nie jest ważna.
  • Model przeskakiwania ciągłego, który przewiduje słowa z określonego zakresu przed i po bieżącym słowie w tym samym zdaniu. Praktyczny przykład tego jest podany poniżej.

W tym samouczku użyjesz metody pomijania gramów. Najpierw zapoznasz się z przeskokami i innymi pojęciami, używając jednego zdania do ilustracji. Następnie wytrenujesz własny model Word2Vec na małym zbiorze danych. Ten samouczek zawiera również kod do eksportowania wytrenowanych osadzeń i wizualizacji ich w TensorFlow Embedding Projector .

Pomijanie gramów i negatywne próbkowanie

Podczas gdy model bag-of-words przewiduje słowo w kontekście sąsiednim, model skip-gram przewiduje kontekst (lub sąsiednie) słowa, biorąc pod uwagę samo słowo. Model jest szkolony na pomijanych gramach, które są n-gramami, które umożliwiają pomijanie tokenów (przykład na poniższym diagramie). Kontekst słowa może być reprezentowany przez zestaw pominiętych par (target_word, context_word) gdzie context_word pojawia się w sąsiednim kontekście target_word .

Rozważ następujące zdanie składające się z 8 słów.

Szeroka droga lśniła w gorącym słońcu.

Słowa kontekstu dla każdego z 8 słów tego zdania są zdefiniowane przez rozmiar okna. Rozmiar okna określa rozpiętość słów po obu stronach target_word , które można uznać za context word . Spójrz na tę tabelę przeskoków dla słów docelowych w oparciu o różne rozmiary okien.

word2vec_skipgrams

Celem szkoleniowym modelu pomijania gramów jest maksymalizacja prawdopodobieństwa przewidywania słów kontekstowych przy danym słowie docelowym. Dla ciągu słów w 1 , w 2 , ... w T , cel można zapisać jako średnie prawdopodobieństwo logarytmiczne

word2vec_skipgram_objective

gdzie c jest rozmiarem kontekstu szkolenia. Podstawowe sformułowanie pomijania gramów definiuje to prawdopodobieństwo za pomocą funkcji softmax.

word2vec_full_softmax

gdzie v i v ' są reprezentacjami słów w wektorze docelowym i kontekstowym, a W jest rozmiarem słownika.

Obliczenie mianownika tego sformułowania polega na wykonaniu pełnego softmaxu na całym słownictwie, które często zawiera duże (10 5 -10 7 ) terminy.

Funkcja straty kontrastowego szacowania szumu jest efektywnym przybliżeniem dla pełnego softmaxu. Mając na celu naukę osadzania słów zamiast modelowania rozkładu słów, utratę NCE można uprościć , używając próbkowania ujemnego.

Uproszczonym celem próbkowania negatywnego dla słowa docelowego jest odróżnienie słowa kontekstowego od num_ns negatywnych próbek pobranych z rozkładu szumu Pn ( w) słów. Dokładniej, efektywne przybliżenie pełnego softmaxu w słownictwie polega na tym, że w przypadku pary przeskoków gramatycznych występuje strata słowa docelowego jako problem klasyfikacji między słowem kontekstowym a num_ns negatywnymi próbkami.

Ujemna próbka jest zdefiniowana jako para (słowo_docelowe, słowo_kontekstu) w taki sposób, że słowo_kontekstu nie pojawia się w sąsiedztwie window_size . W przykładowym zdaniu jest to kilka potencjalnych negatywnych próbek (gdy window_size wynosi 2).

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

W następnej sekcji wygenerujesz pominięte gramy i próbki ujemne dla pojedynczego zdania. W dalszej części samouczka dowiesz się również o technikach podpróbkowania i przeszkolisz model klasyfikacji dla pozytywnych i negatywnych przykładów szkoleniowych.

Ustawiać

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

Zwektoryzuj przykładowe zdanie

Rozważ następujące zdanie:
The wide road shimmered in the hot sun.

Tokenize zdanie:

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

Utwórz słownik, aby zapisać odwzorowania z tokenów na indeksy liczb całkowitych.

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}

Utwórz słownik odwrotny, aby zapisać odwzorowania z indeksów liczb całkowitych na tokeny.

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'}

Zwektoryzuj swoje zdanie.

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

Generuj przeskoki z jednego zdania

Moduł tf.keras.preprocessing.sequence udostępnia przydatne funkcje, które upraszczają przygotowanie danych dla Word2Vec. Możesz użyć tf.keras.preprocessing.sequence.skipgrams do wygenerowania par pomijanych-gramów z przykładowej sekwencji z danym window_size z tokenów z zakresu [0, vocab_size) example_sequence

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

Spójrz na kilka pozytywnych przeskoków.

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

Próbkowanie ujemne dla jednego pominięcia grama

Funkcja skipgrams gramów zwraca wszystkie dodatnie pary pomijanych gramów, przesuwając się po danym zakresie okna. Aby stworzyć dodatkowe pary pomijanych gramów, które posłużyłyby jako próbki ujemne do treningu, musisz pobrać losowe słowa ze słownika. Użyj funkcji tf.random.log_uniform_candidate_sampler , aby próbkować num_ns liczbę negatywnych próbek dla danego słowa docelowego w oknie. Możesz wywołać funkcję na słowie docelowym jednego skip-grams i przekazać słowo kontekstu jako true class, aby wykluczyć je z próbkowania.

# 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']

Skonstruuj jeden przykład szkolenia

Dla danego pominięcia pozytywnego (target_word, context_word) masz teraz także num_ns próbkowanych ujemnych słów kontekstowych, które nie pojawiają się w sąsiedztwie rozmiaru okna target_word . Połącz 1 dodatnie context_word i num_ns ujemne słowa kontekstu w jeden tensor. Daje to zestaw pozytywnych przeskoków (oznaczonych jako 1 ) i negatywnych próbek (oznaczonych jako 0 ) dla każdego słowa docelowego.

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

Przyjrzyj się kontekstowi i odpowiadającym mu etykietom słowa docelowego z powyższego przykładu pomijania gramatyki.

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    : 2
target_word     : wide
context_indices : [4 2 1 4 3]
context_words   : ['shimmered', 'wide', 'the', 'shimmered', 'road']
label           : [1 0 0 0 0]

Krotka tensorów (target, context, label) stanowi jeden przykład treningowy do trenowania modelu Word2Vec z próbkowaniem ujemnym. Zauważ, że cel ma kształt (1,) podczas gdy kontekst i etykieta mają kształt (1+num_ns,)

print("target  :", target)
print("context :", context)
print("label   :", label)
target  : tf.Tensor(2, 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)

Streszczenie

Ten obrazek podsumowuje procedurę generowania przykładu treningowego ze zdania.

word2vec_negative_sampling

Skompiluj wszystkie kroki w jedną funkcję

Pomijanie gramów Tabela próbkowania

Duży zbiór danych oznacza większe słownictwo z większą liczbą częstszych słów, takich jak stopwords. Przykłady uczące uzyskane z próbkowania często występujących słów (takich the , is , on ) nie dodają zbyt wielu przydatnych informacji, z których model mógłby się uczyć. Mikołow i in. zasugeruj podpróbkowanie częstych słów jako pomocną praktykę poprawiającą jakość osadzania.

Funkcja tf.keras.preprocessing.sequence.skipgrams przyjmuje argument tabeli próbkowania do kodowania prawdopodobieństw próbkowania dowolnego tokena. Za pomocą tf.keras.preprocessing.sequence.make_sampling_table można wygenerować probabilistyczną tabelę próbkowania opartą na rangach częstotliwości i przekazać ją do funkcji skipgrams . Spójrz na prawdopodobieństwa próbkowania dla vocab_size 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] oznacza prawdopodobieństwo próbkowania i-tego najczęściej używanego słowa w zbiorze danych. Funkcja przyjmuje rozkład Zipf częstotliwości słów do próbkowania.

Generuj dane treningowe

Skompiluj wszystkie opisane powyżej kroki w funkcję, którą można wywołać na liście zwektoryzowanych zdań uzyskanych z dowolnego zestawu danych tekstowych. Zauważ, że tabela próbkowania jest budowana przed próbkowaniem par słów pomijanych w gramach. Użyjesz tej funkcji w dalszych rozdziałach.

# 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

Przygotuj dane treningowe dla Word2Vec

Rozumiejąc, jak pracować z jednym zdaniem w modelu Word2Vec opartym na próbkowaniu ujemnym, możesz przystąpić do generowania przykładów szkoleniowych z większej listy zdań!

Pobierz korpus tekstowy

W tym samouczku użyjesz pliku tekstowego z tekstami Szekspira. Zmień następujący wiersz, aby uruchomić ten kod na własnych danych.

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

Przeczytaj tekst z pliku i spójrz na kilka pierwszych linijek.

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.

Użyj niepustych wierszy, aby utworzyć obiekt tf.data.TextLineDataset w następnych krokach.

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

Wektoryzuj zdania z korpusu

Możesz użyć warstwy TextVectorization do wektoryzacji zdań z korpusu. Dowiedz się więcej o korzystaniu z tej warstwy w samouczku dotyczącym klasyfikacji tekstu . Zauważ z kilku pierwszych zdań powyżej, że tekst musi być w jednym przypadku, a interpunkcja musi zostać usunięta. Aby to zrobić, zdefiniuj funkcję custom_standardization function , której można użyć w warstwie 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)

Zadzwoń adapt zestaw danych tekstowych, aby utworzyć słownictwo.

vectorize_layer.adapt(text_ds.batch(1024))

Gdy stan warstwy zostanie dostosowany do reprezentowania korpusu tekstowego, słownik można uzyskać za pomocą get_vocabulary() . Ta funkcja zwraca listę wszystkich tokenów słownika posortowanych (malejąco) według ich częstotliwości.

# 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']

Warstwa vectorize_layer może być teraz używana do generowania wektorów dla każdego elementu w text_ds .

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

Uzyskaj sekwencje ze zbioru danych

Masz teraz tf.data.Dataset zawierający zdania zakodowane jako liczby całkowite. Aby przygotować zestaw danych do uczenia modelu Word2Vec, spłaszcz zestaw danych do listy sekwencji wektorów zdań. Ten krok jest wymagany, ponieważ powtarzasz każde zdanie w zestawie danych, aby uzyskać pozytywne i negatywne przykłady.

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

Spójrz na kilka przykładów z 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', '', '', '', '', '', '', '', '']

Generuj przykłady treningowe z sekwencji

sequences jest teraz listą zakodowanych zdań int. Wystarczy wywołać zdefiniowaną wcześniej funkcję generate_training_data() w celu wygenerowania przykładów szkoleniowych dla modelu Word2Vec. Podsumowując, funkcja iteruje po każdym słowie z każdej sekwencji, aby zebrać pozytywne i negatywne słowa kontekstu. Długość celu, konteksty i etykiety powinny być takie same, reprezentując całkowitą liczbę przykładów szkoleniowych.

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:38<00:00, 841.16it/s]
targets.shape: (65623,)
contexts.shape: (65623, 5)
labels.shape: (65623, 5)

Skonfiguruj zbiór danych pod kątem wydajności

Aby wykonać wydajne przetwarzanie wsadowe dla potencjalnie dużej liczby przykładów szkoleniowych, użyj interfejsu API tf.data.Dataset . Po tym kroku będziesz miał obiekt tf.data.Dataset zawierający elementy (target_word, context_word), (label) do uczenia modelu 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 element_spec=((TensorSpec(shape=(1024,), dtype=tf.int64, name=None), TensorSpec(shape=(1024, 5), dtype=tf.int64, name=None)), TensorSpec(shape=(1024, 5), dtype=tf.int64, name=None))>

Dodaj cache() i prefetch() , aby poprawić wydajność.

dataset = dataset.cache().prefetch(buffer_size=AUTOTUNE)
print(dataset)
<PrefetchDataset element_spec=((TensorSpec(shape=(1024,), dtype=tf.int64, name=None), TensorSpec(shape=(1024, 5), dtype=tf.int64, name=None)), TensorSpec(shape=(1024, 5), dtype=tf.int64, name=None))>

Model i szkolenie

Model Word2Vec może być zaimplementowany jako klasyfikator do rozróżniania między słowami prawdziwego kontekstu a pominiętymi słowami i słowami fałszywego kontekstu uzyskanymi przez próbkowanie ujemne. Możesz wykonać iloczyn skalarny między osadzonymi słowami docelowymi i kontekstowymi, aby uzyskać prognozy dla etykiet i straty obliczeniowe względem prawdziwych etykiet w zestawie danych.

Podklasy Model Word2Vec

Użyj interfejsu API Keras Subclassing , aby zdefiniować swój model Word2Vec za pomocą następujących warstw:

  • target_embedding : Warstwa tf.keras.layers.Embedding , która wyszukuje osadzenie słowa, gdy pojawia się ono jako słowo docelowe. Liczba parametrów w tej warstwie to (vocab_size * embedding_dim) .
  • context_embedding : Kolejna warstwa tf.keras.layers.Embedding , która sprawdza osadzanie słowa, gdy pojawia się ono jako słowo kontekstu. Liczba parametrów w tej warstwie jest taka sama jak w target_embedding , tj. (vocab_size * embedding_dim) .
  • dots : warstwa tf.keras.layers.Dot , która oblicza iloczyn skalarny osadzeń celu i kontekstu z pary treningowej.
  • flatten : Warstwa tf.keras.layers.Flatten spłaszczająca wyniki warstwy dots do logit.

W modelu z podklasami można zdefiniować funkcję call() , która akceptuje pary (target, context) które można następnie przekazać do odpowiedniej warstwy osadzania. Zmień kształt context_embedding , aby wykonać iloczyn skalarny z target_embedding i zwrócić spłaszczony wynik.

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

Zdefiniuj funkcję straty i skompiluj model

Dla uproszczenia można użyć tf.keras.losses.CategoricalCrossEntropy jako alternatywy dla ujemnej utraty próbkowania. Jeśli chcesz napisać własną niestandardową funkcję straty, możesz to zrobić również w następujący sposób:

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

Czas zbudować swój model! Utwórz wystąpienie klasy Word2Vec z wymiarem osadzania równym 128 (możesz eksperymentować z różnymi wartościami). Skompiluj model za pomocą optymalizatora 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'])

Zdefiniuj również wywołanie zwrotne, aby rejestrować statystyki treningowe dla Tensorboard.

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

Trenuj model z dataset przygotowanym powyżej dla pewnej liczby epok.

word2vec.fit(dataset, epochs=20, callbacks=[tensorboard_callback])
Epoch 1/20
64/64 [==============================] - 1s 4ms/step - loss: 1.6082 - accuracy: 0.2325
Epoch 2/20
64/64 [==============================] - 0s 3ms/step - loss: 1.5883 - accuracy: 0.5519
Epoch 3/20
64/64 [==============================] - 0s 3ms/step - loss: 1.5392 - accuracy: 0.5956
Epoch 4/20
64/64 [==============================] - 0s 3ms/step - loss: 1.4551 - accuracy: 0.5715
Epoch 5/20
64/64 [==============================] - 0s 3ms/step - loss: 1.3565 - accuracy: 0.5788
Epoch 6/20
64/64 [==============================] - 0s 3ms/step - loss: 1.2595 - accuracy: 0.6057
Epoch 7/20
64/64 [==============================] - 0s 3ms/step - loss: 1.1691 - accuracy: 0.6394
Epoch 8/20
64/64 [==============================] - 0s 3ms/step - loss: 1.0854 - accuracy: 0.6738
Epoch 9/20
64/64 [==============================] - 0s 3ms/step - loss: 1.0078 - accuracy: 0.7062
Epoch 10/20
64/64 [==============================] - 0s 3ms/step - loss: 0.9359 - accuracy: 0.7366
Epoch 11/20
64/64 [==============================] - 0s 3ms/step - loss: 0.8693 - accuracy: 0.7632
Epoch 12/20
64/64 [==============================] - 0s 3ms/step - loss: 0.8078 - accuracy: 0.7845
Epoch 13/20
64/64 [==============================] - 0s 3ms/step - loss: 0.7512 - accuracy: 0.8045
Epoch 14/20
64/64 [==============================] - 0s 3ms/step - loss: 0.6994 - accuracy: 0.8210
Epoch 15/20
64/64 [==============================] - 0s 3ms/step - loss: 0.6519 - accuracy: 0.8360
Epoch 16/20
64/64 [==============================] - 0s 3ms/step - loss: 0.6086 - accuracy: 0.8499
Epoch 17/20
64/64 [==============================] - 0s 3ms/step - loss: 0.5691 - accuracy: 0.8622
Epoch 18/20
64/64 [==============================] - 0s 3ms/step - loss: 0.5331 - accuracy: 0.8731
Epoch 19/20
64/64 [==============================] - 0s 3ms/step - loss: 0.5003 - accuracy: 0.8833
Epoch 20/20
64/64 [==============================] - 0s 3ms/step - loss: 0.4705 - accuracy: 0.8918
<keras.callbacks.History at 0x7f002acb2990>

Tensorboard pokazuje teraz dokładność i stratę modelu Word2Vec.

#docs_infra: no_execute
%tensorboard --logdir logs

Wyszukiwanie i analiza osadzania

Uzyskaj wagi z modelu za pomocą funkcji get_layer() i get_weights() . Funkcja get_vocabulary() udostępnia słownik do tworzenia pliku metadanych z jednym tokenem w wierszu.

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

Utwórz i zapisz wektory i plik metadanych.

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

Pobierz vectors.tsv i metadata.tsv , aby przeanalizować uzyskane osadzania w Projektorze osadzania .

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

Następne kroki

Ten samouczek pokazał Ci, jak zaimplementować od podstaw model Word2Vec pomijania gramatycznego z negatywnym próbkowaniem i wizualizować uzyskane osadzania słów.