余弦相似度很慢

时间:2019-09-29 07:51:13

标签: python-3.x similarity cosine-similarity sentence-similarity

我有一组句子,使用句子编码器将其编码为向量,并且我想找出与传入查询最相似的句子。

搜索功能如下:

def semantic_search(cleaned_query, data, vectors):
    query_vec = get_features(cleaned_query)[0].ravel()
    res = []
    for i, d in enumerate(data):
        qvec = vectors[i].ravel()
        sim = cosine_similarity(query_vec, qvec)
        if sim > 0.5:
            res.append((format(sim * 100, '.2f'), data[i]))
    return sorted(res, key=lambda x: x[0], reverse=True)[:15]

其中cleaned_query是字符串形式的预处理查询,data是一个包含所有句子(总共300个)的列表,而vectors包含维度中数据中每个句子的编码向量(300,500)。

当我向服务发送查询时,处理一个查询大约需要10到12秒的时间,我认为这太慢了。我已经进行了一些调试,并意识到问题出在cosine_similarity函数中,该函数的实现如下:

import numpy as np
def cosine_similarity(v1, v2):
    mag1 = np.linalg.norm(v1)
    mag2 = np.linalg.norm(v2)
    if (not mag1) or (not mag2):
        return 0
    return np.dot(v1, v2) / (mag1 * mag2)

我尝试研究不同的实现,并发现使用numba-nb_cosine可以快速运行,但是效果并不理想,这意味着上面的cosine_similarity可以提供更正确的效果和有意义的结果。这是numba的实现:

import numba as nb
import numpy as np
@nb.jit(nopython=True, fastmath=True)
def nb_cosine(x, y):
    xx,yy,xy=0.0,0.0,0.0
    for i in range(len(x)):
        xx+=x[i]*x[i]
        yy+=y[i]*y[i]
        xy+=x[i]*y[i]
    return 1.0-xy/np.sqrt(xx*yy)

有人可以建议,如何优化我的cosine_similarity函数以使其更快地工作?这300个句子总是一样的。并且以防万一,如果需要的话,下面是get_features函数:

def get_features(texts):
    if type(texts) is str:
        texts = [texts]
    with tf.Session(graph=graph) as sess:
        sess.run([tf.global_variables_initializer(), tf.tables_initializer()])
        return sess.run(embed(texts))

1 个答案:

答案 0 :(得分:0)

我不确定您是否正确计算了余弦相似度 那里;您可能要检查一些获得的值,并确保 他们说得通。

无论如何,加快速度的一种方法是预先计算和存储 您300个句子的每个向量的大小,以及 预计算query_vec的大小。就像现在的代码一样, 重新计算每个呼叫的每个句子的大小,以及 计算query_vec的大小300次。