Sehen Sie sich Keynotes, Produktsitzungen, Workshops und mehr in Google I / O an. Siehe Wiedergabeliste

Word2Vec

Ansicht auf TensorFlow.org In Google Colab ausführen Quelle auf GitHub anzeigenNotizbuch herunterladen

Word2Vec ist kein singulärer Algorithmus, sondern eine Familie von Modellarchitekturen und -optimierungen, mit denen Worteinbettungen aus großen Datenmengen gelernt werden können. Durch Word2Vec erlernte Einbettungen haben sich bei einer Vielzahl von nachgelagerten Aufgaben zur Verarbeitung natürlicher Sprache als erfolgreich erwiesen.

Diese Papiere schlugen zwei Methoden zum Lernen von Darstellungen von Wörtern vor:

  • Kontinuierliches Bag-of-Words-Modell, das das mittlere Wort basierend auf den umgebenden Kontextwörtern vorhersagt. Der Kontext besteht aus einigen Wörtern vor und nach dem aktuellen (mittleren) Wort. Diese Architektur wird als Bag-of-Word-Modell bezeichnet, da die Reihenfolge der Wörter im Kontext nicht wichtig ist.
  • Kontinuierliches Skip-Gramm-Modell, das Wörter innerhalb eines bestimmten Bereichs vor und nach dem aktuellen Wort im selben Satz vorhersagt. Ein Beispiel hierfür ist unten angegeben.

In diesem Tutorial verwenden Sie den Skip-Gram-Ansatz. Zunächst werden Sie Skip-Gramme und andere Konzepte anhand eines einzigen Satzes zur Veranschaulichung untersuchen. Als Nächstes trainieren Sie Ihr eigenes Word2Vec-Modell anhand eines kleinen Datensatzes. Dieses Tutorial enthält auch Code zum Exportieren der trainierten Einbettungen und zur Visualisierung im TensorFlow-Einbettungsprojektor .

Skip-Gramm und Negative Sampling

Während ein Wortsackmodell ein Wort im gegebenen Nachbarkontext vorhersagt, sagt ein Sprunggrammmodell den Kontext (oder die Nachbarn) eines Wortes unter Berücksichtigung des Wortes selbst voraus. Das Modell ist auf Überspring-Gramm trainiert, bei denen es sich um n-Gramm handelt, mit denen Token übersprungen werden können (ein Beispiel finden Sie in der folgenden Abbildung). Der Kontext eines Wortes kann durch eine Reihe von Sprung-Gramm-Paaren von (target_word, context_word) wobei context_word im benachbarten Kontext von target_word .

Betrachten Sie den folgenden Satz von 8 Wörtern.

Die breite Straße schimmerte in der heißen Sonne.

Die Kontextwörter für jedes der 8 Wörter dieses Satzes werden durch eine Fenstergröße definiert. Die Fenstergröße bestimmt die target_word auf beiden Seiten eines target_word , die als context word betrachtet werden context word . Schauen Sie sich diese Tabelle mit Sprunggramm für Zielwörter an, die auf verschiedenen Fenstergrößen basieren.

word2vec_skipgrams

Das Trainingsziel des Skip-Gram-Modells besteht darin, die Wahrscheinlichkeit der Vorhersage von Kontextwörtern bei gegebenem Zielwort zu maximieren. Für eine Folge von Wörtern w 1 , w 2 , ... w T kann das Ziel als durchschnittliche logarithmische Wahrscheinlichkeit geschrieben werden

word2vec_skipgram_objective

Dabei ist c die Größe des Trainingskontexts. Die grundlegende Skip-Gramm-Formulierung definiert diese Wahrscheinlichkeit unter Verwendung der Softmax-Funktion.

word2vec_full_softmax

wobei v und v ' Ziel- und Kontextvektordarstellungen von Wörtern sind und W die Vokabulargröße ist.

