如何计算使用 pgvector (HNSW) 服务 X N 维向量所需的 RAM 量?

问题描述 投票:0回答:1

我正在尝试确定一个函数

f(x, n)
,其中
x
是向量的数量,
n
是向量维度的数量,这样对于任何
x
n
f(x, n)
都大于通过具有 HNSW 索引的 pgvector 数据库为这些向量提供所需的 RAM 量。

我做了一些谷歌搜索,但是

  1. 我找不到索引大小的公式。
  2. 我看到一些数据库(如 Qdrant)可以对向量和索引使用内存映射文件来减少 RAM 消耗,但我没有看到 pgvector 的此类选项。是否需要将整个 HNSW 索引存储在内存中?如果不是,如何确定所需的内存量?

这篇文章说:

HNSW 索引的第三个权衡是它们很大——100 万行 AI 嵌入的索引可以是 8GB 或更大。出于性能原因,您需要将所有这些索引都存储在内存中。

尽管在本文中,据说使用相同 HNSW 索引算法的 Qdrant 仅需要约 1GB RAM 即可服务 100 万个向量(无内存映射)。为什么会有这样的差异?

postgresql vector-database pgvector vector-search
1个回答
0
投票

根据 FAISS 文档,HNSW 索引的内存消耗(以每个向量字节为单位)为

(d * 4 + M * 2 * 4)
,其中
d
是索引向量的维数,
M
是构造的每个节点的边数图(通常使用默认值 32)。

您链接的Qdrant文章使用维度为100的glove100_angular数据集,需要

100 * 4 + 32 * 2 * 4 = 656 bytes/vector
使用HNSW索引进行索引。

这将需要

656_000_000 bytes
内存来索引 1M 向量,或者
0.656GB
,它跟踪 Qdrant 文章估计的 1GB RAM。

查看 PGVector 文档,看起来整个索引不需要来适应 RAM,但是当索引不再适合内存时,索引构建时间将花费更长的时间(我认为这是由于 Postgres 构建造成的)磁盘上的索引)。

注意:在FAISS提供的内存消耗公式(d * 4 + M * 2 * 4)

中,第一部分
(d * 4)
似乎对应于用于存储向量本身的字节数,而
M * 2 * 4
则对应于该数字存储对其 
M
 邻居的引用所需的字节数。由于 HNSW 索引构建的图的层数逐渐变得稀疏,其中基础层每个节点使用 
M * 2
 连接(默认情况下),并且每个后续层每个节点使用 
M
 连接,我的理解是上面公式
only占基础层。

每个节点都

根据概率随机添加到后续层,该概率由值M_L

标准化。 
M_L
 的典型默认值为 
ln(M)
。使用默认值 
M=32
,对于索引 1M 向量的图,每层的节点数将如下所示:

L0: 1000000 L1: 1000000 / ln(32) ~= 288539 L2: 288539 / ln(32) ~= 83254 L3: 83254 / ln(32) ~= 24022 L4: 24022 / ln(32) ~= 6931 L5: 6931 / ln(32) ~= 1999 L6: 1999 / ln(32) ~= 577 L7: 577 / ln(32) ~= 166 L8: 166 / ln(32) ~= 48 L9: 48 / ln(32) ~= 13 --> this value is less than M=32, so it becomes the last layer of the graph (first layer to be searched)

L_i > L0

层中所有节点总和的上限为
N
,因此
N
向量的边总数受以下限制:

M * 2 * N (edges for L0) + M * N (edges for layers L>0) = 3 * M * N

这将使每个向量的内存消耗为:

(d * 4 + M * 3 * 4)

,因此 Qdrant 文章中的数据集将需要:
((100 * 4) + (32 * 3 * 4)) * 1_000_000 = 784000000 bytes (0.784GB)
。这与 FAISS 文档中提供的公式描述的内存消耗非常接近,但在某些情况下差异可能很有意义

© www.soinside.com 2019 - 2024. All rights reserved.