【向量数据库】相似向量检索Faiss数据库的安装及余弦相似度计算(C++)

这篇具有很好参考价值的文章主要介绍了【向量数据库】相似向量检索Faiss数据库的安装及余弦相似度计算(C++)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

简介

Faiss 是一个强大的向量相似度搜索库,具有以下优点:

  1. 高效的搜索性能:Faiss 在处理大规模向量数据时表现出色。它利用了高度优化的索引结构和近似搜索算法,可以快速地执行最近邻搜索和相似度匹配,具有很低的查询延迟。

  2. 高度可扩展:Faiss 提供了多种索引结构和算法的选择,包括 k-d树、IVF(Inverted File System)和 PQ(Product Quantization)等。这些索引结构能够轻松应对大规模的向量数据集,并支持高效的并行计算和分布式处理。

  3. 高精度的近似搜索:Faiss 通过采用近似搜索技术,在保证搜索速度的同时,尽量接近精确搜索的结果。这使得 Faiss 在许多实际应用中能够有效地处理高维度的向量数据,如图像、文本和推荐系统等。

  4. 多语言支持:Faiss 提供了多种编程语言的接口,如 Python、Java 和 Go 等,使得它能够方便地集成到各种应用和平台中。

然而,Faiss 也有一些局限性和缺点:

  1. 内存消耗:Faiss 在处理大规模向量数据时可能需要大量的内存。特别是在使用一些高级索引结构和算法时,内存消耗可能会很高。

  2. 学习曲线陡峭:对于初次接触 Faiss 的开发者来说,学习曲线可能会比较陡峭。理解并配置 Faiss 的索引结构、算法和参数可能需要一定的时间和经验。

综上所述,Faiss 是一个强大而高效的向量相似度搜索库,适用于大规模的向量数据集和高维度的向量数据。它提供了高速的近似搜索和优化的索引结构,有助于构建复杂的检索系统和应用。然而,在使用 Faiss 时需要注意内存消耗和学习曲线的挑战。

安装方法

安装OpenBLAS

OpenBLAS 是一个开源的数值线性代数库,用于高性能科学计算和数据处理。它提供了基于多核处理器和向量指令集的并行化实现,以加速矩阵运算和其他数值计算操作。

git clone https://github.com/xianyi/OpenBLAS.git

gfortran 是 GNU Compiler Collection(简称 GCC)的一部分,它是 GNU 项目开发的免费开源的编译器套件。gfortran 是 GCC 提供的 Fortran 编译器,用于编译和执行 Fortran 程序。
使用gfortran进行编译:

sudo apt install gfortran
cd OpenBLAS
make FC=gfortran
make install
ln -s /opt/OpenBLAS/lib/libopenblas.so  /usr/lib/libopenblas.so
LD_LIBRARY_PATH=/opt/OpenBLAS/lib
export LD_LIBRARY_PATH

在这个特定的命令中,FC=gfortran将设置FC变量的值为"gfortran",指示构建过程使用gfortran作为Fortran编译器。

安装lapack

LAPACK(Linear Algebra Package)是一个用于数值线性代数计算的库,它提供了一系列高性能的算法和子程序,用于解决线性方程组、特征值问题、奇异值分解和相关的数值计算任务。

