当前位置: 首页 > news >正文

【faiss】用于高效相似性搜索和聚类的C++库 | 源码详解与编译安装

目录

●Faiss

■faiss::Index

■faiss::read_index

■faiss::write_index

■faiss::IndexFlatIP

■faiss::Index::idx_t

■完整代码示例

■总结

●Faiss库源码详解

●Faiss库编译安装



Faiss(Facebook AI Similarity Search)是一个用于高效相似性搜索和聚类的 C++ 库,支持在大规模向量集合中快速查找最近邻(ANN, Approximate Nearest Neighbor)。

●Faiss

■faiss::Index

核心基类:Faiss中最核心的抽象类,表示一个向量索引结构。所有索引类型都继承自faiss::Index;提供统一接口:添加向量、搜索最近邻、保存/加载索引等。

常用方法

/*** 向索引中添加 n 个维度为 d 的向量。** 向量会被隐式地分配标签,标签范围为 ntotal 到 ntotal + n - 1。* 该函数将输入的向量切分为比 blocksize_add 小的块,并调用 add_core 函数进行添加。** @param n      向量的数量* @param x      输入矩阵,大小为 n * d*/
virtual void add(idx_t n, const float* x) = 0;
/*** 对索引中的 n 个 d 维向量进行查询。** 此函数用于在索引中搜索每个输入向量的 k 个最近邻向量。* 如果某次查询的结果不足,则结果数组将用 -1 填充。** @param n           输入向量的数量* @param x           要搜索的输入向量数组,大小为 n * d* @param k           需要检索的最近邻向量数量* @param distances   输出的距离数组,存储每个查询向量与最近邻向量之间的距离,大小为 n*k* @param labels      输出的标签数组,存储最近邻向量的标签,大小为 n*k* @param params      可选的搜索参数,用于调整搜索行为(默认为 nullptr)*/
virtual void search(idx_t n,const float* x,idx_t k,float* distances,idx_t* labels,const SearchParameters* params = nullptr) const = 0;

■faiss::read_index

用于从磁盘文件(二进制格式)中加载一个已保存的 Faiss 索引。支持跨平台使用(Linux/Windows/macOS)

函数原型:

faiss::Index* faiss::read_index(const char* fname, int32_t io_flags = 0);
  • fname: 文件路径;
  • io_flags: 可选标志,例如IO_FLAG_MMAP(内存映射加载);

Index* read_index(const char* fname, int io_flags = 0);

Index* read_index(FILE* f, int io_flags = 0);

Index* read_index(IOReader* reader, int io_flags = 0);

使用示例

faiss::Index* index = faiss::read_index("my_index.index");

■faiss::write_index

将当前索引对象保存到磁盘文件。支持跨平台使用(Linux/Windows/macOS)

函数原型:

void faiss::write_index(const Index* index, const char* fname);
  • index: 要保存的索引对象;
  • fname: 保存的文件路径;

使用示例:

faiss::write_index(index, "my_index.index");

■faiss::IndexFlatIP

这是一个精确搜索索引,使用内积(Inner Product)作为相似度度量。适用于向量已经归一化的情况,内积等价于余弦相似度。

暴力搜索:无压缩/量化,完整计算所有向量距离

精度最高,速度最慢(时间复杂度 O(n))

使用示例:

int d = 64; // 向量维度faiss::IndexFlatIP index(d); // 创建一个基于内积的索引,64维向量

特点:不使用近似,精度高;搜索复杂度为 O(N),适合小数据集,需要 100% 准确率的场景

■faiss::Index::idx_t

这是 Faiss 中用于表示索引编号的类型定义,通常为int64_t,64 位整数(支持超大索引)

表示向量 ID(索引),用于add()、search()等函数的参数。

使用示例:

faiss::Index::idx_t n = 1000; 

■完整代码示例

test.cpp内容如下:

