Skip to content
On this page

一、核心思想:什么是 Faiss?

Faiss 是由 Facebook AI Research (FAIR) 团队开发的一个专门用于高效相似性搜索稠密向量聚类的库。

它解决的核心问题是: 假设你有 100 万张图片、100 万篇文章或 100 万个商品,你已经通过深度学习模型(如 BERT, ResNet)将它们转换成了 100 维或 1024 维的向量(即 Embedding)。现在,给定一个查询向量(比如一张新图片的向量),如何从这 100 万个向量中快速找到最相似的 Top-K 个向量?

传统方法(如循环遍历比较)在百万、十亿级数据上是不可行的。Faiss 的价值就在于,它通过巧妙的索引结构和算法,将这种大规模相似性搜索的速度提升了数百甚至数千倍。


二、Faiss 的核心概念

1. 索引

Faiss 的核心是 索引。索引是一种数据结构,它会对我们所有的向量进行预处理和组织,以便进行高效的搜索。Faiss 提供了多种类型的索引,适用于不同的场景,这是其强大和灵活的关键。

2. 度量方式

相似性搜索需要定义“相似”。Faiss 主要支持两种度量方式:

  • 内积: 越大越相似。如果你的向量是归一化的,内积就等价于余弦相似度。
  • L2 距离: 越小越相似。

三、Faiss 索引类型详解(从简单到复杂)

Faiss 的索引名称通常由几部分组成,描述了其结构。我们来看最常见的几种。

1. 精确搜索 - 平坦索引

这种索引不做任何压缩,进行精确的、暴力的距离计算。

  • IndexFlatL2: 使用 L2 距离进行精确搜索。
  • IndexFlatIP: 使用内积进行精确搜索。
  • 特点: 结果 100% 准确,但速度慢,需要将所有向量加载到内存中。适用于数据量不大(例如 < 10万)或作为精度基准的场景。

2. 基于量化的索引 - 压缩向量

为了处理海量数据,Faiss 使用向量量化技术来压缩向量,极大减少内存占用。

  • IndexIVFFlat:
    • 原理: 先将整个向量空间聚类成 nlist 个分区。搜索时,只在与查询向量最接近的 nprobe 个分区内进行精确搜索。
    • 流程: 训练聚类中心 -> 添加向量到分区 -> 在部分分区搜索
    • 特点: 速度大大快于平坦索引,是一种精度和速度的极佳权衡。必须训练
  • IndexIVFPQ:
    • 原理: 在 IVF 的基础上,还对向量进行 乘积量化,将高维向量切分成子段并分别聚类,进一步压缩。
    • 特点: 内存占用极低,可以处理十亿级数据,但会损失一些精度。

3. 分层导航小世界 - IndexHNSWFlat

这是一种基于图结构的索引,被认为是当前精度和速度权衡最好的索引之一。

  • 原理: 将数据点组织成一个多层图,上层是“高速公路”,底层是“详细道路”。搜索时从上层开始,快速导航到目标区域,再逐层细化。
  • 特点: 无需训练,速度快,精度高,但构建索引较慢,内存占用大。

四、一个完整的用法举例(Python)

我们将使用 IndexIVFFlat 索引,因为它非常常用且能展示 Faiss 的核心工作流程。

场景: 我们有 10000 个 64 维的随机向量作为数据库,然后进行相似性搜索。

python
import numpy as np
import faiss

# 1. 准备数据
dimension = 64       # 向量的维度
database_size = 10000
np.random.seed(123)  # 设置随机种子以便复现

# 生成随机数据库向量 (模拟我们的图像或文本嵌入向量)
database_vectors = np.random.random((database_size, dimension)).astype('float32')

# 生成一个查询向量
query_vector = np.random.random((1, dimension)).astype('float32')

# 2. 构建索引
nlist = 100  # 将向量空间聚成 100 个类簇(分区)
quantizer = faiss.IndexFlatL2(dimension)  # 使用 L2 距离的量化器
index = faiss.IndexIVFFlat(quantizer, dimension, nlist, faiss.METRIC_L2)

# 3. 训练索引
# IVF 索引需要先训练,以找到聚类中心
assert not index.is_trained
index.train(database_vectors)
assert index.is_trained

# 4. 添加数据到索引
index.add(database_vectors)
print(f"索引中的向量总数: {index.ntotal}")  # 输出: 10000

# 5. 执行搜索
k = 5  # 返回最相似的 5 个结果
nprobe = 10 # 搜索 10 个最接近的分区

index.nprobe = nprobe  # 设置搜索范围,nprobe 越大,越精确,越慢

# 执行搜索
# D: 与查询向量距离的数组 (L2距离,越小越相似)
# I: 最相似向量在数据库中的索引位置的数组
D, I = index.search(query_vector, k)

# 6. 输出结果
print("查询结果:")
print("最相似向量的索引 (I):", I[0])
print("与查询向量的距离 (D):", D[0])

输出可能类似于:

索引中的向量总数: 10000
查询结果:
最相似向量的索引 (I): [3765 1289 5432 8761 2100]
与查询向量的距离 (D): [20.145323 20.567123 20.789234 21.012345 21.123456]

结果解释:

  • I[0] 告诉我们,数据库中最相似的 5 个向量分别是第 3765, 1289, 5432, 8761, 2100 号向量。
  • D[0] 告诉我们这些向量与查询向量的 L2 距离。

五、GPU 加速

Faiss 一个强大的特性是支持 GPU 加速,通常能带来显著的性能提升。

python
# 接上例,将索引转移到 GPU
res = faiss.StandardGpuResources()  # 声明 GPU 资源

# 将 CPU 索引转移到 GPU
gpu_index = faiss.index_cpu_to_gpu(res, 0, index) # 0 是 GPU 设备号

# 现在使用 GPU 索引进行搜索,速度会快很多
D_gpu, I_gpu = gpu_index.search(query_vector, k)
print("GPU 搜索结果:", I_gpu[0])

六、Faiss 的主要应用场景

  1. 推荐系统: “看了这个商品的人还看了...” -> 将商品向量化,寻找相似商品。
  2. 图像检索: 以图搜图。将图片转换为特征向量,搜索相似向量。
  3. 文本语义搜索: 使用 BERT 等模型将文本变为向量,搜索语义相似的句子或段落。
  4. 音频/视频去重: 将媒体文件向量化,通过搜索快速找到重复或近似重复的内容。
  5. 异常检测: 寻找与大多数数据点都“不相似”的异常点。

七、优缺点总结

优点:

  • 极致的性能: 为大规模相似性搜索做了高度优化。
  • 丰富的算法: 提供多种索引,满足不同精度、速度和内存的需求。
  • 易于使用: Python 接口非常简洁。
  • GPU 支持: 可利用 GPU 获得巨大加速。
  • 成熟稳定: 由 Facebook 维护,被业界广泛使用和验证。

缺点:

  • 仅支持稠密向量: 不适合稀疏向量。
  • 内存消耗: 索引需要常驻内存(或 GPU 显存),对于超大规模数据需要分布式方案。
  • 学习曲线: 需要理解不同索引的原理和参数(如 nlist, nprobe)才能发挥其最大效能。

总结

Faiss 是现代 AI 应用中处理向量相似性搜索的事实上的标准工具。它将复杂的近似最近邻算法封装成简单易用的 API,让开发者能够轻松地在百万甚至十亿级的数据集上实现毫秒级的搜索,是构建智能搜索、推荐和匹配系统不可或缺的利器。

技术文档集合