赞
踩
传统的数据库并不适合用来存储和检索向量数据
因此需要一种专门设计的数据库,用来存储和检索向量数据
给定一个查询向量,然后从众多向量中,找到最为相似的一些向量,这就是“最近邻“问题
夹角越小,余弦值越大
距离越近越相似
依次比较所有向量和查询向量的相似度,挑选出相似度最高的几个
优点:它的搜索质量是完美的,因为它真的比较了每一个向量
缺点:如果库中的向量过多,将导致极高的搜索时间
应用场景:数据规模较小的向量库
①先选定一个想要分类的数量,比如4类
②随机生成4个聚类中心点
③这些向量和哪一个中心点最近,就被分为哪一类
④用当前被分为一类的向量计算出一个平均向量点
⑤把对应的中心点的位置更新为这个平均点
⑥再判断每个向量点和哪一个中心点最近,重新分类
⑦继续用同一类的向量点,计算出一个平均点,把中心点更新过去
⑧一直重复第6步和第7步,直到中心点趋于稳定(或者说收敛)
⑨最终,将这些向量分成了4类
在搜索的时候,只需要找出和查询向量最近的那个聚类中心,搜索这个分类中的向量即可,也就实现了缩小搜索范围的目的
例如,当我们查找和A最相似的向量时,由于在所有的中心点中,A离蓝色块的中心点C最近,所以接下来会去蓝色块中去查对应的相似向量,而实际上,与A相似度最高的向量(也就是离A最近的向量),是B,在紫色块内,所以,无论在蓝色块中怎么查,都无法查到相似度最高的向量,就出现了遗漏的问题
可以指定同时搜索多个最近区域来减少遗漏
如果向量的维度是128,每个维度值是一个32位的浮点数,那么一个向量占用的内存大小为128 x 4为512字节
如果库里面一共有一千万个向量,那么占用存储空间大概有4.77G
而,在真实的应用场景中,上千的向量维度和上亿的向量数量都是很常见的,所以,这样存储,会存在很严重的问题
在k-means聚类算法的基础上,直接用聚类中心(质心)来代替这个聚类中所有的向量
注意:这是一种有损压缩的方法
使用编码+码本来存储向量
每次使用某个向量时,用它的编码值,从码本中找到对应的质心,再复原出质心向量的具体值
如果数据库的向量比较稀疏,可能需要聚很多类,才能保证量化效果
而维度的增加,将导致空间爆炸式的扩张,从而迅速的导致向量的分布变得越来越稀疏
例如,128维的向量,可能需要2 ^ 64个聚类中心,这会导致用来记录质心编码,和向量值的码本变得非常巨大,而为了保存这个巨大的码本所消耗的内存,已经超越乃至远远超越了量化本身所节省下来的内存(质心数量比源数据向量要多很多)
而实际应用中,几百上千维的向量都是很常见的,采用这种方法,显然是不可取的
先把高维的向量分割成若干个低维的子向量,然后在这些子向量上独立进行量化
例如,
①把128维的向量,分成8个16维的子向量
②在8个16维的子空间中,分别独立的对子向量进行k-means聚类训练,于是每个向量便可以使用8个子空间的训练结果,对自己8个对应的子向量进行量化
而且,由于每个子向量的维度,是16,不是很高,因此每个16维的子空间只需要大约256个聚类数量,就能得到不错的量化效果
所以,每个子向量的量化编码值的范围是0~255
③把8个子向量的量化编码值,合并在一起,就得到了原始向量最终的量化编码值
也就是说,现在一个向量被量化为8个编码值,
同样,每个子空间,也会构建自己的子码本
在使用的时候,用8个编码值,分别从对应的子码本中,查询出8个16维的子向量,再拼起来,复原出一个128维的向量
④由于每个子空间的聚类数量只有256,所以每个子码本将变得很小,小到和数据本身相比,忽略不计
而8个子空间的“小码本“,放到一起得到的”大码本“,也仍然足够小
和k-means算法一样
①确定一个hash函数(也就是LSH函数),使得,在计算向量的hash值时,位置越相近,越有可能产生相同的hash值
②对数据库中所有的向量,用①中的hash函数做运算,得到对应的hash值
③把hash值一样的向量分到同一组(同一个桶中),hash值不一样的向量分到不同的组
①计算查询向量的hash值
②找到其所在的桶,再遍历桶中的向量来搜索,因为和查询向量最相似的一些向量,大概率都在这个桶中
以A,B,C三个二维向量为例
①随机生成一条直线,且这条直线区分正反两侧
②如果一个向量,在这条线的正的一侧,他就是1,如果在反的一侧,那么就是0
③再随机生成一条直线,同样正侧的向量是1,反侧的向量是0
④重复上述步骤,我们随机生成若干个这样的直线,每次都根据向量所在的正反侧,得到1或者0
⑤如果一共使用4条随机的直线,如此就为每个向量算出来4个0或1,各自得到一个四位的二进制编码
⑥A,C这两个向量更为相似,因为它们只有第三位不同,相似度为3/4,计算方式为汉明距离/编码位数,而B和AC的相似度都很低
⑦这串二进制的编码,即位向量的hash值
对于更高维度的向量,道理也是一样的,比如三维向量,我们可以使用三维空间中的一个随机平面来做hash函数的计算,这个面,也有正反,正面的向量得到1,反面的得到0,若干个随机平面,也就得到了一串二进制编码的hash值
如果是更高的维度,在这些更高维度中,也存在着高维的“超平面“,也可以完成相应的hash值生成
基于图结构的搜索
要求:
建立步骤:
①先把向量点拿出来
②再随机的一个个的放回向量空间中
③在每次放回点的时候,找到最近的几个点建立连接,比如3个点
④如此进行下去,直到把所有的点都放回去
⑤这个图结构就建好了
在这个图中,先通过长的连接快速导航,找目标点附近的节点,再通过短的连接精细化搜索,找到目标节点(最相似的节点)
NSW算法在搜索时,不是很稳定,并不是每一次导航时,都会快速找到目标点附近的节点,再通过短的连接找到目标节点
特别是当数据量很大时,它可能变得很不稳定,进而在很大的程度上会影响性能
为了解决这个问题,可以使用HNSW算法
整个算法思路,和Redis里面的跳表很类似
构建多层结构时,按照自顶向下,连接平均的长度逐渐变短来设计的,所以从顶部作为入口,就可以保证,先粗快,后细慢的过程平稳的发生
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。