链载Ai

标题: 基于GPU的ANN检索 [打印本页]

作者: 链载Ai    时间: 2 小时前
标题: 基于GPU的ANN检索


导读
introduction
近似最近邻(ANN)向量检索的CPU方案已被广泛地应用于在线检索等多种场景中并取得了不错的效果。GPU相比CPU拥有更强大的并行计算能力,如何将GPU引入ANN检索获取更大收益,成为了业界重点研究的难题之一。百度与NVIDIA技术团队,基于 RAFT[1]开源代码库设计并实现了一种基于GPU的ANN在线检索方案,在一类高检索流量业务场景下获得了显著的成本收益。本文主要介绍整体方案并总结一些思考及展望。

全文9452字,预计阅读时间24分钟。

GEEK TALK

01

ANN简介


随着自然语言处理和深度学习的高速发展,向量检索为提升搜索用户体验发挥出重要作用,近似最近邻(ANN)搜索是在有限时空条件下实现向量搜索的主要方式。ANN的核心思想是近似,所有ANN算法都致力于在低规模计算开销下保证最后选择的邻居是查询向量的最近邻概率很高,但不追求100%的准确性。根据近似思路的不同,ANN检索算法主要分为四类:基于树的ANN算法、基于LSH的ANN算法、基于量化的ANN算法和基于图的ANN算法。接下来对本文涉及的几种ANN算法原理进行简要介绍。

ingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;font-size: 14px;letter-spacing: 1px;text-align: left;caret-color: rgb(0, 0, 0);">ingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;letter-spacing: 0.544px;">△IVF_FLAT

IVF_FLAT:如上图所示,基于量化[2]的方案是通过一组特定的点来表示全部的向量空间,每个特定点代表一个子空间,它常与倒排索引相结合[3],首先对向量空间进行划分,每个数据点按照与其最近的子空间质心形成倒排拉链,这样每条倒排拉链对应一个子空间,拉链中元素为落在该子空间的向量id。检索时首先通过与质心的距离计算选取若干个子空间,然后只计算所选子空间内数据点与查询向量的距离,排序后得到最后结果,该思路被称作IVF_FLAT方案。

ingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;font-size: 14px;letter-spacing: 1px;text-align: left;caret-color: rgb(0, 0, 0);">ingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;letter-spacing: 0.544px;">ingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;letter-spacing: 0.544px;">△IVF_PQ

IVF_PQ:除了借助向量量化选取子空间减少计算以外,量化对于ANN检索的贡献还在于可以使用量化点计算量化距离从而代替精确距离的计算,这样减少了计算但会带来精度损失,这就要求量化的精度不能太低。乘积量化[3](PQ)可以借助几组子向量器的质心,产生大量的质心,降低量化学习的复杂度。它与残差量化[4]相结合可以在有限的时空条件下提升整体量化的精度。基于乘积量化的IVF方案经典思路如上图所示,它是在构建时先对所有数据进行一次向量量化,根据这次向量量化的簇心形成倒排拉链,然后计算出所有数据与其质心的残差,然后再对残差进行乘积量化,记录对应其量化点的编码。检索时同样先与向量量化的质心计算决定候选拉链减少计算量,然后计算查询与质心的残差后对候选点进行距离计算,计算距离时是计算查询残差与候选点的量化距离,最后进行距离排序后返回检索结果,该思路被称作IVF_PQ方案。

ingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;color: rgb(34, 34, 34);letter-spacing: 0.544px;background-color: rgb(255, 255, 255);line-height: 1.75em;overflow-wrap: break-word !important;box-sizing: border-box !important;">ingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;font-size: 14px;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: 1px;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;white-space: normal;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;caret-color: rgb(0, 0, 0);background-color: rgb(255, 255, 255);text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;">ingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;letter-spacing: 0.544px;white-space: normal;">ingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;letter-spacing: 0.544px;">△Cagra

Cagra[6]:基于图的ANN方案进行向量检索的过程都是通过图索引中点的邻接关系逼近到和查询向量点距离最近的若干个结果,图索引的构造和检索策略是基于图的ANN搜索方案研究的重点,需要考虑准召、搜索效率和空间开销等多方面因素。经过业界的不懈研究,以HNSW[5]为代表的诸多基于图的方案凭借优异性能都得到了广泛应用,但大部分的图算法在构建流程和检索路由过程中很难充分利用到GPU的并行能力,NVIDIA针对图算法这一挑战自研了名为Cagra[6]的基于GPU的ANN图算法,如上图所示。该算法以NN-descent[7]图为基础,然后借鉴NGT[8]的路径调整的思路对边进行剪枝,最后对剪枝后的正向图与对应的反向图各取一半的边进行合并,生成最终的Cagra图索引。检索过程维护一个top-M(M大于等于返回结果数目K)的列表和一个长度固定的候选列表,每轮迭代局部排序出距离最小的top-M并更新,然后将top-M的未被检索的邻居添加到候选列表中,直至top-M列表的节点都被遍历,然后选取top-K作为结果返回。Milvus[9]数据库就是借助Cagra算法实现了出色的性能加速。


GEEK TALK

02

我们选择了什么业务场景来使用ANN onGPU


