自学内容网 自学内容网

向量数据库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_cpuindex_cpu_to_gpuindex_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.实施的索引

索引类型 IndexFlatIndexIVFFlatIndexIVFScalarQuantizerIndexIVFPQ 在 GPU 上实现为 GpuIndexFlatGpuIndexIVFFlatGpuIndexIVFScalarQuantizerGpuIndexIVFPQ

除了普通参数之外,它们还接受资源对象作为输入,以及索引存储配置选项和 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
    • 当内存非常紧张时,倒排列表的几何重新分配可能会溢出内存。为了避免这种情况(通常是为了提高添加速度),如果您知道索引有多大,请在 GpuIndexIVFPQGpuIndexIVFFlat 上调用reserveVecs
    • StandardGpuResources 对象默认保留 512 MiB(<= 4 GiB GPU)、1024 MiB(<= 8 GiB GPU)或最大 1536 MiB(所有其他 GPU)的 GPU 内存用于临时计算空间。如果太多,可以减小大小,但可能会降低速度。
    • 添加或搜索大量向量应分批完成。典型的批量大小是 8192 左右的 2 的幂。
  • 当使用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)!