首页 > 其他分享 >Faiss 简介

Faiss 简介

时间:2023-06-30 16:44:35浏览次数:50  
标签:index xb 简介 random np Faiss 向量 faiss

Faiss 简介

1.Faiss是什么

Faiss是Facebook Ai Research开发的一款稠密向量检索工具。引用Faiss Wiki上面的一段简介

Faiss is a library for efficient similarity search and clustering of dense vectors.
It contains algorithms that search in sets of vectors of any size, up to ones that possibly do not fit in RAM.
It also contains supporting code for evaluation and parameter tuning.
Faiss is written in C++ with complete wrappers for Python (versions 2 and 3).
Some of the most useful algorithms are implemented on the GPU.
It is developed by Facebook AI Research.

上面的简介包含了如下信息:

1.Faiss是针对稠密向量进行相似性搜索和聚类的一个高效类库。
2. 它包含可搜索任意大小的向量集的算法,这些向量集的大小甚至都不适合RAM。
3. 它还包含用于评估和参数调整的支持代码。
4. Faiss用C ++编写,并且有python2与python3的封装代码。
5. 一些最有用的算法在GPU上有实现。
6. Faiss是由Facebook AI Research开发的。

2.faiss安装

#cpu 版本
conda install faiss-cpu -c pytorch
# GPU 版本
conda install faiss-gpu cudatoolkit=8.0 -c pytorch # For CUDA8
conda install faiss-gpu cudatoolkit=9.0 -c pytorch # For CUDA9
conda install faiss-gpu cudatoolkit=10.0 -c pytorch # For CUDA10

3.faiss的使用方法简介

整体来说,faiss的使用方式可以分为三个步骤:
1.构建训练数据以矩阵的形式表示,比如我们现在经常使用的embedding,embedding出来的向量就是矩阵的一行。
2.为数据集选择合适的index,index是整个faiss的核心部分,将第一步得到的训练数据add到index当中。
3.search,或者说query,搜索到最终结果。

4.faiss原理与核心算法

faiss的主要功能是对向量进行相似搜索。具体就是给定一个向量,在所有已知的向量库中找出与其相似度最高的一些向量,本质是一个KNN(K近邻)问题,比如google的以图找图功能。随着目前embedding的流行,word2vec,doc2vec,img2vec,item2vec,video2vec,everything2vec,所以faiss也越来越受到大家的欢迎。
根据上面的描述不难看出,faiss本质是一个向量(矢量)数据库,这个数据库在进行向量查询的时候有其独到之处,因此速度比较快,同时占用的空间也比较小。

faiss中最重要的是索引Index

5.IndexFlatL2

看到这个名字大家应该就能猜个八九不离十。没错,这种索引的方式是计算L2距离,为一种暴力的(brute-force))精确搜索的方式,计算方式自然就是计算各向量的欧式距离(L2距离)。

看一下官方给的一个例子

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
index = faiss.IndexFlatL2(d)   # build the index
print(index.is_trained)        # 表示索引是否需要训练的布尔值
index.add(xb)                  # add vectors to the index
print(index.ntotal)            # 索引中向量的数量。


k = 4                          # we want to see 4 nearest neighbors
D, I = index.search(xb[:5], k) # sanity check
print(I)
print(D)

D, I = index.search(xq, k)     # actual search
print(I[:5])                   # neighbors of the 5 first queries
print(I[-5:])                  # neighbors of the 5 last qu

输出结果为

True
100000
[[  0 393 363  78]
 [  1 555 277 364]
 [  2 304 101  13]
 [  3 173  18 182]
 [  4 288 370 531]]
[[0.        7.1751733 7.207629  7.2511625]
 [0.        6.3235645 6.684581  6.7999454]
 [0.        5.7964087 6.391736  7.2815123]
 [0.        7.2779055 7.5279865 7.6628466]
 [0.        6.7638035 7.2951202 7.3688145]]
[[ 381  207  210  477]
 [ 526  911  142   72]
 [ 838  527 1290  425]
 [ 196  184  164  359]
 [ 526  377  120  425]]
[[ 9900 10500  9309  9831]
 [11055 10895 10812 11321]
 [11353 11103 10164  9787]
 [10571 10664 10632  9638]
 [ 9628  9554 10036  9582]]

具体的步骤为:
一、构建数据集
1.xb相当于数据库中待搜索的向量,这些向量都会建立索引并且我们会进行搜索,xb的大小为nb * d。
2.xq为查询向量,我们期望找到xb中xq的K近邻向量。xq的大小为xq * d。如果是查询单个向量,nq = 1。
二、构建索引
三、搜索

IndexFlatL2的结果是精确,可以用来作为其他索引测试中准确性程度的参考。当数据集比较大的时候,暴力搜索的时间复杂度很高,因此我们一般会使用其他方式的索引。

6.IndexIVFFlat

