faiss多GPU量化压缩极限4bit

 group 868373192

 second group 277356808

目前faiss多卡压缩的极限,采用ivfPQ只能到8bit,而SQ可以到4bit,因此采用后者。

参考前述博文:10亿级别向量数据进行faiss-gpu实现快速召回-CSDN博客

量化压缩后的index:faiss新版使用方法-CSDN博客

faiss 用于检索10亿向量(维度768)的方法-CSDN博客

faiss.IndexScalarQuantizer使用方法-CSDN博客

import faiss
import numpy as np# 设置GPU数量
faiss.omp_set_num_threads(4)# 初始化GPU资源
gpu_resources = []
for i in range(4):res = faiss.StandardGpuResources()gpu_resources.append(res)# 创建一个4-bit标量量化的索引
quantizer = faiss.IndexFlatL2(768)
index = faiss.IndexIVFScalarQuantizer(quantizer, 768, 1024, faiss.ScalarQuantizer.QT_4bit)  # 1024个聚类中心,4-bit量化# 将索引转移到GPU
co = faiss.GpuMultipleClonerOptions()
co.useFloat16 = True
co.usePrecomputed = False
co.indicesOptions = faiss.INDICES_64_BIT
co.verbose = True
co.shard = True  # 分片模式# 使用IndexShards进行分片
shards = faiss.IndexShards(768)
for i in range(4):gpu_index = faiss.index_cpu_to_gpu(gpu_resources[i], i, index)shards.add_shard(gpu_index)# 生成随机数据
d = 768
nb = 1000000
np.random.seed(1234)
xb = np.random.random((nb, d)).astype('float32')
xb[:, 0] += np.arange(nb) / 1000.# 训练索引
shards.train(xb)# 添加数据到索引
shards.add(xb)# 搜索示例
nq = 10  # 查询数量
xq = np.random.random((nq, d)).astype('float32')
xq[:, 0] += np.arange(nq) / 1000.k = 5  # 返回最近的5个结果
D, I = shards.search(xq, k)print("查询结果:")
for i in range(nq):print(f"查询 {i}: 最近的 {k} 个向量索引: {I[i]}")

注意,上述数据不能分批加载,这就需要大的瞬时空间(内存),bug如下:

0, in add return _swigfaiss.IndexShards_add(self, n, x) RuntimeError: Error in void faiss::IndexShardsTemplate<IndexT>::add_with_ids(faiss::IndexShardsTemplate<IndexT>::idx_t, const component_t*, const idx_t*) [with IndexT = faiss::Index; faiss::IndexShardsTemplate<IndexT>::idx_t = long int; faiss::IndexShardsTemplate<IndexT>::component_t = float] at /project/faiss/faiss/IndexShards.cpp:240: Error: 'this->ntotal == 0' failed: when adding to IndexShards with sucessive_ids, only add() in a single pass is supported

这个错误表明在使用IndexShards时,add方法不支持多次调用。IndexShards要求在添加数据时,所有数据必须一次性添加,而不是分多次添加。

为了解决这个问题,我们需要确保在调用add方法时,一次性添加所有数据。下面是修改后的代码:

修改后的代码

import faiss
import numpy as np# 设置GPU数量
faiss.omp_set_num_threads(4)# 初始化GPU资源
gpu_resources = []
for i in range(4):res = faiss.StandardGpuResources()gpu_resources.append(res)# 创建一个4-bit标量量化的索引
quantizer = faiss.IndexFlatL2(768)
index = faiss.IndexIVFScalarQuantizer(quantizer, 768, 1024, faiss.ScalarQuantizer.QT_4bit)  # 1024个聚类中心,4-bit量化# 将索引转移到GPU
co = faiss.GpuMultipleClonerOptions()
co.useFloat16 = True
co.usePrecomputed = False
co.indicesOptions = faiss.INDICES_64_BIT
co.verbose = True
co.shard = True  # 分片模式# 使用IndexShards进行分片
shards = faiss.IndexShards(768)
for i in range(4):gpu_index = faiss.index_cpu_to_gpu(gpu_resources[i], i, index)shards.add_shard(gpu_index)# 生成随机数据
d = 768
nb = 1000000
np.random.seed(1234)
xb = np.random.random((nb, d)).astype('float32')
xb[:, 0] += np.arange(nb) / 1000.# 训练索引
shards.train(xb)# 添加数据到索引
shards.add(xb)# 搜索示例
nq = 10  # 查询数量
xq = np.random.random((nq, d)).astype('float32')
xq[:, 0] += np.arange(nq) / 1000.k = 5  # 返回最近的5个结果
D, I = shards.search(xq, k)print("查询结果:")
for i in range(nq):print(f"查询 {i}: 最近的 {k} 个向量索引: {I[i]}")

