github
Faiss 包含多种相似性搜索方法。它假设实例表示为向量并由整数标识,并且可以将向量与 L2(欧几里得)距离或点积进行比较。与查询向量相似的向量是那些与查询向量具有最低 L2 距离或最高点积的向量。它还支持余弦相似度,因为这是归一化向量的点积。
大多数方法,如基于二进制向量和紧凑量化代码的方法,只使用向量的压缩表示,不需要保留原始向量。这通常是以降低搜索精度为代价的,但这些方法可以扩展到单个服务器上主内存中的数十亿个向量。
Faiss 是围绕存储一组向量的索引类型构建的,并提供了一个函数来使用 L2 和/或点积向量比较在它们中进行搜索。一些索引类型是简单的基线,例如精确搜索。大多数可用的索引结构对应于关于
faiss 三个最基础的 index. 分别是 IndexFlatL2, IndexIVFFlat, IndexIVFPQ
。
# IndexFlat2
import numpy as np
d = 64 # 维度
nb = 100000 # 数据大小
nq = 10000 # nb的查询
np.random.seed(1314)
xb = np.random.random((nb, d)).astype('float32')
xb[:,0] += np.arange(nb)/1000.
xq = np.random.random((nq, d)).astype('float32')
xq[:,0] += np.arange(nq)/1000.
import faiss
index = faiss.IndexFlatL2(d) # 建立索引
print(index.is_trained)
index.add(xb) # 添加向量到索引
print(index.ntotal) # 查询总数
k = 4 #top 值
D, I = index.search(xb[:5], k)
print(D) # 相近得分
print(I) # 相近索引
D, I = index.search(xq, k)
print(I)
在d维空间中定义Voronoi单元格,并且每个数据库矢量都落入其中一个单元格中。在搜索时,只有查询x所在单元中包含的数据库向量y与少数几个相邻查询向量进行比较。(划分搜索空间)
import numpy as np
d = 64 # dimension
nb = 100000 # database size
nq = 10000 # nb of queries
np.random.seed(1234) # make reproducible
xb = np.random.random((nb, d)).astype('float32')
xb[:, 0] += np.arange(nb) / 1000.
xq = np.random.random((nq, d)).astype('float32')
xq[:, 0] += np.arange(nq) / 1000.
import faiss
nlist = 100 # 聚类中心的个数 搜索空间
k = 4 # 查找最相似的k个向量
quantizer = faiss.IndexFlatL2(d) # the other index
index = faiss.IndexIVFFlat(quantizer, d, nlist, faiss.METRIC_L2)
assert not index.is_trained
index.train(xb) ## 训练
assert index.is_trained
index.add(xb)
D, I = index.search(xq, k)
print(I[-5:]) # neighbors of the 5 last queries
index.nprobe = 10 # 查找聚类中心的个数,默认为1个。
D, I = index.search(xq, k)
print(I[-5:])
有损存储
索引IndexFlatL2和IndexIVFFlat都存储完整的向量。 为了扩展到非常大的数据集,Faiss提供了基于产品量化器的有损压缩来压缩存储的向量的变体。压缩的方法基于乘积量化(Product Quantizer)。
在这种情况下,由于矢量没有精确存储,搜索方法返回的距离也是近似值。
import numpy as np
d = 64 # dimension
nb = 100000 # database size
nq = 10000 # nb of queries
np.random.seed(1234) # make reproducible
xb = np.random.random((nb, d)).astype('float32')
xb[:, 0] += np.arange(nb) / 1000.
xq = np.random.random((nq, d)).astype('float32')
xq[:, 0] += np.arange(nq) / 1000.
import faiss
nlist = 100
m = 8
k = 4
quantizer = faiss.IndexFlatL2(d) # this remains the same
index = faiss.IndexIVFPQ(quantizer, d, nlist, m, 8)
# 8 specifies that each sub-vector is encoded as 8 bits
index.train(xb)
index.add(xb)
D, I = index.search(xb[:5], k) # sanity check
print(I)
print(D)
index.nprobe = 10 # make comparable with experiment above
D, I = index.search(xq, k) # search
print(I[-5:])
Faiss对一些基础的算法提供了非常高效的失效
通过Faiss文档介绍可以了解faiss的主要功能就是相似度搜索。如下图所示,以图片搜索为例,所谓相似度搜索,便是在给定的一堆图片中,寻找出我指定的目标最像的K张图片,也简称为KNN(K近邻)问题。
GPU 实现可以接受来自 CPU 或 GPU 内存的输入。在具有 GPU 的服务器上,GPU 索引可用作 CPU 索引的直接替换(例如,替换IndexFlatL2
为GpuIndexFlatL2
),并且自动处理到/从 GPU 内存的复制。但是,如果输入和输出都驻留在 GPU 上,结果会更快。支持单 GPU 和多 GPU 使用。
import numpy as np
d = 64 # dimension
nb = 100000 # database size
nq = 10000 # nb of queries
np.random.seed(1234) # make reproducible
xb = np.random.random((nb, d)).astype('float32')
xb[:, 0] += np.arange(nb) / 1000.
xq = np.random.random((nq, d)).astype('float32')
xq[:, 0] += np.arange(nq) / 1000.
import faiss # make faiss available
res = faiss.StandardGpuResources() # use a single GPU
## Using a flat index
index_flat = faiss.IndexFlatL2(d) # build a flat (CPU) index
# make it a flat GPU index
gpu_index_flat = faiss.index_cpu_to_gpu(res, 0, index_flat)
gpu_index_flat.add(xb) # add vectors to the index
print(gpu_index_flat.ntotal)
k = 4 # we want to see 4 nearest neighbors
D, I = gpu_index_flat.search(xq, k) # actual search
print(I[:5]) # neighbors of the 5 first queries
print(I[-5:]) # neighbors of the 5 last queries
## Using an IVF index
nlist = 100
quantizer = faiss.IndexFlatL2(d) # the other index
index_ivf = faiss.IndexIVFFlat(quantizer, d, nlist, faiss.METRIC_L2)
# here we specify METRIC_L2, by default it performs inner-product search
# make it an IVF GPU index
gpu_index_ivf = faiss.index_cpu_to_gpu(res, 0, index_ivf)
assert not gpu_index_ivf.is_trained
gpu_index_ivf.train(xb) # add vectors to the index
assert gpu_index_ivf.is_trained
gpu_index_ivf.add(xb) # add vectors to the index
print(gpu_index_ivf.ntotal)
k = 4 # we want to see 4 nearest neighbors
D, I = gpu_index_ivf.search(xq, k) # actual search
print(I[:5]) # neighbors of the 5 first queries
print(I[-5:]) # neighbors of the 5 last queries
https://blog.csdn.net/kanbuqinghuanyizhang/article/details/80774609
https://www.jianshu.com/p/43db601b8af1