Das Berechnen des Nenners dieser Formulierung beinhaltet das Durchführen eines vollständigen Softmax über das gesamte Vokabular, das häufig große (10 5 - 10 7 ) Begriffe enthält.

Die Noise Contrastive Estimation Loss-Funktion ist eine effiziente Näherung für einen vollständigen Softmax. Mit dem Ziel, Worteinbettungen zu lernen, anstatt die Wortverteilung zu modellieren, kann der NCE-Verlust vereinfacht werden , um negative Stichproben zu verwenden.

Das vereinfachte negative Abtastziel für ein Zielwort besteht darin, das Kontextwort von num_ns negativen Abtastwerten zu unterscheiden, die aus der Rauschverteilung P n (w) von Wörtern gezogen werden. Genauer gesagt besteht eine effiziente Annäherung des vollständigen Softmax über das Vokabular für ein Sprung-Gramm-Paar darin, den Verlust für ein Zielwort als Klassifizierungsproblem zwischen dem Kontextwort und den negativen Stichproben num_ns darzustellen .

Eine negative Stichprobe wird als Paar (Zielwort, Kontextwort) definiert, sodass das Kontextwort nicht in der Nachbarschaft window_size des Zielworts angezeigt wird. Für den Beispielsatz sind dies nur wenige potenzielle negative Stichproben (wenn window_size 2 ist).

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

Im nächsten Abschnitt generieren Sie Sprunggramm und negative Stichproben für einen einzelnen Satz. Sie werden später im Lernprogramm auch etwas über Unterabtastungstechniken lernen und ein Klassifizierungsmodell für positive und negative Trainingsbeispiele trainieren.

Einrichten

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

Vektorisieren Sie einen Beispielsatz

Betrachten Sie den folgenden Satz:
The wide road shimmered in the hot sun.

Tokenisieren Sie den Satz:

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

Erstellen Sie ein Vokabular, um Zuordnungen von Token zu ganzzahligen Indizes zu speichern.

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}

Erstellen Sie ein inverses Vokabular, um Zuordnungen von ganzzahligen Indizes zu Token zu speichern.

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

Vektorisiere deinen Satz.

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

Generieren Sie Sprunggramm aus einem Satz

Das Modul tf.keras.preprocessing.sequence bietet nützliche Funktionen, die die Datenvorbereitung für Word2Vec vereinfachen. Sie können die tf.keras.preprocessing.sequence.skipgrams , um aus der example_sequence mit einer bestimmten window_size aus Token im Bereich [0, vocab_size) überspringende tf.keras.preprocessing.sequence.skipgrams zu generieren.

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

Schauen Sie sich einige positive Sprunggramm an.

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

Negative Stichprobe für ein Sprunggramm

Die Funktion skipgrams gibt alle positiven Skip-Gramm-Paare zurück, indem sie über eine bestimmte Fensterspanne gleitet. Um zusätzliche Sprung-Gramm-Paare zu erzeugen, die als negative Stichproben für das Training dienen, müssen Sie zufällige Wörter aus dem Wortschatz auswählen. Verwenden Sie die tf.random.log_uniform_candidate_sampler Funktion Probe num_ns Anzahl negativer Proben für ein gegebenes Zielwort in einem Fenster. Sie können die Funktion für das Zielwort eines Sprunggramms aufrufen und das Kontextwort als wahre Klasse übergeben, um es von der Abtastung auszuschließen.

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

Konstruieren Sie ein Trainingsbeispiel

Für ein bestimmtes positives (target_word, context_word) Überspring-Gramm haben Sie jetzt auch num_ns negativ abgetastete Kontextwörter, die nicht in der Fenstergrößenumgebung von target_word . context_word num_ns Wörter 1 positives context_word und num_ns negatives Kontextwort zu einem Tensor. Dies erzeugt einen Satz positiver Sprunggramm (als 1 ) und negativer Abtastwerte (als 0 ) für jedes Zielwort.

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