代码解释

  1. GPU资源初始化: 我们初始化了4个GPU资源,每个GPU资源对应一个GPU。

  2. 4-bit标量量化索引: 我们创建了一个IndexIVFScalarQuantizer索引,其中1024是聚类中心的数量,faiss.ScalarQuantizer.QT_4bit表示使用4-bit标量量化。

  3. 索引转移到GPU: 使用faiss.GpuMultipleClonerOptions()将索引转移到GPU,并设置了一些选项,如使用Float16、分片模式等。

  4. 使用IndexShards进行分片: 我们使用IndexShards来管理多个GPU上的索引,确保每个GPU上的索引具有相同的编码大小。

  5. 训练和添加数据: 我们生成了100万个768维的随机向量,并将其用于训练和添加到索引中。注意,add方法是一次性调用的,而不是分多次调用。

  6. 搜索: 我们生成了10个查询向量,并使用索引进行搜索,返回每个查询向量的最近5个向量的索引。

注意事项

  • 内存和显存: 由于数据量较大(100万条768维向量),确保你的GPU有足够的显存来处理这些数据。

  • 性能调优: 你可以调整聚类中心的数量、子向量的数量等参数来优化性能。

  • 多GPU负载均衡: 使用分片模式(shard=True)可以更好地在多个GPU之间分配负载。

通过这个修改后的代码,你应该能够避免IndexShardsadd方法不支持多次调用的问题,并在多GPU环境下成功运行FAISS的4-bit标量量化索引。

我就想分批进行加载数据呢?

下面是一个不使用IndexShards,而是手动管理多个GPU索引并实现分批加载数据的示例代码:

Python代码示例

import faiss
import numpy as np# 设置GPU数量
faiss.omp_set_num_threads(4)# 初始化GPU资源
gpu_resources = []
for i in range(4):res = faiss.StandardGpuResources()gpu_resources.append(res)# 创建一个4-bit标量量化的索引
quantizer = faiss.IndexFlatL2(768)
index = faiss.IndexIVFScalarQuantizer(quantizer, 768, 1024, faiss.ScalarQuantizer.QT_4bit)  # 1024个聚类中心,4-bit量化# 将索引转移到GPU
gpu_indices = []
for i in range(4):gpu_index = faiss.index_cpu_to_gpu(gpu_resources[i], i, index)gpu_indices.append(gpu_index)# 生成随机数据
d = 768
nb = 1000000
np.random.seed(1234)
xb = np.random.random((nb, d)).astype('float32')
xb[:, 0] += np.arange(nb) / 1000.# 分批训练和添加数据
batch_size = nb // 4  # 每个GPU处理的数据量
for i in range(4):start = i * batch_sizeend = (i + 1) * batch_sizebatch_data = xb[start:end]# 训练索引gpu_indices[i].train(batch_data)# 添加数据到索引gpu_indices[i].add(batch_data)# 合并索引
index = faiss.IndexShards(768)
for gpu_index in gpu_indices:index.add_shard(gpu_index)# 搜索示例
nq = 10  # 查询数量
xq = np.random.random((nq, d)).astype('float32')
xq[:, 0] += np.arange(nq) / 1000.k = 5  # 返回最近的5个结果
D, I = index.search(xq, k)print("查询结果:")
for i in range(nq):print(f"查询 {i}: 最近的 {k} 个向量索引: {I[i]}")

