术语等介绍见 关于 Milvus · Open Source Vector Database designed for AI applications
Faiss提供了针对不同场景下应用对Index的封装类,这里我们针对Index基类进行说明。
我所关心的points
- IndexIVFPQ、IndexIVFFlat 支持Gpu;
- IndexFlatIP(内积距离) 支持Gpu;
- CPU支持并发搜索(batch search),GPU不支持、
Fiass - 常见问题总结 - 一小撮人的文章 - 知乎 https://zhuanlan.zhihu.com/p/107241260
考虑因素:候选向量的数量级、index所占内存的大小、检索所需时间(是离线检索还是在线检索)、index构建时间、检索的召回率。
Faiss入门及应用经验记录 - 知乎
Flat :暴力检索 | IVFx Flat :倒排暴力检索 | PQx :乘积量化 | IVFxPQy 倒排乘积量化 | LSH 局部敏感哈希 | HNSWx | |
---|---|---|---|---|---|---|
优点 | 该方法是Faiss所有index中最准确的,召回率最高的方法,没有之一; | IVF利用倒排索引思想,拿出每个聚类中心下的向量ID,每个中心ID后面挂上一堆非中心向量,每次查询向量的时候找到最近的几个中心ID,分别搜索这几个中心下的非中心向量。通过减小搜索范围,提升搜索效率。 | 利用乘积量化的方法,改进了普通k-means,将一个向量的维度切成x段,每段分别进行k-means。因此速度很快,而且占用内存较小,召回率也相对较高(切4段) | 工业界大量使用此方法,各项指标都均可以接受。 | 不同于传统哈希尽量不产生碰撞,局部敏感哈希依赖碰撞来查找近邻。高维空间的两点若距离很近,那么设计一种哈希函数对这两点进行哈希值计算,使得他们哈希值有很大的概率是一样的,若两点之间的距离较远,他们哈希值相同的概率会很小。不同距离度量的哈希函数不同,不是所有距离度量(如内积)都能找到对应局部敏感哈希。 - 训练非常快,支持分批导入,index占内存很小,检索也比较快 | 基于图检索的改进方法,检索速度极快,10亿级别秒出检索结果,而且召回率几乎可以媲美Flat,能达到惊人的97%。检索的时间复杂度为loglogn,几乎可以无视候选向量的量级了。并且支持分批导入,极其适合线上任务,毫秒级别体验。 |
缺点 | 速度慢,占内存大。 | 速度也还不是很快 | 召回率相较于暴力检索,下降较多。 | 召回率非常拉垮。在候选语料比较多的时候(百万级别),检索也不是特别快,大概是秒级别的。 | 构建索引极慢,占用内存极大(是Faiss中最大的,大于原向量占用的内存大小) | |
使用情况 | 向量候选集很少,在50万以内,并且内存不紧张。 | 向量候选集很少,在50万以内,并且内存不紧张。 | 内存及其稀缺,并且需要较快的检索速度,不那么在意召回率。 | 同PQx | 候选向量库非常大,离线检索,内存资源比较稀缺的情况 | 不在乎内存,并且有充裕的时间来构建index。 |
是否GPU | GpuIndexFlat 支持 |
GpuIndexIVFFlat 支持 |
GpuIndexIVFPQ支持 | 不支持 | ||
是否训练 | 否 | 是,因为倒排索引需要训练k-means,因此需要先训练index,再add向量 | 是,因为倒排索引需要训练k-means,因此需要先训练index,再add向量 | 同PQx | 否 | 否 |
参数 | IVFx中的x是k-means聚类中心的个数 | PQx中的x为将向量切分的段数,因此,x需要能被向量维度整除,且x越大,切分越细致,时间复杂度越高 | 同PQx | HNSWx中的x为构建图时每个点最多连接多少个节点,x越大,构图越复杂,查询越精确,当然构建index时间也就越慢,x取4~64中的任何一个整数。 |
是,那就得用Flat。
唯一保证百分百准确性的是IndexFlatL2(L2距离)和IndexFlatIP(内积距离)。可以用来做其他索引的baseline,不支持压缩, 不支持add_with_ids,如果需要可以包一层IDMap,用 “IDMap,Flat” 不需要训练、不用指定参数。
支持GPU加速。
faiss的索引全部存在RAM中,速度和内存是tradeoff。
如果一点都不care内存,就用 HNSWx。
如果你有很多内存,或者数据集很小,HNSW是最好的选择,非常快而且准。x的取值在4到64之间,它是指每个向量的连接数量,x值越大,结果越准确,耗费内存越多。efSearch参数用来平衡速度和准确性,内存占用量 d * 4 + x * 2 * 4 一个向量
HNSW也不支持add_with_ids, 所以如果需要,也是加IDMap。
HNSW不需要训练,不支持从索引中删除向量,不支持gpu加速。
“…”前面三个点表示聚类操作,聚类后 Flat索引仅仅把数据组织到对应的bucket中去,它并不压缩数据,索引占用的内存跟原始的数据集大小相当。速度和准确性的tradeoff是通过设置nprobe参数,即搜索的时候,搜多少个聚类。如果等于nlist,将会等同于bruteforce
支持gpu加速,前提是选的聚类方式也要支持gpu。(倒排索引支持GPU加速)
这个包括两个操作,一个是PCA,降维到x, 一个是PQ也就是乘积量化,把每个向量元素压缩到一个byte,所以总起来一个向量 x个byte。
不支持gpu加速。
PQx表示压缩向量到x个bytes的乘积量化编码,通常x<=64, 对较大编码 SQ通常差不多准,并且还更快,OPQ是个线性变换帮助压缩
y值的要求:y是x的倍数,y <= d,d是输入数据的维数,y <= 4*x。
支持gpu。
这个问题用来确定上面那个三个点 … 数据被聚类到多个bucket里,搜索的时候,只有一部分bucket(nprobe参数)会被搜,聚类是在一堆有代表性的数据样本上做的。
如果向量数小于100万,用 “…,IVFx,…”
x的取值范围4sqrt(N)到16sqrt(N), N是索引向量总数。训练聚类的时候则需要30x到256x这么多样本,当然越多越好.
如果向量总数在100万到1000万间, 用”…,IVF65536_HNSW32,…”
IVF和HNSW组合起来,HNSW用来做聚类分配, 需要3065536到25665536的样本训练。
如果向量总数在1000万到一亿间,用”…,IVF262144_HNSW32,…”
跟上面一样,65536换成262144 训练会很慢
如果向量总数在1亿到10亿间, 用”…,IVF1048576_HNSW32,…”
跟上面一样,65536换成1048576 训练会非常慢。
1、如果关心返回精度,可以使用IndexFlatL2,该索引能确保返回精确结果。一般将其作为baseline与其他索引方式对比,以便在精度和时间开销之间做权衡。不支持add_with_ids,如果需要,可以用“IDMap”给予任意定义id。
2、如果关注内存开销,可以使用“..., Flat“的索引,"..."是聚类操作,聚类之后将每个向量映射到相应的bucket。该索引类型并不会保存压缩之后的数据,而是保存原始数据,所以内存开销与原始数据一致。通过nprobe参数控制速度/精度。
3、对内存开销比较关心的话,可以在聚类的基础上使用PQ进行处理。
vearch优点
根据应用场景选择索引 · Open Source Vector Database designed for AI applications
参考:
笔记︱几款多模态向量检索引擎:Faiss 、milvus、Proxima、vearch、Jina等 - 知乎(多款产品对比,好好好!)
使用Faiss进行海量特征的相似度匹配 - Gemfield的文章 - 知乎
Faiss Indexs 的进一步了解(好好好好好!)