Faiss向量召回引擎如何做到快速查找最近邻

欢迎来我的小站转转~~

背景

Faiss是Facebook开源的向量召回引擎,用于寻找与某个向量最相似的N个向量。

matthijs

Faiss第一次release发布于2018.02.23,但其作者Matthijs在加入Facebook之前的2011年就已经发表了一篇关于最近邻搜索的论文,Faiss就是基于此论文思想实现的。读懂了这篇论文,Faiss的索引方式就清楚了。

问题描述

给定D维向量 x x x和集合 Γ = y 1 , y 2 … y N \Gamma = y_1,y_2 … y_N Γ=y1,y2yN ,需要找到与 x x x距离最短的k个最近邻。

以欧氏距离为例,可表示为:

L = k − a r g m i n i = 0 : N ∣ ∣ x − y i ∣ ∣ L = k-argmin_{i=0:N}|| x-y_i || L=kargmini=0:Nxyi

在我们的应用中, x ∈ Γ x \in \Gamma xΓ

问题规模

我们试着以最粗暴的方法进行穷举搜索,来看一下这个解的复杂度有多高。

exhaustive

  1. 构造距离矩阵:每两个向量 x x x y y y的距离计算公式为 Σ ( x i − y i ) 2 , i ∈ [ 1 , D ] \sqrt{\Sigma{(x_i-y_i)^2}}, i\in [1,D] Σ(xiyi)2 ,i[1,D] ,耗费时间为 O ( D ) O(D) O(D) , 距离矩阵包含 N 2 N^2 N2 个元素,总共耗时为 O ( D ∗ N 2 ) O(D*N^2) O(DN2)
  2. 从距离矩阵中查找到k个最近邻,若用最小堆算法,时间复杂度为 O ( ( N − k ) l o g k ) O((N-k)logk) O((Nk)logk)

N = 2000 W , k = 1000 , D = 1000 N=2000W, k=1000,D=1000 N=2000W,k=1000,D=1000

得到

  • 距离矩阵包含400T个元素,假设每个距离为float占用32bit,至少占用1600TB空间
  • 构造距离矩阵运算时间复杂度数量级为 1 0 17 10^{17} 1017
  • 从距离矩阵中找到k个最近邻的时间复杂度数量级为 1 0 9 10^9 109

stronger

最近邻离线表

一般来说向量集合都是每天更新的,这时候可以试着直接把每个向量对应的k个最近邻保存起来

vector_store

  1. 构造距离矩阵+N个k近邻查找耗时为 O ( D N 2 + N ∗ ( N − k ) ∗ l o g k ) O(DN^2 + N*(N-k)*logk) O(DN2+N(Nk)logk)
  2. 构造最近邻离线表空间占用 N ∗ k N*k Nk

在我们的场景中得到

  1. 找到N个k近邻查找的耗时数量级为 1 0 17 10^{17} 1017
  2. 存储空间为 1600 T B 1600TB 1600TB (构造后删除)+320G(假设每个索引用int表示,分数用float表示)

查找k最近邻的耗时: O(1)

stronger

向量量化(Vector Quantization)

在我们的场景中,其实不需要最精确的距离,允许一定程度的误差。在这种情况下,我们可以引入向量量化方法,将向量的数量大幅度缩小。

所谓向量量化,就是将原来无限的空间 R D R^D RD 映射到一个有限的向量集合 C = { c i , i ∈ [ 1 , l ] } \mathcal{C} = \{c_i, i\in[1,l]\} C={ ci,i[1,l]} 中,其中 l l l 是一个自然数。将这个从 R D R^D RD 到集合 C \mathcal{C} C 的函数记为 q q q ,则 ∀ q ( y ) ∈ C \forall q(y) \in \mathcal{C} q(y)C,在信息论中称 C \mathcal{C} C 为codebook。

当然这里的映射函数也不是随便指定的,需要满足误差最小的原则,一种方法是将优化函数设置为最小平方误差 M S E ( q ) = E X [ d ( q ( y ) , y ) 2 ] MSE(q)=\mathbb{E}_X[d(q(y),y)^2] MSE(q)=EX[d(q(y),y)2]

咦,正好就是k-means方法的目标函数!因此我们可以用k-means作为寻找最佳codebook的方法。

那现在我们来分析一下进行向量量化占用的空间和时间复杂度

假设我们将原来2000W个向量映射到大小为20W的集合中(平均每个中心点代表100个向量,已经引入了较大的误差)

  1. 距离矩阵:只需要存储对应 C \mathcal{C} C 中向量之间的距离,占用的空间为 ∣ ∣ C ∣ ∣ 2 || \mathcal{C} ||^2 C2,此例中为 400 G × 4 B = 1.6 T 400G \times 4B=1.6T 400G×4B=1.6T
  2. y → c ∈ C y \to c \in \mathcal{C} ycC的映射关系,若以int标识一个向量,则共约 N × 4 = 80 M N \times 4=80M N×4=80M内存
  3. 时间复杂度:k-means算法的时间复杂度为 O ( m i t e r N k D
  • 4
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值