代码解释

  1. GPU资源初始化: 我们初始化了4个GPU资源,每个GPU资源对应一个GPU。

  2. 4-bit标量量化索引: 我们创建了一个IndexIVFScalarQuantizer索引,其中1024是聚类中心的数量,faiss.ScalarQuantizer.QT_4bit表示使用4-bit标量量化。

  3. 索引转移到GPU: 使用faiss.index_cpu_to_gpu将索引转移到每个GPU上,并存储在gpu_indices列表中。

  4. 分批训练和添加数据: 我们将数据分成4个批次,每个批次对应一个GPU。每个GPU上的索引分别进行训练和添加数据。

  5. 合并索引: 使用IndexShards将所有GPU上的索引合并成一个索引。

  6. 搜索: 我们生成了10个查询向量,并使用合并后的索引进行搜索,返回每个查询向量的最近5个向量的索引。

注意事项

  • 内存和显存: 由于数据量较大(100万条768维向量),确保你的GPU有足够的显存来处理这些数据。

  • 性能调优: 你可以调整聚类中心的数量、子向量的数量等参数来优化性能。

  • 多GPU负载均衡: 使用分片模式(shard=True)可以更好地在多个GPU之间分配负载。

通过这个示例,你可以了解如何在多GPU环境下手动管理索引并实现分批加载数据。

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

如若内容造成侵权/违法违规/事实不符,请联系一条长河网进行投诉反馈,一经查实,立即删除!

相关文章

C++初阶(十一)--STL--string类

目录 一、string类的概述 二、string类的创建与初始化 1. 直接初始化 2. 无参初始化 3. 从字符数组初始化 三、string类的基本操作 1.string的定义方式 2.string的插入 3.string的拼接 4.string的删除 5.string的查找 6.string的比较 7.string的大小和容量 8.st…

C#笔记 —— 事件

事件的语法 访问修饰符 event 委托类型 事件名&#xff1b; 例&#xff1a; public event Action myEvent; 事件的使用 事件的使用跟委托基本上一模一样&#xff0c; 1.但是事件不能在类外部直接赋值&#xff0c;只能使用 或 - 添加或删除函数&#xff1b; 2.事件不能在类…

Pandas | 理性判断数据是否存在缺失值的一种方法

理性判断 一般思路进一步思考df[B].explode() 一般思路 tcc.info()上述信息info显示没有缺失值 但是真实的情况还是要根据业务实际分析tcc.isnull().sum() # 和tcc.info()作用和tcc.info() 其实是一样的 进一步思考 在此过程中&#xff0c;我们需要检验是否存在采用别的值来表…

leetcode 382.链表随机结点

