【NLP 76、Faiss 向量数据库】

压抑与痛苦,那些辗转反侧的夜,终会让我们更加强大                

                                                                                        —— 25.5.20

        Faiss(Facebook AI Similarity Search)是由 Facebook AI 团队开发的一个开源库,用于高效相似性搜索库,特别适用于大规模向量数据集的存储与搜索

  1. 相似性搜索:Faiss 可以高效地搜索大规模向量集合中与查询向量最相似的向量。这对于图像检索、推荐系统、自然语言处理和大数据分析等领域非常有用。
  2. 多索引结构(软件层面):Faiss 提供了多种索引结构,包括Flat、IVF、HNSW、PQ、LSH 索引等,以满足不同数据集和搜索需求的要求。
  3. 高性能(硬件层面):Faiss 可利用了多核处理器GPU 来加速搜索操作。
  4. 多语言支持:Faiss 支持 Python、C++ 语言。
  5. 开源:Faiss 是开源的,可以免费使用和修改,适用于学术研究和商业应用。

一、基本使用

1.基本操作

准备数据

np.random.rand():NumPy 库中用于生成随机数的函数,它返回一个或多个在 [0, 1) 区间内均匀分布的随机数。

参数类型描述默认值
d0, d1, ..., dnint (可选)指定输出数组的形状。如果不提供任何参数,则返回单个随机浮点数。无(必须至少提供一个维度)

dim:定义向量维度 

    # 1.1 定义数据和向量维度data = np.random.rand(10000, 256)dim = 256   # 存储的向量维度

Ⅰ、创建向量数据库(索引)

① API函数

faiss.IndexFlatL2():创建一个使用 L2 距离(欧氏距离) 进行向量相似度搜索的 Faiss 索引。 

参数类型描述
dint向量的维度

 欧氏(L2)距离公式:

faiss.IndexFlatIP(): 创建一个使用 内积(点积) 进行相似度搜索的 Faiss 索引。

参数类型描述
dint向量的维度

点积公式:

② 工厂函数 

faiss.index_factory():通过字符串描述创建 Faiss 索引,支持多种索引类型(如 "IVF100,Flat")。