在百度的某一类搜索业务场景下,对单次用户查询,会进行扩展检索以召回更多样化的相关结果。具体的业务场景需求:

在这样的超高检索吞吐场景下,基于 GPU 来做高并行度计算会比基于 CPU 的检索有更高的性价比。因此,我们选择在该场景下来做 ANN on GPU 的尝试。


GEEK TALK

03

我们是怎么做的


3.1 索引算法选择

RAFT[1]代码库是NVIDIA设计开发的一套开源代码库,包含了可广泛应用于机器学习和信息检索场景的基本算法和原语,这些算法经过CUDA加速优化并可以通过构建块使编程简易化。它提供了四种GPU-ANN算法:BruteForce、IVF_FLAT、IVF_PQ和Cagra,这些算法都通过相同名称的顶层接口来实现索引的构建(build)、存储(serialize)、加载(deserialize)、检索(search),为用户的使用提供了便利,以IVF_FLAT为例:

//T为数据的类型,IdxT为数据id的类型template <typename T, typename IdxT>auto build(raft::resources const& handle,//资源句柄 const index_params& params,//构建索引参数 raft::device_matrix_view<const T, IdxT, row_major> dataset) //显存中存储的数据集 -> index<T, IdxT>;
template <typename T, typename IdxT> void serialize(raft::resources const& handle,//资源句柄 const std::string& filename,//存储文件名 const index<T, IdxT>& index);//索引对象
template <typename T, typename IdxT>index<T, IdxT> deserialize(raft::resources const& handle, //资源句柄 const std::string& filename);//加载文件名
template <typename T, typename IdxT>void search(raft::resources const& handle,//资源句柄const search_params& params,//检索参数const index<T, IdxT>& index,//索引对象const T* queries,//查询指针uint32_t n_queries,//查询数目uint32_t k,//每条查询返回结果数IdxT* neighbors,//返回结果id的指针float* distances,//返回结果距离的指针rmm::mr::device_memory_resource* mr = nullptr) //可选的内存资源指针


我们对RAFT支持的四种算法进行了对比测试以找到适合我们场景最佳的算法选型,主要结论如下:

因此我们的场景下,最终选择采用 IVF_INT8 索引算法。

3.2离线建库

std::shared_ptr<rmm::mr::device_memory_resource>resource_ptr=std::make_shared<rmm::mr::managed_memory_resource>();rmm::mr::set_current_device_resource(resource_ptr.get());raft::device_resourcesdev_resources(rmm::cuda_stream_per_thread,{nullptr},resource_ptr);
//DataT为输入数据的类型,MathT为实际进行kmeans的类型,IndexT为数据id的类型,MappingOpT为数据类型映射的类型template<typenameDataT,typenameMathT,typenameIndexT,typenameMappingOpT=raft::identity_op>voidfit(constraft::resources&handle,//资源句柄kmeans_balanced_paramsconst&params,//kmeans平衡聚类所需的参数raft::device_matrix_view<constDataT,IndexT>X,//训练数据集raft::device_matrix_view<MathT,IndexT>centroids,//聚类中心MappingOpTmapping_op=raft::identity_op())//输入数据类型到计算数据类型的映射


3.3在线检索

下图展示了我们所设计的基于GPU的ANN在线检索方案,通过batch检索来达到充分发挥GPU并行计算能力的目的。在上游查询到达时,查询将会放入查询队列中,检索线程会按照batchsize取出对应数量的query组成BatchQuery,并将其作为输入进行基于GPU的ANN检索。在检索过程中需要先将BatchQuery拷贝到显存中,然后在GPU上进行IVF_INT8算法检索,返回对应query顺序的BatchResult结果并将其从显存拷贝取出,检索服务模块对BatchResult按query拆分后进行算分、过滤等后置操作后返回结果到上游。

ingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;font-size: 14px;letter-spacing: 1px;text-align: left;caret-color: rgb(0, 0, 0);">△在线检索方案

3.4达到的效果

根据上述方案实现并测试后,对2500w256维数据集构建索引,索引所占显存<10G,建库时间<10分钟,检索服务单实例在返回结果top30的条件下可以承载约2w qps,平均查询延时在ms级。在我们的高检索流量落地场景中,总成本相比于CPU方案分别可以节省30%~50%资源。


GEEK TALK

04

思考和展望


4.1GPU在ANN检索场景的讨论

GPU与CPU相比拥有更强大的并行处理能力,它可以借助成百上千个更小的、更高效的处理核心做到同时处理大量的数据,有益于提升计算吞吐。而是否选择GPU需要注意以下几点:

△不同吞吐下的检索成本对比示意


4.2未来展望

本文以RAFT-LIB IVF_INT8算法为核心算法,借助灵活batch检索充分发挥GPU的并行处理能力,完成了ANN on GPU在百度的一类实际业务场景的应用落地,在吞吐、延迟、召回效果等多个方面保证了很好的效果,并在成本方面取得了不小的收益。后续我们将会和NVIDIA技术团队一起,对RAFT代码库的IVF_INT8算法做进一步优化,并对其它GPU相关ANN前沿算法进行深入探究,以期待GPU在ANN领域获得更多应用。






欢迎光临 链载Ai (https://www.lianzai.com/) Powered by Discuz! X3.5