1.题目要求: 2.题目代码: /*** Definition for singly-linked list.* struct ListNode {* int val;* ListNode *next;* ListNode() : val(0), next(nullptr) {}* ListNode(int x) : val(x), next(nullptr) {}* ListNode(int x, ListNode *next) : val(x)…

Java Development Kit (JDK) 详解

什么是 JDK&#xff1f; JDK 是 Java Development Kit 的缩写&#xff0c;是一组用于开发 Java 应用程序的软件开发工具和库的集合。JDK 包含了 Java 运行时环境&#xff08;JRE&#xff09;和 Java 虚拟机&#xff08;JVM&#xff09;&#xff0c;以及一系列开发工具和库。 …

【5.8】指针算法-双指针验证回文串

一、题目 给定一个字符串&#xff0c;验证它是否是回文串&#xff0c; 只考虑字母和数字字符 &#xff0c;可以忽略字母的大小写。 说明&#xff1a; 本题中&#xff0c;我们将空字符串定义为有效的回文串。 示例 1: 输入: "A man , a plan , a canal : Panama " 输…

多功能 Web 应用渗透测试系统

系统简介 本项目命名为SecurityEye&#xff0c;是一款基于 Python-Django 的多功能 Web 应用渗透测试系统&#xff0c;包含漏洞检测、目录识别、端口扫描、指纹识别、域名探测、旁站探测、信息泄露检测、网站权重探测等功能。 项目功能 本系统通过旁站探测、域名探测、、域名…

libstdc++/so.6: version ‘GLIBCXX_3.4.29‘ not found (required by

matlab使用过程中提示库文件版图过低&#xff0c;如图 1. 网上或者其他eda的工具目录里面找一个libstdc.so.6.29文件&#xff0c;里面包含了glibcxx3.4.29 2. 复制文件到/usr/lib64目录下面 3. libstdc.so.6连接到新的库文件 unlink libstdc.so.6 ln -s libstdc.so.6.0.29 l…

有序数组的平方

给你一个按 非递减顺序 排序的整数数组 nums&#xff0c;返回 每个数字的平方 组成的新数组&#xff0c;要求也按 非递减顺序 排序。 基础使用先平方&#xff0c;后排序的思想 class Solution {public int[] sortedSquares(int[] nums) {for(int i0;i<nums.length;i){nums…

flutter 专题七 Flutter面试之渲染流程

一、 简介 Flutter面试中必问的一个面试题就是渲染相关的话题。作为Google在2018年发布的一款跨平台UI框架&#xff0c;使用Dart作为其开发语言&#xff0c;底层使用Skia图形库进行视图渲染&#xff0c;渲染速度和用户体验堪比原生。 二、Flutter渲染流程 总的来说&#xff…

深入理解 TCP 的握手与挥手机制:为何握手 3 次,挥手 4 次?

在网络通信的世界里&#xff0c;TCP&#xff08;Transmission Control Protocol&#xff0c;传输控制协议&#xff09;是一种非常重要的协议&#xff0c;它确保了数据在网络中的可靠传输。而 TCP 的连接建立&#xff08;握手&#xff09;和连接断开&#xff08;挥手&#xff09…

Python-数据爬取(爬虫)

在数据驱动的时代&#xff0c;Python以其强大的数据处理能力和丰富的库资源&#xff0c;成为数据爬取的首选语言。通过Python&#xff0c;你可以轻松地从网页中抓取所需的数据&#xff0c;无论是价格信息、新闻内容还是用户评论&#xff0c;都能一一收入囊中。使用requests库发…

基于51单片机水位监测控制报警仿真设计

基于51单片机水位监测控制报警仿真设计 1. 主要功能&#xff1a;2. 讲解视频&#xff1a;3. 仿真4. 程序代码5. 设计报告6. 设计资料内容清单&&下载链接资料下载链接&#xff1a; 基于51单片机水位监测控制报警仿真设计( proteus仿真程序设计报告讲解视频&#xff09; …

JavaFX在Linux aarch64上运行

1.适配Jdk Linux开发项目安装在麒麟系统&#xff0c;无法安装&#xff0c;经查询因cpu架构不同导致无法运行 https://www.oracle.com/sg/java/technologies/downloads/#java21 该链接可下载jdk21,Linux aarch64版本。 2.适配Javafx模块 替换jdk之后&#xff0c;JavaFX仍无…

3D区块多重渐变围栏

这里主要用到的就是threejs的shader&#xff0c;至于其他知识点&#xff0c;可以参考json生成3d区域 下面的主要代码&#xff1a; import * as THREE from three; import { OrbitControls } from three/addons/controls/OrbitControls.js import { EffectComposer } from th…

【NLP】使用 SpaCy、ollama 创建用于命名实体识别的合成数据集

命名实体识别 (NER) 是自然语言处理 (NLP) 中的一项重要任务&#xff0c;用于自动识别和分类文本中的实体&#xff0c;例如人物、位置、组织等。尽管它很重要&#xff0c;但手动注释大型数据集以进行 NER 既耗时又费钱。受本文 ( https://huggingface.co/blog/synthetic-data-s…

Git代码托管(三)可视化工具操作(1)

常见的可视化操作工具有 一、官方网页 如码云、gitlab&#xff0c;自带了常见的git操作。 以码云为例&#xff1a; 1、创建分支&#xff1a; 进入分支目录&#xff0c;点击 新建分支 按钮&#xff0c; 在弹出框中输入新分支名称&#xff0c;点击确定即可一键创建分支&…

STL学习-无序容器-unordered set和unorderde multiset

1.定义及初始化 #include <unordered set> #include <iostream> using namespace std; //输出s中的所有元素 template<typename T> void Show(const T& s) { for(auto&x:s) cout << x<<" ";cout << endl; } int main()…

鸿蒙(Harmony)实现滑块验证码

在Android和ios两端已经使用的滑块验证码框架还未适配鸿蒙版&#xff0c;于是需要自己去实现类似如下的滑块验证码&#xff1a; 那么实现这样的验证码主要涉及到几个内容&#xff1a; 1、自定义弹窗 2、base64图片转换 3、滑动组件与滑块的联动&#xff0c;以及横移距离转换…