faiss多GPU量化压缩极限4bit

news2024/11/6 18:32:55

 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_size
    end = (i + 1) * batch_size
    batch_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.coloradmin.cn/o/2234437.html

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

相关文章

Flutter错误: uses-sdk:minSdkVersion 16 cannot be smaller than version 21 declared

前言 今天要做蓝牙通信的功能&#xff0c;我使用了flutter_reactive_ble这个库&#xff0c;但是在运行的时候发现一下错误 Launching lib/main.dart on AQM AL10 in debug mode... /Users/macbook/Desktop/test/flutter/my_app/android/app/src/debug/AndroidManifest.xml Err…

【含开题报告+文档+源码】基于Java的房屋租赁服务系统设计与实现

开题报告 随着城市化进程的加速和人口流动性的增加&#xff0c;租房需求不断增长。传统的租赁方式往往存在信息不对称、流程不规范等问题&#xff0c;使得租户和房东的租赁体验不佳。而而房屋租赁系统能够提供便捷、高效的租赁服务&#xff0c;满足租户和房东的需求。房屋租赁…

斯托克斯矢量,表示电磁波的(不是散射体)平均后,可分解为完全极化电磁波和噪声

可见完全极化分就表示只有一种&#xff0c;在T矩阵中是只有一种散射体&#xff0c;在电磁波协方差矩阵中是只有一种电磁波

微服务day03

导入黑马商城项目 创建Mysql服务 由于已有相关项目则要关闭DockerComponent中的已开启的项目 [rootserver02 ~]# docker compose down WARN[0000] /root/docker-compose.yml: version is obsolete [] Running 4/4✔ Container nginx Removed …

大腾智能荣获盐田区黄金珠宝产业“产业赋能数字化优选能力伙伴”荣誉

11月2日&#xff0c;盐田区黄金珠宝产业数智化转型促进中心&#xff08;简称“促进中心”&#xff09;揭牌仪式圆满举办。盐田区委书记李忠&#xff0c;市工业和信息化局、市市场监督管理局、华为技术有限公司等相关单位、企业负责人共同见证促进中心揭牌启动。 大腾智能也出席…

10天进阶webpack---(2)webpack模块兼容性处理

回顾CMJ和ESM的区别 CMJ的本质可以使用一个函数概括 // require函数的伪代码 function require(path){if(该模块有缓存吗){return 缓存结果;}function _run(exports, require, module, __filename, __dirname){// 模块代码会放到这里}var module {exports: {}}_run.call(mod…

034_Structural_Transient_In_Matlab结构动力学问题求解

结构动态问题 问题描述 我们试着给前面已经做过的问题上加一点有趣的东西。 结构静力学求解 当时求解这个问题&#xff0c;在最外面的竖直切面加载了一个静态的固定的力。下面我们试试看在上方的表面增加一个脉冲压力载荷。 采用统一的有限元框架&#xff0c;定义问题&…

简单的 docker 部署ELK

简单的 docker 部署ELK 这是我的运维同事部署ELK的文档&#xff0c;我这里记录转载一下 服务规划 架构: Filebeat->kafka->logstash->ES kafka集群部署参照: kafka集群部署 部署服务程序路径/数据目录端口配置文件elasticsearch/data/elasticsearch9200/data/elas…

TortoiseSVN小乌龟下载安装(Windows11)

目录 TortoiseSVN 1.14.7工具下载安装 TortoiseSVN 1.14.7 工具 系统&#xff1a;Windows 11 下载 官网&#xff1a;https://tortoisesvn.subversion.org.cn/downloads.html如图选 TortoiseSVN 1.14.7 - 64 位 下载完成 安装 打开 next&#xff0c;next Browse&#xf…

Python实例:爱心代码

前言 在编程的奇妙世界里,代码不仅仅是冰冷的指令集合,它还可以成为表达情感、传递温暖的独特方式。今天,我们将一同探索用 Python 语言绘制爱心的神奇之旅。 爱心,这个象征着爱与温暖的符号,一直以来都在人类的情感世界中占据着特殊的地位。而通过 Python 的强大功能,…

