使用嵌入列表快速执行余弦相似度
Quickly performing cosine similarity with list of embeddings
我有一个列表 phrases
,我想从一组 25k 嵌入向量 (emb2_list
) 中获得最匹配的每个列表。为此,我使用余弦相似度。以下是代码:
from sentence_transformers import SentenceTransformer, util
import numpy as np
import torch
model = SentenceTransformer('bert-base-nli-stsb-mean-tokens')
emb2_list = np.load("emb2_list.npy") #already encoded, len = 25K
phrases = ['phrase 1','phrase 2','phrase 3','phrase 4',]
for phrase in phrases:
emb1 = model.encode(phrase)
cos_sim = []
for emb2 in emb2_list:
cos_sim.append(util.pytorch_cos_sim(emb1, emb2)[0][0].item())
v, i = torch.Tensor(cos_sim).topk(1)
print(f'phrase:{phrase} match index:{i}')
问题是每次迭代大约需要 1 秒(本例中总共需要 4 秒)。一旦 phrases
的大小增加(因为这是在线 API 的一部分),它确实会出现问题。
在数据结构、批处理技术或某种可能加速此过程的 approximation/Nearest 邻域算法方面,是否有更好的方法来查找余弦相似性?
您需要批量计算 (1) 句子编码和 (2) 余弦相似度。
1
sentence_transformers 的文档指出您可以对句子列表调用编码:
emb1 = model.encode(phrases)
2
余弦相似度是矩阵-矩阵乘法。
emb2 = torch.tensor(emb2_list) # cast to torch tensor
emb2 /= emb2.norm(dim=-1, p=2).unsqueeze(-1) # normalize to vector length
emb1 /= emb1.norm(dim=-1, p=2).unsqueeze(-1) # ditto
sims = emb1 @ emb2.t() # matrix-matrix multiply the normalized embeddings
现在 sims[a,b]
将包含 phrases[a]
与嵌入 emb_list[b]
.
的相似性
请注意,对于 m 个短语和 n 个预先计算的嵌入,矩阵乘法的内存成本为 O(mn)。根据您的用例,您可能需要将其分解成块。
我有一个列表 phrases
,我想从一组 25k 嵌入向量 (emb2_list
) 中获得最匹配的每个列表。为此,我使用余弦相似度。以下是代码:
from sentence_transformers import SentenceTransformer, util
import numpy as np
import torch
model = SentenceTransformer('bert-base-nli-stsb-mean-tokens')
emb2_list = np.load("emb2_list.npy") #already encoded, len = 25K
phrases = ['phrase 1','phrase 2','phrase 3','phrase 4',]
for phrase in phrases:
emb1 = model.encode(phrase)
cos_sim = []
for emb2 in emb2_list:
cos_sim.append(util.pytorch_cos_sim(emb1, emb2)[0][0].item())
v, i = torch.Tensor(cos_sim).topk(1)
print(f'phrase:{phrase} match index:{i}')
问题是每次迭代大约需要 1 秒(本例中总共需要 4 秒)。一旦 phrases
的大小增加(因为这是在线 API 的一部分),它确实会出现问题。
在数据结构、批处理技术或某种可能加速此过程的 approximation/Nearest 邻域算法方面,是否有更好的方法来查找余弦相似性?
您需要批量计算 (1) 句子编码和 (2) 余弦相似度。
1
sentence_transformers 的文档指出您可以对句子列表调用编码:
emb1 = model.encode(phrases)
2
余弦相似度是矩阵-矩阵乘法。
emb2 = torch.tensor(emb2_list) # cast to torch tensor
emb2 /= emb2.norm(dim=-1, p=2).unsqueeze(-1) # normalize to vector length
emb1 /= emb1.norm(dim=-1, p=2).unsqueeze(-1) # ditto
sims = emb1 @ emb2.t() # matrix-matrix multiply the normalized embeddings
现在 sims[a,b]
将包含 phrases[a]
与嵌入 emb_list[b]
.
请注意,对于 m 个短语和 n 个预先计算的嵌入,矩阵乘法的内存成本为 O(mn)。根据您的用例,您可能需要将其分解成块。