AI基于近邻图的向量搜索(一)

news2024/9/21 4:33:49

案例介绍

最近邻问题

SPTAG解决的问题是如何从大规模的向量中快速找出近似最近邻点(Approximate Nearest Neighbor),即实现最近邻搜索(Nearest Neighbor Search)

我们可以将问题定义为:

其中,q为查询向量,x为样本向量,我们可以计算它们的L2或余弦距离,获得两者距离最近的样本。

该问题最早是在1973年由高德纳在《计算机程序设计艺术》中提到,并称之为邮局问题,即居民寻找离自己家最近的邮局。

要实现这个目标,有以下几种常见的最近邻搜索算法:

  1. 线性查找

    线性查找通过遍历整个点集,计算它们和目标点之间的距离,从而找出距离最小的样本。该方法的时间复杂度为O(nd),n为样本数,d为样本的维度数,当数据量达到一定规模后,该方法的搜索时间将会变得难以接受。为了解决该问题,又有人提出了利用空间划分树来提高搜索效率。

  2. 空间划分树

    空间划分树常用的是KD-Tree(于1970s提出)。其算法是通过递归地随机选取或根据某种算法选取K维作为结点划分依据,将样本划分成左子树和右子树,最终生成一棵二叉树索引。这类方法的搜索效率通常对于低维度的数据效果比较好(如小于100维),但对于高维数据效果较差。而图片的向量表示通常能够达到1000维甚至更多。

由于KDTree在高维向量空间上的搜索效率不高,于是又有人提出了 近似最近邻搜索(Approximate Nearest Neighbor, ANN) 的算法,即不精确查找,而是利用算法查找出符合要求的近似最近邻。

当前有以下几种近似最近邻搜索算法:

  1. 基于哈希的最近邻搜索

    利用哈希算法(如2010年提出的LSH),在尽可能保留距离关系的情况下,将样本映射到不同的哈希桶(Bucket)中,这时只需比较同一哈希桶中的点即可。但是该方法的查询性能与哈希函数及样本分布有关,样本可能会聚集在某些哈希桶中,导致对于不同点的查询时延差距较大,稳定性不佳。

  2. 近邻图

    通过使样本中所有点连接其近邻点,我们可以构建一张近邻图。再通过使用特定的算法(如2016年提出的HNSW),我们可以在搜索时快速找到与查询点相连的近邻点。但是,我们无法确保我们构建的近邻图是连通图,因此有可能会陷入局部最优。

使用场景

最近邻搜索的应用场景十分广泛,包括计算机视觉、模式识别、基于内容的图像或视频检索等。

在这其中,SPTAG的一个重要应用场景便是搜索引擎了。随着深度学习的发展,我们可以利用深度神经网络将绝大部分的内容(常见的有文本、图片、音频、视频等)映射到高维空间,获取到对应的向量。利用向量,我们便可以更轻易地找出相关联的内容。

在搜索引擎中的应用

在过去,传统的搜索引擎往往是通过"关键词"对内容进行检索,但这就要求了用户需要将问题抽象成几个"关键词",且需要精确描述问题。然而,随着网络信息的爆炸式增长和信息技术的高速发展,工程师们发现用户习惯已经悄然改变:用户搜索的内容越来越长,他们往往期望通过输入一段自然语言甚至一张图片来搜索出他们想要的结果,而不只是通过关键词。网络搜索任务也因此变得更加复杂和多样化了。

为此,我们需要思考如何才能将自然语言或者图片与数据库中的内容匹配,找出最相关的内容呢?为了让计算机认识自然语言、图片等内容,我们需要将其编码成计算机认识的形式,其中,最常见和有效的就是向量了。向量可以是各种形式的内容(如关键词、图片、语音等)在高维空间的表示。我们可以利用现有的算法(如深度神经网络)将不同形式的内容转化的向量,获取到对应的向量。向量在高维空间的表示是有意义的,我们认为关联性越强的内容在空间上的距离越小或相似度越大。

利用向量的表示,我们可以将数据库的内容全部转换成向量,再将用户的搜索输入用同样的算法转换成在同一个空间的向量。此时,搜索引擎的匹配问题就变成了最近邻问题(Nearest Neighbor)。我们的任务就是从大规模的向量中找出与输入向量最相近的一组向量。