Schauen Sie sich den Kontext und die entsprechenden Beschriftungen für das Zielwort aus dem obigen Beispiel für das Überspringen von Gramm an.

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]

Ein Tupel von (target, context, label) Tensoren ist ein Trainingsbeispiel für das Training Ihres Word2Vec-Modells mit negativer Sprungstichprobe. Beachten Sie, dass das Ziel die Form (1,) während der Kontext und die Beschriftung die Form haben (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)

Zusammenfassung

Dieses Bild fasst die Vorgehensweise zum Generieren eines Trainingsbeispiels aus einem Satz zusammen.

word2vec_negative_sampling

Kompilieren Sie alle Schritte in einer Funktion

Skip-Gramm-Probentisch

Ein großer Datensatz bedeutet einen größeren Wortschatz mit einer höheren Anzahl häufigerer Wörter wie Stoppwörter. Trainingsbeispiele aus der Abtastung häufig vorkommende Wörter erhalten (wie the , is , on ) fügen Sie nicht viel nützliche Informationen für das Modell zu lernen. Mikolov et al. Schlagen Sie eine Unterabtastung häufiger Wörter als hilfreiche Methode zur Verbesserung der Einbettungsqualität vor.

Die Funktion tf.keras.preprocessing.sequence.skipgrams akzeptiert ein tf.keras.preprocessing.sequence.skipgrams , um die Wahrscheinlichkeiten für das Abtasten eines Tokens zu codieren. Sie können die tf.keras.preprocessing.sequence.make_sampling_table , um eine tf.keras.preprocessing.sequence.make_sampling_table rangbasierte probabilistische tf.keras.preprocessing.sequence.make_sampling_table zu generieren und an die Funktion skipgrams zu skipgrams . Schauen Sie sich die Stichprobenwahrscheinlichkeiten für eine vocab_size von 10 an.

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] bezeichnet die Wahrscheinlichkeit, das i-te häufigste Wort in einem Datensatz abzutasten. Die Funktion geht von einer Zipf-Verteilung der Worthäufigkeiten für die Abtastung aus.

Trainingsdaten generieren

Kompilieren Sie alle oben beschriebenen Schritte zu einer Funktion, die für eine Liste vektorisierter Sätze aufgerufen werden kann, die aus einem beliebigen Textdatensatz stammen. Beachten Sie, dass die Abtasttabelle vor dem Abtasten von Sprung-Gramm-Wortpaaren erstellt wird. Sie werden diese Funktion in den späteren Abschnitten verwenden.

# 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

Bereiten Sie Trainingsdaten für Word2Vec vor

Mit dem Verständnis, wie man mit einem Satz für ein Word2Vec-Modell auf der Basis von Skip-Gram-Negativ-Samples arbeitet, können Sie Trainingsbeispiele aus einer größeren Liste von Sätzen generieren!

Textkorpus herunterladen

Für dieses Tutorial verwenden Sie eine Textdatei von Shakespeares Schrift. Ändern Sie die folgende Zeile, um diesen Code für Ihre eigenen Daten auszuführen.

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

Lesen Sie den Text aus der Datei und sehen Sie sich die ersten Zeilen an.

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.

Verwenden Sie die nicht leeren Zeilen, um ein tf.data.TextLineDataset Objekt für die nächsten Schritte zu tf.data.TextLineDataset .

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

Vektorisieren Sie Sätze aus dem Korpus

Sie können die TextVectorization Ebene verwenden, um Sätze aus dem Korpus zu vektorisieren. Erfahren Sie mehr über diese Ebene in diesem mit Text Classification Tutorial. Beachten Sie aus den ersten Sätzen oben, dass der Text in einem Fall sein muss und Interpunktion entfernt werden muss. Definieren Sie dazu eine custom_standardization function , die in der TextVectorization-Ebene verwendet werden kann.

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

