![]() |
![]() |
![]() |
![]() |
word2vec 不是單一演算法,而是一系列模型架構和最佳化方法,可用於從大型資料集中學習詞嵌入。透過 word2vec 學習到的嵌入已被證明在各種下游自然語言處理任務中都很成功。
這些論文提出了兩種學習詞表示的方法
- 連續詞袋模型:根據周圍的上下文詞預測中間詞。上下文由當前(中間)詞前後的幾個詞組成。此架構稱為詞袋模型,因為上下文中詞的順序並不重要。
- 連續 skip-gram 模型:預測同一句子中當前詞前後一定範圍內的詞。下面提供了一個實際範例。
在本教學課程中,您將使用 skip-gram 方法。首先,您將使用單一句子來說明 skip-gram 和其他概念。接下來,您將在小型資料集上訓練自己的 word2vec 模型。本教學課程還包含匯出已訓練嵌入並在 TensorFlow Embedding Projector 中視覺化它們的程式碼。
Skip-gram 和負採樣
雖然詞袋模型根據相鄰的上下文預測詞,但 skip-gram 模型根據詞本身預測詞的上下文(或鄰居)。該模型在 skip-gram 上進行訓練,skip-gram 是允許跳過符記的 n-gram(範例請參見下圖)。詞的上下文可以透過一組 (target_word, context_word) 的 skip-gram 對來表示,其中 context_word
出現在 target_word
的相鄰上下文中。
考慮以下由八個詞組成的句子
寬闊的道路在炎熱的陽光下閃爍。
此句子中 8 個詞中每個詞的上下文詞由視窗大小定義。視窗大小決定了 target_word
兩側的詞跨度,這些詞可以被視為 context word
。下表是基於不同視窗大小的目標詞的 skip-gram 表。
skip-gram 模型的訓練目標是最大化在給定目標詞的情況下預測上下文詞的機率。對於詞序列 w1, w2, ... wT,目標可以寫成平均對數機率
其中 c
是訓練上下文的大小。基本的 skip-gram 公式使用 softmax 函數定義此機率。
其中 v 和 v' 是詞的目標和上下文向量表示,W 是詞彙表大小。
計算此公式的分母涉及對整個詞彙表詞執行完整的 softmax,這些詞通常很大(105-107)項。
雜訊對比估計 (NCE) 損失函數是對完整 softmax 的有效近似值。由於目標是學習詞嵌入而不是對詞分佈進行建模,因此 NCE 損失可以簡化為使用負採樣。
目標詞的簡化負採樣目標是將上下文詞與從詞的雜訊分佈 Pn(w) 中抽取的 num_ns
個負樣本區分開來。更準確地說,詞彙表上完整 softmax 的有效近似值是,對於 skip-gram 對,將目標詞的損失表示為上下文詞和 num_ns
個負樣本之間的分類問題。
負樣本定義為 (target_word
, context_word
) 對,其中 context_word
不會出現在 target_word
的 window_size
鄰域中。對於範例句子,以下是一些潛在的負樣本(當 window_size
為 2
時)。
(hot, shimmered)
(wide, hot)
(wide, sun)
在下一節中,您將為單一句子產生 skip-gram 和負樣本。您還將學習有關子採樣技術,並在本教學課程稍後訓練用於正負訓練範例的分類模型。
設定
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
向量化範例句子
考慮以下句子
寬闊的道路在炎熱的陽光下閃爍。
符記化句子
sentence = "The wide road shimmered in the hot sun"
tokens = list(sentence.lower().split())
print(len(tokens))
8
建立詞彙表以儲存從符記到整數索引的對應
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}
建立反向詞彙表以儲存從整數索引到符記的對應
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'}
向量化您的句子
example_sequence = [vocab[word] for word in tokens]
print(example_sequence)
[1, 2, 3, 4, 5, 1, 6, 7]
從一個句子產生 skip-gram
tf.keras.preprocessing.sequence
模組提供了有用的函數,可簡化 word2vec 的資料準備工作。您可以使用 tf.keras.preprocessing.sequence.skipgrams
從 example_sequence
中產生 skip-gram 對,並從範圍 [0
, vocab_size
) 中的符記中給定 window_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
列印一些正 skip-gram
for target, context in positive_skip_grams[:5]:
print(f"({target}, {context}): ({inverse_vocab[target]}, {inverse_vocab[context]})")
(6, 1): (hot, the) (3, 5): (road, in) (1, 6): (the, hot) (4, 3): (shimmered, road) (5, 6): (in, hot)
單個 skip-gram 的負採樣
skipgrams
函數透過滑動給定的視窗跨度傳回所有正 skip-gram 對。若要產生將用作訓練負樣本的其他 skip-gram 對,您需要從詞彙表中採樣隨機詞。使用 tf.random.log_uniform_candidate_sampler
函數在視窗中為給定的目標詞採樣 num_ns
個負樣本。您可以對一個 skip-gram 的目標詞呼叫該函數,並將上下文詞作為真實類別傳遞,以將其排除在採樣之外。
# 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']
建構一個訓練範例
對於給定的正 (target_word
, context_word
) skip-gram,您現在還有 num_ns
個負採樣上下文詞,這些詞不會出現在 target_word
的視窗大小鄰域中。將 1
個正 context_word
和 num_ns
個負上下文詞批次處理成一個張量。這會為每個目標詞產生一組正 skip-gram(標記為 1
)和負樣本(標記為 0
)。
# Reduce a dimension so you can use concatenation (in the next step).
squeezed_context_class = tf.squeeze(context_class, 1)
# Concatenate a positive context word with negative sampled words.
context = tf.concat([squeezed_context_class, negative_sampling_candidates], 0)
# Label the first context word as `1` (positive) followed by `num_ns` `0`s (negative).
label = tf.constant([1] + [0]*num_ns, dtype="int64")
target = target_word
查看上面 skip-gram 範例中目標詞的上下文和對應標籤
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 : 6 target_word : hot context_indices : [1 2 1 4 3] context_words : ['the', 'wide', 'the', 'shimmered', 'road'] label : [1 0 0 0 0]
(target
, context
, label
) 張量的元組構成一個訓練範例,用於訓練您的 skip-gram 負採樣 word2vec 模型。請注意,目標的形狀為 (1
,),而上下文和標籤的形狀為 (1+num_ns
,)
print("target :", target)
print("context :", context)
print("label :", label)
target : 6 context : tf.Tensor([1 2 1 4 3], shape=(5,), dtype=int64) label : tf.Tensor([1 0 0 0 0], shape=(5,), dtype=int64)
摘要
此圖表總結了從句子產生訓練範例的程序
請注意,詞 temperature
和 code
不是輸入句子的一部分。它們與上圖中使用的某些其他索引一樣,屬於詞彙表。
將所有步驟編譯成一個函數
Skip-gram 採樣表
大型資料集意味著更大的詞彙表,其中包含更多常見詞,例如停用詞。從採樣常用詞(例如 the
、is
、on
)獲得的訓練範例對模型學習沒有增加太多有用的資訊。Mikolov 等人建議對常用詞進行子採樣作為提高嵌入品質的有用做法。
tf.keras.preprocessing.sequence.skipgrams
函數接受採樣表引數來編碼採樣任何符記的機率。您可以使用 tf.keras.preprocessing.sequence.make_sampling_table
產生基於詞頻排名的機率採樣表,並將其傳遞給 skipgrams
函數。檢查 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]
表示在資料集中採樣第 i 個最常見詞的機率。該函數假設詞頻率的採樣遵循 Zipf's 分佈。
產生訓練資料
將上述所有步驟編譯成一個函數,該函數可以在從任何文本資料集獲得的向量化句子清單上呼叫。請注意,採樣表是在採樣 skip-gram 詞對之前建立的。您將在後面的章節中使用此函數。
# 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 the 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 a 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)
context = tf.concat([tf.squeeze(context_class,1), 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
準備 word2vec 的訓練資料
了解如何使用單一句子處理基於 skip-gram 負採樣的 word2vec 模型後,您可以繼續從更大的句子清單中產生訓練範例!
下載文本語料庫
在本教學課程中,您將使用莎士比亞著作的文本檔案。變更以下行以在您自己的資料上執行此程式碼。
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 1115394/1115394 ━━━━━━━━━━━━━━━━━━━━ 0s 0us/step
從檔案讀取文本並列印前幾行
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.
使用非空行建構 tf.data.TextLineDataset
物件以進行後續步驟
text_ds = tf.data.TextLineDataset(path_to_file).filter(lambda x: tf.cast(tf.strings.length(x), bool))
從語料庫向量化句子
您可以使用 TextVectorization
層從語料庫向量化句子。在本文本分類教學課程中了解有關使用此層的更多資訊。從上面的前幾個句子中注意到,文本需要統一大小寫,並且需要移除標點符號。為此,定義一個可以在 TextVectorization 層中使用的 custom_standardization function
函數。
# 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 the 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 the `output_sequence_length` length to pad all samples to the
# same length.
vectorize_layer = layers.TextVectorization(
standardize=custom_standardization,
max_tokens=vocab_size,
output_mode='int',
output_sequence_length=sequence_length)
在文本資料集上呼叫 TextVectorization.adapt
以建立詞彙表。
vectorize_layer.adapt(text_ds.batch(1024))
2024-03-13 11:10:22.892874: W tensorflow/core/framework/local_rendezvous.cc:404] Local rendezvous is aborting with status: OUT_OF_RANGE: End of sequence
一旦層的狀態已調整為表示文本語料庫,就可以使用 TextVectorization.get_vocabulary
存取詞彙表。此函數傳回依頻率排序(降序)的所有詞彙表符記的清單。
# 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']
現在可以使用 vectorize_layer
為 text_ds
(tf.data.Dataset
)中的每個元素產生向量。套用 Dataset.batch
、Dataset.prefetch
、Dataset.map
和 Dataset.unbatch
。
# Vectorize the data in text_ds.
text_vector_ds = text_ds.batch(1024).prefetch(AUTOTUNE).map(vectorize_layer).unbatch()
從資料集取得序列
您現在擁有整數編碼句子的 tf.data.Dataset
。若要準備用於訓練 word2vec 模型的資料集,請將資料集展平為句子向量序列的清單。此步驟是必要的,因為您將反覆運算資料集中的每個句子以產生正負範例。
sequences = list(text_vector_ds.as_numpy_iterator())
print(len(sequences))
32777 2024-03-13 11:10:26.564811: W tensorflow/core/framework/local_rendezvous.cc:404] Local rendezvous is aborting with status: OUT_OF_RANGE: End of sequence
從 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', '', '', '', '', '', '', '', '']
從序列產生訓練範例
sequences
現在是整數編碼句子的清單。只需呼叫先前定義的 generate_training_data
函數,即可為 word2vec 模型產生訓練範例。總結一下,該函數會反覆運算每個序列中的每個詞,以收集正負上下文詞。目標、上下文和標籤的長度應相同,表示訓練範例的總數。
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)
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:37<00:00, 865.32it/s] targets.shape: (65462,) contexts.shape: (65462, 5) labels.shape: (65462, 5)
設定資料集以獲得效能
為了對可能大量的訓練範例執行有效率的批次處理,請使用 tf.data.Dataset
API。在此步驟之後,您將擁有 (target_word
, context_word
)、(label
) 元素的 tf.data.Dataset
物件,以訓練您的 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))>
套用 Dataset.cache
和 Dataset.prefetch
以提高效能
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))>
模型與訓練
word2vec 模型可以實作為分類器,以區分來自 skip-gram 的真實上下文詞和透過負採樣獲得的錯誤上下文詞。您可以執行目標詞和上下文詞嵌入之間的點積乘法,以獲得標籤的預測,並針對資料集中的真實標籤計算損失函數。
子類別化的 word2vec 模型
使用 Keras Subclassing API 定義您的 word2vec 模型,其中包含以下層
target_embedding
:tf.keras.layers.Embedding
層,當詞作為目標詞出現時,它會查找詞的嵌入。此層中的參數數量為 (vocab_size
*embedding_dim
)。context_embedding
:另一個tf.keras.layers.Embedding
層,當詞作為上下文詞出現時,它會查找詞的嵌入。此層中的參數數量與target_embedding
中的參數數量相同,即 (vocab_size
*embedding_dim
)。dots
:tf.keras.layers.Dot
層,用於計算來自訓練對的目標詞和上下文詞嵌入的點積。flatten
:tf.keras.layers.Flatten
層,用於將dots
層的結果展平為 logits。
使用子類別化的模型,您可以定義 call()
函數,該函數接受 (target
, context
) 對,然後可以將其傳遞到其對應的嵌入層中。重塑 context_embedding
以執行與 target_embedding
的點積,並傳回展平的結果。
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,
name="w2v_embedding")
self.context_embedding = layers.Embedding(vocab_size,
embedding_dim)
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
定義損失函數並編譯模型
為了簡單起見,您可以使用 tf.keras.losses.CategoricalCrossEntropy
作為負採樣損失的替代方案。如果您想編寫自己的自訂損失函數,您也可以執行以下操作
def custom_loss(x_logit, y_true):
return tf.nn.sigmoid_cross_entropy_with_logits(logits=x_logit, labels=y_true)
現在是時候建構您的模型了!使用 128 的嵌入維度(您可以嘗試不同的值)實例化您的 word2vec 類別。使用 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'])
也定義一個回呼以記錄 TensorBoard 的訓練統計資訊
tensorboard_callback = tf.keras.callbacks.TensorBoard(log_dir="logs")
在 dataset
上訓練模型幾個 epoch
word2vec.fit(dataset, epochs=20, callbacks=[tensorboard_callback])
Epoch 1/20 WARNING: All log messages before absl::InitializeLog() is called are written to STDERR I0000 00:00:1710328268.494065 10203 service.cc:145] XLA service 0x7f0a6c03e960 initialized for platform CUDA (this does not guarantee that XLA will be used). Devices: I0000 00:00:1710328268.494115 10203 service.cc:153] StreamExecutor device (0): Tesla T4, Compute Capability 7.5 I0000 00:00:1710328268.494119 10203 service.cc:153] StreamExecutor device (1): Tesla T4, Compute Capability 7.5 I0000 00:00:1710328268.494124 10203 service.cc:153] StreamExecutor device (2): Tesla T4, Compute Capability 7.5 I0000 00:00:1710328268.494127 10203 service.cc:153] StreamExecutor device (3): Tesla T4, Compute Capability 7.5 31/63 ━━━━━━━━━━━━━━━━━━━━ 0s 3ms/step - accuracy: 0.2072 - loss: 1.6092 I0000 00:00:1710328269.065899 10203 device_compiler.h:188] Compiled cluster using XLA! This line is logged at most once for the lifetime of the process. 63/63 ━━━━━━━━━━━━━━━━━━━━ 2s 8ms/step - accuracy: 0.2166 - loss: 1.6088 Epoch 2/20 63/63 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - accuracy: 0.5957 - loss: 1.5886 Epoch 3/20 63/63 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - accuracy: 0.5979 - loss: 1.5287 Epoch 4/20 63/63 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - accuracy: 0.5498 - loss: 1.4396 Epoch 5/20 63/63 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - accuracy: 0.5653 - loss: 1.3426 Epoch 6/20 63/63 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - accuracy: 0.6005 - loss: 1.2460 Epoch 7/20 63/63 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - accuracy: 0.6369 - loss: 1.1562 Epoch 8/20 63/63 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - accuracy: 0.6744 - loss: 1.0735 Epoch 9/20 63/63 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - accuracy: 0.7076 - loss: 0.9972 Epoch 10/20 63/63 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - accuracy: 0.7377 - loss: 0.9267 Epoch 11/20 63/63 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - accuracy: 0.7628 - loss: 0.8615 Epoch 12/20 63/63 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - accuracy: 0.7838 - loss: 0.8014 Epoch 13/20 63/63 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - accuracy: 0.8037 - loss: 0.7460 Epoch 14/20 63/63 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - accuracy: 0.8198 - loss: 0.6952 Epoch 15/20 63/63 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - accuracy: 0.8354 - loss: 0.6486 Epoch 16/20 63/63 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - accuracy: 0.8497 - loss: 0.6060 Epoch 17/20 63/63 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - accuracy: 0.8613 - loss: 0.5670 Epoch 18/20 63/63 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - accuracy: 0.8727 - loss: 0.5315 Epoch 19/20 63/63 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - accuracy: 0.8836 - loss: 0.4990 Epoch 20/20 63/63 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - accuracy: 0.8918 - loss: 0.4693 <keras.src.callbacks.history.History at 0x7f0c199f7520>
TensorBoard 現在顯示 word2vec 模型的準確度和損失
#docs_infra: no_execute
%tensorboard --logdir logs
嵌入查找和分析
使用 Model.get_layer
和 Layer.get_weights
從模型取得權重。TextVectorization.get_vocabulary
函數提供詞彙表,以建構每行一個符記的中繼資料檔案。
weights = word2vec.get_layer('w2v_embedding').get_weights()[0]
vocab = vectorize_layer.get_vocabulary()
建立並儲存向量和中繼資料檔案
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()
下載 vectors.tsv
和 metadata.tsv
以在 Embedding Projector 中分析獲得的嵌入
try:
from google.colab import files
files.download('vectors.tsv')
files.download('metadata.tsv')
except Exception:
pass
後續步驟
本教學課程已向您展示如何從頭開始實作具有負採樣的 skip-gram word2vec 模型,並視覺化獲得的詞嵌入。
若要深入了解詞向量及其數學表示,請參閱這些筆記。
若要深入了解進階文本處理,請閱讀「用於語言理解的 Transformer 模型」教學課程。
如果您對預先訓練的嵌入模型感興趣,您也可能對探索 TF-Hub CORD-19 Swivel 嵌入或多語言通用句子編碼器感興趣。
您可能也喜歡在新資料集上訓練模型(TensorFlow Datasets 中提供了許多資料集)。