上面的IndexFlatL2为暴力搜索,速度慢,实际中我们需要更快的方式,于是就有了IndexIVFFlat。
为了加快搜索的速度,我们可以将数据集分割为几部分,将其定义为Voronoi Cells,每个数据向量只能落在一个cell中。查询时只需要查询query向量落在cell中的数据了,降低了距离计算次数。
IndexIVFFlat需要一个训练的阶段,其与另外一个索引quantizer有关,通过quantizer来判断属于哪个cell。

IndexIVFFlat在搜索的时候,引入了nlist(cell的数量)与nprob(执行搜索的cell树)参数。通过调整这些参数可以在速度与精度之间平衡。

import numpy as np
d = 64                              # 向量维度
nb = 100000                         # 向量集大小
nq = 10000                          # 查询次数
np.random.seed(1234)                # 随机种子,使结果可复现
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
quantizer = faiss.IndexFlatL2(d)  # the other index
index = faiss.IndexIVFFlat(quantizer, d, nlist, faiss.METRIC_L2)
# here we specify METRIC_L2, by default it performs inner-product search

assert not index.is_trained
index.train(xb)
assert index.is_trained

index.add(xb)                  # 添加索引可能会有一点慢
D, I = index.search(xq, k)     # 搜索
print(I[-5:])                  # 最初五次查询的结果
index.nprobe = 10              # 默认 nprobe 是1 ,可以设置的大一些试试
D, I = index.search(xq, k)
print(I[-5:])                  # 最后五次查询的结果

最后的结果为

[[ 9900  9309  9810 10048]
 [11055 10895 10812 11321]
 [11353 10164  9787 10719]
 [10571 10664 10632 10203]
 [ 9628  9554  9582 10304]]
[[ 9900 10500  9309  9831]
 [11055 10895 10812 11321]
 [11353 11103 10164  9787]
 [10571 10664 10632  9638]
 [ 9628  9554 10036  9582]]

由上面的实验可以看出,结果并不是完全一致的,增大nprobe可以得到与brute-force更为接近的结果,nprobe就是速度与精度的调节器。

7.IndexIVFPQ

IndexFlatL2 和 IndexIVFFlat都要存储所有的向量数据。对于超大规模数据集来说,可能会不大显示。因此IndexIVFPQ索引可以用来压缩向量,具体的压缩算法为PQ(乘积量化, Product Quantizer)。

import numpy as np

d = 64                              # 向量维度
nb = 100000                         # 向量集大小
nq = 10000                          # 查询次数
np.random.seed(1234)                # 随机种子,使结果可复现
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)    # 内部的索引方式依然不变
index = faiss.IndexIVFPQ(quantizer, d, nlist, m, 8)
                                    # 每个向量都被编码为8个字节大小
index.train(xb)
index.add(xb)
D, I = index.search(xb[:5], k)      # 测试
print(I)
print(D)
index.nprobe = 10                   # 与以前的方法相比
D, I = index.search(xq, k)          # 检索
print(I[-5:])

结果为

[[   0   78  608  159]
 [   1 1063  555  380]
 [   2  304  134   46]
 [   3   64  773  265]
 [   4  288  827  531]]
[[1.6157436 6.1152253 6.4348025 6.564184 ]
 [1.389575  5.6771317 5.9956017 6.486294 ]
 [1.7025063 6.121688  6.189084  6.489888 ]
 [1.8057687 6.5440307 6.6684756 6.859398 ]
 [1.4920276 5.79976   6.190908  6.3791513]]
[[ 9900  8746  9853 10437]
 [10494 10507 11373  9014]
 [10719 11291 10424 10138]
 [10122  9638 11113 10630]
 [ 9229 10304  9644 10370]]

IndexIVFPQ能正确找到距离最小的向量(他本身),但是距离不为0,这是因为向量数据存储时候有压缩,会损失一部分精度。

另外搜索真实查询时,虽然结果大多是错误的(与刚才的IVFFlat进行比较),但是它们在正确的空间区域,而对于真实数据,情况更好,因为:
1.统一数据很难进行索引,因为没有规律性可以被利用来聚集或降低维度
2.对于自然数据,语义最近邻居往往比不相关的结果更接近。

8.索引选择

如果需要精确的搜索结果,不要降维、不要量化,使用 Flat,同时,使用Flat 意味着数据不会被压缩,将占用同等大小的内存;
如果内存很紧张,可以使用 PCA 降维、PQ 量化编码,来减少内存占用,最终占用的内存大小约等于 <降维后的向量维度> * <量化后的每个向量的字节数> * <向量个数>; 如果量化编码后的字节数大于64,推荐使用SQx 替换PQx,准确度相同但速度会更快;为了便于量化编码,可以使用 OPQx_y 先对向量做线性变换,y 必须是编码后字节数x的倍数,但最好小于维度dim和4x;
如果总向量个数 N 小于 1百万,推荐使用 IVFx ,x 的选值介于 4sqrt(N) 和 16*sqrt(N) 之间,训练数据的大小至少要是x的30倍;如果总向量个数 N 大于 1百万、小于 1千万,推荐使用 IMI2x10,实际内部聚类个数是 2 ^ (2 * 10),将需要64 * 2 ^ 10 个向量参与训练;如果总向量个数 N 大于 1千万、小于 1亿,推荐使用 IMI2x12;如果总向量个数 N 大于 1亿、小于 10亿,推荐使用 IMI2x14;IMI方法不支持GPU;
IndexIVF 天生支持 add_with_ids 方法,对于不支持 add_with_ids方法的类型,可以使用IndexIDMap 辅助。

