基于局部敏感哈希(Locality-Sensitive Hashing, LSH)的近似最近邻搜索:哈希函数族构造、多桶机制与搜索过程
题目描述
在高维空间中,传统的精确最近邻搜索算法(如k-d树)会因“维数灾难”而效率急剧下降。局部敏感哈希(LSH)是一种概率性的近似最近邻搜索技术,其核心思想是:设计特殊的哈希函数,使得“相似”的数据点(距离近)有高概率被哈希到同一个桶中,而“不相似”的数据点(距离远)有高概率被哈希到不同的桶中。本题目将详细讲解LSH的构建与搜索过程。
解题过程
1. 问题背景与核心思想
- 问题:给定一个高维空间中的大规模点集 \(P\),和一个查询点 \(q\),如何快速找到 \(P\) 中与 \(q\) 最相似的若干点(即近似最近邻)?
- 传统方法的瓶颈:精确方法需要计算 \(q\) 与 \(P\) 中所有点的距离(线性时间),或者使用树形结构(如k-d树),但在高维空间中,这些方法可能退化到接近线性扫描。
- LSH的核心思想:
- 使用一族特殊的哈希函数 \(\mathcal{H}\)。
- 对于任意两个点 \(x\) 和 \(y\),如果它们相似(距离小),则 \(\Pr[h(x) = h(y)]\) 很高;如果它们不相似(距离大),则 \(\Pr[h(x) = h(y)]\) 很低。
- 通过多次哈希,将数据点“投影”到多个哈希桶中。搜索时,只需在查询点 \(q\) 落入的桶及其邻近桶中查找候选点,从而大幅减少比较次数。
2. 哈希函数族的构造(以欧氏距离为例)
LSH的效果高度依赖于哈希函数族的设计。针对不同的距离度量(如欧氏距离、余弦相似度、汉明距离),需构造对应的函数族。
针对欧氏距离(\(L_2\) 距离)的LSH(E2LSH):
- 核心函数族:使用随机投影(随机超平面)哈希。
- 具体步骤:
- 随机生成一个服从 \(d\) 维标准正态分布 \(\mathcal{N}(0, I)\) 的向量 \(a\)(即超平面的法向量)。
- 随机生成一个均匀分布在 \([0, w]\) 内的偏移量 \(b\),其中 \(w\) 是桶宽(一个超参数)。
- 定义哈希函数:
\[ h_{a,b}(x) = \left\lfloor \frac{a \cdot x + b}{w} \right\rfloor \]
- 这里 $ a \cdot x $ 是点 $ x $ 在方向 $ a $ 上的投影值。
- 除以 $ w $ 并向下取整,相当于将实数轴划分成长度为 $ w $ 的区间,每个区间对应一个哈希桶。
- 为什么有效:
- 两个点 \(x\) 和 \(y\) 在方向 \(a\) 上的投影差为 \(a \cdot (x - y)\)。
- 投影差的绝对值 \(|a \cdot (x - y)|\) 越小(即两点在超平面法向上越接近),它们被划分到同一区间的概率就越高。
- 通过理论分析可知,该函数族对欧氏距离是局部敏感的。
3. 多桶机制(Amplification:AND/OR构造)
单个哈希函数区分度有限,可能产生过多误报(不相似的点撞入同桶)或漏报(相似的点未撞入同桶)。通过组合多个哈希函数,可以控制精度与召回率。
-
OR构造(放宽条件,提高召回率):
- 定义一个新的哈希函数 \(g_i(x) = (h_1(x), h_2(x), ..., h_k(x))\),即串联 \(k\) 个独立的哈希函数。
- 两个点 \(x\) 和 \(y\) 只要在至少一个 \(h_j\) 上哈希值相同,它们就被认为在 \(g_i\) 下“碰撞”(即可能落入同一复合桶)。
- 这提高了相似点被哈希到同一桶的概率(高召回),但也增加了不相似点碰撞的概率(低精度)。
-
AND构造(收紧条件,提高精度):
- 定义 \(g_i(x)\) 同上,但要求两个点 \(x\) 和 \(y\) 在所有 \(k\) 个 \(h_j\) 上哈希值都相同,才被认为碰撞。
- 这降低了不相似点碰撞的概率(高精度),但也增加了漏掉相似点的概率(低召回)。
-
组合AND与OR(实际常用):
- 使用 \(L\) 个独立的 \(g_i\) 函数(每个 \(g_i\) 由 \(k\) 个 \(h_j\) 经AND构造而成)。
- 在索引阶段,将每个数据点 \(x\) 插入到 \(L\) 个哈希表中的对应桶(每个表对应一个 \(g_i\))。
- 在查询阶段,对于查询点 \(q\),检查所有 \(L\) 个表中 \(q\) 落入的桶,并收集这些桶中所有候选点。
- 整体效果:通过“OR”这 \(L\) 个表,只要有一个 \(g_i\) 将 \(q\) 和近邻点哈希到同一桶,就能找到该近邻;通过每个 \(g_i\) 内部的“AND”构造,控制单个桶的纯度。
4. 完整的LSH索引构建与搜索过程
步骤1:参数选择
- 选择哈希函数中的桶宽 \(w\)。
- 选择每个复合哈希函数 \(g_i\) 中包含的基哈希函数数量 \(k\)。
- 选择独立哈希表的数量 \(L\)。
- (这些参数通常通过理论分析或实验调优确定,影响效率与准确性的权衡。)
步骤2:构建索引(预处理)
- 随机生成 \(L \times k\) 个独立的基哈希函数 \(h_{a,b}\)(即随机生成 \(L \times k\) 个 \((a, b)\) 对)。
- 构造 \(L\) 个复合哈希函数 \(g_1, g_2, ..., g_L\),其中 \(g_i = (h_{i1}, h_{i2}, ..., h_{ik})\)。
- 初始化 \(L\) 个空的哈希表(字典结构)。
- 对于数据集 \(P\) 中的每个点 \(x\):
- 对于每个 \(g_i\) (\(i = 1\) 到 \(L\)):
- 计算复合哈希键 \(g_i(x)\)(一个由 \(k\) 个整数组成的元组)。
- 将点 \(x\) 的标识符(或数据本身)插入到第 \(i\) 个哈希表中键为 \(g_i(x)\) 的桶内。
- 对于每个 \(g_i\) (\(i = 1\) 到 \(L\)):
步骤3:近似最近邻搜索(查询)
- 给定查询点 \(q\)。
- 初始化一个候选集合 \(C = \emptyset\)。
- 对于每个 \(i = 1\) 到 \(L\):
- 计算 \(g_i(q)\)。
- 在第 \(i\) 个哈希表中查找键为 \(g_i(q)\) 的桶。
- 将该桶内的所有点(去除可能重复的点)加入候选集合 \(C\)。
- 对候选集合 \(C\) 中的所有点,计算它们与 \(q\) 的真实距离(如欧氏距离)。
- 按距离排序,返回前 \(m\) 个最近的点作为近似最近邻结果。
步骤4:性能权衡分析
- 召回率(Recall):找到的真实最近邻占所有真实最近邻的比例。增大 \(L\) 或减小 \(k\) 可以提高召回率。
- 精度(Precision):返回的近似最近邻中真实最近邻的比例。增大 \(k\) 或减小 \(L\) 可以提高精度。
- 时间复杂度:索引构建为 \(O(L \cdot k \cdot d \cdot |P|)\),搜索为 \(O(L \cdot k \cdot d + |C| \cdot d)\),其中 \(|C|\) 远小于 \(|P|\)。
- 空间复杂度:存储 \(L\) 个哈希表,总共 \(O(L \cdot |P|)\) 的指针开销。
总结
局部敏感哈希(LSH)通过精心设计的哈希函数族,将高维空间中距离相近的点以高概率映射到相同的哈希桶中。借助多桶机制(AND/OR构造),可以在召回率与精度之间进行有效权衡。其预处理(索引构建)和快速查询的特性,使其非常适合大规模高维数据的近似最近邻搜索应用,如图像检索、文本去重、推荐系统等。理解LSH的关键在于掌握其概率性保障的思想,以及参数 \(w\)、\(k\)、\(L\) 对搜索性能的影响。