当前位置: 首页 > news >正文

文献分享: Vamana图算法以及面向SSD的DiskANN

原文章

1. \textbf{1. } 1. 写在前面

1.1. \textbf{1.1. } 1.1. 预备知识与文中标记

1️⃣最邻近查询问题:

  1. 精确最邻近( k -NN k\text{-NN} k-NN):
    • 含义:在数据库 P P P中,找到离查询点 q q q最近的 k k k个点
    • 瓶颈:由于维度诅咒的存在, k -ANN k\text{-ANN} k-ANN无法突破线性暴力扫描,故引入近似最邻近查询
  2. 近似最邻近( k -ANN k\text{-ANN} k-ANN):
    • 含义: k -NN k\text{-NN} k-NN Recall<100% \text{Recall<100\%} Recall<100%版本,需要在检索速度和 Recall \text{Recall} Recall中权衡
    • 一些针对 k -ANN k\text{-ANN} k-ANN的索引
      算法优点缺点
      k-d Tree \text{k-d Tree} k-d Tree索引空间小,低维下表现良好维度大于 20 \text{20} 20时性能急剧下降
      LSH \text{LSH} LSH最坏情况下有理论保障无法利用数据分布
      图类( HNSW/NSG \small\text{HNSW/NSG} HNSW/NSG)高维度下表现良好索引(图)构建极其耗时

2️⃣其它预备知识

  1. 倒排索引( Inverted Index \text{Inverted Index} Inverted Index):用于快速全文检索的数据结构,示例如下
    • 文档
      Doc1: fat cat rat rat 
      Doc2: fat cat 
      Doc3: fat
      
    • 构建的倒排索引
      fat: Doc1 Doc2 Doc3
      cat: Doc1 Doc2
      rat: Doc1
      
  2. 查询性能指标:
    • m -recall@ n = ∣ A ∩ B ∣ ∣ A ∣ = ∣ A ∩ B ∣ m m\text{-recall@}n=\cfrac{|A\cap{}B|}{|A|}=\cfrac{|A\cap{}B|}{m} m-recall@n=AAB=mAB
    • 其中 A = A\text{=} A=查询点真实的前 m m m个最邻近集合, B = B\text{=} B=算法返回的前 n n n个结果集合
  3. 中位数结点( Medoid \text{Medoid} Medoid):数据集中,到所有其它点平均距离最小的点
  4. PQ \text{PQ} PQ算法原理: M \text{M} M维原始向量 → 分割 \xrightarrow{分割} 分割 N \text{N} N M N \cfrac{\text{M}}{\text{N}} NM维子向量 → ( 寻求每个子向量最近的质心Index ) 向量量化 \xrightarrow[(寻求每个子向量最近的质心\text{Index})]{向量量化} 向量量化 (寻求每个子向量最近的质心Index) N \text{N} N维短代码(向量)

3️⃣本文符号表示

符号含义与备注
P P P数据集(点集),点集规模用$
G = ( P , E ) G\text{=}(P, E) G=(P,E)有向图,顶点集为 P P P边集为 E E E
N out  ( p ) N_{\text {out }}(p) Nout (p)查询点 p p p的出边集合
x p \mathbf{x}_p xp查询点 p p p的向量表示
d ( p , q ) d(p, q) d(p,q)查询点 p p p q q q之间的欧氏距离

1.2. \textbf{1.2. } 1.2. 关于大规模索引:本文的背景与研究

