向量数据库FAISS之七:GPU上的FAISS
Faiss on the GPU
1.CPU/GPU 互操作
GPU Index 能够容纳宿主和设备的指针作为输入给 add()
和 search()
如果 add()
和 search()
的输入已经与 索引 位于同一 GPU 上,则不会执行任何副本,并且执行速度最快。
否则,将执行 CPU -> GPU 复制(或跨设备,如果输入驻留在与索引不同的 GPU 上),完成后会复制回所有结果(例如,对于 search())。
1.转换
启用 从/到GPU 的转换:
index_gpu_to_cpu
,
index_cpu_to_gpu
,
index_cpu_to_gpu_multiple
传输到 GPU 的两个函数使用一个可选的 GpuClonerOptions
对象,该对象可用于调整 GPU 存储对象的方式。默认值适用于内存不受限制的情况。当内存不足时,可以调整这些字段。
2.Python 中的转换
在 Python 中,index_gpu_to_cpu
、index_cpu_to_gpu
和index_cpu_to_gpu_multiple
可用。
-
index_cpu_to_all_gpus
:将 CPU 索引克隆到所有可用 GPU 或ngpu=3
指定的多个 GPU -
index_cpu_gpu_list
:同样,但另外还需要一个可以用gpus=[2, 4, 6]
指定的 gpu id 列表 -
index_cpu_to_gpu_multiple_py
:实例化多个 GPU 索引时,最好分解 GPU 资源以避免浪费内存。该函数采用可以在索引之间重用的资源对象列表作为其第一个参数,ngpu = 4 resources = [faiss.StandardGpuResources() for i in range(ngpu)] index1_gpu = faiss.index_cpu_to_gpu_multiple_py(resources, index1) index2_gpu = faiss.index_cpu_to_gpu_multiple_py(resources, index2)
2.实施的索引
索引类型 IndexFlat
、IndexIVFFlat
、IndexIVFScalarQuantizer
和 IndexIVFPQ
在 GPU 上实现为 GpuIndexFlat
、GpuIndexIVFFlat
、GpuIndexIVFScalarQuantizer
和 GpuIndexIVFPQ
。
除了普通参数之外,它们还接受资源对象作为输入,以及索引存储配置选项和 float16/float32 配置参数。
1.限制
- 对于所有索引,
k
和nprobe
<= 2048 - 对于
GpuIndexIVFPQ
,允许的每个编码向量的代码大小为 1、2、3、4、8、12、16、20、24、28、32、48、56、64 和 96 字节。 - 内存通常是 GPU 上较稀缺的资源,因此使用 GPU 索引时需要注意一些事项
- 由于共享内存限制,每个代码 56 字节或更多的
GpuIndexIVFPQ
需要使用 float16 IVFPQ 模式(例如,48 x 2^8 x sizeof(float) 为 49152 字节); GpuIndexIVFPQ
的预计算表可能会占用大量内存。如果您看到 cudaMalloc 错误,请禁用预计算表;- 与倒排文件条目对应的索引可以存储在CPU上而不是GPU上,使用
indices_options = INDICES_CPU
- 当内存非常紧张时,倒排列表的几何重新分配可能会溢出内存。为了避免这种情况(通常是为了提高添加速度),如果您知道索引有多大,请在
GpuIndexIVFPQ
或GpuIndexIVFFlat
上调用reserveVecs
。 StandardGpuResources
对象默认保留 512 MiB(<= 4 GiB GPU)、1024 MiB(<= 8 GiB GPU)或最大 1536 MiB(所有其他 GPU)的 GPU 内存用于临时计算空间。如果太多,可以减小大小,但可能会降低速度。- 添加或搜索大量向量应分批完成。典型的批量大小是 8192 左右的 2 的幂。
- 由于共享内存限制,每个代码 56 字节或更多的
- 当使用
index_cpu_to_gpu
从 CPU 索引转换时,默认的GpuCloneOptions
对象被调整为以内存使用为代价最大化速度。
3. GPU vs CPU 比较
GPU 通常比 CPU 实现有显著的加速,但有两个问题需要记住:
1.CPU <-> GPU 副本的开销
- 通常,CPU 通过总线连接到 GPU,该总线的带宽低于 CPU 连接到其主内存的带宽,尤其是 CPU 连接到其自己的缓存的带宽;
- 例如,PCIe3 的最大速度约为 12 GB/秒,而服务器级 CPU 通常具有 50+ GB/秒。
- 将填充的索引从 CPU 复制到 GPU 可能需要花费大量时间。只有当您在 GPU 上执行合理数量的查询时,您才会分摊此开销;
- 最好将索引复制到 GPU 并将其保留在那里,或者在 GPU 上创建索引并将其填充在那里。
2.批量大小和索引大小
GPU 通常比 CPU 具有更高的延迟,但和 CPU 相比具有更高的并行吞吐量和内存带宽。
如果可能的话,最好使用 CPU 或 GPU 进行批量查询,因为这可以在所有查询中分摊索引内存的接触。
Index size 应该相对较大才能看到 GPU 获胜。只有几千个向量的索引通常在 CPU 上总是更快(因为它可以容纳 CPU 的缓存),但数十万到数百万/数十亿个向量将非常适合分摊 GPU 的开销。
总结
- 小查询批量、小索引:CPU 通常更快
- 小查询批量,大索引:GPU 通常更快
- 大查询批量,小索引:两种方式都可以
- 大查询批量、大索引:GPU 通常更快
原文地址:https://blog.csdn.net/weixin_46034279/article/details/143893757
免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!