👉前情提要:
- 神经网络自然语言模型概述
- Transformer \text{Transformer} Transformer与注意力机制概述
📚相关论文:
-
BERT: Pre-training of Deep Bidirectional Transformers for Language Understanding
\text{BERT: Pre-training of Deep Bidirectional Transformers for Language Understanding}
BERT: Pre-training of Deep Bidirectional Transformers for Language Understanding
- 提出了基于双向深度 Transformer \text{Transformer} Transformer的 BERT \text{BERT} BERT交叉编码器
- BERT \text{BERT} BERT的总结
-
ColBERT: Efficient and Effective Passage Search via Contextualized Late Interaction over BERT
\text{ColBERT: Efficient and Effective Passage Search via Contextualized Late Interaction over BERT}
ColBERT: Efficient and Effective Passage Search via Contextualized Late Interaction over BERT
- 提出了基于 BERT \text{BERT} BERT编码的后期 Token \text{Token} Token级交互模式
- ColBERTv1 \text{ColBERTv1} ColBERTv1的总结
-
ColBERTv2: Effective and Efficient Retrieval via Lightweight Late Interaction
\text{ColBERTv2: Effective and Efficient Retrieval via Lightweight Late Interaction}
ColBERTv2: Effective and Efficient Retrieval via Lightweight Late Interaction
- 保留了 ColBERT \text{ColBERT} ColBERT的后期交互架构,但从训练策略 / / /嵌入压缩 / / /数据集上优化
- ColBERTv2 \text{ColBERTv2} ColBERTv2的总结
-
PLAID: An Efficient Engine for Late Interaction Retrieval
\text{PLAID: An Efficient Engine for Late Interaction Retrieval}
PLAID: An Efficient Engine for Late Interaction Retrieval
- 在 ColBERTv2 \text{ColBERTv2} ColBERTv2的基础上,进一步改进了检索策略
- PLAID \text{PLAID} PLAID的总结
-
EMVB: Efficient Multi-Vector Dense Retrieval Using Bit Vectors
\text{EMVB: Efficient Multi-Vector Dense Retrieval Using Bit Vectors}
EMVB: Efficient Multi-Vector Dense Retrieval Using Bit Vectors
- 在 PLAID \text{PLAID} PLAID的基础上,更进一步改进了检索策略
- EMVB \text{EMVB} EMVB的总结
文章目录
1. \textbf{1. } 1. 背景与导论
1.1. \textbf{1.1. } 1.1. 研究背景
1️⃣ IR \text{IR} IR领域的背景
进展 描述 LLM(BERT/GPT) \text{LLM(BERT/GPT)} LLM(BERT/GPT)的引入 有强大的语义(上下文)学习能力,可学习查询 / / /文档的稠密高维表示 多向量技术的发展 对词一级构建密集表示,相比稀疏(词袋) / / /单向量模型能效果更好 后期交互机制的提出 多向量系统中相对轻量级的相似度计算,但其 MaxSim \text{MaxSim} MaxSim仍较耗时 2️⃣后期交互机制的进展
模型 描述 ColBERTv1 \text{ColBERTv1} ColBERTv1 首次提出了后期交互模型,相比交叉编码器大幅降低了计算量,但内存要求极高 ColBERTv2 \text{ColBERTv2} ColBERTv2 改进了 ColBERT \text{ColBERT} ColBERT的训练策略(去噪 + + +硬负样本),嵌入存储上并使用了残差压缩 PLAID \text{PLAID} PLAID 改进了检索策略,提出了基于质心交互的文档预选 1.2. \textbf{1.2. } 1.2. 本文的工作
1️⃣对 PLAID \text{PLAID} PLAID的进一步分析:识别查询过程中最耗时的步骤
- 候选生成阶段:源于需要提取所有查询 Token \text{Token} Token的前 t t t接近的质心
- 质心交互阶段:核心步骤
- 评分重排阶段:源于解压得到最终候选段落的完整嵌入很耗时
2️⃣ EMVB \text{EMVB} EMVB的优化思路
所针对的阶段 所采取的优化 候选生成 引入基于优化位向量的高效文档过滤方法,提取出更少更精的质心 质心交互 引入一种高效列式降维方法,并用 SIMD(Single-Inst. Multi-Data) \text{SIMD(Single-Inst. Multi-Data)} SIMD(Single-Inst. Multi-Data)指令来加速 质心交互 用 PQ \textbf{PQ} PQ压缩替代原有残差的按位压缩,降低空间占用 评分重排 引入一种动态文档 –Token \textbf{–Token} –Token选择标准 3️⃣对 EMVB \text{EMVB} EMVB性能的评估
- 域内评估:较之 PLAID \text{PLAID} PLAID在无检索精度损失的情况下,查询快了 2.8 2.8 2.8倍 / / /内存缩小了 1.8 1.8 1.8倍
- 域外评估:在最多 2.9 \text{2.9} 2.9倍的检索加速下,检索精度的 Trade-Off \text{Trade-Off} Trade-Off最小
2. \textbf{2. } 2. 对 PLAID \textbf{PLAID} PLAID的进一步分析
2.1. \textbf{2.1. } 2.1. 对 PLAID \textbf{PLAID} PLAID的回顾
1️⃣压缩操作:以 t ~ = C t + r ~ \tilde{t}\text{=}C_t\text{+}\tilde{r} t~=Ct+r~形式表示完整(解压)的嵌入
阶段 操作 聚类 对所有文档的所有嵌入组成的空间执行聚类,每个嵌入 t t t分配到其最近的质心 C t C_t Ct 编码 计算每个嵌入的 t t t的残差 r = t – C t r\text{=}t\text{–}C_t r=t–Ct,并将其近似量化编码为 r ~ ≈ t – C t \tilde{r}\text{≈}t\text{–}C_t r~≈t–Ct 2️⃣查询操作:在将查询 q q q的原始文本编码为嵌入向量集合后,可分为四个阶段
阶段概览 目的 候选生成 通过质心计算初步筛选潜在相关段落,生成初始候选集 段落过滤 候选集 → 质心剪枝 \xrightarrow{质心剪枝} 质心剪枝剩下与查询相关性高的质心 → 轻量级相似度 质心交互 + 初排 \xrightarrow[轻量级相似度]{质心交互+初排} 质心交互+初排轻量级相似度最终的候选段落 残差解压 对最终的候选段落进行解压,得到其全精度的嵌入表示 评分重排 计算 MaxSim \text{MaxSim} MaxSim与得分,随后重排以得到最相似文本 2.2. \textbf{2.2. } 2.2. 对 PLAID \textbf{PLAID} PLAID检索延迟的分解
1️⃣整体上:候选生成 + + +段落过滤最为耗时
![]()
2️⃣ PLAID \text{PLAID} PLAID候选生成步:进一步的细节 & \& &延迟分解
- 具体步骤:
步骤 描述 耗时 查询输入 查询矩阵 Q Q Q(所有 Token \text{Token} Token的嵌入向量) + + +质心列表矩阵 C C C(所有质心的向量) 低 得分计算 直接计算 S c , q = C ⸱ Q T S_{c,q}\text{=}C\text{⸱}Q^{T} Sc,q=C⸱QT,其中 S c , q [ i ] [ j ] S_{c,q}[i][j] Sc,q[i][j]是质心 c i c_i ci与查询词元 q j q_j qj的相关性得分 中 质心排序 对每个 q j q_j qj选取排名前 t nprobe t_{\text{nprobe}} tnprobe个质心 高 质心候选 合并所有 q q q的质心选集为最终候选质心集 C ′ C^{\prime} C′ 低 段落候选 若一个段落中存在 q q q被聚类到(属于) C ′ C^{\prime} C′,则将该段落候选之 低 - 分析 & \& &思路:
- PLAID \text{PLAID} PLAID方案:在质心排序时,执行到每个 q j q_j qj时都需要对全体质心
quickselect
,极其耗时- 优化思路:减少参与排序的质心数量,故而引入一种基于阈值( t h t_h th)的质心过滤方法(见下)
3. EMVB \textbf{3. EMVB} 3. EMVB的优化
3.1. \textbf{3.1. } 3.1. 质心交互前: 优化候选段落的预过滤
3.1.1. \textbf{3.1.1. } 3.1.1. 预过滤的整体逻辑
1️⃣有关数据结构
- 近似得分 T ~ i , j \tilde{T}_{i, j} T~i,j:查询 Q Q Q第 i i i个词 q i ↔ 近似得分 q_i\xleftrightarrow{近似得分} qi近似得分 段落 P P P第 j j j个词 T j T_j Tj(实际用 T j T_j Tj的最近质心 C ˉ T j \bar{C}^{T_j} CˉTj代之)
- 质心集:
结构 含义 最近质心集 close i t h \text{close}_i^{th} closeith 包含所有与 q i q_i qi的得分大于阈值 t h th th (threshold) \text{(threshold)} (threshold)的质心 质心 ID \text{ID} ID列表 I P I_P IP 文档 P P P中所有 Token \text{Token} Token的最近质心 ID \text{ID} ID的集合,比如 I P j I_P^j IPj即为 T j T_j Tj最近质心 2️⃣段落过滤原理
- 评分(过滤)函数:
- 表示:[段落 ↔ 相似度 \xleftrightarrow{相似度} 相似度 查询]表示为 F ( P , q ) = ∑ i = 1 n q 1 ( ∃ j s.t. I P j ∈ close i t h ) \displaystyle{}F(P, q) \text{=} \sum_{i=1}^{n_q} \mathbf{1}\left(\exists j \text{ s.t. } I_P^j \text{∈} \text{ close }_i^{t h}\right) F(P,q)=i=1∑nq1(∃j s.t. IPj∈ close ith)
- 逻辑:计算有多少个 q i q_i qi,在 P \text{}P P中有至少有一个相似的 T j T_j Tj(相似即 T j T_j Tj的 I P j ∈ close i t h I_P^j\text{∈}\text{close}_i^{th} IPj∈closeith)
double F_Score = 0; // 遍历查询q的每个词q_i for(int i = 1; i < 查询q的词数; i++) { set<int> close_i_th = q_i的相似质心集合close_i_th; // 遍历文档P的每个词T_j for(int j = 1; j < 文档P的词数; j++) { int I_P_j = T_j的最近质心I_P_j; if(I_P_j.is_in(close_i_th)) { F_Score++; break; // 每个q_1最多只能贡献一分,所以必须break } } }
- 候选生成:根据评分函数将所有段落排序,截取前若干者为过滤所得段落
3️⃣与质心过滤的对比:
![]()
- 橙 / / /绿 / / /蓝线:本文的方法能高效丢弃无关段落
- 红线:剔除本文过滤方法的基线性能,说明本文方法不影响后续质心交互
3.1.2. \textbf{3.1.2. } 3.1.2. 预过滤的实现细节
3.1.2.1. close i t h \textbf{3.1.2.1. }\textbf{close}\boldsymbol{_i^{th}} 3.1.2.1. closeith的计算优化
1️⃣ close i t h \text{close}_i^{th} closeith计算在概念上的实现
- 遍历计算:计算 q i q_i qi与所有质心 C j C_j Cj的得分(内积) C S i , j → 归一化 组合 C S_{i, j}\xrightarrow[归一化]{组合} CSi,j组合归一化得分矩阵 C S C S CS
- 阈值筛选:对于给定的阈值 t h th th收集所有 C S i , j > t h C S_{i, j} \text{>} t h CSi,j>th的质心的索引 j → close i t h j\text{→}\text{close}_i^{th} j→closeith
2️⃣ close i t h \text{close}_i^{th} closeith计算在机器上的朴素
if
实现
- 基本流程:
set<int> close_i_th; for(int i = 1; i < CS行数; i++) // 遍历每个查询 { for(int j = 1; j < CS列数; j++) // 对每个查询, 遍历所有的质心 { if CS[i][j] > threshold; { close_i_th.include(j) // 将质心索引添加到集合中 } } }
- 缺点分析:每次判断都需要引入
if
语句,实际上这会给 CPU \text{CPU} CPU带来大量的分支预测错误3️⃣基于朴素
if
方法的优化
- SIMD \text{SIMD} SIMD向量化加速:一次性处理一批( 16 \text{16} 16个)个 q i q_i qi,大大减少循环次数 + + +跳过不必要处理的质心
set<int> close_i_th; for(int i = 1; i < CS行数; i++) // 遍历每个查询 { for(int j = 1; j < CS列数; j+=16) // 对每个查询, 以16为步长遍历所有质心 { // 加载当前查询第i行的16个质心得分 scores = load(CS[i][j...j+15]); // 比较scores是否大于threshold,生成掩码 mask = judge(scores > threshold); // 掩码全为0(都小于阈值)时,跳过当前16个值 if(mask == 0) continue; // 掩码不全为0(有大于阈值)时,找出那个大于阈值的分数对应的质心索引 else if(mask != 0) { // 提取mask中所有为1的位置,插入满足条件的质心索引 for(int k : extract) close_i_th.include(j + k); } } }
- 无分支优化:基于指针操作完全消除
if
语句set<int> close_i_th; int buffer[CS列数]; // 预分配一个缓冲区,大小为质心的数量 int* p = buffer; // 指针指向缓冲区的起始位置 for(int i = 1; i < CS行数; i++) // 遍历每个查询 { for(int j = 1; j < CS列数; j++) // 对每个查询, 遍历所有的质心 { // is_above_threshold == 1时*p = j -> 将索引写入缓存区,再右移指针 // is_above_threshold == 0时*p =*p -> 保持指针不变以跳过写入 int is_above_threshold = (CS[i][j] > threshold); *p = j * is_above_threshold + *p * (1 - is_above_threshold); p += is_above_threshold; } for (int* it = buffer; it < p; it++) // 将缓冲区中的结果写入集合 { close_i_th.include(*it); } p = buffer; // 重置缓存 }
- 两种优化的结合:
set<int> close_i_th; int buffer[CS列数]; int* p = buffer; for (int i = 1; i < CS行数; i++) // 遍历每个查询 { for (int j = 1; j < CS列数; j += 16) // 每次处理16个质心 { // 加载当前查询第i行的16个质心得分 auto scores = load(CS[i][j...j+15]); // 比较scores是否大于threshold,生成掩码 auto mask = compare(scores > th); // 如果掩码全为0,跳过当前16个值 if (mask == 0) continue; // 提取掩码中为1的位置,将对应的索引写入缓存 for (int k = 0; k < 16; k++) { int is_above_threshold = (mask & (1 << k)) > 0; *p = (j + k) * is_above_th + *p * (1 - is_above_th); p += is_above_th; } } // 将缓冲区中的所有索引写入集合 for (int* it = buffer; it < p; it++) { close_i_th.include*it); } // 重置缓冲区指针到起始位置 p = buffer; }
👉对不同优化的评估
![]()
优化 \ \backslash \模型 Naive IF \textbf{Naive IF} Naive IF Branchless \textbf{Branchless} Branchless Vectorized IF \textbf{Vectorized IF} Vectorized IF VecBranchless \textbf{VecBranchless} VecBranchless 向量化 ❌ ❌ ✅ ✅ 无分支化 ❌ ✅ ❌ ✅ 3.1.2.2. F ( P , q ) \textbf{3.1.2.2. }\boldsymbol{F(P, q)} 3.1.2.2. F(P,q)的计算优化
1️⃣朴素实现
double F_Score = 0; // 遍历查询q的每个词q_i for(int i = 1; i < 查询q的词数; i++) { set<int> close_i_th = q_i的相似质心集合close_i_th; // 遍历文档P的每个词T_j for(int j = 1; j < 文档P的词数; j++) { int I_P_j = T_j的最近质心I_P_j; if(I_P_j.is_in(close_i_th)) { F_Score++; break; // 每个q_1最多只能贡献一分,所以必须break } } }
- 缺陷分析:
if(I_P_j.is_in(close_i_th))
操作需要遍历 close i t h \text{close}_i^{th} closeith所有项- 优化思路:以位向量替代 close i t h \text{close}_i^{th} closeith,从而使集合操作(遍历)被位操作取代
2️⃣优化实现
数据结构:压缩的堆叠位向量
- close i t h \text{close}_i^{th} closeith的位向量表示:每维代表一个质心(一个 ∣ C ∣ |C| ∣C∣维),该维 =1 \text{=1} =1说明对应质心在 close i t h \text{close}_i^{th} closeith中
假设质心总数|C|=6 [1 0 1 0 1 0] -> 质心c1,c3,c4在close_i_th中
- 位向量的垂直堆叠:实际执行层面,会堆叠 n q = 32 n_q\text{=}{32} nq=32个查询(因为 CPU \text{CPU} CPU大多兼容 32 32 32位)
对于质心总数|C|=6, 三个查询q1,q2,q3,...,q32 [1 0 1 0 1 0] -> 质心c1,c3,c4在close_01_th中 [0 1 1 0 1 0] -> 质心c2,c3,c5在close_02_th中 [1 1 0 1 0 0] -> 质心c1,c2,c4在close_03_th中 ...... [0 1 0 1 0 1] -> 质心c2,c3,c6在close_32_th中
- 垂直堆叠的压缩:将每列(一共 32 32 32位)视作一个 32 32 32位整数,由此获得与质心数量相同的整数
[1 0 1 0 1 0] [0 1 1 0 1 0] [1 1 0 1 0 0] ...... [0 1 0 1 0 1] ↓ ↓ ↓ ↓ ↓ ↓ x x x x x x (32位整数即int类型)
优化操作:
- 图中第一步:初始化一个全 0 0 0的 32 \text{32} 32位掩码
- 图中第二步:让掩码与所有的 32 32 32位列(图中示意矩形经过了翻转)累
xor
- 图中第三步:最终 m m m中 1 1 1的个数即为 F ( P , q ) {F(P, q)} F(P,q)
3️⃣优化实验:相比于朴素方法快了 10 – 16 10–16 10–16倍
![]()
3.2. \textbf{3.2. } 3.2. 质心交互时: 对质心交互本身的优化
3.2.1. \textbf{3.2.1. } 3.2.1. 优化的操作
1️⃣优化目标:对质心交互 S ˉ q , P = ∑ i = 1 n q max j = 1 , … , n t q i ⸱ C ˉ T j \displaystyle{}\bar{S}_{q, P}\text{=}\sum_{i=1}^{n_q} \max _{j=1, \ldots, n_t} q_i \text{⸱} \bar{C}^{T_j} Sˉq,P=i=1∑nqj=1,…,ntmaxqi⸱CˉTj的计算,分为以下两个步骤分别优化
- [查询 – – –文档嵌入的质心]得分矩阵: P ~ = q i ⸱ C ˉ T j \tilde{P}\text{=}q_i \text{⸱} \bar{C}^{T_j} P~=qi⸱CˉTj
- 最大规约:找到 P ~ \tilde{P} P~的每一列的最大值 ( MaxSiim ) → (\text{MaxSiim})\text{→} (MaxSiim)→相加(最终得分)
2️⃣ P ~ \tilde{P} P~的构建优化:隐式(转置)构建
- 构建步骤:注意 C S CS CS是查询 q q q与所有质心的相似度
操作 描述 转置 C S CS CS C S T C S^T CST第 i i i行是[质心 C i ↔ 得分 C_i\xleftrightarrow{得分} Ci得分 查询 q q q中每个 Token \text{Token} Token] 找质心 对文档中的 T j T_j Tj,由质心列表定位到其最近质心 I P [ j ] I_P[j] IP[j],并在 C S T C S^T CST定位到行 C ˉ T j \bar{C}^{T_j} CˉTj 构建 P ~ \tilde{P} P~ P ~ T [ j , i ] = q i ⸱ C ˉ T j \tilde{P}^T[j, i] = q_i \text{⸱} \bar{C}^{T_j} P~T[j,i]=qi⸱CˉTj即文档词 T j T_j Tj查询词 q i q_i qi的得分 - 过程分析:
- 理论上: T j T_j Tj的存储是连续的,只有将 P ~ \tilde{P} P~转置才可以使得构建过程 ( T j , j (T_j,j (Tj,j++ ) ) )连续访问内存
- 实验上:比不转置快了两倍
3️⃣最大规约的优化:以查询词数 =32 \text{=32} =32为例,此时 P ~ T \tilde{P}^T P~T每行长 32 32 32
- 分块处理:将 P ~ T \tilde{P}^T P~T第一行,分为上下两份存到两个 16 16 16位寄存器
max_l/max_h
中- 逐行比较:将 P ~ T \tilde{P}^T P~T所有行,依次也分为两份存到两个 16 16 16位寄存器
current_l/current_h
中- 逐行更新:
- 根据比较结果更新掩码 m m m
- 再根据掩码 m m m使用
_mm512_mask_blend_ps
更新max_l/max_h
寄存器- 最终加和:
- 遍历完所有的行后,使用
_mm512_reduce_add_ps
对max_l/max_h
二者的结果相加- 相加结果即为所有位 MaxSim \text{MaxSim} MaxSim的和,也就是最终得分
3.2.2. \textbf{3.2.2. } 3.2.2. 优化的分析
1️⃣理论上:一个 16 16 16位寄存器一次就可并行处理 16 16 16位,
_mm512_
指令也可实现流水线式的并行2️⃣实验上:比 PLAID \text{PLAID} PLAID的质心交互方案快了 1.8 1.8 1.8倍
![]()
3.3. \textbf{3.3. } 3.3. 质心交互后: 对后期交互的优化
1️⃣解压的优化
- 背景:两种压缩的对比
压缩方法 特点 PQ \text{PQ} PQ压缩 压缩前后数据类型都是浮点数,维度填充对齐后(而非解压)即可进行算点积 二进制压缩 压缩后数据类型变为 bit \text{bit} bit,必须解压后才能算点积 - 优化的操作:将质心的量化表示由二进制压缩换为 PQ(OPQ/JMPQ) \text{PQ(OPQ/JMPQ)} PQ(OPQ/JMPQ)压缩,然后
- 评分函数的分解: S q , P = ∑ i = 1 n q max j = 1 … n t ( q i ⸱ C ˉ T j + q i ⸱ r T j ) \displaystyle{}S_{q, P}\text{=}\sum_{i=1}^{n_q} \max _{j=1 \ldots n_t}\left(q_i \text{⸱} \bar{C}^{T_j}\text{+}q_i \text{⸱} r^{T_j}\right) Sq,P=i=1∑nqj=1…ntmax(qi⸱CˉTj+qi⸱rTj)
- PQ \text{PQ} PQ压缩的替换: S q , P ≈ ∑ i = 1 n q max j = 1 … n t ( q i ⸱ C ˉ T j + q i ⸱ r p q T j ) \displaystyle{}S_{q, P}\text{≈}\sum_{i=1}^{n_q} \max _{j=1 \ldots n_t}\left(q_i \text{⸱} \bar{C}^{T_j}\text{+}q_i \text{⸱} r_{p q}^{T_j}\right) Sq,P≈i=1∑nqj=1…ntmax(qi⸱CˉTj+qi⸱rpqTj),即完成计算
2️⃣过滤机制的进一步改进
- 背景:在大多情况下 S q , P ≈ ∑ i = 1 n q max j = 1 … n t ( q i ⸱ C ˉ T j + q i ⸱ r p q T j ) \displaystyle{}S_{q, P}\text{≈}\sum_{i=1}^{n_q} \max _{j=1 \ldots n_t}\left(q_i \text{⸱} \bar{C}^{T_j}\text{+}q_i \text{⸱} r_{p q}^{T_j}\right) Sq,P≈i=1∑nqj=1…ntmax(qi⸱CˉTj+qi⸱rpqTj)中 q i ⸱ C ˉ T j ≫ r p q T j q_i \text{⸱} \bar{C}^{T_j}\text{≫}r_{p q}^{T_j} qi⸱CˉTj≫rpqTj
- 思路:得分主要由 q i ⸱ C ˉ T j q_i \text{⸱} \bar{C}^{T_j} qi⸱CˉTj主导,干脆直接将 q i ⸱ C ˉ T j q_i \text{⸱} \bar{C}^{T_j} qi⸱CˉTj作为近似值对 T j T_j Tj再筛选一次
- 优化:直接在后期交互中屏蔽掉 q i ⸱ C ˉ T j < t h q_i \text{⸱} \bar{C}^{T_j}\text{<}th qi⸱CˉTj<th(某阈值)的点
4. \textbf{4. } 4. 实验与结果
4.1. \textbf{4.1. } 4.1. 实验设置
1️⃣数据集: MS MARCO passages \text{MS MARCO passages} MS MARCO passages用于域内评估, LoTTE \text{LoTTE} LoTTE用于域外评估
2️⃣模型测试
- 模型:用 ColBERTv2 \text{ColBERTv2} ColBERTv2嵌入 + FAISS +\text{FAISS} +FAISS实现 PQ \text{PQ} PQ(在 MS MARCO \text{MS MARCO} MS MARCO上通过 JMPQ \text{JMPQ} JMPQ优化) + EMVB +\text{EMVB} +EMVB检索
- 基线: PLAID \text{PLAID} PLAID
3️⃣评估指标:嵌入所需空间,查询延迟,检索质量( MRR@10/Recall@100/Recall@1000 \text{MRR@10/Recall@100/Recall@1000} MRR@10/Recall@100/Recall@1000)
4️⃣软硬件配置:
- 仅在 CPU \text{CPU} CPU上测试: Intel Xeon Gold 5318Y \text{Intel Xeon Gold 5318Y} Intel Xeon Gold 5318Y,主频 2.10 GHz \text{2.10 GHz} 2.10 GHz,支持 AVX512 \text{AVX512} AVX512指令集
- 编译环境: GCC 11.3.0 -O3 \text{GCC 11.3.0 -O3} GCC 11.3.0 -O3级优化, Linux 5.15.0-72 \text{Linux 5.15.0-72} Linux 5.15.0-72系统
4.2. \textbf{4.2. } 4.2. 实验结果
1️⃣域内检索:进行了保守压缩 / / /激进( m = 32 / 16 m\text{=}32/16 m=32/16)压缩,激进压缩策略就足以取得查过 PLAID \text{PLAID} PLAID的性能
方面 EMVB \textbf{EMVB} EMVB较 PLAID \textbf{PLAID} PLAID的进展 内存占用 m = 16 m\text{=}16 m=16时内存需求减少了近一半 查询速度 m = 16 m\text{=}16 m=16时最高提高了 2.8 \text{2.8} 2.8倍速 检索质量 m = 16 m\text{=}16 m=16时无明显退化, m = 32 m\text{=}32 m=32是有达 2.5 \text{2.5} 2.5倍的提升 2️⃣域外评估
方面 EMVB \textbf{EMVB} EMVB较 PLAID \textbf{PLAID} PLAID 备注 查询速度 提高了 2.9 \text{2.9} 2.9倍速 LoTTE \text{LoTTE} LoTTE文档平均更长,更利于 EMVB \text{EMVB} EMVB的位向量过滤 检索质量 略微低于 PLAID \text{PLAID} PLAID 原有在于 JMPQ \text{JMPQ} JMPQ优化形同虚设,换为 OPQ \text{OPQ} OPQ优化稍好点