今天的文章还是由一个我亲身经历的故事来开篇。在一次面试中,面试官问我怎么处理“新用户冷启动”的问题,当时,我是从算法的角度来回答的,比如通过online learning,加快线上模型的更新频率;再比如,我当时想把PinSAGE由item-2-item升级为user-2-item,这样只要新用户点击过一个item A,我就可以将A的信息、点击过A的其他user的信息、点击过A的其他用户点击过的item信息、......都聚合到新用户身上。巴拉巴拉讲了一堆,面试官显得不是很满意,只见他大手一挥,中气十足地说到:“没那么复杂,处理新用户,归根结底就一句话,尽可能多地找这个用户的数据!!!”。当时我还是有点小受震撼的,感叹道,面试官一眼看到问题本质,怪不得是人家面试我呢。于是,我立刻切换到产品思路,比如构建产品矩阵,从其他产品了解用户;通过弹窗问卷的方式,收集用户的兴趣爱好;......,这下面试官方才满意,于是面试愉快地进行下去。
现在回过头来,重新思考“新用户冷启”这个问题。毫无疑问,针对我们所知甚少的新用户做推荐,是一个极其困难的问题,尽一切努力收集用户信息,也绝对是top priority。但是,因此我们算法就无事可做,等着产品和前端同学把新用户的数据送过来?
根据我近年来的经验,新用户的数据是极其重要的,但是并非问题的全部。比如,新老用户在app中的行为模式有很大不同(e.g., 比如一些产品设计不允许新用户做点赞、评论等动作)。但是,在训练的时候,老用户的样本在数量级上碾压新用户的样本(本来dau就主要是由老用户贡献,再加上一个老用户能够贡献多条样本),导致模型主要拟合老用户的行为模式,忽略了新用户。在这种情况下,增加几个对新用户友好的特征(比如年龄、性别等),因为主导模型的老用户不care(影响老用户推荐结果的主要是其过去历史,而非人口属性),加了也是白加。
噢,看似是一个样本不均衡的问题,也不是毫无办法。比如:
对付新用户,以上方法虽然简单,但是真的不妨一试。如果也觉得以上方法的缺点无法接受,不妨向下读,看看本文替你总结出的一些从算法层面助力新用户冷启的技巧。
正文开始之前,先提前声明几点:
既然我们通过数据分析,先验已知新老用户的行为模式有着较大差异,我们希望把这一先验知识告诉模型,让模型对新老用户能够区别对待。至于如何注入这样的先验知识,我已经在我的另一篇文章《先入为主:将先验知识注入推荐模型》介绍过了,简述如下。
首先,我们要构造能够显著标识新用户的特征,比如:
可以把这些强bias特征加得离final logit近一些,让它们对最终loss的影响更直接一些。比如:
方法二,将这些强bias的特征,喂入SENet或或LHUC(Learn Hidden Unit Contribution,如下图所示),用来决定其他特征的重要性
强bias特征作为LHUC的输入,经过sigmiod激活函数后,输出是一个N维度向量,N是所有fileld的个数
N维向量就是各field的重要性,将其按位乘到各field的embedding上,起到增强或削弱的作用。比如:
加权后的各field embedding再拼接起来,喂入上层DNN
这样做,相比于将所有特征“一视同仁”、一古脑地喂入DNN最底层等候上层DNN筛选,更能发挥那些对新用户友好的重要特征的作用。
正如开篇所说,为了避免新用户数据被老用户淹没,干脆分家,用新用户的数据单独训练一个模型只服务新用户。但是有两个问题不好解决,一是新用户数据少,单独训模型可能训不好;二是,单独训练+部署,有点浪费资源。
其实这个问题属于multi-domain learning的解决范畴。不要和multi-task learning相混淆,multi-domain learning研究的是如何将多个相关渠道的数据放在一起训练,而能够相互促进,而非相互干扰。这方面的工作并不多,让我们看看阿里近年来在这一领域发表的两篇文章。提醒读者,尽管两篇文章的初衷都不是针对新用户,但是在阅读过程中,我们可以代入new user domain vs. old user domain的场景。
一篇是《One Model to Serve All: Star Topology Adaptive Recommender for Multi-Domain CTR Prediction》。这篇文章研究的是,如何训练并部署一个模型,就能胜任“首页推荐”、“猜你喜欢”等多个领域。前两个改进也很“直觉”(嘿嘿,知道我模仿的是谁吗?)
第三个改进,就是所谓的星型拓扑结构,也就是论文标题的来源。简单来说,就是每个domain要经过的final dense weight是domain specific part和shared part融合而成。
是domain 'p'的样本最终要经过的final weight,
是domain "p"独有的weight,只让domain "p"的样本参与迭代更新
W是shared weight,所有domain的数据都要参与更新。
是element-wise multiplication
我有点不太好评价这种结构。其实想结合domain specific information与shared information也不算什么新概念,比如下面两种:
文中并没有给出 这种融合方式,相对于我在上文提出的两种融合方式的优势,或许没啥大道理,又是实验得出的结论。我自己给出的理由只能是:
AliExpress的文章《Improving Multi-Scenario Learning to Rank in E-commerce by Exploiting Task Relationships in the Label Space》聚焦于多国家场景下的推荐。这个场景,和我们新用户的场景更加类似一些,多个国家的人口迥异,市场进入有早有晚,相对于先发国家庞大的用户基数和丰富的行为,后发国家的用户少、行为少,可以类比于“新用户冷启”的场景。
这篇文章提出的HMoE与STAR完全相反,没有所谓的shared weight。其原理假设是:
具体做法上:
这种方法的思路是,新用户训练困难是因为数据少。但是,如果新用户的初始值并非随机,而是已经非常靠谱了,通过少量数据+几次迭代,就能收敛到不错的用户表示,岂不妙哉!
上述思路简直就是为MAML(Model-Agnostic Meta-Learning)量身定做的。MAML主打的招牌就是Fast Adaptation
于是基于MAML,韩国人提出了MeLU想学习出对新用户友好的初始值。文章的细节,我就不多说了,因为如果基础错了,剩下的实现细节也就毫无价值,浪费笔墨罢了。
我就问两个问题:
我也就纳闷了,这种脱离推荐系统实际、毫无实战价值的文章,是怎么被KDD录入的?还被那么多讲新用户冷启的文章引用!简直是误人子弟!!!
介绍一种我自己设计的方法,用来获取良好的new user id embedding初值,在一些场景下的效果还不错。
我的方法的前提假设是:
既然user id embedding那么重要,而新用户的user id embedding质量却那么差(训练时得到的随机向量,预测时得到的是全0向量),那么能不能找到一个替代方案?这时,Airbnb的经典文章《Real-time Personalization using Embeddings for Search Ranking at Airbnb》给我提供了一种思路。在Airbnb的实践中,由于booking这个行为太稀疏,所以绝大多数用户都是“新用户”,而Airbnb的思路就是根据规则将用户划分为若干用户组(比如,“讲英语,使用苹果手机”的用户群,和“讲西班牙语,使用Android手机”的用户群),然后用user group embedding代替单独的user id embedding参与后续训练与预测。
基于以上假设,解决思路是:
将user id embedding(无论新老用户)拆解成
是“初始的用户群”的embedding。
代表自用户进入app之后,随着在app内部行为越来越丰富,他距离当初“初始用户群”embedding的个性化残差
对于老用户,原来的方法是直接学习每人各自的user id embedding,现在是改学 ,所有个性化信息都包含在这个个性化残差里了。
对于新用户
目前还遗留一个问题,就是 怎么得到?我的方法是采用预训练的方法
如上所述,分群是“初始用户群”,划分时,只能依靠那些对新用户友好的特征,比如:年龄、性别、安装那些(种类)的app,是被哪个(类)广告拉新进来的、......
借鉴Airbnb的方法,用类似word2vec的方法获得各 ,具体来说,
注意,在我的实践中,进行以上预训练,只采用新用户的数据,不用老用户的数据。
预训练完毕,将各init user group embedding保存起来
注意,在正式训练的时候,
最后提一下,既然要利用new user friendly feature分群,再用user group embedding代替新用户的user id embedding,那为什么不直接将这些特征接入DNN,直接让DNN学习不就完了,何必这么麻烦?如果有小伙伴能够想到这一层,首先要为你自己的独立思考能力点赞。问题的关键还是这些new user friendly feature的接入位置:
本文聚集于新用户冷启这一让推荐算法工程师头疼的问题,从以下几个方面总结了我个人的看法与经验:
由于公众号试行乱序推送,您可能不再准时收到机器学习与推荐算法的推送。为了第一时间收到本号的干货内容, 请将本号设为星标,以及常点文末右下角的“在看”。