对于大规模数据,Brute-Force或线性查找的时间复杂度是难以接受的。因此,我们需要合适的算法来提高搜索速度。传统的关键词检索可以通过构建倒排索引(Inverted Index)来提高检索速度,但是我们无法为向量构建这样的索引。对于向量,我们通常是利用树或图(如KD-Tree, HNSW)来构建索引,从而帮助我们在大量的向量中找出最相似的向量。当然,鱼与熊掌不可兼得,速度的提升往往是以牺牲精度为前提的。于是,问题最终变成了近似最近邻(Approximate Nearest Neighbor, ANN)问题

但无论是使用树还是图,它们都有各自的问题,例如,KD-Tree在面对高维度数据时效果显著下降,而使用近邻图则容易陷入局部最优。因此,微软提出了SPTAG,通过结合树和图,在弥补各自的不足的基础上,还做出了一定的优化。SPTAG解决的核心问题其实是上述的ANN问题,因此,我们还可以将SPTAG应用到许多不同的场景,如计算机视觉、模式识别等领域。

核心知识点

  • KD-Tree(K维树)
  • BKTree(平衡 K 均值树)
  • KNN 图(K 最近邻图)
  • RNG(相对邻域图)

先修知识

  • C++
  • 数据结构(包含二叉树、哈希算法、图论等基础知识)

推荐学习时长

该案例推荐学习时长为:3小时

案例详解

SPTAG架构

可见,上述提到的算法都有各自的问题,适用于不同的场景,而SPTAG的核心思路是将树和图结合,从而弥补各自的缺陷,使场景更为通用。

其架构如图:

SPTAG分为了Tree部分和Graph部分。Tree部分利用KD-Tree或BKTree实现,Graph部分使用了基于KNN图改进的RNG。在进行搜索时,SPTAG首先会从Tree部分获取“种子”向量,将该种子向量作为Graph中的起始点进一步搜索近邻点。

Tree部分

Tree部分SPTAG使用了KDTree和BKTree实现。在调用时,可以根据需求选择任意一种。KD-Tree适合低维度(如小于100维)的向量,反之,BKTree适合高维度的向量。

KD-树

KD-Tree的本质是每个结点都以某一维划分的二叉树,是二叉搜索树(BST)的拓展。二叉搜索树的每个结点可以视为一个划分,小于等于该结点的归入左子树,大于该结点的归入右子树。

那么,如何构建二叉搜索树呢?

给定一组数据:[8, 3, 6, 10, 4, 1, 7, 14, 13]。我们选取数据中第一位作为划分结点,小于等于该值的归入左子树,大于该值的归入右子树,以此规则递归生成一棵二叉搜索树。

  1. 选取8作为划分结点,可以得到左子树l:[3, 6, 4, 1, 7],右子树r:[10, 14, 13]。

  2. 进一步划分左子树l,选3作为划分结点,得到新的左子树l-l为:[1],右子树l-r:[6, 4, 7]。

  3. 由于左子树l-l只有一个结点,划分完成,开始划分右子树l-r,选6为划分结点,得到左子树l-r-l:[4],右子树l-r-r:[7]。

  4. 此时,左子树l划分完成,开始划分右子树r。选10为划分结点,得到左子树r-l:[ ],右子树r-r:[14, 13]。

  5. 由于左子树r-l为空,划分完成,开始划分右子树r-r。选14为划分结点,得到左子树r-r-l:[13],右子树r-r-r:[ ]。

至此,划分完成,可以得到下图的BST。

二叉搜索树的数据仅有一维,而对于多维数据,我们可以在每次划分时选择其中的任意一维作为划分值,若数据中选定的某一维度的值小于等于划分值,归入左子树,大于划分值则归入右子树。除此之外,其构建过程与二叉搜索树的构建过程一致。

另外,在选择划分值构建KD-Tree时,我们通常会选择方差最大的维度的平均值作为划分值。因为方差越大,代表数据越分散,而选择数据比较分散的维度,会更容易将样本划分开。当然,划分的规则并不是绝对的,还可以轮流选择维度、随机选择维度等,我们可以根据实际的需求而调整。

