作者:爱奇艺推荐中台

随着深度学习浪潮的兴起,embedding技术也随之快速发展。embedding自身表达能力的增强使得直接利用embedding生成推荐列表成了可行的选择。 因此,利用embedding向量的相似性,将embedding作为推荐系统召回层的方案逐渐被推广开来。 我们在了解了embedding生成的常用算法模型之余,对于推荐系统的实现而言,了解其工程化实践也非常重要, 本文将介绍在线向量召回服务在爱奇艺的工程化实践。

01 背景: 深度学习浪潮

推荐系统的架构已在多本书籍与多篇文章中被提及,而较为经典的流程描述之一如图1所示。从图中我们可知一个推荐服务包括几个模块: 推荐池、用户画像、特征工程、召回、排序、策略等。 我们可以看到,整个推荐流程中,召回处在整个环节的第一环,它从整体内容池中圈定了一个子集,供推荐系统从中再择优吐出至用户面前。 从这个角度而言,召回候选集的好坏,从很大程度上决定了推荐的整体好坏,召回的重要性也就不言而喻。

图1. 推荐系统的技术架构示意图

对于召回而言,有不少耳熟能详的方法,常见模型对比如下。

我们可以看到,模型的不断更迭,都是为了能加强特征组合与选择,以及整体泛化能力的强化,而随着深度学习浪潮的兴起,这些问题又进一步被推进, 深度学习可以使得模型同时具备记忆能力与泛化能力。

注释: 记忆能力可以理解为模型直接学习并利用历史数据中物品或者特征的共现频率的能力;泛化能力可以理解为模型传递特征的相关性,以及发掘稀疏甚至从未出现过的稀有特征与最终标签相关性的能力。

深度学习的流行与embedding技术的发展,使得embedding具备了 综合信息的能力强、能将高维稀疏特征向量转换成低维稠密特征向量、能通过向量运算揭示内容及用户相似度等特点。 embedding本身也是极其重要的特征向量。embedding自身表达能力的增强使得直接利用embedding生成推荐列表成了可行的选择。因此,利用embedding向量的相似性,将embedding作为推荐系统召回层的方案逐渐被推广开来。以下图2是YouTube推荐利用embedding进行候选物品进行召回的做法。

图2 YouTube向量召回模型结构图

对于embedding的算法模型有很多,如对embedding具有奠基性意义的 Word2Vec,基于Word2Vec在推荐领域推广出来的 Item2Vec,亦有广义的Item2Vec(如DSSM双塔模型),也有引入了更多结构信息的图嵌入技术的 graph embedding(如DeepWalk,Node2vec,EGES等),其对应的实现也有较多论文与文章讲述,因此本文中我们对算法模型不再过多讲述, 而是将焦点置于工程上如何能快速部署在线向量召回服务,并能让推荐引擎在线上高效访问,也就是图2的工程化落地实现。

02 在线向量召回服务化实践

1.效率是第一生产力

在业务开发中,作为工程师都知道,单一服务于某个业务与同时向多个业务服务,所要考虑的点是有较多不同的, 后者需要更多的抽象与通用性,而这也是推荐中台要解决的问题,只有这样,才能提升服务搭建的效率,解放人力用于更多的业务思考当中,而不是重复工作。

在一个推荐系统的研发过程中,往往需要算法工程师与系统研发工程师的紧密协作,前者的职责是基于业务实现可用的算法模型, 而后者的职责,一者是协同算法工程师将模型封装服务化,二者是开发推荐引擎及其它依赖子服务将整个推荐流程进行串联,供下游调用推荐接口,如图3所示。

图3 推荐系统工程师的一般职责划分

如果我们基于图3,来看向量召回服务的接入过程,将会得到图4的结果。算法工程师将基于业务特点,进行算法编写并产出embedding,同时,系统研发工程师和算法工程师将协作搭建起在线的向量召回服务,供推荐引擎调用,推荐引擎负责线上所有用户的推荐,其对性能的要求是非常高的,因此向量召回服务的性能也极其重要。对于不同业务而言,**如果向量召回服务没有通用化与服务化,****则不同业务的算法与系统开发工程师各自需要重复搭建,且需要自行进行服务运维,**这无疑是增加了推荐开发工程师的负担,也是对开发效率的损耗。

图4 向量召回服务的接入过程

对于单业务支撑而言,我们只需考虑如何搭建起一个向量召回服务,从而能对海量embedding数据进行top N检索,同时保证服务的高性能即可。而对于推荐中台而言, 在服务于多业务的情况下,需要在此基础之上再考虑如何将这个服务的搭建与运维简易化、自助化、自动化以及平台化。

2.高维向量检索引擎选型

近似最近邻算法(ANN) 目前是对海量高维向量求TOPN相似内容的主流算法。而Facebook实现的 C++库 faiss 也是经常被使用的lib,基于faiss去实现向量召回服务是1个选择。此外, 业界常用的开发框架vearch和milvus也是可选的服务之一,图5是服务选型对比。

