Косинус сходство медленно - PullRequest
       82

Косинус сходство медленно

1 голос
/ 29 сентября 2019

У меня есть набор предложений, который кодируется с использованием кодировщика предложений в векторы, и я хочу найти наиболее похожее предложение для входящего запроса.

Функция поиска выглядит следующим образом:

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 голосов
/ 29 сентября 2019

Я не уверен, правильно ли вы там вычисляете косинусное сходство;вы можете проверить некоторые значения, которые вы получаете, и убедиться, что они имеют смысл.

В любом случае, один из способов ускорить процесс - это предварительно рассчитать и сохранить величину каждого вектора для ваших 300 предложений, а такжерассчитать величину query_vec.Поскольку код теперь такой, вы пересчитываете величину каждого предложения с каждым вызовом и вычисляете величину query_vec 300 раз.

...