#include <faiss/IndexFlat.h>
#include <faiss/index_io.h>
#include <iostream>
#include <vector>int main() {// 向量维度int d = 64;// 创建索引faiss::IndexFlatIP index(d);// 准备训练数据(1000 个向量)size_t nb = 1000;std::vector<float> xb(d * nb);for (size_t i = 0; i < xb.size(); i++) {xb[i] = drand48();  // 随机初始化}// 添加向量到索引中,添加完成后,索引结构内部会组织这些向量,以便在后续的 search 操作中快速找到最近邻。// nb:要添加的向量数量(本例中是 1000 个向量)。// xb.data():指向存储所有向量数据的内存起始地址。// xb 是一个 std::vector<float>,其中存储了 nb 个向量,每个向量有 d 个浮点数index.add(nb, xb.data());// 保存索引到文件faiss::write_index(&index, "index.faiss");// 重新加载索引faiss::Index* loaded_index = faiss::read_index("index.faiss");// 查询向量(1 个)std::vector<float> xq(d);// 这个循环为 xq 向量填充了 64 个随机浮点数值,构造出一个随机的查询向量。// 假设 d = 5,运行这段代码后,xq 可能是这样一个向量:xq = [0.123, 0.456, 0.789, 0.012, 0.345]for (int i = 0; i < d; i++) {xq[i] = drand48();  // 随机查询向量}// 搜索最近邻(top-10)int k = 10;std::vector<float> distances(k);std::vector<faiss::idx_t> labels(k);// 已经训练好的索引 loaded_index,现在有一个查询向量 xq// 在这个索引里找出与它最相似的前 k 个向量,并把它们的距离和 ID 分别保存在 distances 和 labels 里loaded_index->search(1, xq.data(), k, distances.data(), labels.data());// 输出结果std::cout << "Top-" << k << " 最近邻 ID 和距离:" << std::endl;for (int i = 0; i < k; i++) {std::cout << "ID: " << labels[i] << ", 距离: " << distances[i] << std::endl;}// 清理资源delete loaded_index;return 0;
}

编译:

g++ test.cpp -o test -lfaiss -lopenblas -fopenmp
./test

运行结果示例:

■总结

类/函数名

作用

faiss::Index

所有索引的基类,提供统一接口

faiss::read_index

从文件加载索引

faiss::write_index

将索引保存到文件

faiss::IndexFlatIP

精确搜索索引,使用内积(适用于归一化向量)

faiss::Index::idx_t

表示索引编号的类型,通常为int64_t

●Faiss库源码详解

  • faiss/index_io.h
/** Copyright (c) Meta Platforms, Inc. and affiliates.** This source code is licensed under the MIT license found in the* LICENSE file in the root directory of this source tree.*/// I/O code for indexes#ifndef FAISS_INDEX_IO_H
#define FAISS_INDEX_IO_H#include <cstdio>
#include <string>
#include <typeinfo>
#include <vector>/** I/O functions can read/write to a filename, a file handle or to an* object that abstracts the medium.** The read functions return objects that should be deallocated with* delete. All references within these objectes are owned by the* object.*/namespace faiss {// 前向声明常用的数据结构
struct Index;                // 索引基类
struct IndexBinary;          // 二值索引
struct VectorTransform;      // 向量变换
struct ProductQuantizer;     // 乘积量化器
struct IOReader;             // 输入流抽象
struct IOWriter;             // 输出流抽象
struct InvertedLists;        // 倒排列表/// IO标志位:跳过图索引的存储数据
const int IO_FLAG_SKIP_STORAGE = 1;// 将Index对象写入文件
void write_index(const Index* idx, const char* fname, int io_flags = 0);
void write_index(const Index* idx, FILE* f, int io_flags = 0);
void write_index(const Index* idx, IOWriter* writer, int io_flags = 0);// 将二值索引写入文件
void write_index_binary(const IndexBinary* idx, const char* fname);
void write_index_binary(const IndexBinary* idx, FILE* f);
void write_index_binary(const IndexBinary* idx, IOWriter* writer);// read_index 支持的标志位,仅部分索引类型支持
const int IO_FLAG_READ_ONLY = 2;                         // 只读模式
const int IO_FLAG_ONDISK_SAME_DIR = 4;                   // 文件路径相对于索引文件目录
const int IO_FLAG_SKIP_IVF_DATA = 8;                     // 不加载 IVF 数据到内存,仅保留列表大小
const int IO_FLAG_SKIP_PRECOMPUTE_TABLE = 16;            // 不预计算查找表
const int IO_FLAG_PQ_SKIP_SDC_TABLE = 32;                // 不计算 SDC 表,禁用 PQ 相关距离计算
const int IO_FLAG_MMAP = IO_FLAG_SKIP_IVF_DATA | 0x646f0000; // 使用内存映射读取数据// 从文件/流中读取Index对象
Index* read_index(const char* fname, int io_flags = 0);
Index* read_index(FILE* f, int io_flags = 0);
Index* read_index(IOReader* reader, int io_flags = 0);// 从文件/流中读取二值索引
IndexBinary* read_index_binary(const char* fname, int io_flags = 0);
IndexBinary* read_index_binary(FILE* f, int io_flags = 0);
IndexBinary* read_index_binary(IOReader* reader, int io_flags = 0);// 写入VectorTransform对象
void write_VectorTransform(const VectorTransform* vt, const char* fname);
void write_VectorTransform(const VectorTransform* vt, IOWriter* f);// 从文件/流中读取VectorTransform对象
VectorTransform* read_VectorTransform(const char* fname);
VectorTransform* read_VectorTransform(IOReader* f);// 写入ProductQuantizer对象
void write_ProductQuantizer(const ProductQuantizer* pq, const char* fname);
void write_ProductQuantizer(const ProductQuantizer* pq, IOWriter* f);// 从文件/流中读取ProductQuantizer对象
ProductQuantizer* read_ProductQuantizer(const char* fname);
ProductQuantizer* read_ProductQuantizer(IOReader* reader);// 写入倒排列表
void write_InvertedLists(const InvertedLists* ils, IOWriter* f);// 从输入流中读取倒排列表
InvertedLists* read_InvertedLists(IOReader* reader, int io_flags = 0);} // namespace faiss#endif
  • faiss/IndexFlat.h
