在搜索推荐中,通常使用相似Embedding进行推荐,此时就会有一个问题:如何快速找到与一个Embedding相近的其他Embedding。
如果两个Embedding在同一个向量空间中,我们就可以通过很多种方式(内积、余弦、欧氏距离等)计算其相似度;例如在推荐系统中,用户和物品的Embedding都在同一个空间中,物品总数为,那么计算一个用户和所以物品向量相似度的时间复杂度是(),而通常都能达到百万甚至上亿,这样的计算方式是无法接受的。
1.1 聚类
如果将相似点聚类在一起,在检索相似向量的时候则可以快速缩小范围,只计算目标Embedding所在的聚类范围内的相似度,这里可以使用叫常见的[K-means]聚类方法;
但是这种方法在聚类的边缘会出现些问题,如果只检索类别内的向量,则可能遗漏在其他类别中的相近点;另外,对于K-means方法,K值得选择也是一个问题,如果K选的太大,则迭代过程会很缓慢;K值选的太小,则搜索范围无法有效降低;
K值得选择经验:K=Embedding的维度开4次方根,调参按照2的整数次幂进行调整
1.2 索引
例如使用经典的[Kd-tree]向量空间索引算法中,同样存在边缘点的问题,Kd-tree会找到最邻近的区域,但是其他区域同样存在可能的最近点;另外Kd-tree的索引结构较为复杂,导致离线和在线的维护也相对复杂;
局部敏感哈希(Locality Sensitive Hashing, LSH)高效地解决了Embedding匹配的问题。
局部敏感哈希基本思想,是【将相邻的点落入同一个“桶”,这样在进行最邻近搜索时,仅需要在一个桶内或邻近几个桶内进行搜索,只需要保证每个桶内的元素个数保持在一个较小的范围内】;
如下图所示例子,首先需要确定一个结论:在[欧式空间]中,【将高位空间的点映射到低维空间,原本接近的点在低维空间中肯定依然接近,但原本远离的点则有一定概率变成接近的点】。
利用上面的【低维空间保留高维空间相近距离关系的性质】,我们可以设计构造多个“桶”。假设是高位空间中的维Embedding向量,是随机生成的维向量,可以得到一个数值,即 h ( v ) = v ⋅ x h(v)=v \cdot x h(v)=v⋅x【也就是两个等长向量点击的结果】。
根据这个数值,我们设计哈希函数ℎ()进行分桶:
h x , b ( v ) = [ x ⋅ v + b w ] h^{x,b}(v)=[\frac{x \cdot v + b}{w}] hx,b(v)=[wx⋅v+b]
上面公式中是分桶宽度(将映射后点积的结果,按照w的宽度进行分块),是0到之间的一个均匀分布随机变量,其作用是避免分桶边界固化。为了避免映射操作损失信息,可以使用个哈希函数进行分桶,如果同时掉入多个桶,则其相似的概率将会增加。在确定了桶后,就在其有限的集合内进行[K近邻]搜索即可【本质看起来和PQ量化的思想一致】,PQ量化可以参考笔者文章Faiss PQ 乘积量化。
当存在多个哈希函数的时候,聚合中的点可能以不同的分布方式落在多个桶当中。最简单的就是一个点在匹配的桶中都出现(AND)以及在任意一个桶中出现(OR)两种策略。多桶策略还可以更复杂,比如三个分桶,可以选择同时落入两个桶中的点作为候选点。下面有一些建议的策略:
例如在商品推荐系统中,商品称为(item)有对应的item_id,可以使用以下方案:
LSH相比一些朴素的方法,高效地解决了相似向量查找的问题,通过多桶机制减小其哈希分桶的损失;但是也存在一些问题,大数据量情况下哈希函数的个数不好确定,另外在进行哈希计算的时候,可能会存在哈希冲突,导致召回率降低。
此外向量相似查找,还有一些基于树、基于量化、基于图的方法,根据不同的场景也可一试。
[1].局部敏感哈希-向量相似搜索