Rufen Sie adapt für den Textdatensatz auf, um Vokabeln zu erstellen.

vectorize_layer.adapt(text_ds.batch(1024))

Sobald der Status der Ebene angepasst wurde, um den Textkorpus darzustellen, kann mit get_vocabulary() das Vokabular zugegriffen werden. Diese Funktion gibt eine Liste aller Vokabeltoken zurück, die nach ihrer Häufigkeit sortiert (absteigend) sind.

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

Die vectorize_layer kann jetzt verwendet werden, um Vektoren für jedes Element in text_ds zu generieren.

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

Beziehen Sie Sequenzen aus dem Datensatz

Sie haben jetzt eintf.data.Dataset von ganzzahlig codierten Sätzen. Reduzieren Sie den Datensatz in eine Liste von Satzvektorsequenzen, um den Datensatz für das Training eines Word2Vec-Modells vorzubereiten. Dieser Schritt ist erforderlich, da Sie jeden Satz im Datensatz durchlaufen würden, um positive und negative Beispiele zu erstellen.

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

Schauen Sie sich einige Beispiele aus 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', '', '', '', '', '', '', '', '']

Generieren Sie Trainingsbeispiele aus Sequenzen

sequences ist jetzt eine Liste von int-codierten Sätzen. Rufen Sie einfach die zuvor definierte Funktion generate_training_data() auf, um Trainingsbeispiele für das Word2Vec-Modell zu generieren. Zusammenfassend lässt sich sagen, dass die Funktion jedes Wort aus jeder Sequenz durchläuft, um positive und negative Kontextwörter zu sammeln. Die Länge des Ziels, der Kontexte und der Beschriftungen sollte gleich sein und die Gesamtzahl der Trainingsbeispiele darstellen.

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, 1277.68it/s]
64460 64460 64460

Konfigurieren Sie das Dataset für die Leistung

Verwenden Sie die APItf.data.Dataset um eine effiziente Stapelverarbeitung für die möglicherweise große Anzahl von Schulungsbeispielentf.data.Dataset . Nach diesem Schritt hätten Sie eintf.data.Dataset Objekt mit (target_word, context_word), (label) -Elementen, um Ihr Word2Vec-Modell zu trainieren!

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

Fügen Sie cache() und prefetch() , um die Leistung zu verbessern.

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

Modell und Ausbildung

Das Word2Vec-Modell kann als Klassifizierer implementiert werden, um zwischen echten Kontextwörtern von Sprunggramm und falschen Kontextwörtern zu unterscheiden, die durch negative Abtastung erhalten wurden. Sie können ein Punktprodukt zwischen den Einbettungen von Ziel- und Kontextwörtern ausführen, um Vorhersagen für Beschriftungen zu erhalten und den Verlust anhand der tatsächlichen Beschriftungen im Datensatz zu berechnen.

Untergeordnetes Word2Vec-Modell

Verwenden Sie die Keras-Unterklassen-API , um Ihr Word2Vec-Modell mit den folgenden Ebenen zu definieren:

Mit dem untergeordneten Modell können Sie die Funktion call() definieren, die (target, context) Paare akzeptiert (target, context) die dann an die entsprechende Einbettungsschicht übergeben werden können. context_embedding das context_embedding , um mit target_embedding ein Punktprodukt target_embedding und das abgeflachte Ergebnis zurückzugeben.

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)

Verlustfunktion definieren und Modell kompilieren

Der Einfachheit halber können Sie tf.keras.losses.CategoricalCrossEntropy als Alternative zum negativen Stichprobenverlust verwenden. Wenn Sie Ihre eigene benutzerdefinierte Verlustfunktion schreiben möchten, können Sie dies auch wie folgt tun:

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

Es ist Zeit, Ihr Modell zu bauen! Instanziieren Sie Ihre Word2Vec-Klasse mit einer Einbettungsdimension von 128 (Sie können mit verschiedenen Werten experimentieren). Kompilieren Sie das Modell mit dem Optimierer 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'])

