近年来,我国陌生人社交用户规模不断增长,陌生人社交产品随之如雨后春笋般出现,多数以用户卡牌或列表等形式将异性资料呈现给用户。
本文将以卡牌形式玩法的陌生人社交产品积目App的实践为例,从算法和工程两方面,介绍卡牌社交推荐的架构设计。
积目App是中国首个垂直于青年文化领域的泛娱乐社交平台。积目基于用户兴趣目的匹配的社交方式,创目的图标语言,快速找到兴趣相投的朋友,实现精准匹配。通过智能分析用户画像、LBS、社交目的等信息,推荐符合调性的同类用户进行匹配,为95后-00后搭载真实社交场景,建立有效社交关系。
积目主要包括卡牌和社区两大场景,此外也有聊天室语音房等多种玩法,为用户提供了结交朋友的多种方式和渠道。
本文主要介绍我们在积目卡牌场景的工程和算法的优化实践。
积目卡牌玩法主要过程如下所示。
Step1:用户可以点击左上角“筛选”按钮,通过设置不同的基本信息进行筛选,确认后会展示符合条件的用户
Step2:用户若喜欢当前卡牌用户可以右滑,否则左滑,若当前用户A右滑了用户B,且在此之前或之后B也右滑喜欢了A,则两人匹配成功
Step3:匹配成功的用户双方则可以开始聊天
推荐策略挑战
积目卡牌社交场景,用户从滑动卡牌到最终互相聊天的整个转化链路,可以由下图来表示。
p1:右滑(喜欢)概率
p2:右滑后的匹配概率
p3:匹配后的发送聊天概率
p4:发送聊天后收到回复概率(达成aba的概率)
由上图可以看出,卡牌社交场景存在转换链路长的特点,导致需要优化的子目标众多。
陌生人社交最终需要以双向匹配聊天为最终转化目标,用户右滑卡牌后,如果长期无法得到匹配回应后,则用户很可能流失。
因此在这种场景下,相比于常规的视频、商品推荐,陌生人社交推荐转化链路会更长,建模负责度会更高。
一个良好的陌生人社交产品体验,不仅仅包括当前用户单向的喜欢,也要考虑后续的双向匹配,以及最终的深度聊天等更长远的转化。
卡牌推荐系统的核心是推出符合用户条件的合适的数据,整套体系的基本功能应该满足:
能推出数据(内部维护可用数据源)
能进行数据条件按筛选(构建数据索引)
不能推出重复的数据(已读维护)
以某app的卡牌推荐系统为例,整个业务推荐体系,经过两年的迭代,逐渐趋于平稳,形成了一套合理的架构,将数据的维护、分发流程分层化、服务化。
整个系统的流程如下:
这套系统在面对更高用户数场景的情况下,会逐渐显露出各种问题,业务上急需针对性优化,统一整个业务推荐架构。
这套系统下,向量召回中一些重点功能的设计:
内部维护可用数据源:用户信息读取到内存中,需要定期ftp拉取全量用户,更新内存中信息
构建数据索引:读取全量用户信息后,在内存中穷举用户可能的筛选组合,构建多个hash索引
已读维护:依赖客户端曝光上报,维护一个当日全站匹配的布隆过滤器
为了加速检索过程,初版方案将依赖的数据都加载到内存中,但是用户数增多后,种种弊端开始展现出来,以千万级别用户为例:
常态下用户数据+用户索引+用作已读的布隆占据了每台机器大概近百G的内存
数据更新时,经历ftp拉取文件+加载数据的过程,导致单台机器不可用时间高达数十分钟
已读方案不合理,因为没做到精确到用户的已读数据维护,导致已读数据过大,检索效率低,单个请求耗费cpu资源极高,在32核机器测试,qps仅能达到5
核心问题在于:
如何提供高效率的元数据筛选机制?
如何提高硬件资源利用率?
如何提高服务可用性?
这三个核心问题,完全限制了业务发展,在原有方案下,若想将服务的用户数提高,需要资源在横向、纵向上都做升级,但是单台机器配置已经很高了,继续升级资源显然不合理。
积目卡牌整个推荐流程框架设计如下图所示,采用通用的推荐系统框架,召回和排序以及重排三大部分。
本文主要会对排序模型部分进行介绍。
推荐算法的数据流和模型框架如下图所示。
我们将整个系统分为4层:
业务层:负责实现产品逻辑,包含卡牌内容渲染、二次过滤、卡牌强插等逻辑,与推荐系统相关性不大
策略层:可以根据用户所在地、注册时间、实验id,使用户命中不同的业务、算法推荐策略
召回层:负责处理数据的获取流程,每个召回层会包含一个召回源,用户的每一次请求,可能命中多个召回源
模型层:负责算法模型的实现,产出最基础的数据,供给召回层
市面上的基于位置服务(Location Based Services,LBS)的社交产品,一般核心功能是推荐附近符合用户筛选条件的人(也称为卡牌),基于用户对卡牌的喜欢与不喜欢,构建之后的社交链路。
一个完整的流程为:用户发起筛选卡牌请求 -> 业务层聚合卡牌信息(如头像框、距离、签名、动态...) -> 推荐层根据用户画像,执行不同推荐的策略 -> 召回层获取符合条件的卡牌数据。
实际的数据流转:
积目卡牌的核心指标包括以下几个:
喜欢率(喜欢次数/曝光次数),
匹配率(匹配次数/曝光对数),
聊天率(主动发消息会话/曝光次数),
在实践场景中,增加定义了aba聊天率(双方聊天一回合以上会话/曝光次数)
匹配模型需要在综合考虑整个链路,最终达到核心指标的提升。
不同用户有不同的外貌、兴趣、职业,我们需要在众多异性用户中,根据当前用户的兴趣,快速筛选推荐出其感兴趣的用户,提供给用户良好的使用和社交体验。
卡牌场景,算法优化核心指标有多个,是标准的多目标优化场景,且具有链式转化特点,后续目标只能在前一个任务发生后再发生,例如匹配只能在喜欢之后发生。
解决多目标任务的通用方案有两种,分别是,多模型融合和多任务学习模型,如下图所示。
经过分析,多模型融合的方式,在任务关联性不高,样本充足的情况下会有较好的效果;
多任务学习方式,则是在任务关联性高,且部分子任务样本稀疏或较为复杂的情况下有诸多优点,如通过“隐式数据增强”和“特征信息窃取”等[参考资料1]方式提升效果。
从前文分析可以看出,在社交场景中用户行为具有以下两点特征:
1、存在前后的链式依赖关系
2、转化链路较长
其中特征2导致越是更深层次的转化,样本会越稀疏,从而难以直接建模学习,故适用于采用多任务学习的方式进行建模。
即通过多任务的联系性,提升了易训练性和鲁棒性,且在多个优化目标的场景下,更容易优化维护。
阿里巴巴在2018年提出的ESMM模型[参考资料2]的思想,为电商的稀疏转化场景建模提供了新的思路,训练过程中共享ctr和cvr模型的参数,进行知识迁移,提升了模型效果。
在业务实践过程中,我们初版参考ESMM模型,设计了如下模型,主要分为三部分:
1、输入特征层
特征主要分为稀疏特征和稠密特征,稀疏onehot特征经过Embedding层转为dense向量,multihot特征经过Embedding层进行sum pooling,再与dense特征三者拼接,作为多任务tower部分的输入
2、多任务tower网络
根据优化目标,建模四个tower模型,分别拟合右滑率,右滑后的匹配率,匹配后的聊天率以及聊天后的aba率四个子目标
3、输出层
根据条件概率公式,可以得到右滑率、右滑匹配率、右滑匹配聊天率以及右滑匹配聊天aba率共四个预测值
为了进一步提升模型效果,经过分析后,主要做了以下几方面的优化。
Base模型中,处理非定长的multihot序列特征,在经过Embedding层后,进行了sum pooling操作,没有体现出用户序列中不同用户和当前候选用户的相关性。
阿里巴巴于2018年提出的DIN网络[参考资料3]很好地解决了这个问题,通过激活单元,局部地激活用户的历史兴趣,赋予和候选广告相关的历史兴趣更高的weight。
我们使用了这种方式来处理用户的序列特征,其结构形式如下图所示,序列中不同用户weight的多样性同时也实现了用户兴趣的多样性表达。
为了进一步使模型能更有效地学习特征交叉,我们参考使用DCN-V2[参考资料10]网络,采用堆叠(串行)的方式,如下图所示。
交叉网络(Cross NetWork)每层的特征交叉公式为:
该函数网络具体工作原理如下图所示。
可以看出该交叉网络能够更加有效地学习显式和隐式特征交叉,提升了模型的表达能力。
腾讯2020年提出的PLE[参考资料4]进解决了子任务之间的冲突问题和任务关系复杂情况下的跷跷板现象(牺牲其他任务性能来改进某些任务)。
在实际应用过程中,根据积目卡牌场景的具体优化目标,经过ESMM以及MMoE模型的开发迭代,最终设计开发了基于谷歌2016年提出的Wide and Deep[参考资料5]架构的PLE模型,如下图所示(为了简化,图中表示出只有两个链式目标的网络)。
模型的Wide线性部分可以有效地记忆稀疏特征,而在深层神经网络部分通过挖掘特征之间的交互,提升模型的泛化能力。
在深度模型模块,我们通过PLE模型中的共享专家模块去学习各个子任务之间的共性,私有专家模块去学习子任务的独特性,从而同时优化多个子任务。
多目标模型的多个子任务目标,同时进行优化,不同任务的loss量级不同,可能出现loss加大的任务主导模型的现象,如何分配给不同子任务更合适的权重,则是模型优化的一大难点。
我们参考了剑桥大学在2018年提出的可训练的loss权重[参考资料6],具体公式如下,
可以看到,权重分母为可训练的自适应参数,并增加了正则项。
在模型训练过程中,根据loss的量级进行加权,如果loss增大,不确定性增强,则其权重减轻,反之loss减小,不确定性低,则增大其权重。
经过实践证明,相比于固定权重,自适应的方法能够使多任务模型子任务学习得更加充分,效果更加平衡。
新模型开发完成后,对比上版本的MMoE模型,各个子任务目标AUC有了明显的提升,如下图所示
提高系统吞吐,提高系统可用性,降低资源成本,支撑百万级社交推荐场景。
业界包含布隆过滤的几种方案对比:
RoaringBitmap
Bloom Filter
HyperLogLog
原始的已读以天维护当天全站喜欢/不喜欢记录,导致每个用户的已读过滤,需要判断近90个的超大布隆过滤器。一个简单的优化思路是单个用户的已读单独维护,结合RoaringBitmap[参考资料7]方案后,已读维护使用流程:
与历史方案对比:
每次已读信息放在请求中透传,不需要内存中维护已读信息,使得服务内存占用显著降低,服务启动加载数据耗时大幅降低,同时请求平响大幅提升。
rbm已读的增删机制,使得用户拉黑后/取消拉黑后,已读也能及时变更,避免了多个来源的已读复杂的维护机制。
历史方案上为了加速检索,讲用户信息及查询索引都在内存中构建,他的形式类似于:
|
用户信息使用上仅需要键值对查询,所以hash是一种非常高效的方式。但前期同时使用了hash作为查询,随着查询条件越来越多,越来越复杂,所需要维护的hash索引也越来越多。导致数据更新流程较为复杂。
用户实时信息的变化依赖外部脚本去调用服务暴露的数据接口,更新元数据及查询索引。同时,为了防止索引更新异常或外部脚本异常,会定时拉取全量数据,在服务内构建索引。
这样的流程带来两个核心问题:
外部脚本未服务化,不能保证可用性,非常容易出程序问题及逻辑问题,导致元数据信息不一致,从而使得全量更新的步骤必不可少
全量更新过程中服务io、cpu飙升,即使做了平滑更新,也达不到高可用要求,只能在定时更新过程中摘除流量
同时也带来其他一些问题:
数据存放在本机内存中,服务器间无法共享,随着机器的增多,内存资源无法相互利用
索引逻辑复杂,每当产品需求调整,需要调整索引配置,及硬编码索引查询逻辑
涉及距离筛选使用geohash,只满足固定范围内的查询
针对现有需求:
满足基于lbs的多条件查询
数据可实时更新
提供一定的向量加速检索功能
对比了业界一些技术方案[参考资料8]:
因为业界的一些方案不满足我们的基本需求,如不支持lbs查询、不支持繁杂的多条件筛选,或是为了构建支持向量加速检索的耗时过多。最终我们决定使用pgsql提供数据存储及查询功能,自研向量计算模块代码(参考历史服务)。
元数据方面:
使用pgsql完美契合了我们需求并提供了不错的性能
元数据可以随时更新(当然,常见sql都支持)
支持地理位置范围查询[参考资料9]
支持复杂的查询条件
加速检索:
历史上向量检索过程中并没有做加速操作,在对比业界方案[备注2]后,考虑到我们的卡牌推荐,天然就是依赖地理位置聚类,用户附近的可选卡牌并不多 ,所以我们讲向量推荐过程从查询+相似度计算,变更为先查询,再计算,这样达到计算量可控,不需要加速检索。
数据流向:
自研模块中,我们改变了过去用数据来通信的模式,不再定时拉取ftp文件,而是用通信来改变数据,算法研发产出向量数据后,投递到消息队列,业务研发消费数据,维护算法推荐池。
至此为止,整体的数据流转变更为:
最后,结合业务推荐框架,我们将向量召回做成了一路与业务数据源本质上一致的数据源。可以高自由度的配置,达到数据源与业务数据源任意混合的方式。
新的架构下,在保证机器资源缩减82%的明显优势下,单机qps还同比上升了2900%。
同时,也逐渐将业务与算法的卡牌推荐流程统一,复用业务组件,最终将算法推荐容纳在业务推荐系统内,做到对研发白盒且无额外门槛,降低研发心智负担。
陌生人社交App的良好用户体验需要工程和算法的共同协作。工程是用户流畅使用体验的基础,算法是优质内容的保障,二者缺一不可。
随着用户规模的增长,算法模型复杂度提升,模型大小逐渐增长,算法侧如何在保证模型效果的前提下,优化模型体积和计算复杂度,工程侧如何保障上线大模型时的服务稳定性,则是未来工作的优化重点。
一文"看透"多任务学习:https://cloud.tencent.com/developer/article/1824506
https://arxiv.org/pdf/1804.07931.pdf
https://arxiv.org/pdf/1706.06978.pdf
https://dl.acm.org/doi/abs/10.1145/3383313.3412236
https://arxiv.org/abs/1606.07792
https://openaccess.thecvf.com/content_cvpr_2018/papers/Kendall_Multi-Task_Learning_Using_CVPR_2018_paper.pdf
RBM优势:https://www.jianshu.com/p/818ac4e90daf
pgsql地址位置索引:https://www.alibabacloud.com/blog/spatial-search-geometry-and-gist-combination-outperforms-geohash-and-b-tree_597174
常见向量检引擎:https://zhuanlan.zhihu.com/p/364923722
https://arxiv.org/pdf/2008.13535.pdf