ENSP RIP动态路由

RIP&#xff08;距离矢量路由协议&#xff09;以网络中所有链路的距离和矢量为依据计算最佳路径&#xff0c;是第一个动态路由协议。条数作为唯一的度量单位。默认开启水平分割&#xff08;从一个路由接口学到的路由信息&#xff0c;便不在从这个接口发送出去&#xff09;防止路…

Qt 练习做一个登录界面

练习做一个登录界面 效果 UI图 UI代码 <?xml version"1.0" encoding"UTF-8"?> <ui version"4.0"><class>Dialog</class><widget class"QDialog" name"Dialog"><property name"ge…

C++——priority_queue模拟实现过程中的优化

前言的前言&#xff1a; 大佬写博客给别人看&#xff0c;菜鸟写博客给自己看&#xff0c;我是菜鸟。 前言&#xff1a; 1.priority_queue&#xff08;优先队列&#xff09;的底层原理和堆极其相似&#xff0c;因此在模拟实现的过程中&#xff0c;主要借助堆的思想取完成&…

蓝桥杯真题——三角回文数(C语言)

问题描述 对于正整数 n, 如果存在正整数 k 使得 n123⋯kk(k1)2n123⋯kk(k1)/2​, 则 n 称为三角数。例如, 66066 是一个三角数, 因为 66066123⋯36366066123⋯363 。 如果一个整数从左到右读出所有数位上的数字, 与从右到左读出所有数位 上的数字是一样的, 则称这个数为回文数…

密码学知识点整理一:密码学概论

密码学是什么&#xff1f; 密码学是一门研究编制密码和破译密码的技术科学。 密码学&#xff0c;作为信息安全的核心技术之一&#xff0c;其重要性在于能够为信息传输提供安全保障&#xff0c;确保数据在存储或传输过程中的机密性、完整性与真实性不被破坏。从古至今&#x…

51单片机教程(五)- LED灯闪烁

1 项目分析 让输入/输出口的P1.0或P1.0~P1.7连接的LED灯闪烁。 2 技术准备 1、C语言知识点 1 运算符 1 算术运算符 #include <stdio.h>int main(){// 算术运算符int a 13;int b 6;printf("%d\n", ab); printf("%d\n", a-b); printf("%…

Unity中实现伤害飘字或者提示飘字效果(DoTween实现版本)

&#xff01;&#xff01;&#xff01;在实现以下效果之前&#xff0c;一定要往项目中导入DoTween插件。 一、搭建测试场景 1、在场景中新建一个带有Text组件的游戏物体A&#xff0c;并把这个游戏物体A中Text组件的Color属性中alpha值为0&#xff0c;让文字在场景中隐藏。 …

其他节点使用kubectl访问集群,kubeconfig配置文件 详解

上述两种方式&#xff1a;可使用kubectl连接k8s集群。 $HOME/.kube/config 是config文件默认路径&#xff0c;要么直接定义环境变量&#xff0c;要么就直接把文件拷过去 config文件里面&#xff0c;定义了context&#xff0c;里面指定了用户和对应的集群信息&#xff1a; ku…

【vim文本编辑器gcc编译器gdb调试器】

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 一、vimvim安装vim常用快捷键vim使用vimtutor zh文档 二、gcc编译器安装gcc工具编译源代码 三、gdb调试器gdb安装gdb常用指令gdb简单上手使用gdb的单步调试功能 总结…

陀螺仪BMI323驱动开发测试(基于HAL库SPI通信)

参考资料 编写代码 读取芯片ID void BMI160_Init(void) {uint16_t chipID BMI323_read(BMI160_REG_CHIP_ID);debug("BMI323芯片ID为0x%x;", chipID);if (chipID ! 0x43){debug("未检测到BMI323;");}elsedebug("检测到陀螺仪BMI323;");u8 buf_…