Definieren Sie auch einen Rückruf, um Trainingsstatistiken für Tensorboard zu protokollieren.

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

Trainieren Sie das Modell mit dem oben für einige Epochen vorbereiteten dataset .

word2vec.fit(dataset, epochs=20, callbacks=[tensorboard_callback])
Epoch 1/20
62/62 [==============================] - 2s 11ms/step - loss: 1.6082 - accuracy: 0.2333
Epoch 2/20
62/62 [==============================] - 0s 6ms/step - loss: 1.5888 - accuracy: 0.5541
Epoch 3/20
62/62 [==============================] - 0s 6ms/step - loss: 1.5416 - accuracy: 0.5999
Epoch 4/20
62/62 [==============================] - 0s 6ms/step - loss: 1.4599 - accuracy: 0.5756
Epoch 5/20
62/62 [==============================] - 0s 6ms/step - loss: 1.3620 - accuracy: 0.5836
Epoch 6/20
62/62 [==============================] - 0s 6ms/step - loss: 1.2647 - accuracy: 0.6102
Epoch 7/20
62/62 [==============================] - 0s 6ms/step - loss: 1.1738 - accuracy: 0.6427
Epoch 8/20
62/62 [==============================] - 0s 5ms/step - loss: 1.0897 - accuracy: 0.6761
Epoch 9/20
62/62 [==============================] - 0s 6ms/step - loss: 1.0119 - accuracy: 0.7084
Epoch 10/20
62/62 [==============================] - 0s 5ms/step - loss: 0.9398 - accuracy: 0.7376
Epoch 11/20
62/62 [==============================] - 0s 5ms/step - loss: 0.8729 - accuracy: 0.7626
Epoch 12/20
62/62 [==============================] - 0s 6ms/step - loss: 0.8112 - accuracy: 0.7856
Epoch 13/20
62/62 [==============================] - 0s 6ms/step - loss: 0.7543 - accuracy: 0.8062
Epoch 14/20
62/62 [==============================] - 0s 6ms/step - loss: 0.7020 - accuracy: 0.8233
Epoch 15/20
62/62 [==============================] - 0s 5ms/step - loss: 0.6541 - accuracy: 0.8380
Epoch 16/20
62/62 [==============================] - 0s 6ms/step - loss: 0.6104 - accuracy: 0.8517
Epoch 17/20
62/62 [==============================] - 0s 6ms/step - loss: 0.5704 - accuracy: 0.8643
Epoch 18/20
62/62 [==============================] - 0s 6ms/step - loss: 0.5340 - accuracy: 0.8759
Epoch 19/20
62/62 [==============================] - 0s 5ms/step - loss: 0.5009 - accuracy: 0.8850
Epoch 20/20
62/62 [==============================] - 0s 6ms/step - loss: 0.4707 - accuracy: 0.8937
<tensorflow.python.keras.callbacks.History at 0x7f907e9712d0>

Tensorboard zeigt jetzt die Genauigkeit und den Verlust des Word2Vec-Modells an.

%tensorboard --logdir logs

Einbetten von Lookup und Analyse

Erhalten Sie die Gewichte aus dem Modell mit get_layer() und get_weights() . Die Funktion get_vocabulary() stellt das Vokabular zum Erstellen einer Metadatendatei mit einem Token pro Zeile bereit.

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

Erstellen und speichern Sie die Vektoren und Metadatendateien.

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

Laden Sie die vectors.tsv und metadata.tsv herunter, um die erhaltenen Einbettungen im Einbettungsprojektor zu analysieren.

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

Nächste Schritte

Dieses Tutorial hat Ihnen gezeigt, wie Sie ein Word2Vec-Modell mit überspringendem Gramm mit negativer Stichprobe von Grund auf neu implementieren und die erhaltenen Worteinbettungen visualisieren.