构建算法
  1. 从方差最大的前N个维度(SPTAG选取了前5维)中随机选择一个维度作为划分维度,将中位数作为划分值,划分出两组子空间,小于等于划分值的归入左子树空间,大于划分值的归入右子树空间。
  2. 分别对划分的子空间递归以上步骤,直到划分的子空间中只有一个点,然后将其作为叶子结点。

下面演示一下KD-Tree的构建过程。

假设我们有一组2维(x,y)数据:[(2,3), (5,4), (4,7), (7,2), (9,6), (8,1)]。

  1. 分别计算这两维的方差: $var(x) = 5.8$, $var(y) = 4.5$。 所以我们选择x维作为划分维度,选择x维的中位数较大的(7,2)作为划分结点。得到左子空间l:[(2,3), (5,4), (4,7)],右子空间r:[(9,6), (8,1)]。
  2. 开始划分左子空间l。分别计算x,y维方差:$var(x)=1.6$, $var(y)=2.9$。所以选择y维作为划分维度。选择y维的中位数(5,4)作为划分结点,得到左子空间l-l:[(2,3)],右子空间r-l:[(4,7)]。
  3. 由于左子空间l-l和右子空间r-l都只有一个点,将其作为叶子结点,划分结束。开始划分右子空间r。计算方差:$var(x)=0.25$, $var(y)=6.25$。选择y维作为划分空间,中位数中较大的(9,6)作为划分点,得到左子空间r-l:[(8,1)],右子空间r-r:[]。
  4. 左子空间r-l只有一个结点,右子空间r-r为空,划分结束。

最后,我们可以得到下图的KD-Tree。

从将上述的点画到平面空间,可以看到我们利用KD-Tree将空间做了如下的切分:

对于三维的KD-Tree,可能对空间进行了这样的划分(图自维基百科):

KD-Tree中的最近邻搜索

在KD-Tree中搜索最近邻点,大多数情况下我们可以不必搜索整个空间,从而加快搜索速度。

  1. 从根结点开始,递归向下搜索,计算查询点与经过的结点的距离,记录当前的最小距离和对应的结点。
  2. 直到叶子结点,开始"回溯"。"回溯"过程为:判断查询点与当前父结点的划分平面的距离是否小于当前最小距离,若小于则应继续递归搜索该兄弟结点,否则返回上一层,重复该步骤,直到根结点为止。

从KD-Tree中找出的最近邻点将作为后续在图中搜索的“种子”向量。

KD-Tree的详细介绍可以参考:

  1. KD Tree的原理及Python实现
  2. KD-Tree的构造与搜索

BKTree

BKTree是平衡K-means Tree,即利用K-Means聚类后划分出来的K叉树。

K-Means聚类

K-means将训练样本分成K个类别(K为人为设定),每个类别都有中心点。当我们需要预测一个新的点类别时,我们将该点分别与K个类别的中心点计算距离,距离最近的中心点的类别即为新的点的类别。

那么,如何确定K-means的K个中心点呢?

具体算法如下:

  1. 初始化中心点。采用随机策略或Kmeans++算法生成K个中心点。
  2. 对所有样本赋值类别。为每个样本选取最近中心点所在的类作为其类别。
  3. 更新中心点。将所有属于某类的样本每维求和取平均,将均值作为新的中心点。
  4. 重复步骤2~3,直到中心点不再变化。

关于K-means的详细介绍可以参考:K-Means聚类算法

BKTree构建算法

了解了K-means以后,我们可以利用K-means构建BKTree。

具体算法如下:

  1. 每次使用K-means聚类划分K组子空间,每个结点代表一个子空间,其中心为该类样本的中心点。
  2. 分别对划分的子空间递归以上步骤,直到无法继续划分(所有结点都相同或子空间太小),将叶子结点指向这些数据点。
BKTree中的最近邻搜索

使用Best-Frist Search的方式搜索BKTree,记录查询的最小距离的结点,直到到达叶子结点。将叶子结点作为后续在图中搜索的"种子"向量。

