如何加快添加两个大元组向量的速度?

时间:2019-01-20 12:49:14

标签: machine-learning python gensim

最近,我正在我的硕士论文中使用一种论文来实现一种算法,但是在执行某些操作所需的时间时遇到了一些问题。

在开始详细介绍之前,我只想补充一下,我的数据集大约包含4kk个数据点条目。

我有两个从框架(annoy)获取的元组列表,该框架计算向量与数据集中其他向量之间的余弦相似度。最终格式如下:

[(name1, cosine), (name2, cosine), ...]

由于算法的原因,我在其中有两个名称相同(元组的第一个值)的列表,但有两个不同的余弦相似度。我要做的是将两个列表中的余弦值相加,然后对数组排序并获得前N个最高的余弦值。

我的问题是:花了太长时间。我对该实现的实际代码如下:

def topN(self, user, session):
    upref = self.m2vTN.get_user_preference(user)
    spref = self.sm2vTN.get_user_preference(session)

    # list of tuples 1
    most_su = self.indexer.most_similar(upref, len(self.m2v.wv.vocab))
    # list of tuples 2
    most_ss = self.indexer.most_similar(spref, len(self.m2v.wv.vocab))

    # concat both lists and add into a dict
    d       = defaultdict(int)      
    for l, v in (most_ss + most_su): 
        d[l] += v  


     # convert the dict into a list, and then sort it
    _list    = list(d.items())
    _list.sort(key=lambda x: x[1], reverse=True)

    return [x[0] for x in _list[:self.N]]

如何使此代码更快?我试过使用线程,但是不确定是否会更快。获取列表不是这里的问题,而是串联和排序。

谢谢!英语不是我的母语,所以很抱歉拼写错误。

1 个答案:

答案 0 :(得分:0)

“太长”是什么意思?这两个列表有多大?您的模型和中期结果是否有可能大于RAM,从而迫使虚拟内存分页(这将导致令人沮丧的缓慢性)?

如果您实际上在模型中使用所有向量获得了余弦相似度,那么烦恼索引器将无济于事。 (其目的是更快地获取一小部分最近邻,以牺牲完美的准确性为代价。但是,如果您要计算与每个候选者的相似度,则使用ANNOY不会带来任何好处或优势。

此外,如果您要将两个这样的计算中的所有距离进行合并,则无需进行most_similar()通常会进行的排序-这只会使以后合并值变得更加复杂。对于gensim向量模型,您可以提供一个虚假的topn值,以按顺序获取到所有模型向量的未排序距离。然后,您将拥有两个大型的距离数组,它们以模型的相同本机顺序排列,很容易将它们逐元素相加。例如:

udists = self.m2v.most_similar(positive=[upref], topn=False)
sdists = self.m2v.most_similar(positive=[spref], topn=False)
combined_dists = udists + sdists

combined_dists未标记,但顺序与self.m2v.index2entity相同。然后,您可以按照类似于most_similar()方法本身的方式对它们进行排序,以找到排名最接近的。例如,请参见gensim的那部分的most_similar()源代码:

https://github.com/RaRe-Technologies/gensim/blob/9819ce828b9ed7952f5d96cbb12fd06bbf5de3a3/gensim/models/keyedvectors.py#L557

最后,您可能根本不需要自己进行此计算。您可以向most_similar()提供多于一个的向量作为positive目标,然后它将返回最接近两个向量的平均值的向量。例如:

sims = self.m2v.most_similar(positive=[upref, spref], topn=len(self.m2v))

这与您的其他总和不会是相同的值/等级,但其行为可能非常相似。 (如果您想要的不是所有相似之处,那么也可以以这种方式使用ANNOY indexer。)