wget http://www.netlib.org/lapack/lapack-3.4.2.tgz
tar -zxf lapack-3.4.2.tgz
cd lapack-3.4.2
cp ./INSTALL/make.inc.gfortran ./
mv make.inc.gfortran make.inc
vi Makefile # 修改如下
[#lib: lapacklib tmglib
lib: blaslib variants lapacklig tmglib]
make
cd lapacke
make  
cp include/*.h /usr/include   
cd .. 
cp *.a /usr/lib

编译Faiss

git clone https://github.com/facebookresearch/faiss.git
cd faiss
#这个命令是使用 CMake 构建一个项目,并将构建产物放置在名为 “build” 的目录中。
cmake -B build .  -DFAISS_ENABLE_GPU=OFF -DFAISS_ENABLE_PYTHON=OFF
#这个命令是使用 make 构建名为 “faiss” 的目标,并且指定构建目录为 “build”。
make -C build -j faiss
#这个命令是使用 make 进行构建,并将构建产物安装到系统中。同样在build目录下构建
make -C build install

代码示例

余弦相似度计算

给定一个向量,在已有的两个向量中,找到余弦相似度最优的一个向量:

#include <iostream>
#include <cmath>
#include <faiss/IndexFlat.h>
#include <faiss/index_io.h>
#include <faiss/utils/distances.h>
int main() {
  // 创建索引对象
  faiss::IndexFlatIP index(2); // 使用L2距离度量,2维向量
  // 添加向量数据
  float xb[4] = {1.0, 1.0, 0.0, 0.5}; // 2个2维向量
  //存储向量个数:
  int n=2;
  // 为了使用内积求出余弦相似度,要对每个向量进行归一化操作
  size_t d = 2; // 向量维度
  float norm[d]={0,0};
  // 计算向量的 L2 范数,是已经过开方的
  // 函数有四个参数:
  // x:指向输入向量数组的指针,所有向量在内存中是连续存储的。即向量数组的布局是 [x₀₀, x₀₁, ..., xₙ₋₁(d-1)]。
  // norms:指向输出结果数组的指针,用于存储计算出的 L2 范数。结果数组的布局和输入向量相同,即 [norm₀, norm₁, ..., normₙ₋₁]。
  // d:向量的维度,即每个向量的元素数目。
  // n:向量的数量(或者说是向量数组的长度)。
  faiss::fvec_norms_L2(norm, xb,d,n); 

  // 将每个向量归一化为单位向量,同时添加到索引中
  #pragma omp parallel
  {
    #pragma omp for
      for (int i = 0; i < n; i++) {
          // 每个向量的起始地址
          float* vector = &xb[i * d]; 
          // 将向量归一化为单位向量
          for (size_t j = 0; j < d; j++) {
              vector[j] /= norm[i];
          }
          // 每次将1个向量添加到索引中
          #pragma omp critical
          {
            index.add(1, vector);
          }
      }
    //进行同步
    #pragma omp barrier
  }
  // 保存索引到文件
  faiss::write_index(&index, "index.faissindex");

  // 从文件加载索引
  faiss::Index* loaded_index = faiss::read_index("index.faissindex");

  // 执行搜索
  float xq[2] = {1.0, 0.0}; // 查询向量
  int k = 1; // 返回最接近的2个邻居
  faiss::idx_t* I = new faiss::idx_t[k]; // 邻居索引
  float* D = new float[k]; // 邻居距离

// search 方法的主要参数如下:
// n:表示要搜索的查询向量的数量,即查询向量的个数。
// x:一个指向浮点数的指针,表示查询向量的数据。x 的大小应该为 n 乘以向量的维度。
// k:表示要返回的相似邻居的数量。
// distances:一个指向浮点数的指针,用于存储查询向量与相似邻居之间的距离。distances 的大小应该为 n 乘以 k。
// labels:一个指向整数的指针,用于存储相似邻居的索引(标签)。labels 的大小应该为 n 乘以 k。

   loaded_index->search(1, xq, k, D, I);

  // 打印结果
  std::cout << "查询结果:" << std::endl;
  std::cout << "邻居索引: " << I[0] << ", 距离: " << D[0] << std::endl;
  //返回原始向量:
  // 获取索引为 i 的向量
  // 向量的维度
  std::vector<float> vectors(index.d);
  index.reconstruct(I[0], vectors.data());
  // 使用循环遍历并打印该向量每个元素
  for (const auto& element : vectors) {
        std::cout << element << " ";
  }
  std::cout << std::endl;
  // 释放内存
  delete loaded_index;
  delete[] I;
  delete[] D;

  return 0;
}

对应cmakelist:文章来源地址https://www.toymoban.com/news/detail-731229.html

cmake_minimum_required(VERSION 3.5)
project(fangdou)
FIND_PACKAGE( OpenMP REQUIRED)
if(OPENMP_FOUND)
message("OPENMP FOUND")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${OpenMP_C_FLAGS}")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${OpenMP_CXX_FLAGS}")
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${OpenMP_EXE_LINKER_FLAGS}")
endif()

# 添加 Faiss 库的路径
set(FAISS_INCLUDE_DIR /usr/local/include/faiss)
set(FAISS_LIBRARY_DIR /usr/local/lib)

include_directories(
${FAISS_INCLUDE_DIR}
)

SET(OpenCV_DIR /usr/local/lib/cmake/opencv4/)
FIND_PACKAGE(OpenCV REQUIRED)

file(GLOB_RECURSE cpp_srcs ${CMAKE_SOURCE_DIR}/src/*.cpp ${CMAKE_SOURCE_DIR}/src/*.cc ${CMAKE_SOURCE_DIR}/src/*.h)

link_directories(
/usr/lib/x86_64-linux-gnu/
${FAISS_LIBRARY_DIR}
)

add_executable(${PROJECT_NAME} ${cpp_srcs})

target_link_libraries(${PROJECT_NAME}  ${OpenCV_LIBS} faiss openblas)

输出ID号而非索引的改进版

#include <iostream>
#include <cmath>
#include <faiss/IndexFlat.h>
#include <faiss/index_io.h>
#include <faiss/utils/distances.h>
#include <faiss/IndexIDMap.h>
int main() {

  // 创建一个IndexFlatIP内积索引对象作为内部索引
  faiss::IndexFlatIP inner_index(2);

  // 创建一个IndexIDMap对象,将内部索引设置为IndexFlatIP
  faiss::IndexIDMap index(&inner_index);
  // 添加向量数据
  float xb[4] = {1.0, 1.0, 0.0, 0.5}; // 2个2维向量
  //ids
  faiss::idx_t ids[] = {1001, 1002};
  //存储向量个数:
  int n=2;
  // 为了使用内积求出余弦相似度,要对每个向量进行归一化操作
  size_t d = 2; // 向量维度
  float norm[d]={0,0};
  // 计算向量的 L2 范数,是已经过开方的
  // 函数有四个参数:
  // x:指向输入向量数组的指针,所有向量在内存中是连续存储的。即向量数组的布局是 [x₀₀, x₀₁, ..., xₙ₋₁(d-1)]。
  // norms:指向输出结果数组的指针,用于存储计算出的 L2 范数。结果数组的布局和输入向量相同,即 [norm₀, norm₁, ..., normₙ₋₁]。
  // d:向量的维度,即每个向量的元素数目。
  // n:向量的数量(或者说是向量数组的长度)。
  faiss::fvec_norms_L2(norm, xb,d,n); 

  // 将每个向量归一化为单位向量,同时添加到索引中
  #pragma omp parallel
  {
    #pragma omp for
      for (int i = 0; i < n; i++) {
          // 每个向量的起始地址
          float* vector = &xb[i * d]; 
          // 将向量归一化为单位向量
          for (size_t j = 0; j < d; j++) {
              vector[j] /= norm[i];
          }
          // 每次将1个向量添加到索引中
          #pragma omp critical
          {
            index.add_with_ids(1, vector,&ids[i]);
          }
      }
    //进行同步
    #pragma omp barrier
  }
  // 保存索引到文件
  faiss::write_index(&index, "index.faissindex");

  // 从文件加载索引
  faiss::Index* loaded_index = faiss::read_index("index.faissindex");

  // 执行搜索
  float xq[2] = {1.0, 0.0}; // 查询向量
  int k = 1; // 返回最接近的2个邻居
  faiss::idx_t* I = new faiss::idx_t[k]; // 邻居索引
  float* D = new float[k]; // 邻居距离

// search 方法的主要参数如下:
// n:表示要搜索的查询向量的数量,即查询向量的个数。
// x:一个指向浮点数的指针,表示查询向量的数据。x 的大小应该为 n 乘以向量的维度。
// k:表示要返回的相似邻居的数量。
// distances:一个指向浮点数的指针,用于存储查询向量与相似邻居之间的距离。distances 的大小应该为 n 乘以 k。
// labels:一个指向整数的指针,用于存储相似邻居的索引(标签)。labels 的大小应该为 n 乘以 k。

   loaded_index->search(1, xq, k, D, I);

  // 打印结果
  std::cout << "查询结果:" << std::endl;
  std::cout << "邻居索引: " << I[0] << ", 距离: " << D[0] << std::endl;
  //此时不再支持返回原向量。
  // 释放内存
  delete loaded_index;
  delete[] I;
  delete[] D;

  return 0;
}

到了这里,关于【向量数据库】相似向量检索Faiss数据库的安装及余弦相似度计算(C++)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • LangChain 4用向量数据库Faiss存储,读取YouTube的视频文本搜索Indexes for information retrieve

    接着前面的Langchain,继续实现读取YouTube的视频脚本来问答Indexes for information retrieve LangChain 实现给动物取名字, LangChain 2模块化prompt template并用streamlit生成网站 实现给动物取名字 LangChain 3使用Agent访问Wikipedia和llm-math计算狗的平均年龄 引用向量数据库Faiss 查看OpenAI model main.p

    2024年02月05日
    浏览(39)
  • milvus: 专为向量查询与检索设计的向量数据库

    milvus docs milvus release Milvus的目标是:store, index, and manage massive embedding vectors generated by deep neural networks and other machine learning (ML) models. Milvus 向量数据库专为向量查询与检索设计,能够为万亿级向量数据建立索引。 与现有的关系数据库主要按照预定义的模式处理结构化数据不同,

    2024年02月15日
    浏览(26)
  • 向量数据库:usearch的简单使用+实现图片检索应用

    usearch是快速开源搜索和聚类引擎×,用于C++、C、Python、JavaScript、Rust、Java、Objective-C、Swift、C#、GoLang和Wolfram 🔍中的向量和🔜字符串× 一个简单的例子(注:本例子在运行时向index中不断添加项目,并将最后的index持久化为一个文件,在运行时由于添加项目内存占用会不断增

    2024年02月02日
    浏览(31)
  • Spring AI - 使用向量数据库实现检索式AI对话

     Spring AI 并不仅限于针对大语言模型对话API进行了统一封装,它还可以通过简单的方式实现LangChain的一些功能。本篇将带领读者实现一个简单的检索式AI对话接口。  在一些场景下,我们想让AI根据我们提供的数据进行回复。因为对话有最大Token的限制,因此很多场景下我们

    2024年04月14日
    浏览(30)
  • Java开发者的Python快速实战指南:探索向量数据库之图像相似搜索-文字版

    首先,我要向大家道个歉。原本我计划今天向大家展示如何将图片和视频等形式转换为向量并存储在向量数据库中,但是当我查看文档时才发现,腾讯的向量数据库尚未完全开发完成。因此,今天我将用文本形式来演示相似图片搜索。如果您对腾讯的产品动态不太了解,可以

    2024年02月05日
    浏览(51)
  • 🔥🔥Java开发者的Python快速实战指南:探索向量数据库之图像相似搜索-文字版

    首先,我要向大家道个歉。原本我计划今天向大家展示如何将图片和视频等形式转换为向量并存储在向量数据库中,但是当我查看文档时才发现,腾讯的向量数据库尚未完全开发完成。因此,今天我将用文本形式来演示相似图片搜索。如果您对腾讯的产品动态不太了解,可以

    2024年02月05日
    浏览(53)
  • 计算两个向量的余弦相似度

    余弦相似度是判断两个向量相似度常用的算法,我在做行人重识别的时候,用到了余弦相似度的算法,记录一下。 余弦相似度算法:一个向量空间中两个向量夹角间的余弦值作为衡量两个个体之间差异的大小,余弦值接近1,夹角趋于0,表明两个向量越相似,余弦值接近于

    2024年02月03日
    浏览(34)
  • AIGC:【LLM(五)】——Faiss:高效的大规模相似度检索库

    1.1 什么是Faiss Faiss的全称是Facebook AI Similarity Search,是Facebook的AI团队针对大规模相似度检索问题开发的一个工具,使用C++编写,有python接口,对10亿量级的索引可以做到毫秒级检索的性能。 简单来说,Faiss的工作就是把我们自己的候选向量集封装成一个index数据库,它可以加速

    2024年02月13日
    浏览(30)
  • ModaHub魔搭社区:AI原生云向量数据库Zilliz Cloud与 OpenAI 集成搭建相似性搜索系统

    目录 准备工作 检索图书 本文将讨论如何使用 OpenAI 的 Embedding API 与 Zilliz Cloud 搭建相似性搜索系统。 在本篇中你将看到如何使用 OpenAI 的 Embedding API 和 Zilliz Cloud 完成图书检索。当前,很多的图书检索方案,包括公共图书馆里使用的那些方案,都是使用匹配的方式获取

    2024年02月15日
    浏览(33)
  • 基于SimCSE和Faiss的文本向量检索实践

    目录 文本的向量表示 1、SimCSE 2、支持无监督训 3、训练注意事项 向量检索 1、精准查找flat 2、HNSWx 3、IVFx 4、PQx 5、LSH 对博客标题进行向量检索 数据向量化 构建索引 文本检索 测试检索 传统的文本检索一般是建立倒排索引,对搜索词的召回结果进行打分排序返回最终结果,但

    2024年02月16日
    浏览(29)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包