/** Copyright (c) Meta Platforms, Inc. and affiliates.** This source code is licensed under the MIT license found in the* LICENSE file in the root directory of this source tree.*/// -*- c++ -*-#ifndef INDEX_FLAT_H
#define INDEX_FLAT_H#include <vector>#include <faiss/IndexFlatCodes.h>namespace faiss {/*** IndexFlat 是一个存储完整向量并执行穷举搜索的索引结构。* 它继承自 IndexFlatCodes。*/
struct IndexFlat : IndexFlatCodes {/*** 构造函数* @param d 输入向量的维度* @param metric 距离度量类型,默认为 L2*/explicit IndexFlat(idx_t d, ///< 输入向量的维度MetricType metric = METRIC_L2);/*** 搜索与查询向量最接近的 k 个向量* @param n 查询向量的数量* @param x 查询向量,大小为 n * d* @param k 需要返回的最近邻数量* @param distances 输出的距离,大小为 n * k* @param labels 输出的标签,大小为 n * k* @param params 可选的搜索参数*/void search(idx_t n,const float* x,idx_t k,float* distances,idx_t* labels,const SearchParameters* params = nullptr) const override;/*** 在指定半径范围内搜索向量* @param n 查询向量的数量* @param x 查询向量,大小为 n * d* @param radius 搜索半径* @param result 输出范围搜索结果* @param params 可选的搜索参数*/void range_search(idx_t n,const float* x,float radius,RangeSearchResult* result,const SearchParameters* params = nullptr) const override;/*** 重构指定索引处的向量* @param key 要重构的向量的索引* @param recons 输出重构的向量*/void reconstruct(idx_t key, float* recons) const override;/*** 计算与部分向量的子集之间的距离* @param x 查询向量,大小为 n * d* @param labels 每个查询向量需要比较的向量索引,大小为 n * k* @param distances 对应的输出距离,大小为 n * k*/void compute_distance_subset(idx_t n,const float* x,idx_t k,float* distances,const idx_t* labels) const;// 获取指向浮点数据的指针float* get_xb() {return (float*)codes.data();}const float* get_xb() const {return (const float*)codes.data();}IndexFlat() {} // 默认构造函数/*** 获取距离计算器* @return 返回一个 FlatCodesDistanceComputer 实例*/FlatCodesDistanceComputer* get_FlatCodesDistanceComputer() const override;/* 独立编解码接口(在这种情况下只是内存拷贝) */void sa_encode(idx_t n, const float* x, uint8_t* bytes) const override;void sa_decode(idx_t n, const uint8_t* bytes, float* x) const override;
};/*** IndexFlatIP 是 IndexFlat 的特例,使用内积(Inner Product)作为距离度量*/
struct IndexFlatIP : IndexFlat {explicit IndexFlatIP(idx_t d) : IndexFlat(d, METRIC_INNER_PRODUCT) {}IndexFlatIP() {}
};/*** IndexFlatL2 是 IndexFlat 的特例,使用 L2 范数作为距离度量* 它还支持缓存 L2 范数以加速计算*/
struct IndexFlatL2 : IndexFlat {std::vector<float> cached_l2norms; ///< L2 范数缓存/*** 构造函数* @param d 输入向量的维度*/explicit IndexFlatL2(idx_t d) : IndexFlat(d, METRIC_L2) {}IndexFlatL2() {}/*** 获取距离计算器(针对 L2 范数缓存进行优化)* @return 返回一个 FlatCodesDistanceComputer 实例*/FlatCodesDistanceComputer* get_FlatCodesDistanceComputer() const override;void sync_l2norms(); ///< 计算并缓存 L2 范数void clear_l2norms(); ///< 清除 L2 范数缓存
};/*** IndexFlat1D 是 IndexFlatL2 的优化版本,专门用于 1D 向量*/
struct IndexFlat1D : IndexFlatL2 {bool continuous_update = true; ///< 是否连续更新排列?std::vector<idx_t> perm; ///< 排序后的数据库索引explicit IndexFlat1D(bool continuous_update = true); ///< 构造函数/*** 如果未启用连续更新,则在最后一次添加和首次搜索之间调用此函数*/void update_permutation();void add(idx_t n, const float* x) override; ///< 添加向量void reset() override; ///< 重置索引/*** 搜索最近邻(返回的是 L1 距离,而不是 L2)* @param n 查询向量的数量* @param x 查询向量,大小为 n * d* @param k 需要返回的最近邻数量* @param distances 输出的距离,大小为 n * k* @param labels 输出的标签,大小为 n * k* @param params 可选的搜索参数*/void search(idx_t n,const float* x,idx_t k,float* distances,idx_t* labels,const SearchParameters* params = nullptr) const override;
};} // namespace faiss
#endif

