如何在doc2vec模型中提高两个文档(句子)的余弦相似度?

时间:2017-06-16 06:07:00

标签: python nlp gensim word2vec doc2vec

我正在使用gensim库通过doc2vec模型在Python中构建一个NLP聊天应用程序。我有硬编码文档并给出了一组训练样例,我通过抛出用户问题然后找到大多数类似文档作为第一步来测试模型。在这种情况下,我的测试问题是来自训练示例的文档的精确副本。

import gensim
from gensim import models
sentence = models.doc2vec.LabeledSentence(words=[u'sampling',u'what',u'is',u'tell',u'me',u'about'],tags=["SENT_0"])
sentence1 = models.doc2vec.LabeledSentence(words=[u'eligibility',u'what',u'is',u'my',u'limit',u'how',u'much',u'can',u'I',u'claim'],tags=["SENT_1"])
sentence2 = models.doc2vec.LabeledSentence(words=[u'eligibility',u'I',u'am',u'retiring',u'how',u'much',u'can',u'claim',u'have', u'resigned'],tags=["SENT_2"])
sentence3 = models.doc2vec.LabeledSentence(words=[u'what',u'is',u'my',u'eligibility',u'post',u'my',u'promotion'],tags=["SENT_3"])
sentence4 = models.doc2vec.LabeledSentence(words=[u'what',u'is', u'my',u'eligibility' u'post',u'my',u'promotion'], tags=["SENT_4"])
sentences = [sentence, sentence1, sentence2, sentence3, sentence4]
class LabeledLineSentence(object):
    def __init__(self, filename):
        self.filename = filename
    def __iter__(self):
        for uid, line in enumerate(open(filename)):
            yield LabeledSentence(words=line.split(), labels=['SENT_%s' % uid])
model = models.Doc2Vec(alpha=0.03, min_alpha=.025, min_count=2)
model.build_vocab(sentences)
for epoch in range(30):
    model.train(sentences, total_examples=model.corpus_count, epochs = model.iter)
    model.alpha -= 0.002  # decrease the learning rate`
    model.min_alpha = model.alpha  # fix the learning rate, no decay
model.save("my_model.doc2vec")
model_loaded = models.Doc2Vec.load('my_model.doc2vec')
print (model_loaded.docvecs.most_similar(["SENT_4"]))

结果:

[('SENT_1', 0.043695494532585144), ('SENT_2', 0.0017897281795740128), ('SENT_0', -0.018954679369926453), ('SENT_3', -0.08253869414329529)]

SENT_4SENT_3的相似度仅为-0.08253869414329529,因为它们应该是1,因为它们完全相同。我该如何提高这种准确性?是否有一种特定的培训方式,我错过了什么?

1 个答案:

答案 0 :(得分:1)

Word2Vec / Doc2Vec在玩具大小的示例(例如少量文本,短文本和少数总词)上效果不佳。许多理想的属性只能通过数百万字的训练集或数万个文档可靠地实现。

特别是,只有5个例子,只有十几个或两个单词,但是100维的建模向量,训练不是强制做主要的事情,使word-vectors / doc-vectors有用:compress将表示形式转换为密集嵌入,其中类似的项需要在向量空间中逐渐轻推,因为没有办法在巨型查找表中保留所有原始变体。由于维度变异超过语料库变异,您的相同标记SENT_3SENT_4可以采用截然不同的文档向量,并且该模型仍然足够大,可以在其训练任务上做得很好(基本上,'过度匹配' ),没有所需的类似文本的最终状态,强制使用相似的向量。

你有时可以通过更多的训练迭代和更小的模型(在向量size方面)来挤出更多的意义,但实际上:这些向量需要大量不同的数据集才能成为有意义。

这是主要问题。示例代码中的其他一些低效或错误:

  • 您的代码不使用类LabeledLineSentence,因此不需要在此处包含它 - 它是无关的样板文件。 (另外,TaggedDocument是最近gensim版本中words + tags文档类的首选名称,而不是LabeledSentence。)

  • alphamin_alpha的自定义管理不太可能有用。这些最好保留默认值,除非你已经有了一些工作,很好地理解算法,然后想尝试细微的优化。

  • train()将进行自己的迭代,因此您无需在外部循环中多次调用它。 (这个代码在其第一个循环中执行5 model.iter次迭代alpha值从0.03逐渐下降到0.025,然后5次迭代在固定的alpha值为0.028,然后再增加5次在0.026,然后再增加27次减少alpha时的5次迭代,在固定的alpha -0.028的第30个循环结束。这是一个无意义的结束值 - 学习率永远不应该是负的 - 在无意义的进展结束时。即使有大数据集,这150次迭代,大约一半发生在负alpha值,可能会产生奇怪的结果。)