https://blog.csdn.net/bitcarmanlee/article/details/106447629

https://zhuanlan.zhihu.com/p/357414033

https://www.cnblogs.com/yhzhou/p/10568728.html

标签:index,xb,简介,random,np,Faiss,向量,faiss
From: https://www.cnblogs.com/michaelcjl/p/17517208.html

相关文章

  • 德遂然维简介
    德遂然维出生于24世纪最好的时代,那是一个通货膨胀,科技发展到巅峰的时代,而德遂然维是那个时代的佼佼者。德遂然维发现并证明了时空隧道的存在,德遂然维不仅在自己的学科领域(量子物理)上有巨大成就,德遂然维还是个全面发展的,不可多得的人才。德遂然维著有名著:《量子物理给我带来了什么......
  • 1.1 Metasploit 工具简介
    Metasploit简称(MSF)是一款流行的开源渗透测试框架,由Rapid7公司开发,可以帮助安全和IT专业人士识别安全性问题,验证漏洞的缓解措施,并管理专家驱动的安全性进行评估,提供真正的安全风险情报。并且该框架还提供了一系列攻击模块和Payload工具,可用于漏洞利用、及漏洞攻击。同时软件自身支......
  • 1.1 Metasploit 工具简介
    Metasploit简称(MSF)是一款流行的开源渗透测试框架,由Rapid7公司开发,可以帮助安全和IT专业人士识别安全性问题,验证漏洞的缓解措施,并管理专家驱动的安全性进行评估,提供真正的安全风险情报。并且该框架还提供了一系列攻击模块和Payload工具,可用于漏洞利用、及漏洞攻击。同时软件自身支......
  • 光脚丫学LINQ(014):LINQ to SQL简介
    视频演示:http://u.115.com/file/f29f7838f6 LINQtoSQL是.NETFramework3.5版的一个组件,提供了用于将关系数据作为对象管理的运行时基础结构。说明关系数据显示为由二维表(关系或平面文件)组成的集合,其中公共列将表互相关联起来。若要有效地使用LINQtoSQL,您必须略为熟悉关......
  • 微软Silverlight简介
    WPF与Silverlight有何不同?WPF(WindowsPresentationFoundation),主要是提供统一的展现层模组,来建立诸如WindowsVista智慧型使用者体验,包含了使用者介面、3D模组、多媒体、文件等;而Silverlight是跨浏览器上的外掛,传达下一代网页多媒体互相性功能,隶属于WPF功能上的子集,并可与Ajax......
  • 从数据洞察中获取灵感:8种业务分析模型简介
    提及火爆抖音的IP“商业顾问张琦老师”,相信大家并不陌生,作为抖音管理经营类视频代表性IP,张琦创造了现象级互联网营销的典例。随着互联网+快速发展以及产业经济结构转型对为从业者职业技能和素养提出更高的要求,社会开始提倡“终身学*”。*日,巨量引擎旗下内容消费趋势洞察品牌巨量......
  • 安装faiss-gpu失败的问题
    安装faiss-gpu失败的问题安装faiss-gpu出现问题:尝试使用:condainstall-cconda-forgefaiss-gpu或者用对应的whl包https://github.com/kyamagu/faiss-wheels/releases/tag/v1.7.3https://github.com/kyamagu/faiss-wheels/issues/54......
  • 24W机壳式AC-DC降压开关电源模块AP21-24W24N产品简介
    输入电压:100~250V输出电压:24V输出电流:1000mA输出功率:24W产品尺寸:85*58*33mm安装方式:螺丝固定功能特点:高精度工业电源产品简介:AP21-24W24N是一款小体积机壳式开关电源,交流直流两用,输入电压85~264Vac/100~370Vdc,超低纹波、超低功耗、高效率、安全隔离、高可靠性等优点;符合IEC60950......
  • 1、前端知识简介
    1.网页1、什么是HTMLHTML指的是超文本标记语言(HyperTextMarkupLanguage),它是用来描述网页的一种语言。HTML不是一种编程语言,而是一种标记语言(markuplanguage)2、网页的形成网页是由网页元素组成的,这些元素是利用html标签描述出来,然后通过浏览器解析来显示给用户的。前端人员......
  • Spark简介
    SparkSpark是一种快速、通用、可扩展的大数据分析引擎,2009年诞生于加州大学伯克利分校AMPLab,2010年开源,2013年6月成为Apache孵化项目,2014年2月成为Apache的顶级项目,2014年5月发布spark1.0,2016年7月发布spark2.0,2020年6月18日发布spark3.0.0特点Hadoop的MapReduce作为第一代分布......