Doc2Vec infer_vector 未按预期工作

Doc2Vec infer_vector not working as expected

程序应该返回列表中最相似的第二个文本,因为它是同一个词。但这里不是这样。

import gensim
from nltk.tokenize import word_tokenize
from gensim.models import Word2Vec
from gensim.models.doc2vec import Doc2Vec, TaggedDocument


data = ["I love machine learning. Its awesome.",
        "I love coding in python",
        "I love building chatbots",
        "they chat amagingly well"]


tagged_data=[TaggedDocument(word_tokenize(_d.lower()),tags=[str(i)]) for i,_d in enumerate(data)]

max_epochs = 100
vec_size = 20
alpha = 0.025

model = Doc2Vec(size=vec_size,
                alpha=alpha, 
                min_alpha=0.00025,
                min_count=1,
                negative=0,
                dm =1)

model.build_vocab(tagged_data)

for epoch in range(max_epochs):
    #print('iteration {0}'.format(epoch))
    model.train(tagged_data,
                total_examples=model.corpus_count,
                epochs=model.iter)
    # decrease the learning rate
    model.alpha -= 0.0002
    # fix the learning rate, no decay
    model.min_alpha = model.alpha

model.save("d2v.model")


loaded_model=Doc2Vec.load("d2v.model")
test_data=["I love coding in python".lower()]

v1=loaded_model.infer_vector(test_data)

similar_doc=loaded_model.docvecs.most_similar([v1])
print similar_doc

输出:

[('0', 0.17585766315460205), ('2', 0.055697083473205566), ('3', -0.02361609786748886), ('1', -0.2507985532283783)]

它显示列表中的第一个文本而不是第二个文本最相似。你能帮忙解决这个问题吗?

首先,使用玩具大小的数据集的 Doc2Vec 风格模型不会获得好的结果。仅四个文档和大约 20 个独特单词的词汇表,无法创建充满 20 维向量的有意义对比 "dense embedding" 向量模型。

其次,如果您在模型初始化中设置 negative=0,您将禁用默认的模型训练校正模式 (negative=5) – 而您不会启用非默认的, 不太推荐的替代方案 (hs=1)。根本不会进行任何培训。代码输出中也可能会显示错误——而且,如果您的 运行 至少是 INFO 级别的日志记录,您可能会注意到输出中的其他问题。

第三,infer_vector() 需要一个单词标记列表作为其参数。您提供的是纯字符串。对于代码来说,这看起来像是一个单字符单词列表,所以就像您要求它推断 23 个单词的句子一样:

['i', ' ', 'l', 'o', 'v', 'e', ' ', 'c', ...]

infer_vector() 的参数应该被标记化,就像训练文本被标记化一样。 (如果您在训练期间使用了 word_tokenize(),那么在推理期间也使用它。)

infer_vector() 还将对等于 Doc2Vec 模型中的 'epochs' 值的文本使用多次重复推理传递,除非您指定另一个值。由于您没有指定 epochs,该模型仍将具有其默认值(继承自 Word2Vecepochs=5。大多数 Doc2Vec 工作在训练期间使用 10-20 个 epoch,在推理期间至少使用同样多的 epoch 似乎是一个很好的做法。

还有:

不要尝试在循环中多次调用 train(),或在您自己的代码中管理 alpha,除非您是专家。

任何在线示例建议的代码块都像您...

for epoch in range(max_epochs):
    #print('iteration {0}'.format(epoch))
    model.train(tagged_data,
                total_examples=model.corpus_count,
                epochs=model.iter)
    # decrease the learning rate
    model.alpha -= 0.0002
    # fix the learning rate, no decay
    model.min_alpha = model.alpha

...是一个不好的例子。它错误地上下发送有效 alpha 速率,如果您想更改 epochs 的数量,它会非常脆弱,它实际上会结束 运行 500 个纪元(100 * model.iter),它的代码比必要的多得多。

相反,不要更改默认 alpha 选项,并在创建模型时指定所需的迭代次数。因此,该模型将缓存一个有意义的 epochs 值,以供稍后 infer_vector().

使用

然后,只调用一次 train()。它将正确处理所有时期和 alpha 管理。例如:

model = Doc2Vec(size=vec_size,
                min_count=1,  # not good idea w/ real corpuses but OK
                dm=1,  # not necessary to specify since it's the default but OK  
                epochs=max_epochs)
model.build_vocab(tagged_data)
model.train(tagged_data, 
            total_examples=model.corpus_count, 
            epochs=model.epochs)