milvus本身是为海量特征向量的近似最近邻搜索而设计, 相比于faiss这样的算子库,其提供了完整的向量数据更新、索引与查询框架。 milvus也支持利用GPU进行索引加速与查询加速,可大幅提高单机性能。目前milvus也已经得到了头部机器视觉公司的技术认可,技术社区氛围活跃。

vearch是一个分布式向量搜索系统,可以用来计算向量相似度,能应用于图像识别、视频识别或自然语言处理等机器学习领域。vearch也是基于faiss实现,提供了快速的向量检索功能。其提供类似elasticsearch的restful api可以方便地对数据及表结构进行管理查询等工作。

图5 选型对比

自实现服务与开源框架的功能基本类似,且基本都是基于C++实现。对于0-1的服务搭建,以及在充分借力社区效率的考量下,在已有的服务框架下进行开发是个不错的选择。在综合考虑各服务实现的sdk丰富度、性能指标、是否开源,开源社区是否活跃,再结合业务上推荐引擎使用java语言实现的比例越来越高, 最终选用milvus框架来实现在线向量召回服务。

3.向量召回服务化具体实现

在构建在线向量召回服务时,我们考虑到算法同学经常会针对不同场景去调整算法实现,因此,只通过封装并内置某些embedding算法实现,会使算法同学产生束缚感。因此,我们设定了embedding模型的schema,并当算法同学在推荐中台上创建了服务后,开放给算法同学一个指定路径供存放embedding模型, 此后,在设置一些必要参数后,可在推荐中台上启动在线向量召回服务,并暴露出规范接口供推荐引擎调用。 其具体设计如图6所示,在向量检索引擎上,推荐中台与爱奇艺深度学习平台进行了合作共建。 基于milvus框架,我们进行上层应用构建,来降低推荐业务开发同学的搭建成本;支持数据版本管理,来提高业务侧稳定性;支持多机房部署与服务健康检测机制,提高底层容灾能力。

图6 在线向量召回服务的整体架构

在milvus的使用过程中,我们也发现了一些问题, 例如,milvus在索引构建时CPU使用率会非常高,导致查询服务基本不可用,针对这个问题,我们也进行了解决,当我们进行数据版本更新时,我们会另起一个服务单独更新,而当更新完成时,会进行线上服务的替换,线上数据版本会保留最近2个版本。如图7所示。

图7 解决milvus索引构建时cpu使用率过高问题

考虑到业务推荐引擎使用java语言实现的比例越来越高,而milvus的查询接口以grpc接口为主, 因此,我们在其之上进行了dubbo接口的封装,便于java服务框架进行接入,这会在很大程度上简化服务的接入难度。 通过dubbo服务发现,也实现了多机房部署对业务侧的无感知。

图8 向量召回服务的dubbo服务封装示意图

在此服务封装与实现下,业务同学要创建在线向量召回服务时可达到无门槛分钟级创建,且支持在线调试。在milvus(2核6 G)& dubbo查询服务(4核 12G)8*8实例下,对600w * 64维数据进行查询,当查询qps在3k时,p99延迟在20ms左右。而业务同学的接入流程亦如图9所示,不需要再封装与搭建向量召回服务。

图9 向量召回服务化后的接入过程

03 在线推理召回一体化

在上述服务化实现中,做到了服务的通用化抽象,当在一个业务中,推荐系统开发人员要接入一个在线向量召回服务时,可以在平台上通用自助操作后,在分钟级就能获得一个服务并暴露一个通用接口供推荐引擎调用。但细心一点会发现(可以参考图9), 在向量召回过程中,查询query的向量生成并没有包含到服务中,仍然在推荐引擎模块中。 而query向量的生成方法, 一种较为简单的方式为可根据业务特点通过规则或简单算法对已有相关embedding进行加权生成,另一种就是利用embedding生成模型,在提供输入特征后实时生成。 显然,将query向量的生成包含在服务中,无论是对于解放业务同学而言,还是对于整体推荐服务构建效率提升而言,都是比较重要的。

在对整体方案与选型进行了再评估后,首先对于0-1的快速实现, 选择成熟封装好的ANN服务性价比是比较高的,这也是最终选择milvus框架的原因之一。 而随着服务建设的持续推进,后续对性能、功能的优化速度与契合度有较多考量,类似于YouTube DNN这种在线向量召回,希望把推理与召回封装到一起,如果基于milvus会涉及到新功能的依赖以及与社区迭代计划的匹配,与现阶段的内部诉求不一定一致。 另外在之前的实践过程中,我们发现milvus还有一定的问题存在,当然milvus社区也比较活跃,所存在的问题也在逐步解决。 但在综合评估之后,我们决定联合爱奇艺深度学习平台,基于hnsw lib进行改造。 之所以可以进行快速切换,主要原因有:

(1)爱奇艺深度学习平台 对hnsw lib进行了封装,并产出了一套类似于milvus的服务,并在快速迭代升级;

(2)基于hnsw lib封装的服务在索引创建时,服务依然可用, 可以解决milvus在索引创建时,cpu load较高而查询不可用问题,也能简化整体设计;

(3) 基于hnsw lib在实现类似YouTube DNN的在线推理召回一体化时相较于milvus较为便捷(我们应