Gensim 的 word2vec 从 epoch 1 开始损失为 0?
Gensim's word2vec has a loss of 0 from epoch 1?
我正在使用 Gensim 库的 Word2vec 模块来训练词嵌入,数据集是 400k 个句子和 100k 个独特的词(不是英语)
我正在使用此代码来监控和计算损失:
class MonitorCallback(CallbackAny2Vec):
def __init__(self, test_words):
self._test_words = test_words
def on_epoch_end(self, model):
print("Model loss:", model.get_latest_training_loss()) # print loss
for word in self._test_words: # show wv logic changes
print(model.wv.most_similar(word))
monitor = MonitorCallback(["MyWord"]) # monitor with demo words
w2v_model = gensim.models.word2vec.Word2Vec(size=W2V_SIZE, window=W2V_WINDOW, min_count=W2V_MIN_COUNT , callbacks=[monitor])
w2v_model.build_vocab(tokenized_corpus)
words = w2v_model.wv.vocab.keys()
vocab_size = len(words)
print("Vocab size", vocab_size)
print("[*] Training...")
# Train Word Embeddings
w2v_model.train(tokenized_corpus, total_examples=len(tokenized_corpus), epochs=W2V_EPOCH)
问题是从epoch 1开始,loss为0,被监控词的向量根本没有变化!
[*] Training...
Model loss: 0.0
Model loss: 0.0
Model loss: 0.0
Model loss: 0.0
那么这里的问题是什么?这是正常的吗?标记化语料库是一个列表列表,类似于 tokenized_corpus[0] = [ "word1" , "word2" , ...]
我用谷歌搜索了一下,好像一些旧版本的 gensim 在计算损失函数时有问题,但它们是将近一年前的事了,现在似乎应该修复了?
我也尝试了这个问题答案中提供的代码,但损失仍然是 0 :
EDIT1 : 添加compute_loss=True后,损失出现了,但是越来越高,而且最相似的词和它们的相似度完全没有变化:
Model loss: 2187903.5
Model loss: 3245492.0
Model loss: 4103624.5
Model loss: 4798541.0
Model loss: 5413940.0
Model loss: 5993822.5
Model loss: 6532631.0
Model loss: 7048384.5
Model loss: 7547147.0
您的代码的最大问题是您没有使用 Word2Vec
初始化参数来切换 loss-tracking:compute_loss=True
(参见 https://radimrehurek.com/gensim/models/word2vec.html#gensim.models.word2vec.Word2Vec 的 'parameters' 部分)
即使进行了该修复,loss-reporting 仍然存在很多问题(截至 gensim-3.8.3
和 2020 年 8 月撰写本文):
- 这不是人们可能期望的 per-epoch 总数或 per-example 平均值。 (因此,如果您需要它,作为一种解决方法,您的回调应该记住最后一个值并计算增量,或者将内部计数器重置为
0.0
,每个纪元结束。)
- 它在较大的训练运行中肯定会失去精度,最终变得毫无用处。 (这对您来说可能不是问题。)
- 由于多线程 value-overwriting,它可能会丢失一些计数。 (这对您来说可能不是实际问题,具体取决于您查询损失值的原因。)
我正在使用 Gensim 库的 Word2vec 模块来训练词嵌入,数据集是 400k 个句子和 100k 个独特的词(不是英语)
我正在使用此代码来监控和计算损失:
class MonitorCallback(CallbackAny2Vec):
def __init__(self, test_words):
self._test_words = test_words
def on_epoch_end(self, model):
print("Model loss:", model.get_latest_training_loss()) # print loss
for word in self._test_words: # show wv logic changes
print(model.wv.most_similar(word))
monitor = MonitorCallback(["MyWord"]) # monitor with demo words
w2v_model = gensim.models.word2vec.Word2Vec(size=W2V_SIZE, window=W2V_WINDOW, min_count=W2V_MIN_COUNT , callbacks=[monitor])
w2v_model.build_vocab(tokenized_corpus)
words = w2v_model.wv.vocab.keys()
vocab_size = len(words)
print("Vocab size", vocab_size)
print("[*] Training...")
# Train Word Embeddings
w2v_model.train(tokenized_corpus, total_examples=len(tokenized_corpus), epochs=W2V_EPOCH)
问题是从epoch 1开始,loss为0,被监控词的向量根本没有变化!
[*] Training...
Model loss: 0.0
Model loss: 0.0
Model loss: 0.0
Model loss: 0.0
那么这里的问题是什么?这是正常的吗?标记化语料库是一个列表列表,类似于 tokenized_corpus[0] = [ "word1" , "word2" , ...]
我用谷歌搜索了一下,好像一些旧版本的 gensim 在计算损失函数时有问题,但它们是将近一年前的事了,现在似乎应该修复了?
我也尝试了这个问题答案中提供的代码,但损失仍然是 0 :
EDIT1 : 添加compute_loss=True后,损失出现了,但是越来越高,而且最相似的词和它们的相似度完全没有变化:
Model loss: 2187903.5
Model loss: 3245492.0
Model loss: 4103624.5
Model loss: 4798541.0
Model loss: 5413940.0
Model loss: 5993822.5
Model loss: 6532631.0
Model loss: 7048384.5
Model loss: 7547147.0
您的代码的最大问题是您没有使用 Word2Vec
初始化参数来切换 loss-tracking:compute_loss=True
(参见 https://radimrehurek.com/gensim/models/word2vec.html#gensim.models.word2vec.Word2Vec 的 'parameters' 部分)
即使进行了该修复,loss-reporting 仍然存在很多问题(截至 gensim-3.8.3
和 2020 年 8 月撰写本文):
- 这不是人们可能期望的 per-epoch 总数或 per-example 平均值。 (因此,如果您需要它,作为一种解决方法,您的回调应该记住最后一个值并计算增量,或者将内部计数器重置为
0.0
,每个纪元结束。) - 它在较大的训练运行中肯定会失去精度,最终变得毫无用处。 (这对您来说可能不是问题。)
- 由于多线程 value-overwriting,它可能会丢失一些计数。 (这对您来说可能不是实际问题,具体取决于您查询损失值的原因。)