faiss 三种基础索引方式

简介: faiss 三种基础索引方式

       faiss 三个最基础的 index. 分别是 IndexFlatL2, IndexIVFFlat, IndexIVFPQ


       搜索时,可以以查询向量为中心,返回距离在一定范围内的结果,如返回数据库中与查询向量距离小于0.3的结果。不是所有的Index都支持按距离检索,但是下面三种Index都支持,只支持在CPU使用。

一、IndexFlatL2 - 最基础的Index

IndexFlatL2索引的结果是精确的,可以用来作为其他索引测试中准确性程度的参考.

import numpy as np
import faiss
import time
 
def demo_IndexFlatL2():
    d = 2048  # 2048维的数据
    nb = 2  # database size
    nq = 1  # nb of queries
    np.random.seed(1234)
    index = faiss.IndexFlatL2(d)
    print(index.is_trained)
    # 随机nb个数据插入索引
    xb = np.random.random((nb, d)).astype('float32')
    xb[:, 0] += np.arange(nb) / 1000.
    index.add(xb)
    # 再随机nb个数据插入索引
    xb1 = np.random.random((nb, d)).astype('float32')
    xb1[:, 0] += np.arange(nb) / 1000.
    index.add(xb1)
    print('index.ntotal:', index.ntotal)
    # 随机nq个数据用于查询
    xq = np.random.random((nq, d)).astype('float32')
    xq[:, 0] += np.arange(nq) / 1000.
    k = 4  # 查询距离最近的4个
    D, I = index.search(xq, k)  # 返回值D是距离 I是索引
    print("I: ", I)
    # 按照距离查询
    dist = 1000  # 定义一个半径/阈值
    _, D, I = index.range_search(xb[[2], :], dist)  # 用第2个向量查询
    print('range_search res:', I)
    # 删除元素,dtype=np.int64非常重要
    print('remove之前ntotal:', index.ntotal)
    index.remove_ids(np.asarray((2,3), dtype=np.int64))
    print('remove之后ntotal:', index.ntotal)
 
if __name__ == '__main__':
    demo_IndexFlatL2()

二、更快的搜索 - IndexIVFFlat

       为了加快搜索速度,可以将数据集分割成几部分。我们在d维空间中定义Voronoi单元格,并且每个数据库矢量都落入其中一个单元格中。在搜索时,只有查询x所在单元中包含的数据库向量y与少数几个相邻查询向量进行比较。(划分搜索空间)

       这种类型的索引需要一个训练的过程,可以在与数据库向量具有相同分布的任何向量集合上执行。


       这IndexIVFFlat还需要另一个索引,即量化器(quantizer),它将矢量分配给Voronoi单元。每个单元由一个质心定义,找到一个矢量所在的Voronoi单元包括在质心集中找到该矢量的最近邻居。这是另一个索引的任务,通常是索引IndexFlatL2。


搜索方法有两个参数:

  • nlist 划分单元的数量
  • nprobe 执行搜索访问的单元格数(不包括nlist)

nprobe 参数始终是调整结果速度和准确度之间折中的一种方式 。设置 nprobe = nlist 将给出与蛮力搜索(但会更慢)相同的结果。

 

import numpy as np
import faiss
import time
 
def demo_IndexIVFFlat():
    d = 64  # 向量维度
    nb = 200  # 向量集大小
    nq = 10000  # 查询次数
    np.random.seed(1234)  # 随机种子,使结果可复现
 
    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
 
    xb = np.random.random((nb, d)).astype('float32')
    xb[:, 0] += np.arange(nb) / 1000.
    index.train(xb)
    index.add(xb)  # 添加索引可能会有一点慢
    print('index.ntotal:', index.ntotal)
    xb1 = np.random.random((nb, d)).astype('float32')
    xb1[:, 0] += np.arange(nb) / 1000.
    index.train(xb1)
    index.add(xb1)  # 添加索引可能会有一点慢
    print('index.ntotal:', index.ntotal)
    xq = np.random.random((nq, d)).astype('float32')
    xq[:, 0] += np.arange(nq) / 1000.
    D, I = index.search(xq, k)  # 搜索
    print(I[-5:])  # 最初五次查询的结果
    index.nprobe = 10  # 执行搜索访问的单元格数 默认 nprobe 是1 ,可以设置的大一些试试
    D, I = index.search(xq, k)
    print(I[-5:])  # 最后五次查询的结果
    # 按照距离查询
    dist = 1000  # 定义一个半径/阈值
    _, D, I = index.range_search(xb[[2], :], dist)  # 用第2个向量查询
    print('range_search res:', I)
    # 删除元素,dtype=np.int64非常重要
    print('remove之前ntotal:', index.ntotal)
    index.remove_ids(np.asarray((2,3), dtype=np.int64))
    print('remove之后ntotal:', index.ntotal)
 