参数类型描述
dint向量的维度
descriptionstr索引描述字符串(如 "IVF100,Flat"
metricint (可选)

距离度量(faiss.METRIC_L2 欧氏距离 或 faiss.METRIC_INNER_PRODUCT 点积计算

    # 1.2 创建向量数据库(索引)对象 API函数index1 = faiss.IndexFlatL2(dim)  # Flat:线性搜索 (O(n))  L2:使用欧式距离计算相似度  dim: 向量维度index2 = faiss.IndexFlatIP(dim)  # Flat:线性搜索 (O(n))  IP:使用点积计算相似度  dim: 向量维度# 1.3 创建向量数据库(索引)对象 工厂函数index3 = faiss.index_factory(dim, "Flat", faiss.METRIC_L2)  # Flat:线性搜索 (O(n))  L2:使用欧式距离计算相似度  dim: 向量维度index4 = faiss.index_factory(dim, "Flat", faiss.METRIC_INNER_PRODUCT)    # Flat:线性搜索 (O(n))  INNER_PRODUCT:使用点积计算相似度  dim: 向量维度

Ⅱ、添加向量

向量数据库对象(索引).add():向向量数据库(索引)中添加向量数据。

参数类型描述
xbnp.array待添加的向量数组(形状 (n, d)
    # 2.添加向量index1.add(data)index2.add(data)index3.add(data)index4.add(data)

Ⅲ、搜索向量

np.random.rand():NumPy 库中用于生成随机数的函数,它返回一个或多个在 [0, 1) 区间内均匀分布的随机数。

参数类型描述默认值
d0, d1, ..., dnint (可选)指定输出数组的形状。如果不提供任何参数,则返回单个随机浮点数。无(必须至少提供一个维度)

向量数据库对象(索引).search():在向量数据库(索引)中搜索最相似的 k 个向量。

参数类型描述
xqnp.array查询向量(形状 (m, d)
kint返回的最近邻数量

D:Distance 两向量相似度

I:最相似的向量的索引

    # 3.搜索向量query_vectors = np.random.rand(2, 256) # 创建两个 256 维的向量作为查询向量# query_vectors: 待搜索的向量  k: 返回的向量个数D, I = index1.search(query_vectors, k=2)# D: Distance 两向量相似度  I: Index 返回最相似的向量的索引print("index1_D:", D, "index1_I:", I)D, I = index2.search(query_vectors, k=2)print("index2_D:", D, "index2_I:", I)D, I = index3.search(query_vectors, k=2)print("index3_D:", D, "index3_I:", I)D, I = index4.search(query_vectors, k=2)print("index4_D:", D, "index4_I:", I)

Ⅳ、删除向量

np.array():将 Python 列表或类似结构转换为 NumPy 数组。

参数类型描述
datalist/array-like输入数据
dtypestr/np.dtype (可选)数据类型(如 'float32'

向量数据库对象(索引).remove_ids():从索引中删除指定 ID 的向量。

参数类型描述
idsnp.array/list要删除的向量 ID 列表

向量数据库对象(索引).reset():清空索引中的所有向量。

向量数据库对象(索引).ntotal:返回索引中当前存储的向量数量(属性,非函数)。

    # 4.删除向量index1.remove_ids(np.array([0, 1, 2, 3])) # 删除索引为 0, 1, 2, 3 的向量print("index1剩余向量个数为:", index1.ntotal) # 打印剩余的向量个数index2.remove_ids(np.array([0, 1, 2, 3])) # 删除索引为 0, 1, 2, 3 的向量print("index2剩余向量个数为:", index2.ntotal) # 打印剩余的向量个数index3.remove_ids(np.array([0, 1, 2, 3])) # 删除索引为 0, 1, 2, 3 的向量print("index3剩余向量个数为:", index3.ntotal) # 打印剩余的向量个数index4.remove_ids(np.array([0, 1, 2, 3])) # 删除索引为 0, 1, 2, 3 的向量print("index4剩余向量个数为:", index4.ntotal) # 打印剩余的向量个数index3.reset()  # 删除全部向量print("index3剩余向量个数为:", index3.ntotal)  # 打印剩余的向量个数

Ⅴ、存储向量数据库(索引)

faiss.write_index():将 Faiss 索引保存到磁盘。

参数类型描述
indexfaiss.IndexFaiss 索引对象
file_pathstr保存路径
    faiss.write_index(index1, 'flat.faiss')

Ⅵ、加载向量数据库(索引)

faiss.read_index():从磁盘加载 Faiss 索引。

参数类型描述
file_pathstr索引文件路径
    faiss.read_index('flat.faiss')

Ⅶ、完整代码

import faiss
import numpy as npnp.random.seed(0)# 一、基本操作
def test01():# 1.构建索引(向量数据库)# 1.1 定义数据和向量维度data = np.random.rand(10000, 256)dim = 256   # 存储的向量维度# 1.2 创建索引对象 API函数index1 = faiss.IndexFlatL2(dim)  # Flat:线性搜索 (O(n))  L2:使用欧式距离计算相似度  dim: 向量维度index2 = faiss.IndexFlatIP(dim)  # Flat:线性搜索 (O(n))  IP:使用点积计算相似度  dim: 向量维度# 1.3 创建索引对象 工厂函数index3 = faiss.index_factory(dim, "Flat", faiss.METRIC_L2)  # Flat:线性搜索 (O(n))  L2:使用欧式距离计算相似度  dim: 向量维度index4 = faiss.index_factory(dim, "Flat", faiss.METRIC_INNER_PRODUCT)    # Flat:线性搜索 (O(n))  INNER_PRODUCT:使用点积计算相似度  dim: 向量维度# 2.添加向量index1.add(data)index2.add(data)index3.add(data)index4.add(data)# 3.搜索向量query_vectors = np.random.rand(2, 256) # 创建两个 256 维的向量作为查询向量# query_vectors: 待搜索的向量  k: 返回的向量个数D, I = index1.search(query_vectors, k=2)# D: Distance 两向量相似度  I: Index 返回最相似的向量的索引print("index1_D:", D, "index1_I:", I)D, I = index2.search(query_vectors, k=2)print("index2_D:", D, "index2_I:", I)D, I = index3.search(query_vectors, k=2)print("index3_D:", D, "index3_I:", I)D, I = index4.search(query_vectors, k=2)print("index4_D:", D, "index4_I:", I)# 4.删除向量index1.remove_ids(np.array([0, 1, 2, 3])) # 删除索引为 0, 1, 2, 3 的向量print("index1剩余向量个数为:", index1.ntotal) # 打印剩余的向量个数index2.remove_ids(np.array([0, 1, 2, 3])) # 删除索引为 0, 1, 2, 3 的向量print("index2剩余向量个数为:", index2.ntotal) # 打印剩余的向量个数index3.remove_ids(np.array([0, 1, 2, 3])) # 删除索引为 0, 1, 2, 3 的向量print("index3剩余向量个数为:", index3.ntotal) # 打印剩余的向量个数index4.remove_ids(np.array([0, 1, 2, 3])) # 删除索引为 0, 1, 2, 3 的向量print("index4剩余向量个数为:", index4.ntotal) # 打印剩余的向量个数index3.reset()  # 删除全部向量print("index3剩余向量个数为:", index3.ntotal)  # 打印剩余的向量个数# 5.存储索引faiss.write_index(index1, 'flat.faiss')# 6.加载索引faiss.read_index('flat.faiss')if __name__ == '__main__':test01()


2.ID映射

Ⅰ、创建向量数据库(索引)

 faiss.IndexFlatL2():创建一个使用 L2 距离(欧氏距离) 进行向量相似度搜索的 Faiss 索引。 

参数类型描述
dint向量的维度

 欧氏(L2)距离公式:

    # 1.创建索引(向量数据库)index = faiss.IndexFlatL2(256)

Ⅱ、⭐ 包装向量数据库(索引)

实现自定义向量编号

faiss.IndexIDMap():为索引添加自定义 ID 映射,支持按 ID 管理向量。

参数类型描述
indexfaiss.Index底层索引(如 IndexFlatL2
    # 2.包装索引:实现自定义向量编号index = faiss.IndexIDMap(index)

Ⅲ、添加向量【准备数据】

np.random.rand():生成 [0, 1) 区间均匀分布的随机数组。

参数类型描述
d0, d1, ..., dnint (可选)数组形状

向量数据库对象(索引).add_with_ids():添加向量并指定自定义 ID(需配合 IndexIDMap 使用)。

参数类型描述
xbnp.array向量数组
idsnp.array对应的 ID 数组

np.arange():生成等间隔数值序列(类似 Python range)。

参数类型描述
startint/float起始值(默认 0
stopint/float结束值(不包含)
stepint/float步长(默认 1
    # 3.添加向量data = np.random.rand(10000, 256)index.add_with_ids(data, np.arange(10000, 20000))  # 向量编号从 10000 开始, 20000 结束

Ⅳ、搜索向量

向量数据库对象(索引).ntotal:返回索引中当前存储的向量数量(属性,非函数)。

向量数据库对象(索引).remove_ids():从索引中删除指定 ID 的向量。

参数类型描述
idsnp.array/list要删除的向量 ID 列表

np.array():将 Python 列表或类似结构转换为 NumPy 数组。

参数类型描述
datalist/array-like输入数据
dtypestr/np.dtype (可选)数据类型(如 'float32'
    # 4.删除索引向量print("index1向量个数为:", index.ntotal)  # 打印向量个数index.remove_ids(np.array([0, 1, 2, 3]))  # 删除索引为 0, 1, 2, 3 的向量print("index1剩余向量个数为:", index.ntotal)  # 打印剩余的向量个数# 有些索引类型本身支持用户指定 ID,如果不支持的话,可以使用IndexIDMap包装一下

Ⅴ、完整代码

import faiss
import numpy as npnp.random.seed(0)# 二、向量 ID 映射
def test02():# 1.创建索引(向量数据库)index = faiss.IndexFlatL2(256)# 2.包装索引:实现自定义向量编号index = faiss.IndexIDMap(index)# 3.添加向量data = np.random.rand(10000, 256)index.add_with_ids(data, np.arange(10000, 20000))  # 向量编号从 10000 开始, 20000 结束# 4.删除索引向量print("index1向量个数为:", index.ntotal)  # 打印向量个数index.remove_ids(np.array([0, 1, 2, 3]))  # 删除索引为 0, 1, 2, 3 的向量print("index1剩余向量个数为:", index.ntotal)  # 打印剩余的向量个数# 有些索引类型本身支持用户指定 ID,如果不支持的话,可以使用IndexIDMap包装一下if __name__ == '__main__':test02()


二、更快的索引

        IndexFlat 索引是一种基于线性搜索的索引,它通过逐个计算与每个向量的相似度来进行搜索。在数据量较大的时候,搜索效率会较低。此时,我们可以使用 IndexIVFFlat 索引来提升搜索效率。它的原理如下:对于所有的向量进行聚类,相当于把所有的数据进行分类。当进行查询时,在最相似的 N 个簇中进行线性搜索。这就减少了需要进行相似度计算的数据量,从而提升搜索效率。

        需要注意:这种方法是一种在查询的精度效率之间平衡的方法。簇数目越多,精度越高,效率越低

1.定义数据和向量维度

np.random.rand():生成等间隔数值序列(类似 Python range

参数类型描述
startint/float起始值(默认 0
stopint/float结束值(不包含)
stepint/float步长(默认 1

np.arange():生成等间隔数值序列(类似 Python range)。

参数类型描述
startint/float起始值(默认 0
stopint/float结束值(不包含)
stepint/float步长(默认 1

np.random.seed():设置随机数生成器的种子,确保结果可复现。

参数类型描述
seedint随机种子
# 1.1 定义数据和向量维度
data = np.random.rand(1000000, 256)
dim = 256  # 存储的向量维度
ids = np.arange(0, 1000000)
np.random.seed(4)
query_vector = np.random.rand(1, 256)

2.线性搜索

faiss.IndexFlatL2():创建一个使用 L2 距离(欧氏距离) 进行向量相似度搜索的 Faiss 索引。 

参数类型描述
dint向量的维度

 欧氏(L2)距离公式:

向量数据库对象(索引).add():向向量数据库(索引)中添加向量数据。

参数类型描述
xbnp.array待添加的向量数组(形状 (n, d)

time.time():返回当前时间的时间戳(自纪元以来的秒数,浮点数形式)。常用于计算代码执行时间或记录时间点。

向量数据库对象(索引).search():在向量数据库(索引)中搜索最相似的 k 个向量。

参数类型描述
xqnp.array查询向量(形状 (m, d)
kint返回的最近邻数量

D:Distance 两向量相似度

I:最相似的向量的索引

# 使用线性搜索
def test01():# 1.构建索引(向量数据库)# 1.2 创建索引对象 API函数index1 = faiss.IndexFlatL2(dim)  # Flat:线性搜索 (O(n))  L2:使用欧式距离计算相似度  dim: 向量维度# 2.添加向量index1.add(data)# 3.搜索向量start = time.time()# query_vector: 待搜索的向量  k: 返回的向量个数D, I = index1.search(query_vector, k=1)# D: Distance 两向量相似度  I: Index 返回最相似的向量的索引print("index1_D:", D, "index1_I:", I)print("method1_time:", time.time() - start)

3.聚类搜索

faiss.IndexFlatL2():创建一个使用 L2 距离(欧氏距离) 进行向量相似度搜索的 Faiss 索引。 

参数类型描述
dint向量的维度

 欧氏(L2)距离公式:

faiss.IndexIVFFlat():创建一个基于倒排文件(Inverted File, IVF)和扁平化量化(Flat Quantization)的索引结构。适用于大规模向量搜索,通过聚类减少搜索空间,提升查询效率。

参数类型说明
dint向量维度(必填)
nlistint聚类中心数量(必填)
metricfaiss.MetricType距离度量方式(默认 faiss.METRIC_L2,即欧氏距离)
use_precomputed_tableint是否使用预计算的码本表(默认 0,不使用)

向量数据库对象.train():对索引进行训练,需提供一组代表性向量(通常为数据集的子集),用于学习聚类中心或其他模型参数(如量化码本)。训练是构建索引的必要步骤。

参数类型说明
xbnumpy.ndarray训练数据矩阵,形状为 (n_samples, d),其中 d 是向量维度
niterint训练迭代次数(部分索引类型支持,可选)
verbosebool是否打印训练日志(可选,默认 False

向量数据库对象(索引).add():向向量数据库(索引)中添加向量数据。

参数类型描述
xbnp.array待添加的向量数组(形状 (n, d)

time.time():返回当前时间的时间戳(自纪元以来的秒数,浮点数形式)。常用于计算代码执行时间或记录时间点。

向量数据库对象(索引).search():在向量数据库(索引)中搜索最相似的 k 个向量。

参数类型描述
xqnp.array查询向量(形状 (m, d)
kint返回的最近邻数量

D:Distance 两向量相似度

I:最相似的向量的索引

# 使用聚类索引 IVF
def test02():# 第一个参数 —— 量化参数:quantizer# 第二个参数 —— 向量维度:dim# 第三个参数 —— 聚类中心个数:nlistquantizer = faiss.IndexFlatL2(dim)  # 使用欧式距离计算相似度  dim: 向量维度index = faiss.IndexIVFFlat(quantizer, dim, 100)index.train(data)  # 训练索引,找到所有簇的质心# 将向量分配到距离最近的簇中index.add(data)  # 添加向量到索引中start = time.time()# 近似相似的搜索D, I = index.search(query_vector, k=1)print("index1_D:", D, "index1_I:", I)print("method2_time:", time.time() - start)

4.聚类搜索(指定聚类簇数)

 faiss.IndexFlatL2():创建一个使用 L2 距离(欧氏距离) 进行向量相似度搜索的 Faiss 索引。 

参数类型描述
dint向量的维度

 欧氏(L2)距离公式:

faiss.IndexIVFFlat():创建一个基于倒排文件(Inverted File, IVF)和扁平化量化(Flat Quantization)的索引结构。适用于大规模向量搜索,通过聚类减少搜索空间,提升查询效率。

参数类型说明
dint向量维度(必填)
nlistint聚类中心数量(必填)
metricfaiss.MetricType距离度量方式(默认 faiss.METRIC_L2,即欧氏距离)
use_precomputed_tableint是否使用预计算的码本表(默认 0,不使用)

向量数据库对象.nprobe():设置或获取搜索时的探查聚类中心数量(nprobe)。控制搜索时访问的聚类中心数目,影响查询速度和精度(值越大越精确,但速度越慢)。

参数类型说明
nprobeint要探查的聚类中心数量(仅用于设置时传入)

向量数据库对象.train():对索引进行训练,需提供一组代表性向量(通常为数据集的子集),用于学习聚类中心或其他模型参数(如量化码本)。训练是构建索引的必要步骤。

参数类型说明
xbnumpy.ndarray训练数据矩阵,形状为 (n_samples, d),其中 d 是向量维度
niterint训练迭代次数(部分索引类型支持,可选)
verbosebool是否打印训练日志(可选,默认 False

向量数据库对象(索引).add():向向量数据库(索引)中添加向量数据。

参数类型描述
xbnp.array待添加的向量数组(形状 (n, d)

向量数据库对象(索引).search():在向量数据库(索引)中搜索最相似的 k 个向量

参数类型描述
xqnp.array查询向量(形状 (m, d)
kint返回的最近邻数量

time.time():返回当前时间的时间戳(自纪元以来的秒数,浮点数形式)。常用于计算代码执行时间或记录时间点。

D:Distance 两向量相似度

I:最相似的向量的索引

# 使用聚类索引 IVF 效率与准确率平衡
def test03():# 第一个参数 —— 量化参数:quantizer# 第二个参数 —— 向量维度:dim# 第三个参数 —— 聚类中心个数:nlistquantizer = faiss.IndexFlatL2(dim)  # 使用欧式距离计算相似度  dim: 向量维度index = faiss.IndexIVFFlat(quantizer, dim, 100)index.nprobe = 10  # 指定在最相似的前多少个簇中进行线性搜索index.train(data)  # 训练索引,找到所有簇的质心# 将向量分配到距离最近的簇中index.add(data)  # 添加向量到索引中start = time.time()# 近似相似的搜索D, I = index.search(query_vector, k=1)print("index1_D:", D, "index1_I:", I)print("method2_plus_time:", time.time() - start)

5.完整代码

import faiss
import numpy as np
import time# 1.1 定义数据和向量维度
data = np.random.rand(1000000, 256)
dim = 256  # 存储的向量维度
ids = np.arange(0, 1000000)
np.random.seed(4)
query_vector = np.random.rand(1, 256)# 使用线性搜索
def test01():# 1.构建索引(向量数据库)# 1.2 创建索引对象 API函数index1 = faiss.IndexFlatL2(dim)  # Flat:线性搜索 (O(n))  L2:使用欧式距离计算相似度  dim: 向量维度# 2.添加向量index1.add(data)# 3.搜索向量start = time.time()# query_vector: 待搜索的向量  k: 返回的向量个数D, I = index1.search(query_vector, k=1)# D: Distance 两向量相似度  I: Index 返回最相似的向量的索引print("index1_D:", D, "index1_I:", I)print("method1_time:", time.time() - start)# 使用聚类索引 IVF
def test02():# 第一个参数 —— 量化参数:quantizer# 第二个参数 —— 向量维度:dim# 第三个参数 —— 聚类中心个数:nlistquantizer = faiss.IndexFlatL2(dim)  # 使用欧式距离计算相似度  dim: 向量维度index = faiss.IndexIVFFlat(quantizer, dim, 100)index.train(data)  # 训练索引,找到所有簇的质心# 将向量分配到距离最近的簇中index.add(data)  # 添加向量到索引中start = time.time()# 近似相似的搜索D, I = index.search(query_vector, k=1)print("index1_D:", D, "index1_I:", I)print("method2_time:", time.time() - start)# 使用聚类索引 IVF 效率与准确率平衡
def test03():# 第一个参数 —— 量化参数:quantizer# 第二个参数 —— 向量维度:dim# 第三个参数 —— 聚类中心个数:nlistquantizer = faiss.IndexFlatL2(dim)  # 使用欧式距离计算相似度  dim: 向量维度index = faiss.IndexIVFFlat(quantizer, dim, 100)index.nprobe = 10  # 指定在最相似的前多少个簇中进行线性搜索index.train(data)  # 训练索引,找到所有簇的质心# 将向量分配到距离最近的簇中index.add(data)  # 添加向量到索引中start = time.time()# 近似相似的搜索D, I = index.search(query_vector, k=1)print("index1_D:", D, "index1_I:", I)print("method2_plus_time:", time.time() - start)if __name__ == '__main__':test01()print("————————————————————————————————")test02()print("————————————————————————————————")test03()# 这种方法是一种在查询的精度和效率之间平衡的方法。 # time 与 nprobe 的关系是:nprobe 越大,查询的精度越高,但是查询的时间也会增加。


三、更少的内存

        前面的几个索引类型为了实现向量搜索,都需要将向量存储到 Faiss 中,当向量的数量较多时就会占用更多的内存。 这也影响了 Faiss 的应用。所以,为了减少内存的占用,我们就需要会存储的向量进行重新编码、压缩,使其占用更少的内存,从而能够容纳更多的向量。

        量化技术可以使用较低精度的表示来近似向量数据,从而降低内存需求而又不牺牲准确性。 这对于大规模向量相似性搜索应用程序特别有用。

1.PQ量化压缩

        Product Quantization 是一种有效的近似最近邻搜索方法,具有较高的搜索效率较低的内存消耗。该方法已被广泛应用于图像检索、文本检索和机器学习等领域。

        PQ 将高维数据点分成多个子空间,并对每个子空间使用独立的编码方法,将数据点映射到一个有限的编码集合中。这个编码过程将高维数据转换成低维编码,从而降低了存储和计算的成本。

        例如,我们有 N 个 1024 维的数据点:

        将每个向量划分为 8 个 128 维的子向量 subvectors,更多的子向量划分意味着将原始向量空间划分为更多的子空间进行量化,有助于减少量化误差

        对每一组子向量进行聚类,这里簇的数量为 256,聚类的质心数量越多,误差就越小。如下:

        聚类之后的每个 subvector 的质心可以作为码本,用于将子向量映射到一个整数

        此时,当我们拿到某一个 1×1024 的数据时,我们就可以通过下面的过程将其量化(用每一个子向量所属质心的编号来表示):

        最终得到结果,量化前:1 × 1024 = 1024 字节,量化后:1 × 8 = 8 字节

代码实现

np.random.rand():是 NumPy 库中的一个函数,用于生成指定形状的数组,数组中的元素是从均匀分布中随机采样的,范围在 [0, 1) 之间。

参数类型说明
d0, d1, ..., dnint, 可选定义输出数组的维度。如果不提供任何参数,则返回一个浮点数(标量)。

faiss.ProductQuantizer():是 Faiss 库中的一个类,用于实现乘积量化(Product Quantization, PQ)。乘积量化是一种高效的向量压缩和搜索技术,通过将高维向量分解为多个低维子向量,并对每个子向量进行独立量化,从而减少存储空间并加速搜索过程。

参数类型说明
dint向量的总维度(必填)。
Mint子向量的数量,即将原始向量分成 M 个子向量,每个子向量的维度为 d // M(必填)。
nbitsint, 可选每个子量化的码本大小(即每个子向量使用的比特数),默认是 8,对应 256 个码字。
metric_typefaiss.MetricType, 可选距离度量类型,默认是 faiss.METRIC_L2(欧氏距离)。可选值包括 faiss.METRIC_INNER_PRODUCT 等。
train_typefaiss.ProductQuantizer.TrainType, 可选训练类型,控制训练过程的行为,默认是 faiss.ProductQuantizer.TrainType.DEFAULT

pq:创建一个 ​​Product Quantizer (PQ)​​ 对象,用于将 ​​32 维向量​​ 压缩为 ​​8 个子向量​​,每个子向量用 ​​8 比特(256 个码字)​​ 进行量化。

pq.train():训练乘积量化(PQ)的码本(codebook),学习每个子向量的量化中心。

需要提供足够多样本的训练数据,使码本能覆盖数据的分布特征。

训练完成后,才能进行向量编码(compute_codes())。

参数类型说明
xnumpy.ndarray训练数据矩阵,形状为 (n_samples, d)dtype=float32(必填)。
其中 d 必须与 ProductQuantizer 初始化时的维度一致。

pq.compute_codes():将输入向量编码为压缩后的码字(整数数组)。

每个子向量会被映射到其对应的量化中心(由码本定义),最终输出一个紧凑的码字表示。编码后的码字可用于存储或快速检索。

参数类型说明
xnumpy.ndarray待编码的向量矩阵,形状为 (n_samples, d)dtype=float32(必填)。
其中 d 必须与 ProductQuantizer 初始化时的维度一致。

pq.decode():将码字解码为近似原始向量(通过码本中的量化中心重建)。

由于量化存在误差,解码后的向量可能与原始向量不完全相同,但能显著减少存储和计算开销。

参数类型说明
codesnumpy.ndarray输入的码字矩阵,形状为 (n_samples, M)dtype=uint8 或 int32(必填)。
每个元素必须是 0 到 2^nbits - 1 的整数。
import faiss
import numpy as npdef test():data = np.random.rand(10000, 32).astype('float32')# 训练码本(向量维度、子向量数量、子向量质心数量(位数))pq = faiss.ProductQuantizer(32, 8, 8)# pq.verbose = Truepq.train(data)# 编码量化x1 = np.random.rand(1, 32).astype('float32')x2 = pq.compute_codes(x1)# 解码量化x3 = pq.decode(x2)print('原始向量:\n', x1)print('编码量化:\n', x2)print('解码量化:\n', x3)if __name__ == '__main__':test()


2.定义数据和向量维度

np.random.seed():设置随机数生成器的种子,确保每次运行代码时生成的随机数序列相同(可复现性)。常用于调试或实验中需要固定随机结果的情况。

参数类型说明
seedint 或 None随机数种子(整数)。若为 None,则使用系统时间作为种子(默认行为)。

np.random.rand():生成指定形状的数组,元素从均匀分布 [0, 1) 中随机采样。

参数类型说明
d0, d1, ..., dnint, 可选定义输出数组的维度。若无参数,返回单个浮点数。

np.arrange():生成一个等差数列数组,类似于 Python 内置的 range(),但返回的是 NumPy 数组而非列表。

参数类型说明
startnumber, 可选起始值(默认 0)。
stopnumber结束值(不包含该值)。
stepnumber, 可选步长(默认 1)。
dtypedtype, 可选输出数组的数据类型(默认推断)。

np.random.rand():NumPy 库中的一个函数,用于生成指定形状的数组,数组中的元素是从均匀分布中随机采样的,范围在 [0, 1) 之间。

参数类型说明
d0, d1, ..., dnint, 可选定义输出数组的维度。如果不提供任何参数,则返回一个浮点数(标量)。
np.random.seed(0)
data = np.random.rand(1000000, 256)
ids = np.arange(0, 1000000)
query_vector = np.random.rand(1, 256)

3.线性搜索

faiss.IndexFlatL2():创建一个使用 L2 距离(欧氏距离) 进行向量相似度搜索的 Faiss 索引。 

参数类型描述
dint向量的维度

 欧氏(L2)距离公式:

faiss.IndexIDMap():将外部ID映射到Faiss索引的内部向量ID,允许通过用户自定义的ID(如数据库ID)检索向量,而非Faiss自动生成的连续整数ID。

参数类型说明
indexfaiss.Index基础Faiss索引对象(必填)。
own_fieldsbool是否接管基础索引的所有权(默认 False)。

向量数据库对象(索引).add_with_ids(): 向Faiss索引中添加向量及其对应的自定义ID(需配合IndexIDMap使用),实现通过外部ID检索向量。

参数类型说明
xnumpy.ndarray向量数据,形状为 (n, d)dtype=float32(必填)。
idsnumpy.ndarray对应的自定义ID数组,形状为 (n,)dtype=long(必填)。

time.time():返回当前时间的时间戳(自纪元以来的秒数,浮点数形式)。常用于计算代码执行时间或记录时间点。

向量数据库对象(索引).search():在向量数据库(索引)中搜索最相似的 k 个向量。

参数类型描述
xqnp.array查询向量(形状 (m, d)
kint返回的最近邻数量

D:Distance 两向量相似度

I:最相似的向量的索引

faiss.write_index():将Faiss索引保存到磁盘文件,支持后续加载复用。

参数类型说明
indexfaiss.Index要保存的Faiss索引对象(必填)。
filenamestr目标文件路径(必填)。

os.stat():获取文件或目录的状态信息(如大小、修改时间等),返回一个os.stat_result对象。

参数类型说明
pathstr 或 bytes文件/目录路径(必填)。

.st_size:os.stat_result对象中获取文件的大小(字节)。

def test01():index = faiss.IndexFlatL2(256)index = faiss.IndexIDMap(index)# 添加向量index.add_with_ids(data, ids)# 搜索向量s = time.time()D, I = index.search(query_vector, k=2)print('time1:', time.time() - s)print(D, I)faiss.write_index(index, 'flat.faiss')print("space1:", os.stat('flat.faiss').st_size)

4.聚类搜索(指定聚类数目)

 faiss.IndexFlatL2():创建一个使用 L2 距离(欧氏距离) 进行向量相似度搜索的 Faiss 索引。 

参数类型描述
dint向量的维度

 欧氏(L2)距离公式:

faiss.IndexIVFFlat():创建基于倒排文件(IVF)和扁平化量化(Flat)的索引结构,用于高效的大规模向量搜索。通过聚类减少搜索空间,显著提升查询速度。

参数类型说明
dint向量维度(必填)。
nlistint聚类中心数量(必填)。
metricfaiss.MetricType距离度量方式(默认 faiss.METRIC_L2,即欧氏距离)。
use_precomputed_tableint是否使用预计算的码本表(默认 0,不使用)。

向量数据库对象.nprobe():设置或获取搜索时的探查聚类中心数量(nprobe)。控制搜索时访问的聚类中心数目,影响查询速度和精度(值越大越精确,但速度越慢)。

参数类型说明
nprobeint要探查的聚类中心数量(仅用于设置时传入)。

向量数据库对象.train():对索引进行训练,需提供一组代表性向量(通常为数据集的子集),用于学习聚类中心或其他模型参数(如量化码本)。训练是构建索引的必要步骤。

参数类型说明
xbnumpy.ndarray训练数据矩阵,形状为 (n_samples, d),其中 d 是向量维度
niterint训练迭代次数(部分索引类型支持,可选)
verbosebool是否打印训练日志(可选,默认 False

向量数据库对象.add_with_ids():

向量数据库对象(索引).search():在向量数据库(索引)中搜索最相似的 k 个向量。

参数类型描述
xqnp.array查询向量(形状 (m, d)
kint返回的最近邻数量

D:Distance 两向量相似度

I:最相似的向量的索引

time.time():返回当前时间的时间戳(自纪元以来的秒数,浮点数形式)。常用于计算代码执行时间或记录时间点。

faiss.write_index():将Faiss索引保存到磁盘文件,支持后续加载复用。

参数类型说明
indexfaiss.Index要保存的Faiss索引对象(必填)。
filenamestr目标文件路径(必填)。

os.stat():获取文件或目录的状态信息(如大小、修改时间等),返回一个os.stat_result对象。

参数类型说明
pathstr 或 bytes文件/目录路径(必填)。

.st_size:os.stat_result对象中获取文件的大小(字节)。

def test02():# 第一个参数 —— 量化参数:quantizer# 第二个参数 —— 向量维度:dim# 第三个参数 —— 聚类中心个数:nlistindex = faiss.IndexFlatL2(256)index = faiss.IndexIVFFlat(index, 256, 100)index.nprobe = 4 # 指定在最相似的前多少个簇中进行线性搜索index.train(data) # 训练索引,找到所有簇的质心index.add_with_ids(data, ids)s = time.time()D, I = index.search(query_vector, k=2)print('time2:', time.time() - s)print(D, I)faiss.write_index(index, 'ivfflat.faiss')print("space2:", os.stat('ivfflat.faiss').st_size)

5.完整代码

import osimport faiss
import numpy as np
import timenp.random.seed(0)
data = np.random.rand(1000000, 256)
ids = np.arange(0, 1000000)
query_vector = np.random.rand(1, 256)def test01():index = faiss.IndexFlatL2(256)index = faiss.IndexIDMap(index)# 添加向量index.add_with_ids(data, ids)# 搜索向量s = time.time()D, I = index.search(query_vector, k=2)print('time1:', time.time() - s)print(D, I)faiss.write_index(index, 'flat.faiss')print("space1:", os.stat('flat.faiss').st_size)def test02():# 第一个参数 —— 量化参数:quantizer# 第二个参数 —— 向量维度:dim# 第三个参数 —— 聚类中心个数:nlistindex = faiss.IndexFlatL2(256)index = faiss.IndexIVFFlat(index, 256, 100)index.nprobe = 4 # 指定在最相似的前多少个簇中进行线性搜索index.train(data) # 训练索引,找到所有簇的质心index.add_with_ids(data, ids)s = time.time()D, I = index.search(query_vector, k=2)print('time2:', time.time() - s)print(D, I)faiss.write_index(index, 'ivfflat.faiss')print("space2:", os.stat('ivfflat.faiss').st_size)def test03():# 第一个参 —— 量化参数:quantizer# 第二个参数 —— 向量维度:dim# 第三个参数 —— 质心数量:nlist# 第四个参数 —— 聚类中心个数:ncentroids# 第四个参数 —— 子空间数量(或称为段数):p 较大的值意味着将原始向量空间划分为更多的子空间进行量化,有助于减少量化误差,因为每个子空间都将被更精细地量化。# 第五个参数 —— 量化码本中码字的位数,每个段聚类的数量(8位256): q 决定了每个量化码字的精度,位数越多,每个码字能够表示的信息就越多,量化误差就越小。quantizer = faiss.IndexFlatL2(256)index = faiss.IndexIVFPQ(quantizer, 256, 100, 64, 10)index.nprobe = 4index.train(data)index.add_with_ids(data, ids)# 搜索向量s = time.time()D, I = index.search(query_vector, k=2)print('time3:', time.time() - s)print(D, I)faiss.write_index(index, 'ivfpq.faiss')print("space3:", os.stat('ivfpq.faiss').st_size)if __name__ == '__main__':test01()print("————————————————————————————————")test02()print("————————————————————————————————")test03()


四、GPU训练

        传统 CPU 计算在处理大规模向量数据时往往效率低下,而 GPU 具有并行计算能力强、吞吐量高、延迟低等优势,可以显著提高向量相似度搜索的速度例如:在 Faiss 官方提供的基准测试中,使用 GPU 计算的 Faiss 可以将向量相似度搜索的速度提高数十倍甚至数百倍。

faiss.StandardGpuResources():创建 GPU 资源管理对象,用于在 GPU 上执行 Faiss 操作(如索引构建和搜索)。需配合 index_cpu_to_gpu() 将 CPU 索引转移到 GPU。

faiss.IndexFlatL2():创建基于 L2 距离(欧氏距离)的暴力搜索索引,直接计算所有向量间的距离。适用于小规模数据或作为其他索引的量化器。

参数类型说明
dint向量维度(必填)。

faiss.index_cpu_to_gpu():将 CPU 上的 Faiss 索引转移到 GPU 上,以加速搜索和训练操作。需先创建 StandardGpuResources 对象

参数类型说明
resfaiss.StandardGpuResourcesGPU 资源对象(必填)。
deviceintGPU 设备 ID(默认 0)。
indexfaiss.Index要转移的 CPU 索引(必填)。
syncbool是否同步 GPU 操作(默认 True)。

向量数据库对象(索引).search():在向量数据库(索引)中搜索最相似的 k 个向量。

参数类型描述
xqnp.array查询向量(形状 (m, d)
kint返回的最近邻数量

向量数据库对象(索引).add():向向量数据库(索引)中添加向量数据。

参数类型描述
xbnp.array待添加的向量数组(形状 (n, d)

np.random.rand():生成指定形状的数组,元素从均匀分布 [0, 1) 中随机采样。

参数类型说明
d0, d1, ..., dnint, 可选定义输出数组的维度。若无参数,返回单个浮点数。

D:Distance 两向量相似度

I:最相似的向量的索引 

import faiss
import numpy as npdef test():# 创建标准的 GPU 资源对象,用它来管理GPU相关的计算资源。res = faiss.StandardGpuResources()# 1. 在 CPU 创建索引index_cpu = faiss.IndexFlatL2(256)print(index_cpu)# 2. 将索引转到 GPU# 参数1:GPU 使用资源# 参数2:GPU 设备编号# 参数3:转移的索引index_gpu = faiss.index_cpu_to_gpu(res, 0, index_cpu)print(index_gpu)# 3. 插入数据index_gpu.add(np.random.rand(100000, 256))# 4. 向量搜索D, I = index_gpu.search(np.random.rand(2, 256), k=2)print(D)print(I)if __name__ == '__main__':test()

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.pswp.cn/web/81007.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Go 语言简介

1. Go 语言简介 1.1 什么是 Go 语言 Go语言,通常被称为Golang,是由Google在2007年开始开发,并在2009年正式发布的一种开源编程语言。Go语言的设计初衷是解决大型软件开发中的效率和可维护性问题,特别是在多核处理器和网络化系统…

VMware虚拟机突然无法ssh连接

遇到的情况: 功能全部正常的情况下,没有修改任何配置,重启电脑之后无法ssh连接 其实不太可能的可能原因: 1、虚拟机内部sshd服务未运行 systemctl status sshd systemctl start sshd 2、检查SSH端口监听 netstat -an | grep :…

[ 计算机网络 ] | 宏观谈谈计算机网络

(目录占位) 网络间通信,本质是不同的两个用户通信;本质是两个不同主机上的两个进程间通信。 因为物理距离的提升,就衍生出了很多问题。TCP/IP协议栈 / OSI七层模型,将协议分层,每一层都是为了…

Oracle 11g导出数据库结构和数据

第一种方法:Plsql 利用plsql可视化工具导出,首先根据步骤导出表结构: 工具(Tools)->导出用户对象(export user objects)。 其次导出数据表结构: 工具(Tools)->导出表(export Tables)->选中表->sql inserts(where语…

跟Gemini学做PPT:汇报背景图寻找指南

PPT 汇报背景图寻找指南 既然前端功能已经完善,现在可以专注于汇报了。对于 PPT 背景图,你有几个选择: 1. 内置模板和主题: 优点: 最简单、快速,PowerPoint、Keynote、Google Slides 等演示软件都内置了…

【Hadoop】大数据技术之 HDFS

目录 一、HDFS 概述 1.1 HDFS 产出背景及定义 1.2 HDFS 优缺点 1.3 HDFS 组成架构 1.4 HDFS 文件块大小 二、HDFS 的Shell 操作 三、HDFS 的读写流程(面试重点) 3.1 HDFS 写数据流程 3.2 HDFS 读数据流程 四、DataNode 4.1 DataNode 的工作机制…

Spring Boot WebFlux流式返回全攻略:从基础到企业级实践

目录 流式返回的核心价值与适用场景WebFlux核心机制解析基础流式接口开发实战企业级应用场景与优化方案客户端对接全方案常见问题与调优策略未来发展趋势1. 流式返回的核心价值与适用场景 1.1 传统响应模式的局限性 传统Spring MVC采用同步阻塞模型,在以下场景面临挑战: 大…

AI浪潮下,第五消费时代的商业进化密码

解锁 AI 与第五消费时代 在时代的长河中,消费浪潮的更迭深刻地影响着商业的格局。当下,我们正处于第五消费时代,这个时代有着鲜明的特征,如老龄化、单身化趋势日益显著,社会逐渐步入低欲望、个性化与共享化并行的阶段 。随着人工智能技术的飞速发展,它在商业领域的渗透也…

氢气传感器维护常见问题及解决方法

氢气传感器在工业生产和氢能源系统中扮演着关键角色,用于实时检测氢气浓度以预防爆炸和中毒事故。然而,传感器的维护过程中可能会遇到一些常见问题,这些问题可能会影响传感器的性能和检测准确性。本文将详细探讨这些常见问题及其解决方法。 1…

【普及+/提高】洛谷P2613 ——【模板】有理数取余

见:P2613 【模板】有理数取余 - 洛谷 题目描述 给出一个有理数 cba​,求 cmod19260817 的值。 这个值被定义为 bx≡a(mod19260817) 的解。 输入格式 一共两行。 第一行,一个整数 a。 第二行,一个整数 b。 输出格式 一个整…

RK常见系统属性设置/获取命令使用

设置有线mac地址 ifconfig eth0 hw ether 021234567000 读取mac地址 public static String getEthMacAddressBySysFs() { try (BufferedReader reader new BufferedReader(new FileReader("/sys/class/net/eth0/address"))) { return reader.r…

文章记单词 | 第115篇(六级)

一,单词释义 solar /ˈsoʊlər/ adj. 太阳的;太阳能的bruise /bruːz/ n. 瘀伤;擦伤 v. (使)青肿;挫伤thus /ʌs/ adv. 因此;这样;于是drink /drɪŋk/ v. 喝;饮 n. 饮…

9大开源AI智能体概况

项目GitHub 链接开发组织核心功能应用领域典型应用案例活跃度AutoGPT (176k⭐)链接Significant Gravitas 团队基于 GPT-4 的自主代理,能够自动分解任务并生成多步提示循环执行,支持调用工具(如网络搜索、文件操作等)。自动化办公、…

SpringBoot3整合WebSocket

一、WebSocket简介 WebSocket协议是基于TCP的一种新的网络协议。它实现了浏览器与服务器全双工(full-duplex)通信,允许服务器主动向客户端推送数据。 与传统的 HTTP 请求-响应模式不同,WebSocket 在建立连接后,允许服务器和客户端之间进行双向…

FTP Bounce Attack:原理、影响与防御

一、引言 FTP(文件传输协议)是一种用于在网络上进行文件传输的协议,广泛应用于各种网络环境中。然而,FTP协议的安全性问题一直备受关注,其中FTP Bounce Attack(FTP跳转攻击)是一种具有代表性的…

文献阅读——NeuroBayesSLAM

原文地址 1.核心理论:贝叶斯多感官整合框架 目标:结合视觉线索 c v i c_{vi} cvi​和前庭线索 c v e c_{ve} cve​来估计头部方向或位置 θ 贝叶斯公式 p ( θ ∣ c v i , c v e ) ∝ p ( c v i ∣ θ ) p ( c v e ∣ θ ) p ( θ ) p(\theta | c_{vi…

sentinel核心原理-高频问题

核心原理 ‌限流实现机制‌ ‌滑动窗口算法‌:将时间切分为子窗口动态统计QPS,避免固定窗口的边界问题。‌责任链模式‌:通过NodeSelectorSlot、FlowSlot等Slot链式处理限流逻辑。 ‌熔断降级策略‌ ‌慢调用比例‌:当慢请求比例…

DataX 的大概简单介绍(与Kettle做对比介绍)

DataX 是由阿里巴巴开源的轻量级 ETL 工具,专为批量数据同步设计,主打 “高性能、易扩展、跨数据源”。如果你熟悉 Kettle,可把它理解为 “更适合大数据场景的 ETL 选手”。以下从核心特性、应用场景、与 Kettle 对比等角度通俗解析&#xff…

通过上传使大模型读取并分析文件实战

一、技术背景与需求分析 我们日常在使用AI的时候一定都上传过文件,AI会根据用户上传的文件内容结合用户的请求进行分析,给出用户解答。但是这是怎么实现的呢?在我们开发自己的大模型应用时肯定是不可避免的要思考这个问题,今天我会…

RHCSA Linux 系统 硬盘管理

Linux 系统 硬盘管理 1扇区 512B,分区 多个扇区 512B 查看硬盘命令 [rootlocalhost ~]# lsblk 1.一般存储相关操作 (1) 分区 ① MBR 分区 ➤分区数量限制:主分区 0 - 4 个&#x…