1️⃣大规模数据的索引:在十亿级个点中找最邻近,主要有以下两种方法

  1. 倒排索引 + \text{+} +数据压缩: FAISS \small\text{FAISS} FAISS( TBDATA’19 \small\text{TBDATA'19} TBDATA’19), IVFOADC+G+P \small\text{IVFOADC+G+P} IVFOADC+G+P (ECCV’18) \small\text{(ECCV'18)} (ECCV’18)
    • 方法概述:
      方法含义
      数据分区将数据库点分为多个分区,查询最邻近时只考虑查询点附近几个分区
      数据压缩即产品量化,原始高维向量 → 每个子向量量化成低维 分为多个低维子向量 \xrightarrow[每个子向量量化成低维]{分为多个低维子向量} 分为多个低维子向量 每个子向量量化成低维低维向量
    • 硬件性能:占用内存较小(十亿点索引后小于 64GB \text{64GB} 64GB) + \text{+} +可利用 GPU \text{GPU} GPU加速压缩后的数据
    • 查询性能:对于 1-recall@ k \text{1-recall@}k 1-recall@k k =1 k\text{=1} k=1时较低 k =100 k\text{=100} k=100时较高
  2. 分片( Shard \text{Shard} Shard)法: MRNG \small\text{MRNG} MRNG (VLDB’19) \small\text{(VLDB'19)} (VLDB’19)
    • 索引构建:分割数据为多片 → \to 为每片构建索引(并加载到内存中),其中数据维度并未压缩
    • 查询流程:查询请求发给每片/特定几片 → \to 相应片执行查询 → \to 排序合并各片查询结果
    • 性能:由于未压缩故占用内存较大,但也正因此查询精准度更高,扩展成本极大

2️⃣大规模索引的难题:物理化 RAM or SSD \text{RAM or SSD} RAM or SSD

  1. 目前 ANN \text{ANN} ANN算法的索引都存储在 RAM \text{RAM} RAM中,可实现高速存取但存储空间贵
  2. ANN \text{ANN} ANN索引放在 SSD \text{SSD} SSD的尝试:
    • SSD \text{SSD} SSD的读取延时比 RAM \text{RAM} RAM高出几个数量级,对查询性能是灾难性的
    • 改进途径在于,减少每次查询所需读取 SSD \textbf{SSD} SSD磁盘的次数

3️⃣本文对大规模索引的贡献:提出依托图算法 Vamana \text{Vamana} Vamana DiskANN \text{DiskANN} DiskANN,使 SSD \text{SSD} SSD也能支持大规模 ANN \text{ANN} ANN

  1. 关于 Vamana \text{Vamana} Vamana图算法:
    • 生成图索引直径远小于 NSG/HNSW \small\text{NSG/HNSW} NSG/HNSW → { 若放内存中 : 性能优于HNSW/NSG 若放磁盘中 : 减少DiskANN访问磁盘次数 \to\begin{cases}若放内存中:性能优于\text{HNSW/NSG}\\\\若放磁盘中:减少\text{DiskANN}访问磁盘次数\end{cases} 若放内存中:性能优于HNSW/NSG若放磁盘中:减少DiskANN访问磁盘次数
    • 为分割后的每个(重叠)数据分区构建 Vamana \small\text{Vamana} Vamana索引再合并成大索引,与不分割暴力构建性能相当
    • Vamana \text{Vamana} Vamana图构建可与 PQ \text{PQ} PQ结合 → { 放内存中的 : 压缩向量 放磁盘中的 : 全精度向量+构建的图索引 \to\begin{cases}放内存中的:压缩向量\\\\放磁盘中的:全精度向量\text{+}构建的图索引\end{cases} 放内存中的:压缩向量放磁盘中的:全精度向量+构建的图索引
  2. 关于 DiskANN \text{DiskANN} DiskANN的实际表现:
    • 条件: 64GB \text{64GB} 64GB内存,十亿个百维数据点
    • 性能: 1-recall@1=95 % \text{1-recall@1=95}\% 1-recall@1=95%并且 Latency<5ms \text{Latency<5ms} Latency<5ms

2. \textbf{2. } 2.  Vamana \small\textbf{Vamana} Vamana图构建算法

2.1. \textbf{2.1. } 2.1.  ANN \textbf{ANN} ANN图算法: 构建/剪枝/查询

1️⃣图查询算法:贪心搜索 GreedySearch ( s , x q , k , L ) \text{GreedySearch} \left(s, \mathrm{x}_q, k, L\right) GreedySearch(s,xq,k,L)

image-20241019000253117

2️⃣图构建与剪枝算法

  1. 图构建算法:稀疏邻居域图 SNG \text{SNG} SNG (SODA’93) \text{(SODA'93)} (SODA’93),对 ∀ p ∈ P \forall{}p\text{∈}P pP按照以下方法确定出边
    image-20241018003422968
    • 目的:使 GreedySearch \text{GreedySearch} GreedySearch算法能从任意点快速收敛到最邻近的充分条件
    • 缺陷:构建时间复杂度为 O ( n 2 ) + {O(n^2)}+ O(n2)+生成图在直径/密度上无灵活性
  2. 图剪枝算法:健壮性剪枝 RobustPrune ( p , R , α , L ) \text{RobustPrune}(p, R, \alpha, L) RobustPrune(p,R,α,L)
    图片4
    • 目的:构建稀疏图(避免冗余连接) + + +保持连通性
    • 关于剪枝条件:对于 p p p,如果可以通过其最邻近 p ∗ p^* p快速到达 p ′ p{'} p,那么就没必要直连 p p p p ′ p{'} p

2.2. Vamana \textbf{2.2. Vamana} 2.2. Vamana

1️⃣ Vamana \text{Vamana} Vamana的提出的背景

  1. 贪心搜索:算法从初始点 → 接近 \xrightarrow{接近} 接近 最邻近的距离递减模式
    图结构距离递减模式磁盘读取示例
    传统 SNG \text{SNG} SNG逐步线性缓慢减少高频D → D-d → D-2d →...→ 0
    RobustPrune \text{RobustPrune} RobustPrune按以 α >1 \alpha\text{>1} α>1的指数快速收敛低频D → D/α → D/α² →...→ 0
  2. 全局候选集的剪枝: RobustPrune ( p , P \ { p } , α , ∣ P ∣ − 1 ) \text{RobustPrune}(p, P \backslash\{p\}, \alpha, |P|-1) RobustPrune(p,P\{p},α,P1),其中 ∣ P ∣ = n |P|=n P=n
    • 含义:考虑所有的结点可作为 p p p的潜在出邻居
    • 性能:可使 GreedySearch ( s , p , 1 , 1 ) \text{GreedySearch}(s, p, 1,1) GreedySearch(s,p,1,1) O ( log ⁡ n ) O(\log n) O(logn)事件内收敛到 p p p,但构建复杂度高达 O ( n 2 ) O(n^2) O(n2)
  3. Vamana \text{Vamana} Vamana改进思路:将候选集大小由 n − 1 n-1 n1缩小至 O ( log ⁡ n ) O(\log{}n) O(logn) O ( 1 ) O(1) O(1),使构建复杂度降到 O ( n log ⁡ n ) O(n\log{}n) O(nlogn)

2️⃣ Vamana \text{Vamana} Vamana索引算法

  1. 算法输入:
    类型备注
    数据集 P P P为数据集(用于构建图 G G G),含 n n n个数据点(第 i i i点的坐标为 x i \mathrm{x}_i xi)
    参数 α \alpha α为距离阈值(控制剪枝), L L L为列表大小(控制搜索广度), R R R为结点出度限制
  2. 算法流程:
    图片6
    • 添加反向边的意义:确保访问集 V V V中所有点都可与 p p p连接,使后续搜索可快速收敛到 p p p
    • 算法需两次遍历:令 α = 1 \alpha{}\text{=}1 α=1初步构建一次(确保连通) + + + α > 1 \alpha{}\text{>}1 α>1(用户定义)再构建一次(优化收敛)

3️⃣ Vamana/HNSW/NSG \text{Vamana/HNSW/NSG} Vamana/HNSW/NSG的对比

  1. 共同:都是用 GreedySearch ( s , p , 1 , L ) \text{GreedySearch}\left(s, \mathcal{p}, 1, L\right) GreedySearch(s,p,1,L) RobustPrune ( p , V , α , R ) \text{RobustPrune}(p, \mathcal{V}, \alpha, R) RobustPrune(p,V,α,R)来确定 p p p邻居
  2. 不同:
    不同点 Vamana \text{Vamana} Vamana HNSW \text{HNSW} HNSW NSG \text{NSG} NSG备注
    α \alpha α可调❌( α = 1 \alpha\text{=}1 α=1)❌( α = 1 \alpha\text{=}1 α=1)使 Vamana \small\text{Vamana} Vamana可很好权衡度数和直径
    剪枝 V \mathcal{V} V G S \small{}GS GS访问集 G S \small{}GS GS结果集 G S \small{}GS GS访问集使 Vamana/NSG \small\text{Vamana/NSG} Vamana/NSG有长距边(无需层次)
    初始图随机图空图近似 k -NN \small{}k\text{-NN} k-NN随即图质量高于空且成本远低于 k -NN \small{}k\text{-NN} k-NN
    遍历两次一次一次基于观察,二次遍历可以提高图的质量

3. DiskANN \textbf{3. DiskANN} 3. DiskANN总体设计: 索引 & \& &搜索

3.0. \textbf{3.0. } 3.0. 概览

1️⃣ DiskANN \text{DiskANN} DiskANN总体工作流程

  1. 索引构建:将数据集 P P P加载入内存 → \to P P P上运行 Vamana \text{Vamana} Vamana → \to 将生成图存储在 SSD \text{SSD} SSD
  2. 查询方式:从 SSD \text{SSD} SSD加载图信息到内存 → \to 获取邻居信息 + + +计算/比较距离 → \to 迭代搜索

2️⃣ DiskANN \text{DiskANN} DiskANN索引布局

介质每点存储每边(图结构)存储
内存压缩向量 NULL \text{NULL} NULL
SSD \text{SSD} SSD原始向量存储每点定长 R R R的邻居标识(邻居 < R \text{<}R <R时补 0 0 0)
  1. 关于定长邻居标识:
    • 使得 SSD \text{SSD} SSD对每点的存储(全精度向量 + + +邻居标识)都是定长的
    • 遍历了偏移的计算( OffSet i = i ×FixedSize \text{OffSet}_{i}=i\text{×FixedSize} OffSeti=i×FixedSize),无需再在内存中存储偏移信息
  2. SSD \text{SSD} SSD存储的扇结构
    • 将一点定长的全精度向量 + + +邻居标识 ↔ 统一放在 \xleftrightarrow{统一放在} 统一放在 一个扇区中对齐(如 4KB \text{4KB} 4KB)
    • SSD \text{SSD} SSD的读取以扇为单位,比如读取某点邻居信息时 → \to 必定能同时获取该点全精度向量

3.1. \textbf{3.1. } 3.1. 索引构建设计: 面向内存空间的优化

1️⃣存在的问题:

  1. 构建过程需先将数据点向量载入内存
  2. 一股脑将全部数据暴力载入内存将导致内存过载

2️⃣构建优化:将数据集 P P P进行重叠分簇

  1. 步骤:
    • 划分:用 k -means k\text{-means} k-means P P P分为多干簇(每簇有一中心),再将 P P P所有点分给 ℓ > 1 \ell\text{>}1 >1个中心以构成重叠簇
    • 索引:在每个重叠簇中执行 Vamana \text{Vamana} Vamana算法,构建相应有向边
    • 合并:将所有构建的有向边合并在一个图中,完成构建
  2. 重叠分簇:为了保证图的连通性,以及后续搜索的 Navigable \text{Navigable} Navigable

3.2. \textbf{3.2. } 3.2. 查询方法设计

3.2.1. \textbf{3.2.1. } 3.2.1. 查询方法设计: 面向减少 SSD \textbf{SSD} SSD访问的优化

1️⃣ BeamSearch \text{BeamSearch} BeamSearch算法

  1. 算法流程: BeamSearch \text{BeamSearch} BeamSearch GreedySearch \text{GreedySearch} GreedySearch
    wrfebargsh
  2. 优化原理:
    • 一次性获取多点的邻居信息,有助于减少访问 SSD \text{SSD} SSD的频次
    • SSD \text{SSD} SSD获取多个(但少量)随机扇区,与获得一个扇区所需时间几乎相同
  3. 带宽参数 W \text{W} W
    • 含义: BeamSearch \text{BeamSearch} BeamSearch一次性获取 W W W个结点( p ∗ p^* p及其 W - 1 W\text{-}1 W-1个邻居)的邻居信息
    • 选取:当 W W W增加时吞吐量增加 + + +延时会因 IO \text{IO} IO饱和而恶化, Trade-Off \text{Trade-Off} Trade-Off实验结果如下
      W W W大小对性能的影响
      W = 1 W=1 W=1 BeamSearch \text{BeamSearch} BeamSearch退化为 GreedySearch \text{GreedySearch} GreedySearch
      W = 2 , 4 , 8 W=2,4,8 W=2,4,8可在延迟和吞吐量之间取得良好平衡
      W > 16 W>16 W>16容易导致 IO \text{IO} IO队列饱和从而增加延时

2️⃣ DiskANN \text{DiskANN} DiskANN缓存

  1. 原理:将 SSD \text{SSD} SSD中一部分结点缓存到 DRAM(Cache) \text{DRAM(Cache)} DRAM(Cache)中,以超高速访问并避免访问 SSD \text{SSD} SSD
  2. 缓存策略:
    • 基于已知的查询分布
    • s s s开始在 C = 3 , 4 C\text{=}3,4 C=3,4跳的结点 (节点数随 C C C指数增长 → C \text{→}C C不宜太大)

3.2.2. \textbf{3.2.2. } 3.2.2. 查询方法设计: 面向内存空间的优化

1️⃣存在的问题:

  1. 查询过程需先将 SSD \text{SSD} SSD中存储的图结点(向量)载入内存
  2. 全精度向量暴力载入内存会导致内存过载

2️⃣查询优化:使所有结点能放进内存

  1. PQ \text{PQ} PQ将所有 p ∈ P p\text{∈}P pP(以及查询点)压成低维 x p ~ \widetilde{x_p} xp 并载入内存
  2. 查询时对比近似距离 d ( x p ~ , x q ) d\left(\widetilde{x_p}, \mathrm{x}_q\right) d(xp ,xq)

3️⃣隐式重排( Implicit Re-Ranking \text{Implicit Re-Ranking} Implicit Re-Ranking):对一部分点进行全精度距离计算的隐式方法

  1. 原理: BeamSearch \text{BeamSearch} BeamSearch缓存结点邻居时也会缓存其全精度向量 → \to 可精确返回离 q q q最近的 L L L个候选点
  2. 思考:这正是有必要在 SSD \textbf{SSD} SSD中存放全精度向量的原因

4. \textbf{4. } 4. 评估与对比

1️⃣ HNSW/NSG/Vamana \text{HNSW/NSG/Vamana} HNSW/NSG/Vamana In-Memory \text{In-Memory} In-Memory搜索性能​评估

  1. 实验设置
    item \textbf{item} item设置备注
    数据集 SIFT1M/GIST1M/DEEP1M \text{SIFT1M/GIST1M/DEEP1M} SIFT1M/GIST1M/DEEP1M高维/百万数量级数据集
    物理实现数据都完全加载到内存中 Vamana \text{Vamana} Vamana也在内存(而非 SSD \text{SSD} SSD)上实现
  2. 实验结果(相同延迟下 Recall \text{Recall} Recall更高者视为更好):
    • 所有情况下 NSG \text{NSG} NSG Vamana \text{Vamana} Vamana好于 HNSW \text{HNSW} HNSW,在最高维数据上 Vamana \text{Vamana} Vamana性能最佳
    • Vamana \text{Vamana} Vamana索引构建时间最快

2️⃣ HNSW/NSG/Vamana \text{HNSW/NSG/Vamana} HNSW/NSG/Vamana的跳数( Hops \text{Hops} Hops)评估

  1. 跳数:搜索关键路径上磁盘读取的轮次数,直接影响搜索延时
  2. 实验结果:
    • Vamana \text{Vamana} Vamana可大幅减少跳数(从而快速收敛),尤其在高维数据上
    • 随着 α \alpha α和最大出度的增加 Vamana \text{Vamana} Vamana跳数会减少,而 NSG/HNSW \text{NSG/HNSW} NSG/HNSW的基本不变

3️⃣ HNSW/NSG/Vamana \text{HNSW/NSG/Vamana} HNSW/NSG/Vamana在十亿级数据上的评估

  1. 两种 Vamana \text{Vamana} Vamana算法:
    • 单一 Vamana \text{Vamana} Vamana:将十亿级数据整块载入内存暴力构建
    • 合并 Vamana \text{Vamana} Vamana:将十亿级数据进行(重叠)分簇 → \to 每簇分别构建 → \to 合并
  2. 实验结果
    • 单一索引的性能优于合并索引,这源于合并索引需要遍历更多结点才能找到相同邻域
    • 合并索引也超过了其它算法,故可认为合并索引更能权衡内存 ↔ \xleftrightarrow{} 性能

4️⃣ IVF-based \text{IVF-based} IVF-based方法 /Vamana \text{/Vamana} /Vamana在十亿级数据上的评估

  1. 关于 FAISS \text{FAISS} FAISS:由于其性能劣于 IVFOADC+G+P \text{IVFOADC+G+P} IVFOADC+G+P以及需要 GPU \text{GPU} GPU构建索引,故忽略
  2. 对于 IVFOADC+G+P \text{IVFOADC+G+P} IVFOADC+G+P:分别使用 16/32 \text{16/32} 16/32字节的 OPQ \text{OPQ} OPQ码本构建, IVFOADC+G+P-32 \text{IVFOADC+G+P-32} IVFOADC+G+P-32性能更优
  3. 对于 DiskANN \text{DiskANN} DiskANN:在与 IVFOADC+G+P-32 \text{IVFOADC+G+P-32} IVFOADC+G+P-32相同内存占用下比较,性能远优

http://www.mrgr.cn/news/54535.html

相关文章:

  • Resources的资源加载管理器
  • 来自骨关节炎计划的膝关节MR图像的自动异常感知3D骨骼和软骨分割|文献速递-基于生成模型的数据增强与疾病监测应用
  • 深度解析机器学习的四大核心功能:分类、回归、聚类与降维
  • 点菜问题(北京大学考研机试题01背包)
  • 数据结构7——二叉树的顺序结构以及堆的实现
  • 什么是大数据分析:定义、优缺点、应用、机遇和风险
  • 第五届机器学习与计算机应用国际学术会议(ICMLCA 2024)
  • Leetcode 1926. 迷宫中离入口最近的出口
  • 数据库产品中审计与日志(Auditing and Logging)的功能简介
  • 计算机指令系统,打个结~
  • 【电子电力】三相逆变器下垂控制单机并离网,并网预同步
  • XGO Rider:全球首创双轮足AI机器人,集成ChatGPT,实现智能互动
  • 基于SSM汽车零部件加工系统的设计
  • 28——循环结构之累加应用(配套练习后续更新~~~~~)
  • 使用 F5-TTS 生成指定人物的声音:一步步指南
  • 国产AI模型“Yi-Lightning”逆袭超越GPT-4!
  • 使用函数制作一个简易的计算机
  • Python学习的自我理解和想法(17)
  • 巴西税收政策及主要税收
  • 诺贝尔物理学奖与机器学习、神经网络:一场跨时代的融合与展望
  • 【YOLO目标检测道路破损检测数据集】共665张、已标注txt格式、有训练好的yolov5的模型
  • PPT自动化:掌握 python-pptx 的基础元素
  • iOS -- 代码优化
  • 多IP访问多网段实验
  • 12、论文阅读:SpikeYOLO:高性能低能耗目标检测网络
  • 靠卡车赚钱,小马智行等待Robotaxi的春天