if __name__ == '__main__':
    demo_IndexIVFFlat()

三、更低的内存占用 - IndexIVFPQ

       索引IndexFlatL2IndexIVFFlat都存储完整的向量。 为了扩展到非常大的数据集,Faiss提供了基于产品量化器的有损压缩来压缩存储的向量的变体。压缩的方法基于乘积量化(Product Quantizer)

在这种情况下,由于矢量没有精确存储,搜索方法返回的距离也是近似值

import numpy as np
import faiss
import time
 
def demo_IndexIVFPQ():
    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.
 
    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:])
    # 按照距离查询
    dist = 1000  # 定义一个半径/阈值
    _, D, I = index.range_search(xb[[2], :], dist)  # 用第2个向量查询
    print('range_search res:', I)
    # 删除元素,dtype=np.int64非常重要
    print('remove之前ntotal:', index.ntotal)
    index.remove_ids(np.asarray((2,3), dtype=np.int64))
    print('remove之后ntotal:', index.ntotal)
 
if __name__ == '__main__':
    demo_IndexIVFPQ()

相关文章
|
存储 自然语言处理 数据可视化
可视化FAISS矢量空间并调整RAG参数提高结果精度
随着开源大型语言模型的性能不断提高,编写和分析代码、推荐、文本摘要和问答(QA)对的性能都有了很大的提高。但是当涉及到QA时,LLM通常会在未训练数据的相关的问题上有所欠缺,很多内部文件都保存在公司内部,以确保合规性、商业秘密或隐私。当查询这些文件时,会使得LLM产生幻觉,产生不相关、捏造或不一致的内容。
693 0
|
机器学习/深度学习 分布式计算 DataWorks
EasyRec 使用介绍|学习笔记
快速学习 EasyRec 使用介绍。
2183 0
|
SQL 机器学习/深度学习 消息中间件
十大行业经典案例!Apache Flink 的 40 个最佳实践
如今,Apache Flink 行业应用几何?在降本增效的需求驱动下,企业如何实现数据与算力价值最大化?本文整理了 Flink 社区近一年的社区案例,并按照行业进行分类,供大家参考!
十大行业经典案例!Apache Flink 的 40 个最佳实践
|
12月前
|
存储 分布式计算 数据可视化
Hadoop生态圈深度解读:从数据到可视化的全景视图
数据处理后可通过多种方式输出,计算后的数据输出可通过传统数据库或文件形式,并通过Tomcat服务器可视化展示结果。ZooKeeper为分布式系统提供可靠的协调服务。最后,计算分析结果将通过传统Tomcat服务器进行可视化展示。同时,ZooKeeper作为Google Chubby的开源实现,为大型分布式系统提供可靠协调服务,封装了复杂且易出错的关键服务,为用户提供简单易用、性能高效且功能稳定的系统。 至此,我们对整个大数据Hadoop生态体系的层次划分、技术支持和运行流程有了初步了解。接下来,我们将着手搭建Hadoop生态体系集群,深入解析各个框架的实现过程与执行原理,以完成项目数据分析。
|
12月前
|
存储 机器学习/深度学习 算法
|
10月前
|
存储 机器学习/深度学习 人工智能
RAG系统嵌入模型怎么选?选型策略和踩坑指南
嵌入是RAG系统的核心,直接影响检索质量。本文详解嵌入原理,解析稠密/稀疏、长上下文、多向量等类型,梳理选型关键:领域匹配、上下文长度、维度与成本,并结合MTEB基准给出实用建议,助你为业务挑选高效稳健的嵌入方案。
1135 2
RAG系统嵌入模型怎么选?选型策略和踩坑指南
|
10月前
|
存储 算法 数据可视化
SpQR: 稀疏量化表示实现大语言模型近无损压缩——论文阅读
SpQR是一种创新的稀疏量化方法,通过识别并高精度存储导致大量化误差的异常权重,将其他权重压缩至3-4比特,实现大语言模型的近无损压缩。该方法在LLM压缩中首次跨模型规模达到接近16位精度的性能,压缩后模型平均误差低于1%。实验表明,SpQR在推理速度与压缩率上优于现有技术,使高质量大模型可在消费级设备高效运行。
1064 9
|
人工智能 自然语言处理 搜索推荐
LLM在电商推荐系统的探索与实践
LLM在电商推荐系统的探索与实践
4758 2
|
机器学习/深度学习 存储 算法
Faiss为啥这么快?原来是量化器在做怪!1
Faiss为啥这么快?原来是量化器在做怪!
2041 0
|
PyTorch 算法框架/工具
Pytorch学习笔记(七):F.softmax()和F.log_softmax函数详解
本文介绍了PyTorch中的F.softmax()和F.log_softmax()函数的语法、参数和使用示例,解释了它们在进行归一化处理时的作用和区别。
1879 1
Pytorch学习笔记(七):F.softmax()和F.log_softmax函数详解