收录自 DataFunTalk 公众号

分享嘉宾:刘金老师

编辑整理: 李亚俊

内容来源: DataFun AI Talk《饿了么推荐算法演进及在线学习实践》

出品社区: DataFun

本次分享的主要内容包括以下三个方面:首先是介绍推荐业务背景,包括推荐产品形态及算法优化目标;然后是算法的演进路线;最后重点介绍在线学习是如何在饿了么推荐领域实践的。

一、 推荐业务背景

推荐产品形态

大部分人都熟悉饿了么app,甚至通过饿了么app点过外卖。上图中着重圈出的内容就涉及推荐排序,其中首页推荐、类目、搜索构成了整个饿了么流量的入口,通过这些入口覆盖了全网90%以上的订单。

目前饿了么每天的订单量达到千万级别,属于国内Top级,这就意味着流量分发的效率尤为关键,因为它涉及用户体验、商户利益、平台价值,而算法就在该领域发挥着重要的价值。

算法优化目标

在外卖领域有4个重要环节:流量、供给、转化和履约,其中算法在履约环节起着关键的作用。

在不同的业务阶段想要实现的目标也是不一样的。业务成长初期,优化app的点击率、转化率,当用户点击之后想促成成交;随后考虑平台收益就会关注客单价、单均价等;以及后期的满意度等抽象指标,需要将这些大目标拆解为小目标,分别建立不同的算法子模型进行优化。

二、 算法演进路线

从2016年至今,饿了么主要经历了数据、特征、模型、业务理解4个方面的升级。

数据&特征升级

数据及特征方面进行了4个方面的升级:

1) 生产方面:将离线数据升级为实时数据;

引入Flume、Kafka等实时体系,通过模型打分将业务端实时生成的业务日志输出到日志服务器,构建样本时就不需要离线拼接样本特征及标签而是在线生成特征,进而保证特征的质量,避免了特征穿越、特征不准等问题。

2) **时效方面:**数据采集从天级别升级为实时,且增加了多维度实时特征;

3) 规模方面:不仅引入大规模的稀疏特征,而且将item、user、query等业务流程中涉及的环节通过Word2Vector等实现了向量表达。

4) 监控方面:在特征覆盖及波动、异常值检测、埋点问题等方面进行了实时监控。

模型升级

最初通过人工规则提取特征,基于人工经验敲定采用的因子及权重,线上进行A/B Test实验。当线上效果不太满意时,再次修改因子或权重,这样不仅浪费了时间,而且浪费了很大的流量。

16年上线了简单的LR线性模型,通过机器学习的方法获得各因子权重,与此同时引入用户维度信息,这一阶段形成了个性推荐的雏形。相对于人工规则,点击率、转化率提升了10%。

16年底采用了非线性模型,包括GBDT树模型、FM等,相对于线性模型,在特征交叉表达方面效果提升明显。16年底我们上线了第一版本XGBoost点击率预估,随后基于业务的理解将其拆分为点击率、转化率2个子模型,并引入用户、商户的实时反馈特征,如用户点击某个餐厅、餐厅近一个小时或者一天的情况,效果提升7%-8%。可见用户维度信息增多了,特征维度丰富了,模型结构复杂了,真正做到了千人千面个性化推荐。

从17年饿了么开始在推荐领域尝试使用深度学习及在线学习。目前在线学习已应用在饿了么的很多业务场景。

下面简单介绍Wide&Deep、DeepFM两个深度学习模型是如何应用在饿了么推荐排序领域。

(一)Wide**&** Deep

初始阶段参照Google发表的论文,复用GBDT模型使用的特征,将用户稀疏特征、商户稀疏特征输入线性部分,在没有引入更多特征的前提下,相对于base版本效果没有特别大的突破。

随后将用户稠密特征等加入Deep部分,将GBDT的叶子节点通过One-Hot或者重新编码的方式加入Wide部分,效果有了较大的提升。

但是模型结构复杂度的增加使得在线预测达不到工程响应时间要求。现阶段模型一直在优化,在业务低峰期仍使用此模型,业务高峰期工程上采用降级的方式。

(二)DeepFM

随后尝试了DeepFM,总体结构和论文保持一致,充分利用DNN提取高阶特征组合以及FM提取二阶特征的能力,实现了自动提取特征,是一个端到端的模型。该模型在很长一段时间用于首页推荐,实验效果比较理想。

模型经过不断地演化,现阶段外卖推荐系统架构与大部分推荐系统架构类似:

1)数据来源:包括业务日志、服务端日志、用户行为日志;

2)基础设施层:包括大数据处理的Spark、Hadoop以及用于实时计算的平台、工具。可以看出引入了很多开源组件,加入阿里后考虑引入公共基础设施,避免由于开源组件本身存在的问题困扰业务发展;

3)特征层:包括商户、用户、上下文、交叉组合等维度特征;