Best-First Search 的算法如下:

  1. 计算查询点q与BKTree的根结点v的距离
  2. 将v的所有子结点放入优先级队列Q
  3. 从优先级队列Q中取出与q距离最近的点v
  4. 重复步骤2~3,直到找到叶子结点

搜索完成后,叶子结点即为最近邻点。

另外,关于上述的优先级队列Q

对于队列中的所有点,与查询点q的距离为其优先级,距离越短优先级越高,因此每次取出的点v为队列中与查询点v距离最近的点。

我们可以使用最小值堆(Min Heap)来实现这样的优先级队列,利用最小堆,可以提供比较高的查询性能,查找的时间复杂度为O(log n)。

在搜索时使用优先级队列,可以使我们不断地在距离近的分支上搜索,从而减少需要搜索的分支数,进而提高搜索的速度。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1398722.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【51单片机Keil+Proteus8.9+ADC0804】ADC实验 模拟转数字实验

一、实验名称 ADC实验 模拟转数字实验 二、设计思路 电路设计 1.选用AT89C51单片机作为电路核心单元,外接8位单通道AD转换器ADC0804芯片和LM016L显示器以及滑动变阻器等其它常用元器件构成电路。 2.将ADC0804芯片的控制引脚RD,WR,INTR接到AT89C51芯片对应引脚&…

双指针(JAVA语言)

目录 力扣283.移动零 力扣1089复写零(难度较大,要重点理解,可以记不住咋写,但要记住想法) 力扣202题快乐数 力扣11题.盛最多水的容器(好写代码,方法不好想) 力扣283.移动零 public static voi…

第一部分 概述

