获取最相似的文档(Doc2Vec)

44

我正在尝试构建一个文档检索模型,它可以按照与查询或搜索字符串相关性最高的顺序返回大多数文档。为此,我使用 gensim 中的 Doc2Vec 模型训练了一个 doc2vec 模型。我的数据集以每行一个字符串的形式存储在 pandas 数据集中。这是我目前的代码:

import gensim, re
import pandas as pd

# TOKENIZER
def tokenizer(input_string):
    return re.findall(r"[\w']+", input_string)

# IMPORT DATA
data = pd.read_csv('mp_1002_prepd.txt')
data.columns = ['merged']
data.loc[:, 'tokens'] = data.merged.apply(tokenizer)
sentences= []
for item_no, line in enumerate(data['tokens'].values.tolist()):
    sentences.append(LabeledSentence(line,[item_no]))

# MODEL PARAMETERS
dm = 1 # 1 for distributed memory(default); 0 for dbow 
cores = multiprocessing.cpu_count()
size = 300
context_window = 50
seed = 42
min_count = 1
alpha = 0.5
max_iter = 200

# BUILD MODEL
model = gensim.models.doc2vec.Doc2Vec(documents = sentences,
dm = dm,
alpha = alpha, # initial learning rate
seed = seed,
min_count = min_count, # ignore words with freq less than min_count
max_vocab_size = None, # 
window = context_window, # the number of words before and after to be used as context
size = size, # is the dimensionality of the feature vector
sample = 1e-4, # ?
negative = 5, # ?
workers = cores, # number of cores
iter = max_iter # number of iterations (epochs) over the corpus)

# QUERY BASED DOC RANKING ??

我遇到的难点在于找到与查询最相似/相关的文档。我使用了infer_vector,但意识到它将查询视为文档,更新模型并返回结果。我尝试使用most_similarmost_similar_cosmul方法,但得到的结果是单词及其相似度分数(我猜是相似度分数)。我想要做的是,在输入搜索字符串(即查询)时,应返回最相关的文档(ID),以及相似度得分(余弦等)。我该怎么做才能完成这一部分呢?


你的查询在数据集中存在吗?如果是,你可以使用sentence_tag来查找相似的句子。如果不是,你可以创建一个推理向量(在gensim 0.12.4之后),并用它进行查询。两者都可以使用model.docvecs.most_similar() - umutto
@umutto 我的查询是一个字符串,例如-客户细分。客户和细分都存在于词汇表中。通过 sentence_tag 你是指我们在 LabeledSentence 中传递的标签吗?如果是这样,那么我已经使用文档 ID(基本上是一个数字1、2、3...num_docs)作为标签。我使用了 infer_vector,但它并没有帮助我,因为它将查询视为文档,更新模型权重并返回相似的文档。我不想每次传递查询时都更新模型。 最后,可以使用 model.docvecs.most_similar(),但它需要一个向量来查找最相似的文档。 - Clock Slave
@umutto 所以基本上问题归结为如何在不改变模型的情况下获得查询的向量表示。 - Clock Slave
infer方法将忽略任何它在vocsb上没有的单词,并且据我所知不应该更新权重。将推断向量传递给most_similar函数确实会返回类似文档的标签。你试过了吗?发生了什么?你保存并重新加载模型了吗? - Luke Barker
1
@ClockSlave 目前我认为没有其他方法可以获得向量表示。如果您的查询词汇表中存在,则可以使用它们的标签(在您的情况下为文档ID)来计算相似性或获取它们的向量。但我不认为推断向量会更新权重。由于某些算法的非确定性特性(负采样,dbow=1等),您可能会看到来自同一查询的不同结果。但这并不意味着模型已被更改。 - umutto
@umutto,“infer_vector”方法接受参数,如“alpha”、“min_alpha”,因此我认为它们也会更新模型。但是,我不确定它们是学习率还是其他参数。 - Clock Slave
1个回答

55
您需要使用infer_vector来获取新文本的文档向量-这不会改变底层模型。
下面是实现方法:
tokens = "a new sentence to match".split()

new_vector = model.infer_vector(tokens)
sims = model.docvecs.most_similar([new_vector]) #gives you top 10 document tags and their cosine similarity

编辑:

这里是一个例子,展示了在调用infer_vec方法之后,基础模型不会发生改变。

import numpy as np

words = "king queen man".split()

len_before =  len(model.docvecs) #number of docs

#word vectors for king, queen, man
w_vec0 = model[words[0]]
w_vec1 = model[words[1]]
w_vec2 = model[words[2]]

new_vec = model.infer_vector(words)

len_after =  len(model.docvecs)

print np.array_equal(model[words[0]], w_vec0) # True
print np.array_equal(model[words[1]], w_vec1) # True
print np.array_equal(model[words[2]], w_vec2) # True

print len_before == len_after #True

1
你确定它不会更新模型吗?infer_vector方法接受像alphamin_alpha这样的参数。我猜它们是学习率。文档中没有提供太多信息,所以我不确定它们是学习率还是其他参数。此外,我认为它在更新模型,因为每次我将相同的句子传递给infer_vector,然后传递给most_similar时,每次都会得到不同的结果。 - Clock Slave
3
“infer_vector”类似于训练过程中存在非确定性元素,每次调用都会得到不同的向量。在Gensim的邮件列表和GitHub的问题记录中有许多讨论。这是一个很好的例子:https://github.com/RaRe-Technologies/gensim/issues/447。此外,您可以测试模型是否发生变化。请参考我的编辑。 - Erock
5
在doc2vec论文中明确指出,在推理时,模型的所有参数都是固定的。因此,该模型肯定不会被更新。 - Antoine
@ClockSlave 是的,infer_vector正在改变模型。我在infer_vector之后重新加载模型,输出是确定性的。非常有用的帖子! - user2849678

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接