4)模型层:特征层的数据输入模型层后调用实时数据、用户画像等数据服务层;

5)数据服务层:包含实时数据服务、画像服务、特征服务等;

6)业务层:结合模型输出的结果用于在线业务投放等。

三、 在线学习实践

目前在线学习(Online Learing)这几年比较热门,利用一年左右的时间,从无到有搭建了在线学习。

3.1 在线学习的特点

为什么要做在线学习?很多时候我们会遇到类似问题:利用离线数据训练的模型效果很好,而在线效果却不理想。这就意味着离线评测与在线效果之间存在很大的gap。

这是什么原因造成的呢?主要是由于数据分布数据时刻发生变化,特别是外卖业务,用户在不同的时间段会选择不同类型的外卖,而商户会随时上线各种营销活动,这就使得数据分布范围、分布趋势发生很大的变化。

而在线学习的优势就是利用实时收集的样本数据及用户反馈实时更新模型参数进行预估,最后进行最新的投放,进而实时反馈用户兴趣爱好等变化带来的影响。

在线学习与离线学习的一个重要区别是它可以简单地理解为数据集无限大,时间序列无限长。它不需要存储大量的样本数据,而是利用样本流数据逐条地更新模型,样本学习完成后丢弃。这就避免了离线模型随着数据量增大导致模型无法训练,即便采用分布式训练,训练速度也会变慢。

最后,总结在线学习的特点:

##3.2理论基础

FTRL模型是参照谷歌发表的论文实现的,模型参数、响应速度均可达到电商领域或推荐领域的生产要求。

3.3 在线学习技术栈

    在线学习使用的技术栈包括以下几个方面,引入了很多的开源组件:

3.4 在线学习流程图

现阶段在线学习流程图如下:

最左侧是 实时效果归属:基于在线排序引擎实时收集业务日志、用户行为日志,利用storm聚合生成一个实时样本流;然后进入 在线模型训练 实时消费样本流,利用FTRL模型实时更新参数,在不同时间将模型参数快照定时存入redis。说到快照的好处,它不仅支持模型增量学习,而且即使模型训练终止,也可以加载历史参数从某个节点重新进行模型训练。

在线预测:定时拉取redis中的模型参数提供线上预测服务。至于为什么采用定时更新参数,稍后给出答案。

上述三个模块最终能够形成一个闭环,关键在于将所有的数据源join起来。

那么又是如何做到将所有的数据源join起来,在此特别介绍一下实时归属模块。将用户行为、服务端日志、订单日志等数据经过清洗、过滤等,在Storm中利用唯一id将整个业务join起来。在整个数据体系设计过程中给每一次排序打上唯一id,在整个的业务流程环节中标记此id。特别地,Storm对状态管理支持不是特别好,目前通过web存储的方式进行状态管理,防止任务挂了丢失状态信息。

通过Storm 聚合之后可以产出时间列、维度列、事实列三种基础效果数据,其中时间列包括数据产生的时间节点即时间戳等;维度列主要包含数据的入口、位置、业务场景、特征等信息;事实列包括信息是否曝光、用户是否点击、购买以及购买金额、商品信息等。

三种基础效果数据相当于样本特征及标签,可用于在线学习,对应的模型结构如下:

从模型结构上来看,将GBDT与FTRL进行了融合:基于实时样本流,利用点击 GBDT模型、下单GBDT模型产出叶子节点进行编码,原始特征分桶或者离散后加入模型,利用FTRL更新模型参数存入redis实现在线排序。

目前模型结构相对来说简单,业务效果的提升主要体现在模型调参,在此简单地介绍 几个小技巧:

采样策略

1)位置截断:考虑到不可能利用所有的实时样本,因此会结合业务特点及数据特点进行位置截断:

如用户不小心刷到位置特别靠后的列表数据,这部分数据对于预测效果价值不大就会丢弃;

2)业务过滤:之所以存在业务过滤,是因为最后的投放不仅仅取决于算法结果,也取决于业务规则。如新店的加入或扶持特定的商家,需要将它的排序强行放在首位,这样带来订单量的提升就不是算法的功劳。

3)根据样本目标设置样本权重:根据不同阶段的目前进行样本权重的调整,比如现阶段的业务目标是优化GMV,将会调高GMV的样本权重。

参数更新

为什么采用定时更新参数的策略,而不是实时更新参数?主要是考虑到工程的难度,在线预测服务不可能实时获取参数,否则将影响在线服务性能。目前采用5分钟定时获取模型参数,保证模型抖动不会太剧烈。若由于样本延迟造成正负样本比例发生变化或者特殊情况导致参数发生波动,这样的更新策略就可保证模型的稳定性 。

样本不均衡

在外卖场景中,正样本特别宝贵。假如与跟正样本相关的订单数据流由于网络等原因造成延迟导致样本数据都