目录 一、计算机网络在信息时代的作用 大众熟悉的三大类网络有 Internet 互连网与互联网的区别 可以从两种不同的方面来认识互联网: 互联网在生活中的地位 互联网 互联网负面影响 二、互联网的概述 网络的网络 基本概念 互连网基础结构发展的三个阶段 万维网www(…

未来 AI 可能给哪些产业带来哪些进步与帮助?

AI时代如何要让公司在创新领域领先吗?拥抱这5种创新技能,可以帮助你的公司应对不断变化。包括人工智能、云平台应用、数据分析、 网络安全和体验设计。这些技能可以帮助你提高业务效率、保护公司知识资产、明智决策、满足客户需求并提高销售额。 现在就加…

使用.NET API 中的 EventCounters进行指标监控

写在前面 为了实现轻量级、跨平台、准确实时的性能指标收集,从 .NET Core 3.0 版本开始引入 EventCounters API。除了 .NET 运行时提供的 EventCounters 外,还可以实现自定义的 EventCounters。 以便跟踪各种指标,EventCounters 作为 EventS…

比亚迪50亿重拳出击,建全球首个全地形赛车场,到底闹哪样?

比亚迪这是在悄无声息中准备的一击重拳吗?新建赛车场背后,到底藏着什么不为人知的战略目的?它是否再次玩转行业规则,一举带动整车文化的更深度发展?作为一直以来重视技术和长远规划的比亚迪来说,这里面肯定…

【C语言】- 设置控制台标题、编码、文字颜色、大小和字体

【C语言】- 设置控制台标题、编码、文字颜色、大小和字体 文章目录 【C语言】- 设置控制台标题、编码、文字颜色、大小和字体1 - 设置控制台标题2 - 设置控制台编码3 - 设置控制台字体和大小参考链接 1 - 设置控制台标题 因为要用到 Windows API,所以需要包含头文件…

【谭浩强C程序设计精讲 chap4】选择结构程序设计

文章目录 第4章 选择结构程序设计一、用 if 语句实现选择结构二、用 switch 语句实现多分支选择结构三、条件运算符和条件表达式 第4章 选择结构程序设计 一、用 if 语句实现选择结构 一般形式: if (表达式)  语句1 [ else  语句2 ] 其他形式,常用的…

Linux 批量添加 known_hosts

前言 我们在做完linux ssh 免密登录后,通常会执行一些自动化任务(比如启动Spark集群),也就是需要ssh到每台节点执行相同命令。但是有一个问题就是如果 known_hosts 文件中不存在这个ip的话,在第一次连接时会弹出确认公…

Unity常用的优化技巧集锦

Unity性能优化是面试的时候经常被问道的一些内容,今天给大家分享一些常用的Unity的优化技巧和思路,方便大家遇到问题时候参考与学习。 对啦!这里有个游戏开发交流小组里面聚集了一帮热爱学习游戏的零基础小白,也有一些正在从事游…

傲空间私有部署Windows指南

推荐阅读 智能化校园:深入探讨云端管理系统设计与实现(一) 智能化校园:深入探讨云端管理系统设计与实现(二) 安装 docker 请下载对应的 Docker,安装完成后启动。 Docker Desktop for Windows…

【Redis配置】Linux下的Redis安装配置

压缩包方式的Redis下载与安装 进入官网 Redis官网:https://redis.io/download/ 往下翻可以找到其他版本的Redis,或者访问https://download.redis.io/releases/查找自己所需Redis版本。 下载自己所需版本 此处我选择下载的是6.2.14版本 上传到Linux…

Crow:实现点击下载功能

Crow:设置网站的index.html-CSDN博客 讲述了如何完成一个最简单的网页的路由 很多网页提供了下载功能,怎么实现呢,其实也很简单。 假设网页的目录结构如图 $ tree static static ├── img │ └── goodday.jpg └── index.html //index.html <html> <body&…

VMnet1、VMnet8到底是什么?

VMnet1、VMnet8到底是什么&#xff1f; 当我们安装VMware Workstation后&#xff0c;在宿主机(物理电脑)上会多出两个网卡VMNet1、VMNet8。 VMnet1和VMnet8是两个虚拟网卡&#xff0c;主要作用是让虚拟机可以通过你的宿主机的网线上网。 VMnet1是为host-only方式服务的&#x…

CSS实现平行四边形

1、为什么实现平行四边形 在日常开发过程中&#xff0c;有些时候我们可以会遇到一种情况&#xff0c;如可视化大屏中要求我们横线实现对应的进度条&#xff0c;但进度条的内容是由无数个平行四边形组装类似于进度条的形式&#xff0c;那么我们就需要使用CSS来进行对应的实现。 …

后台管理系统: 数据可视化基础

数据可视化简单理解&#xff0c;就是将数据转换成易于人员辨识和理解的视觉表现形式&#xff0c;如各种 2D 图表、3D 图表、地图、矢量图等等。 例如Excel等等 canvas <canvas> 标签只是图形容器&#xff0c;相当于一个画布&#xff0c;canvas 元素本身是没有绘图能力…

内存那点事:让我们一点点的搞懂它

内存是计算机系统中至关重要的组成部分&#xff0c;它不仅储存了运行中的程序和数据&#xff0c;还直接关系到系统的性能和稳定性。让我们一起深入探讨Linux系统下内存管理的核心原理&#xff0c;揭开它的神秘面纱。 基础概念 物理地址 概念&#xff1a;物理地址是指计算机内…

一个关于自动化工具的操作手册

整体 整个软件由首页、设计页构成 首页 按钮功能 清除缓存&#xff1a;主要为了避免线程占用的问题&#xff0c;端口占用无法重新执行。所以操作执行任务、修改任务、新建任务没有响应时&#xff0c;可以操作该事件新建任务&#xff1a;顾名思义就是创建一个网页自动化任务执…

世界上真的存在比苹果品质还好的笔记本电脑吗?

苹果笔记本电脑的品质一直是业界标杆&#xff0c;但它真的是最好的吗&#xff1f;答案是肯定的&#xff0c;但也要看你怎么定义“好”。为什么mac那么贵&#xff0c;还有很多人买&#xff1f;探索高性能的Mac系列&#xff0c;包括 MacBook Pro、Mac Studio和Mac Pro&#xff0c…

后台管理系统: spu管理模块

spu管理模块业务 spu 可以理解为类 例如 people类【spu】 sku可以理解为实例 例如&#xff1a;小明 18 男 spu跟sku可以理解为类跟多个实例的关系 spu管理模块静态 <template><div><el-card style"margin: 20px 0px"><CategorySelect get…