想象一下,试图在数百万个数据点的数字大海捞针。在人工智能和机器学习的世界中,选择正确的向量索引就像给自己配备一块磁铁——它不仅可以使搜索更快,而且可以更准确。无论您是在构建推荐系统、聊天机器人还是任何检索增强生成 (RAG) 应用程序,您选择的向量索引都会显著影响性能。那么,您如何做出正确的选择呢?让我们深入探讨一下。
什么是相似性搜索?
在深入研究向量索引之前,了解相似性搜索至关重要。相似性搜索旨在根据某些定义的标准或距离度量来查找与给定查询项目相似的项目。在机器学习中,这通常涉及比较表示数据点(如图像、文本嵌入或用户偏好)的高维向量。
什么是向量索引?
可以将向量索引视为高维数据的专用归档系统。就像图书馆索引可以帮助您在数千本书中快速找到一本书一样,向量索引可以帮助算法高效地检索相关数据。不同的向量索引技术针对内存使用量、搜索速度和准确性之间的各种权衡进行了优化。
热门向量索引概述
每种索引技术的性能高度依赖于数据集结构和参数配置。但是,它们确实具有一些共同的特征。AWS 发布了比较 HNSW 和 IVF-PQ 的基准测试,这两种索引经常用于生产应用程序。
下面,我们将探讨几种索引方法、它们的优缺点以及如何根据您的特定需求对其进行微调。
平缓指数
概述:
平面索引以简单、未改变的格式按原样存储向量 – 就像将所有文件保存在一个大文件夹中而没有任何组织一样。
工作原理:
- 搜索过程:在搜索过程中,算法计算查询向量与数据集中每个其他向量之间的距离。
- 无近似值:由于没有聚类或近似值,搜索结果非常准确。
[ 向量 1 ] - > [ 向量 2 ] - > [ 向量 3 ] - > ... - > [ 向量 N ]
所有向量都存储在单个平面列表中,没有任何分组或层次结构。
平面索引的优点:
- 高精度:由于搜索详尽,因此提供准确的结果。
- 简单:易于实现,无需任何复杂的配置。
平面索引的缺点:
- 搜索速度慢:不能很好地适应大型数据集;搜索时间随着向量的数量线性增加。
- 高内存使用率:存储所有向量而不进行任何压缩。
理想用例:
- 小型数据集,其中精确的结果至关重要,而搜索速度则不是问题。
倒排索引 (IVF)
概述:
倒排文件索引 (IVF) 是一种常用技术,它通过聚类缩小搜索范围,从而加快向量相似性搜索速度。IVF 不会将查询向量与数据集中的每个向量进行比较(如平面索引),而是将向量组织成簇(也称为“桶”或“质心”),从而显著减少搜索过程中的比较次数。
工作原理:
索引阶段(训练):
数据集聚类:
nlist
使用 k-means 等聚类算法将整个数据集划分为聚类。- 每个聚类由一个质心(聚类的平均向量)表示。
- 数据集中的每个向量都被分配到最近的质心,形成聚类。
将向量存储在簇中:
- 向量存储在倒排索引中,其中每个条目对应一个簇,并包含分配给该簇的向量列表。
+ --------- + + --------- + + --------- +
|簇| |簇| |簇|
| 1 | | 2 | ... | K |
+ ---- + ---- + + ---- + ---- + ---- + + ---- + ---- +
| | |
+ --------- + --------- + | + --------- + --------- + | | | | | | [向量] [向量] [向量] [向量] [向量] [向量] [向量] [向量] cs
向量被分配到簇中。在搜索过程中,只扫描相关的簇。
搜索阶段:
将查询分配给集群:
- 当查询向量到达时,它会被分配给其最近的质心。
- 搜索不是搜索整个数据集,而是在分配给最近聚类的向量内进行。
查询 向量 Q
|
+ -- 分配 给 最近的 质心
|
+ -- 选定的 簇(nprobe)
/ | \
簇 i 簇 j 簇 k
| | |
[向量] [向量] [向量]
| | |
计算 选定簇中向量的距离 |根据这些距离找到最近的邻居
试管受精的优点:
- 减少搜索时间:通过将搜索限制在集群的子集内,与平面索引相比,IVF 可显著加快查询速度。
- 可扩展性:比穷举搜索方法更适合大型数据集。
- 灵活性:通过调整
nlist
和nprobe
,您可以在速度和准确性之间取得平衡。
试管受精的缺点:
- 准确度降低:由于搜索仅限于选定的簇,因此可能会错过一些最近的邻居。
- 需要训练:聚类步骤需要训练数据和计算资源。
- 参数敏感性:性能取决于
nlist
和的仔细调整nprobe
。
影响搜索的参数:
nprobe
:搜索期间探测的簇的数量。- 通过搜索多个集群,您可以在搜索速度和准确性之间取得平衡。
参数调整:
选择nlist
:
- 一种常见的启发式方法是设置
nlist
与向量数量的平方根成比例(nlist ≈ √num_vectors
)。 - 对于
num_vectors = 1,000,000
,nlist
可能在 左右1,000
。
选择nprobe
:
- 从较小的数量开始
nprobe
(例如 1%nlist
),然后逐渐增加,直到达到可接受的召回率。 - 搜索速度和准确性之间存在权衡。
内存使用量估算:
可以使用以下公式估算 IVF 指数的内存要求:
内存 ≈ 1.1 * (((4 * d) * num_vectors) + (4 * nlist * d)) 字节
在哪里:
d
:向量维数num_vectors
:向量数量nlist
:聚类数
计算示例:
假设:
d = 128
(向量维度)num_vectors = 1,000,000
(向量数量)nlist = 10,000
(簇数)
代入数值:
内存≈ 1.1 * ( ( ( 4 * 128 ) * 1,000,000 ) + ( 4 * 10,000 * 128 ) )字节内存≈ 1.1 * ( ( 512 * 1,000,000 ) + ( 512 * 10,000 ) )字节内存≈ 1.1 * ( 512,000,000 + 5,120,000 )字节内存≈ 1.1 * 517,120,000字节内存≈ 568,832,000字节(约569 MB)
理想用例:
- 对于大型数据集,可以接受某种近似值来提高速度。
产品量化
概述:
乘积量化是一种强大的技术,可将高维向量压缩为紧凑的表示形式,从而显著减少内存使用量并加快搜索过程中的距离计算。与减少维数 ( d
) 的降维方法不同,乘积量化保留了原始维数,但通过量化向量空间压缩了每个维度内的数据。
工作原理:
索引阶段:
向量分裂:
- 将每个维度的原始向量
d
分成m
大小相等的子向量。 - 每个子向量的维度为
d' = d / m
。
子矢量量化:
- 对于每个子
m
向量组,都会创建一个单独的码本(质心集)。 - 这些质心是通过使用 k-means 等算法对子向量进行聚类而获得的。
- 每个子向量的质心数量为
k = 2^b
,其中b
是每个子向量分配的位数。
编码向量:
- 每个子向量都被其对应码本中最近的质心的索引所替换。
- 因此,原始向量由
m
质心索引表示。
压缩表示:
- 压缩矢量现在只需要
m * b
位。 - 这减少了内存要求并加快了距离计算。
原始 向量:[V1 | V2 | V3 | V4 | V5 | V6 | V7 | V8]
| | | | | | |
拆分 为 子向量:[V1 V2] [V3 V4] [V5 V6] [V7 V8]
| | | |
量化 子向量: C1 C2 C3 C4
每个向量被分成子向量,然后量化为质心(C1、C2 等)。
搜索阶段:
搜索过程中的距离计算:
在搜索过程中,为了计算查询向量Q
和数据库向量之间的近似距离V
,算法:
- 分割
Q
成m
子向量:Q = [Q1, Q2, ..., Qm]
- 对于每个子向量
Qi
,计算到相应码本中所有质心的距离。 - 预先计算大小的距离表
m x k
。 - 计算总距离作为和之间的距离之
Qi
和C_Vi
,其中是表示的第个子向量的C_Vi
质心。i
V
从数学上来说:
近似距离(Q, V) = Σ_{i= 1 }^m距离(Qi, C_Vi)
PQ的优点:
- 内存效率:通过使用紧凑代码表示向量,PQ 大大减少了内存消耗。
- 快速距离计算:利用预先计算的距离加速搜索过程。
- 可扩展性:适用于存储全精度向量不切实际的非常大的数据集。
PQ的缺点:
- 降低准确度:压缩会引入量化误差,从而可能降低搜索召回率。
- 实施复杂性:需要仔细调整参数(
m
,b
)并对码本进行适当的训练。 - 训练开销:构建代码本涉及聚类,这可能需要大量计算。
参数调整:
选择m
:
- 必須分
d
均。 - 较大的值
m
会增加量化的粒度,从而提高准确性,但也会增大码本的大小。
选择b
:
- 每个子向量的位数越多(
b
)越能提高准确性,但会增加压缩代码的内存使用量。 - 常见值为4、8位。
质心数量k
:
- 由 决定
k = 2^b
。 - 值越大
k
意味着质心越多,从而实现更精细的量化。
内存使用量估算:
存储压缩向量的内存要求:
内存 ≈ num_vectors * m * b / 8字节
计算示例:
鉴于:
num_vectors = 1,000,000
m = 16
b = 8
位
计算:
内存≈ 1,000,000 * 16 * 8 / 8字节内存≈ 1,000,000 * 16字节内存≈ 16,000,000字节(约16 MB )
与将原始 128 维向量存储在 32 位浮点数中相比,这是一个显著的减少:
内存(原始) = num_vectors * d * 4字节 内存
(原始) = 1,000,000 * 128 * 4字节内存(原始) = 512,000,000字节(约512 MB)
理想用例:
- 对于非常大的数据集,内存是一个重要的考虑因素,但可以接受一定的准确性损失。
分层可导航小世界图
概述
分层可导航小世界图 (HNSW) 是一种高效的基于图的索引方法,可为大规模近似最近邻搜索提供高精度和高速度。它构建了一个多层可导航小世界图,允许高效地遍历和检索最近邻。
工作原理
图形构建:
- 层: HNSW 构建了一个层次结构,其中每个较高层都是一个稀疏图,包含来自下层的节点子集。
- 连接:每个节点(数据点)根据接近度连接到同一层内的有限数量的其他节点(邻居)。
- 插入:添加新节点时,将其插入到几层中,直到概率确定的最大层。
- 可导航性:以图形展现小世界属性的方式建立连接,从而实现有效导航。
级别 3(顶层)
[入口点]
|
v
级别 2
[节点 A] --- [节点 B]
| |
v v
级别 1
[节点 C] --- [节点 D] --- [节点 E]
| | |
v v v
级别 0(底层)
[数据点 1] - [数据点 2] - .. .- [数据点 N]
向量被组织成多层。每个较高层都是一个更稀疏的图,有助于高效地导航到底层。
搜索过程:
- 起点:搜索从顶层的入口点节点开始。
- 贪婪搜索:在每一层,算法使用贪婪的方法移动到最接近查询向量的邻居节点。
- 层转换:一旦找到当前层的最近节点,搜索将继续到下一个较低层,并使用当前最近的节点作为新的起点。
- 最终搜索:在最低层,算法探索局部邻域以找到近似的最近邻。
[从顶层入口点开始]
|
v
[遍历到第 2 级最近的节点]
|
v
[遍历到第 1 级最近的节点]
|
v
[遍历到第 0 级最近的节点]
|
v
[探索邻域以查找最近邻居]
HNSW 的优势:
- 高精度:提供与精确方法相当的搜索结果。
- 搜索速度快:实现对数搜索时间复杂度。
- 无需训练:不需要像聚类那样的单独训练阶段。
HNSW 的缺点:
- 高内存使用率:图的附加连接消耗更多内存。
- 复杂性:与简单的索引方法相比,理解和实施更为复杂。
参数及其影响:
M
(每个节点的最大连接数):
- 控制图中每个节点的双向链接的数量。
- 更高的值
M
可以提高搜索的准确性,但会增加内存使用量和索引时间。
efConstruction
:
- 控制构建图形时考虑的邻居数量。
- 值越高,图形质量越好(准确度越高),但索引时间也会增加。
efSearch
:
- 控制搜索期间动态候选列表的大小。
- 较高的值可以提高召回率(准确度),但会延长搜索时间。
参数调整:
选择M
:
- 典型值范围是 5 至 48。
- 更高的
M
精度会增加,但也会提高内存使用量和索引时间。
环境efConstruction
:
- 通常设置在
100
和之间200
。 - 值越高,图形质量越高。
环境efSearch
:
- 应设置得高于
M
。 - 增加
efSearch
会提高召回率,但会牺牲搜索速度。
内存使用量估算:
可以使用以下方法估算 HNSW 索引的内存要求:
内存 ≈ 1.1 * (4 * d + 8 * M) * num _vectors 字节
在哪里:
d
:向量维数M
:每个节点的最大连接数num_vectors
:向量数量
计算示例:
假设:
d = 128
M = 16
num_vectors = 1,000,000
计算:
内存 ≈ 1.1 * (4 * 128 + 8 * 16) * 1,000,000字节
内存 ≈ 1.1 * (512 + 128) * 1,000,000 字节
内存 ≈ 1.1 * 640 * 1,000,000 字节
内存 ≈ 704,000,000 字节(约 704 MB)
理想用例:
- 大型数据集需要快速、准确的搜索,并且不太关心内存使用情况。
综合指数
向量索引是可组合的。可以组合多种索引技术,以在成本、速度或准确性方面取得可接受的权衡,实现所需的输出。
指数IVFFlat
将索引划分为多个存储桶。首先将给定的(查询)向量与存储桶匹配,然后在该存储桶中执行 IndexFlatL2 搜索。因此,搜索范围显著缩小,这意味着查询时间有所改善,但结果的准确性有所下降。由于此方法将向量聚类到多个存储桶中,因此需要额外的训练步骤。
+ --------- + + --------- + + --------- +
|簇| |簇| |簇|
| 1 | | 2 | ... | K |
+ ---- + ---- + + ---- + ---- + + ---- + ---- +
| | |
+ ------- + ------- + + ------- + ------- + + ------- + ------- + + ------- +
| | | | | | [平面索引] [平面索引] ... [平面索引]
[ 平面索引]
使用 IVF 对向量进行聚类,并在每个聚类内使用平面索引。
索引IVFPQ
与 IndexIVFFlat 类似,IndexIVFPQ 将索引划分为nlist
存储桶并使用 PQ 压缩向量。与 IndexFlatL2 相比,这可以缩短查询时间并减少内存消耗。但是,这会导致搜索准确率降低。此索引也需要训练。我们可以使用以下公式来计算 IVF-PQ 索引的内存需求:
1.1 * ((((m/8) * m + 每个向量的开销) * num_vectors) + (4 * nlist * d) + (2 m * 4 * d)
+ --------- + + --------- + + --------- +
|集群| |集群| |集群|
| 1 | | 2 | ... | K |
+ ---- + ---- + + ---- + ---- + + ---- + ---- +
| | |
+ ------- + ------- + + ------- + ------- + + ------- + ------- + + ------- +
| | | | | |
[PQ 压缩] [PQ 压缩] ... [PQ 压缩] [PQ 压缩]
使用 IVF 进行聚类并使用 PQ 进行聚类内压缩。
指数HNSW持平
HNSW 图存储在平面列表中(就像平面索引一样),没有其他向量压缩或量化。
HNSW 图层 | [平面指数]
HNSW 图是在平面索引上构建的,无需进行额外的压缩。
选择索引
选择指数主要是在以下四个因素之间进行权衡:
- 查询速度:您需要多快获得搜索结果。
- 准确率(召回率):搜索结果的质量。
- 内存使用情况:您愿意或能够使用的 RAM 数量。
- 索引时间:建立索引需要多长时间。
决策指南
如果结果准确(召回率 = 1.0):
- 用途:平面索引
- 时间:小型数据集,准确性至关重要。
如果 RAM 不是问题或数据集较小
- 用途: HNSW
- 调整:
m
并ef_search
进行速度与准确度的权衡。
如果 RAM 不是问题或数据集很大
- 使用: IVFPQ
- 调整:设置
nlist=1024
;调整m
,k_factor
用于 PQ,以及nprobe
用于 IVF。
如果担心 RAM:
- 用途: IVFFlat
- 调整:
nprobe
为了速度和准确度的权衡。
如果内存非常有限:
- 使用: PQ 技术或降维(例如 OPQ)
集群注意事项
对于每一种技术,添加聚类都可以改善搜索时间,但代价是增加索引时间。
对于少于 100 万个向量的数据集:
- 用途:体外受精
- 集合
K
:在4 * sqrt(N)
和之间16 * sqrt(N)
,其中N
是向量的数量,K
是IVF簇的数量。 - 所需训练向量: 30* K到 256* K个用于训练的向量(越多越好)。
对于 1M 到 10M 矢量之间的数据集:
- 使用方法: IVF 与 HNSW 结合。HNSW 进行集群分配。
- 设置
M
:32,其中M
是 HNSW 图中每个节点的最大连接数。 - 集合
K
: 65,536,其中K
是 IVF 簇的数量。 - 所需训练向量:
30 * 65,536
和向量之间256 * 65,536
用于训练。
对于 10M 到 100M 矢量之间的数据集:
- 使用方法: IVF 与 HNSW 结合。HNSW 进行集群分配。
- 设置
M
:32,其中M
是 HNSW 图中每个节点的最大连接数。 - 集合
K
:2¹⁸ = 262,144,其中K
是 IVF 簇的数量。 - 所需训练向量:
30 * 262,144
和向量之间256 * 262,144
用于训练。
对于 100M 到 1B 向量之间的数据集:
- 使用方法: IVF 与 HNSW 结合。HNSW 进行集群分配。
- 设置
M
:32,其中M
是 HNSW 图中每个节点的最大连接数。 - 集合
K
:2²⁰ = 1,048,576,其中K
是 IVF 簇的数量。 - 所需训练向量:
30 * 1,048,576
和向量之间256 * 1,048,576
用于训练。
常见问题 (FAQ)
问: 我是否需要一直训练我的指数?
答:不一定。像 HNSW 和 Flat Index 这样的指数不需要训练。但是,像 IVF 和基于 PQ 的指数这样的指数需要训练步骤来创建集群或量化质心。
问: 我如何在 HNSW 和 IVF-PQ 之间做出选择?
答:如果内存不是主要问题,并且您需要高精度和高速度,那么 HNSW 是一个不错的选择。如果您要处理非常大的数据集并且需要节省内存,那么 IVF-PQ 可能更合适。
问: 向量维数对索引性能有何影响?
答:更高的维度会增加内存使用量和计算复杂度。PQ 和降维等技术可以帮助解决这个问题。
结论
选择正确的向量索引是一项关键决策,它会显著影响应用程序的性能。通过了解每种索引技术的优势和局限性,您可以做出明智的选择,平衡速度、准确性、内存使用量和索引时间。
记住:
- 评估您的需求:了解您的数据集大小、维度和应用程序要求。
- 平衡权衡:决定什么更重要——速度、准确性还是内存。
- 实验和调整:使用参数来针对您的特定用例微调索引。
RA/SD 衍生者AI训练营。发布者:chris,转载请注明出处:https://www.shxcj.com/archives/6449