●Faiss库编译安装

编译安装

安装依赖

#安装依赖sudo apt-get updatesudo apt-get install libomp-dev
# 安装 OpenBLASsudo apt-get install libopenblas-dev

下载faiss源码并编译安装

#下载源码git clone https://github.com/facebookresearch/faiss.gitcd faissmkdir build && cd build
​
cmake .. -DFAISS_ENABLE_CXX=ON -DFAISS_ENABLE_PYTHON=OFF -DBUILD_SHARED_LIBS=ON  -DCMAKE_BUILD_TYPE=Release  -DFAISS_ENABLE_GPU=OFF  -DOpenMP_CXX_FLAGS="-fopenmp"  -DOpenMP_CXX_LIB_NAMES="gomp" -DOpenMP_gomp_LIBRARY=/usr/lib/x86_64-linux-gnu/libgomp.so.1 -DBUILD_TESTING=OFF 
make -j$(nproc)  && sudo make install

报错Could NOT find OpenMP_CXX (missing: OpenMP_gomp_LIBRARY) (found version"4.5")

解决方法-DOpenMP_gomp_LIBRARY=/usr/lib/x86_64-linux-gnu/libgomp.so.1

默认安装路径为/usr/local/,头文件位于/usr/local/include/faiss/,库文件位于/usr/local/lib/libfaiss.a


交叉编译到Android

【Android】交叉编译faiss库 | 问题解决-CSDN博客


至此,本文的内容就结束了。

http://www.dtcms.com/a/295154.html

相关文章:

  • C基础 07_综合案例《猜拳游戏》
  • 机器学习与视觉结合开发基础
  • IPTV电视直播源更新工具和检测直播源工具
  • Python打卡Day22 kaggle泰坦尼克号生存预测
  • 基于Informer+BiGRU-GAtt的并行预测模型
  • Java开发岗面试记录合集
  • 二分查找----3.在排序数组中查找元素的第一个和最后一个位置
  • 语音增强相关技术
  • 【世纪龙科技】新能源汽车维护与故障诊断-汽车专业数字课程资源
  • 第八讲:C++中的vector
  • Ⅹ—6.计算机二级综合题5---6套
  • Fast Frequency Estimation Algorithm by Least Squares Phase Unwrapping
  • OpenLayers 快速入门(三)Source 对象补充
  • 车载绝缘子放电状态检测系统数据分析软件需求说明书
  • android15 wifi信号格数DB值对应关系及wifi回连时间
  • Python3常见接口函数
  • 详解FreeRTOS开发过程(四)-- 任务切换
  • 进程间通信之-----零拷贝
  • 【已解决】Jetson Orin NX apt更换国内源
  • 网络基础DAY18-动态路由协议基础
  • 零增益扰动!纯相位旋转:二阶全通滤波器实现精准超前矫正
  • 压测软件JMeter安装配置以及创建桌面快捷方式(详细图解)
  • 【每日算法】专题十八_BFS 解决拓扑排序
  • 前端开发性能监控详解
  • OpenCV(02)图像颜色处理,灰度化,二值化,仿射变换
  • 高可用架构模式——如何设计计算高可用架构
  • 前端学习日记(十一)
  • Spark 之 DataFrame
  • Android模块化实现方案深度分析
  • 深度学习的Logits:logist 是什么,上一维度的隐藏向量怎么获取