У меня есть набор предложений, который кодируется с использованием кодировщика предложений в векторы, и я хочу найти наиболее похожее предложение для входящего запроса.
Функция поиска выглядит следующим образом:
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))