Faiss教程:索引(1)
索引是faiss的关键知识,我们重点介绍下。
索引方法汇总
有些索引名,我就不翻译了,根据英文名去学习更准确。
| 索引名 | 类名 | index_factory | 主要参数 | 字节数/向量 | 精准检索 | 备注 |
|---|---|---|---|---|---|---|
| 精准的L2搜索 | IndexFlatL2 | "Flat" | d | 4*d | yes | brute-force |
| 精准的内积搜索 | IndexFlatIP | "Flat" | d | 4*d | yes | 归一化向量计算cos |
| Hierarchical Navigable Small World graph exploration | IndexHNSWFlat | "HNSWx,Flat" | d, M | 4*d + 8 * M | no | - |
| 倒排文件 | IndexIVFFlat | "IVFx,Flat" | quantizer, d, nlists, metric | 4*d | no | 需要另一个量化器来建立倒排 |
| Locality-Sensitive Hashing (binary flat index) | IndexLSH | - | d, nbits | nbits/8 | yes | optimized by using random rotation instead of random projections |
| Scalar quantizer (SQ) in flat mode | IndexScalarQuantizer | "SQ8" | d | d | yes | 每个维度项可以用4 bit表示,但是精度会受到一定影响 |
| Product quantizer (PQ) in flat mode | IndexPQ | "PQx" | d, M, nbits | M (if nbits=8) | yes | - |
| IVF and scalar quantizer | IndexIVFScalarQuantizer | "IVFx,SQ4" "IVFx,SQ8" | quantizer, d, nlists, qtype | d or d/2 | no | 有两种编码方式:每个维度项4bit或8bit |
| IVFADC (coarse quantizer+PQ on residuals) | IndexIVFPQ | "IVFx,PQy" | quantizer, d, nlists, M, nbits | M+4 or M+8 | no | 内存和数据id(int、long)相关,目前只支持 nbits <= 8 |
| IVFADC+R (same as IVFADC with re-ranking based on codes) | IndexIVFPQR | "IVFx,PQy+z" | quantizer, d, nlists, M, nbits, M_refine, nbits_refine | M+M_refine+4 or M+M_refine+8 | no | - |
Cell-probe方法
加速查找的典型方法是对数据集进行划分,我们采用了基于Multi-probing(best-bin KD树变体)的分块方法。
- 特征空间被切分为ncells个块
- 数据被划分到这些块中(k-means可根据最近欧式距离),归属关系存储在ncells个节点的倒排列表中
- 搜索时,检索离目标距离最近的nprobe个块
- 根据倒排列表检索nprobe个块中的所有数据。
这便是IndexIVFFlat,它需要另一个索引来记录倒排列表。
IndexIVFKmeans 和 IndexIVFSphericalKmeans 不是对象而是方法,它们可以返回IndexIVFFlat对象。
注意:对于高维的数据,要达到较好的召回,需要的nprobes可能很大
和LSH的关系
最流行的cell-probe方法可能是原生的LSH方法,可参考E2LSH。然而,这个方法及其变体有两大弊端:
- 需要大量的哈希函数(=分块数),来达到可以接受的结果
- 哈希函数很难基于输入动态调整,实际应用中容易返回次优结果
LSH的示例
n_bits = 2 * d
lsh = faiss.IndexLSH (d, n_bits)
lsh.train (x_train)
lsh.add (x_base)
D, I = lsh.search (x_query, k)
d是输入数据的维度,nbits是存储向量的bits数目。
PQ的示例
m = 16 # number of subquantizers
n_bits = 8 # bits allocated per subquantizer
pq = faiss.IndexPQ (d, m, n_bits) # Create the index
pq.train (x_train) # Training
pq.add (x_base) # Populate the index
D, I = pq.search (x_query, k) # Perform a search
带倒排的PQ:IndexIVFPQ
coarse_quantizer = faiss.IndexFlatL2 (d)
index = faiss.IndexIVFPQ (coarse_quantizer, d,
ncentroids, m, 8)
index.nprobe = 5
复合索引
使用PQ作粗粒度量化器的Cell Probe方法
相应的文章见:The inverted multi-index, Babenko & Lempitsky, CVPR'12。在Faiss中可使用MultiIndexQuantizer,它不需要add任何向量,因此将它应用在IndexIVF时需要设置quantizer_trains_alone。
nbits_mi = 12 # c
M_mi = 2 # m
coarse_quantizer_mi = faiss.MultiIndexQuantizer(d, M_mi, nbits_mi)
ncentroids_mi = 2 ** (M_mi * nbits_mi)
index = faiss.IndexIVFFlat(coarse_quantizer_mi, d, ncentroids_mi)
index.nprobe = 2048
index.quantizer_trains_alone = True
预过滤PQ编码,汉明距离的计算比PQ距离计算快6倍,通过对PQ中心的合理重排序,汉明距离可以正确地替代PQ编码距离。在搜索时设置汉明距离的阈值,可以避免PQ比较的大量运算。
# IndexPQ
index = faiss.IndexPQ (d, 16, 8)
# before training
index.do_polysemous_training = true
index.train (...)
# before searching
index.search_type = faiss.IndexPQ.ST_polysemous
index.polysemous_ht = 54 # the Hamming threshold
index.search (...)
# IndexIVFPQ
index = faiss.IndexIVFPQ (coarse_quantizer, d, 16, 8)
# before training
index. do_polysemous_training = true
index.train (...)
# before searching
index.polysemous_ht = 54 # the Hamming threshold
index.search (...)
阈值设定是注意两点:
- 阈值在0到编码bit数(16*8)之间
- 阈值越小,留下的需要计算的PQ中心数越少,推荐<1/2*bits
复合索引中也可以建立多级PQ量化索引。
预处理和后处理
为了获得更好的索引,可以remap向量ids,对数据集进行变换,re-rank检索结果等。
Faiss id mapping
默认情况下,Faiss为每个向量设置id。有些Index实现了add_with_ids方法,为向量添加64bit的ids,检索时返回ids而不需返回原始向量。
index = faiss.IndexFlatL2(xb.shape[1])
ids = np.arange(xb.shape[0])
index.add_with_ids(xb, ids) # this will crash, because IndexFlatL2 does not support add_with_ids
index2 = faiss.IndexIDMap(index)
index2.add_with_ids(xb, ids) # works, the vectors are stored in the underlying index
IndexIVF原生提供了ass_with_ids方法,就不需要IndexIDMap了。
预变换
| 变换方法 | 类名 | 备注 |
|---|---|---|
| random rotation | RandomRotationMatrix | useful to re-balance components of a vector before indexing in an IndexPQ or IndexLSH |
| remapping of dimensions | RemapDimensionsTransform | 为适应索引推荐的维度,通过重排列减少或增加向量维度d |
| PCA | PCAMatrix | 降维 |
| OPQ rotation | OPQMatrix | OPQ通过旋转输入向量更利于PQ编码,见 Optimized product quantization, Ge et al., CVPR'13 |
换行可以通过train进行训练,通过apply应用到数据上。这些变化可以通过IndexPreTransform方法应用到索引上。
# the IndexIVFPQ will be in 256D not 2048
coarse_quantizer = faiss.IndexFlatL2 (256)
sub_index = faiss.IndexIVFPQ (coarse_quantizer, 256, ncoarse, 16, 8)
# PCA 2048->256
# also does a random rotation after the reduction (the 4th argument)
pca_matrix = faiss.PCAMatrix (2048, 256, 0, True)
#- the wrapping index
index = faiss.IndexPreTransform (pca_matrix, sub_index)
# will also train the PCA
index.train(...)
# PCA will be applied prior to addition
index.add(...)
IndexRefineFlat
对搜索结果进行精准重排序
q = faiss.IndexPQ (d, M, nbits_per_index)
rq = faiss.IndexRefineFlat (q)
rq.train (xt)
rq.add (xb)
rq.k_factor = 4
D, I = rq:search (xq, 10)
从IndexPQ的最近4*10个邻域中,计算真实距离,返回最好的10个结果。注意IndexRefineFlat需要积累全向量,占用内存较高。
IndexShards
如果数据分开为多个索引,查询时需要合并结果集。这在多GPU以及平行查询中是必需的。
Faiss教程:索引(1)的更多相关文章
- 【转】微信公众账号 Senparc.Weixin.MP SDK 开发教程 索引
微信公众账号 Senparc.Weixin.MP SDK 开发教程 索引 Senparc.Weixin.MP SDK从一开始就坚持开源的状态,这个过程中得到了许多朋友的认可和支持. 目前SDK已经达到 ...
- Faiss教程:基础
Faiss对一些基础算法提供了非常高效的实现:k-means.PCA.PQ编解码. 聚类 假设2维tensor x: ncentroids = 1024 niter = 20 verbose = Tr ...
- Spring教程索引
Spring教程索引 2016-11-15 1 入门 1 概述.深入浅出Spring(一)Spring概述 2 体系结构 3 环境设置 4 Hello World 实例 5 IoC 容器 IoC容 ...
- Faiss教程:索引(2)
索引的I/O与复制 所有的函数都是深复制,我们不需要关心对象关系. I/O函数: write_index(index, "large.index"): 写索引到文件 Index * ...
- Orchard教程索引页
Orchard官方教程(译)索引 链接标注 原文 则表示未译,其他带有中文标题的表示译文内容. 入门 安装Orchard--Installing Orchard 通过zip包手动安装Orchard-- ...
- 微信公众账号 Senparc.Weixin.MP SDK 开发教程 索引
Senparc.Weixin.MP SDK从一开始就坚持开源的状态,这个过程中得到了许多朋友的认可和支持. 目前SDK已经达到比较稳定的版本,这个过程中我觉得有必要整理一些思路和经验,和大家一起分享. ...
- Senparc.Weixin.MP SDK 微信公众平台开发教程 索引
Senparc.Weixin.MP SDK从一开始就坚持开源的状态,这个过程中得到了许多朋友的认可和支持. 目前SDK已经达到比较稳定的版本,这个过程中我觉得有必要整理一些思路和经验,和大家一起分享. ...
- Senparc.Weixin SDK 微信公众号 .NET 开发教程 索引
Senparc.WeixinSDK从一开始就坚持开源的状态,这个过程中得到了许多朋友的认可和支持. 目前SDK已经达到比较稳定的版本,这个过程中我觉得有必要整理一些思路和经验,和大家一起分享.也欢迎大 ...
- Faiss教程:入门
Faiss处理固定维度d的数据,矩阵每一行表示一个向量,每列表示向量的一项.Faiss采用32-bit浮点型存储. 假设xb为数据集,维度为\(nb\times{d}\):xq是查询数据,维度为\(n ...
随机推荐
- ASP.NET Core Linux环境安装并运行项目
原文地址:https://blog.csdn.net/u014368040/article/details/79192622 一 安装环境 1. 从微软官网下载 Linux版本的.NetCoreSd ...
- YY老总李学凌给记者们的几句话
从记者到总编,从狗狗.多玩到如今的 YY.100 教育,似乎李学凌在这么多年来一直没有放缓过脚步.作为记者转型的成功案例,李学凌总结记者生涯有几方面令其获益匪浅: 1.平常心.对待再高层次的人,也用一 ...
- df -h和du -sh显示结果不一样的原因及解决
一.背景:一台2T硬盘的mysql服务器,保存电话的CDR信息.按照历史数据的水平,一个月能生成20+GB的文件.然而短短的半年时间,满了?! 登录服务器看谁占了这么大的空间?好吧,slow-quer ...
- 在Java中final类与一般类有什么样的区别
final修饰的类不能被继承. Sting就是一个被final修饰的类,我们只能用,不用继承final不仅可以修饰类,还可以修饰变量,被final修饰的变量就是一个常量,只能赋值一次注意final和f ...
- 如何使用git 提交作业 收作业
如何使用git 提交作业 收作业 方法论: 今天就来用一个通俗易懂的自然模型来解释Git的commit,pull和push.不过,我们首先要理解两个名词,remote,local. remote,翻译 ...
- 类里的通用成员函数应声明为static
类C的成员函数f,如果f的实现实现不依赖于C的任何成员变量,则f为通用函数. 对于通用函数f,可以将其从类C中分离出来做成一个全局函数,也可以仍然让它属于类C,但加上static. 两种处理方法实际都 ...
- collections集合的总括。
序言 突然遇到集合的有关面试题,感觉很懵逼,所以特意总结了一下,关于我们常用的 ArrayList.LinkedList.Set等集合的一些区别和用法. 还有,这份微小型总结肯定是从很多博文中摘取精华 ...
- ios7新特性--1
1.用户界面的扁平化 2.UIKit 动态行为支持 应用程序可以设置UIView 对象和其他对象(遵从UIDynamicItem 协议)的动态行为属性.遵从UIDynamicItem协议的对象被称为d ...
- 91平台iOS接入demo
源码:http://pan.baidu.com/s/1DuBl6 今天整理硬盘,找到了一个有趣的demo.一年前,91助手游戏联运呈爆棚趋势,但是许多使用FlashAir开发的优秀的游戏和应用都卡在了 ...
- 【Unity】第5章 3D坐标系和天空盒
分类:Unity.C#.VS2015 创建日期:2016-04-20 一.简介 这一张主要介绍3D坐标系的基础知识以及各种形状的天空盒. 二.示例 本章的示例都在ch05Demos工程下.