“用户冷启动问题是因 ID 嵌入的质量不够高,或者行为数据少做不好预估而造成的。”
这句话当然没错,可是把注意力全放在这里能做的很有限,就好比图片中的物体识别,图片中的物体一旦被遮挡住,能做的无非是怎么更好地利用以前的经验来猜而已。同理,对用户冷启动问题也可以更合理地猜,但“天花板”很低。
另外,在新用户刚刚登录的阶段,模型对结果的影响也被控制得较小。在实际业务中,并不是新用户一上来就把推送的权限完全交给模型,一般也会维护类似精品池和新闻池来推出结果。这个好理解,新用户刚来时,为了吸引他,就是要把平台里有的最好的东西拿出来,让他一看觉得我们很有品位才行。
因此,可以把新用户再细分为两个阶段:在第一个阶段,新用户几乎没有行为记录,但此时精品池和新品池(主要是新闻等,见下节)对用户的影响很大;在第二个阶段,新用户的行为数据就不是那么缺乏了,此时模型的作用渐渐占据主导。
这里要分情况讨论,如果是商业化场景,点击购买的绝对值是很低的,在 1%~2%量级很常见;而在内容平台上完整播放的绝对值较高,甚至能到 40%以上。如果是前者,新用户的行为还不够填充正向行为序列①,但在内容平台消费曝光几十个内容后就可以填满了。在这种场景下模型唯一的弱点只有物料 ID 嵌入。如此说来,冷启动问题是否就不大了?
我们这里要说的是,其实目前排序模型的建模在第二个阶段还存在一个难点:新用户和老用户的行为分布存在巨大差异。新老用户的分布差异如图所示。
老用户的所有行为平均起来作为零点,然后以此为基准绘制新用户的分布。
可以看出,新用户的观看时长短,播放数少,他们还没有形成黏性,大多数人就是上来随便逛逛。新用户的点赞率会偏高,因为很多物料他们第一次见,新鲜感还在,而老用户已经见过很多相似的东西,点赞率就降下去了。另外,新用户的完整播放率会偏高,这也是我们在机制上做的处理,给他们推荐了更多短视频(这涉及一个产品问题,为了让用户更快地积累完成感)。
想象中,一个模型想要同时掌握两种不一样的分布,至少得有一个特征,如用指示物(是否为新用户特征,区分是否为新用户)来进行区分。模型响应这个特征,输出不同决策。要验证模型是否响应此类特征,可查看深层特征图是否因输入的不同取值而有所变化。但在实际情况下,我们会发现并非如此。掩盖某特征后对深层特征图造成的差异如图所示。
比如用户过去点击过的广告,在模型里用的话,在几十条这个量级。
图中上面的部分是某层特征图的可视化结果,这里分别计算新用户和老用户两种情况后做差(累积多个样本),可以看出差距很小,而下面的部分是将用户所在的国家这个特征改变得到的差别,从中可以明显看出模型在响应用户所在的国家,而几乎忽略了“是否为新用户”特征,那么改变就无法发挥上面我们期望的作用。我们可以说,“是否为新用户”特征被“淹没”了。
那么是什么原因造成特征被“淹没”呢?
“是否为新用户”是一个高度不平衡的特征,样本中只有 5%以下的属于新用户。根据我们网络拟人化的观点,不加特别的约束,网络肯定是很“懒惰”而不愿意去专门优化这部分的。
从理论上说,如果网络的能力只能做好一种用户的预估,或者在某些点上两类样本的梯度有冲突,网络一定会偏向样本多的用户。这种现象在机器学习问题中并不少见,无论是分新老用户、分年龄段、分活跃度都有可能发生这样的问题。
那么怎么解决此处的问题呢?
我们把不平衡的特征转换到平衡的组合上去。
假如用模型 A 专门服务新用户,用模型 B 专门服务老用户,那么我们就能解决“淹没”的问题,因为一定有一个模型对新用户负责,不管它的数据有多稀疏。
当然这样训练的结果一定不会好,因为新老用户是我们按照某种规则排出来的,很“生硬”,而且老用户的数据也能对新用户的数据预估起到帮助。灵活一点的处理方式是假设有一组基底模型,不指定其具体语义,只把新老用户看成这组基底的不同组合,那么相应地,对新老用户的决策是这组模型输出的不同加权和:
此处的 wi 为组合系数,系数可以手动指定,但我们用门网络来决定,它接受“是否为新用户”特征的不同输入,输出具体的组合系数:
到这里已经完成防止“淹没”的目标了。不过仅仅是这样还不够,推荐系统,尤其是精排模型对算力很敏感,上式用了多个模型,复杂度升得太高了。可以柔和一点,把这种加权和从整个模型的输出变成中间模块的输出,就会得到 POSO 的概念形式:
式中, x 表示第l 层的特征图;而 ˆx 表示下一层的特征图, xpc 中 pc 表示个性化编码(Personalization Code),指的是形成个性化的指示特征,目前就是“是否为新用户”。
从这里可以看出,POSO 是先分后合的,在某一层设定多个模块,然后把它们的输出合并起来。这样设计的好处是可以灵活处理整个网络,如果觉得有必要,某层可以单独拆开,同时不影响其他层。
本质上,POSO 的原理是,把在多种分布的情况下做好预测这个任务从一个模块转移到多个模块,由它们自己分化决定负责对象。
比如有 3 个模块,门网络对新用户的输出是 3、1、0,对老用户的输出是 0、1、2。我们就可以说,1 号模块主要负责新用户,3 号模块主要负责老用户,而 2 号模块则既服务新用户又服务老用户。注意和 MMoE 等方法不同的地方在于,POSO 对门网络并没有加任何归一化的约定,但为了防止特征图的尺度漂移,前面加了一个校正系数 C。
即使已经把多个模型缩减到多个模块,直接套用上面的形式对复杂度仍然不够友好。从实践角度出发,需要把精排模型中已有的模块代入 POSO 的基本公式,推导出相应的简化形式再应用。
目前常见的精排模型中存在 MLP、MHA、MMoE 这三种模块,根据我们在模型篇和前沿篇中的讲解,MHA 用来对序列特征进行抽象,MLP 是从嵌入到预测值的重要抽象环节,而 MMoE 则是多任务学习的重要工具。下面给出这三种关键模块简化后的形式。
POSO(MLP)的最终形式是
式中,xq 是输入的嵌入中第 q 个元素,所以 , W x pq q 就是原本单层的全连接层,也就是说,这样的操作相当于生成一个和特征图等大的掩码,按元素乘到特征图上去。
读者可以自行验证,有激活元的情况也是一样的。那么以此类推,POSO 代入 MLP 后的最终形式就是,通过门网络生成多份掩码,分别按元素乘在每一层的特征图上,记为POSO(MLP),由于掩码仅由“是否为新用户”这一个特征生成,复杂度的增加微乎其微。这里等价的个性化模块,即承担分化作用的对象是激活元,是比较轻量级的个性化。
POSO(MHA)的最终形式为
式中,
表示按元素乘法;这里对 Q 没有做任何个性化处理,因为它往往是所有非序列特征的拼接,本身已经是高度个性化的;对 K 做了轻量级的个性化处理,掩码和上面的 POSO(MLP)一样,是按照按元素乘的方式乘上来的;而对 V 则做了完整的个性化处理,一点简化也没有施加。这也和它的地位有关,因为 V 是直接决定输出的。
POSO(MMoE)的最终形式为
对于专家,先乘以新老用户的门网络,再乘以任务的门。注意公式中两个门网络的输入有所区别。
实践中使用 POSO 就是使用 POSO(MLP)/POS(MHA)/POSO(MMoE)分别替代 MLP/MHA/MMoE。
至此,整体框架已经得到,但在细节上还有需要重新思考的方。“是否为新用户”这个特征固然能区分新老用户,但它并不是一个完全合理的标识。
在业务中我们往往用多长时间内或多少播放数内来区分新老用户,但是好像存在一条硬线,用户过了就会发生突变,从新用户跳变成老用户。我们可以构造一个更加光滑的特征来处理这种情况,如“用户历史曝光数”(做了有界化处理,不会无限增长),即从用户下载App 开始,统计系统一共向他曝光了多少物料。曝光量小,更像是新用户,反之则是老用户。
使用用户历史曝光数作为个性化编码的好处是,既分辨了新老用户,又能在一定程度上反映非活跃用户。
注意:POSO 虽然是针对用户冷启动问题被提出的,但对于视频冷启动也适用,只需要把门网络的输入从表示用户相关的特征改为视频年龄的特征即可。
欢迎阅读《现代推荐算法》一书,了解更多相关内容!
本文分享自 博文视点Broadview 微信公众号,前往查看
如有侵权,请联系 cloudcommunity@tencent.com 删除。
本文参与 腾讯云自媒体同步曝光计划 ,欢迎热爱写作的你一起参与!