【推荐系统】Faiss index选择

术语等介绍见 关于 Milvus · Open Source Vector Database designed for AI applications

Faiss提供了针对不同场景下应用对Index的封装类,这里我们针对Index基类进行说明。

【推荐系统】Faiss index选择_第1张图片

 我所关心的points

  1. IndexIVFPQ、IndexIVFFlat 支持Gpu;
  2. IndexFlatIP(内积距离) 支持Gpu;
  3. CPU支持并发搜索(batch search),GPU不支持、

Fiass - 常见问题总结 - 一小撮人的文章 - 知乎 https://zhuanlan.zhihu.com/p/107241260

index选择

考虑因素:候选向量的数量级、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中的任何一个整数。
  • 只要倒排索引就需要train index;

Faiss索引类型怎么选择

1. 是否需要精确的结果?

是,那就得用Flat。

唯一保证百分百准确性的是IndexFlatL2(L2距离)和IndexFlatIP(内积距离)。可以用来做其他索引的baseline,不支持压缩, 不支持add_with_ids,如果需要可以包一层IDMap,用 “IDMap,Flat” 不需要训练、不用指定参数。

支持GPU加速。

2. 内存是否紧张?

faiss的索引全部存在RAM中,速度和内存是tradeoff。

如果一点都不care内存,就用 HNSWx。

如果你有很多内存,或者数据集很小,HNSW是最好的选择,非常快而且准。x的取值在4到64之间,它是指每个向量的连接数量,x值越大,结果越准确,耗费内存越多。efSearch参数用来平衡速度和准确性,内存占用量 d * 4 + x * 2 * 4 一个向量
HNSW也不支持add_with_ids, 所以如果需要,也是加IDMap。

HNSW不需要训练,不支持从索引中删除向量,不支持gpu加速。

3. 如果内存不是要多少有多少,就用 …Flat

“…”前面三个点表示聚类操作,聚类后 Flat索引仅仅把数据组织到对应的bucket中去,它并不压缩数据,索引占用的内存跟原始的数据集大小相当。速度和准确性的tradeoff是通过设置nprobe参数,即搜索的时候,搜多少个聚类。如果等于nlist,将会等同于bruteforce

支持gpu加速,前提是选的聚类方式也要支持gpu。(倒排索引支持GPU加速)

4. 如果很在意内存 就用 PCARx,…,SQ8

这个包括两个操作,一个是PCA,降维到x, 一个是PQ也就是乘积量化,把每个向量元素压缩到一个byte,所以总起来一个向量 x个byte。

不支持gpu加速。

5. 如果非常非常在意内存 就用 OPQx_y,…,PQx

PQx表示压缩向量到x个bytes的乘积量化编码,通常x<=64, 对较大编码 SQ通常差不多准,并且还更快,OPQ是个线性变换帮助压缩
y值的要求:y是x的倍数,y <= d,d是输入数据的维数,y <= 4*x。

支持gpu。

6. 数据量有多大?

这个问题用来确定上面那个三个点 … 数据被聚类到多个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优点

  1. 支持分布式部署;(Faiss支持分布式储存、检索
  2. 支持实时增量插入;
  3. 每条记录可带有标量信息;
  4. 支持标量的数值过滤;
  5. 使用类似于 ES 的restful api对用户友好;

Milvus根据应用场景选择索引

根据应用场景选择索引 · Open Source Vector Database designed for AI applications

【推荐系统】Faiss index选择_第2张图片


 

参考:

笔记︱几款多模态向量检索引擎:Faiss 、milvus、Proxima、vearch、Jina等 - 知乎(多款产品对比,好好好!)

使用Faiss进行海量特征的相似度匹配 - Gemfield的文章 - 知乎

Faiss Indexs 的进一步了解(好好好好好!)

你可能感兴趣的:(推荐系统,机器学习)