推荐算法丨向量召回

矩阵补充

模型训练

矩阵补充模型首先通过两个Embedding矩阵将用户向量和物品向量映射成低维向量,再将二者求内积得到用户u对物品i的预估兴趣分数。

训练的目标函数为: 其中y是用户u对物品i的真实兴趣分数。该目标函数的目的是最小化预估兴趣分数和真实兴趣分数的距离,以此训练Embedding矩阵。训练后,我们便可使用作为兴趣分数来补充共现矩阵中没有产生过交互的用户和物品。

线上服务

训练得到用户和物品的embedding,将embedding的结果存储到key-value表,用户的key-value表中key为用户id,value为embedding后的向量。

线上服务过程如下:

  • 把用户id作为key查询用户的向量,记作a。
  • 最邻近查找:查找用户最有可能感兴趣的k个物品,作为召回结果。
    • 第i号物品的embedding向量记作
    • 内积是用户对第i号物品兴趣的预估。
    • 返回内积最大的k个物品。

但是矩阵补充实际效果并不好,原因如下:

  • 为利用物品、用户属性信息。
  • 负样本选取方式不对。
  • 内积不如余弦相似度,平方损失函数不如交叉熵损失。

双塔模型

双塔模型(two-tower)也叫 DSSM,是推荐系统中最重要的召回通道。

双塔模型有两个塔:用户塔、物品塔。两个塔各输出一个向量,作为用户、物品的表征。两个向量的余弦相似度作为对兴趣的预估。

用户塔
物品塔

模型训练

将物品样本分为正样本(用户感兴趣的物品)和负样本(用户不感兴趣的物品)。

  • Pointwise: 独立看待每个正样本、负样本,做简单的二元分类

  • Pairwise: 每次取一个正样本、一个负样本

  • Listwise: 每次取一个正样本、多个负样本

Pointwise训练

工业界一般使用这种方法。

把召回看作二分类任务:

  • 对于正样本,鼓励cos(a,b)接近+1。
  • 对于负样本,鼓励cos(a,b)接近-1。

其中a为用户的表征,b为物品的表征。正负样本数量通常控制在1:2或1:3。

Pairwise训练

Pairwise每次取一个正样本、一个负样本。基本想法是要鼓励cos(a,b+)大于cos(a,b-),b+是正样本的表征,b-是负样本的表征。

损失函数:

  • Triplet hinge loss

    • 如果cos(a,b+)大于cos(a,b-)+m,则没有损失

    • 否则,损失等于cos(a,b-)+m-cos(a,b+)

  • Triplet logistic loss σ大于0的超参数。

Listwise训练

Listwise每次取一个正样本、多个负样本。这些物品样本与用户表征的余弦相似度经过softmax后,要使正样本尽可能大(接近1),使负样本尽可能小(接近0)。损失函数使用交叉熵损失。

listwise训练

正负样本

模型应用

双塔模型训练完成后,通过两个步骤投入实际应用:

  • 离线存储:用物品塔计算每个物品的特征向量b,把<特征向量b,物品ID>保存到向量数据库用作最近邻查找。

  • 线上召回:需要推荐时,调用用户塔线上计算用户向量a,并用a作为query查询向量数据库,查找和a余弦相似度最高的k个物品向量,返回这k个物品ID。

之所以存储物品向量而线上计算用户向量,是因为:

  • 每次召回只用到一个用户向量,而用到大量物品向量,线上计算物品向量代价过大。
  • 用户特征变化较快,而物品特征相对稳定,离线存储用户向量不利于推荐效果。

模型需要定期做更新,分为全量更新(天级别)和增量更新(实时):

  • 全量更新:每天做一次全量更新,训练整个模型,包括embedding和全连接层。
    • 将昨天的数据random shuffle。
    • 在昨天模型参数的基础上(不受增量更新影响),用昨天的数据训练1epoch。
    • 训练完成后发布新的用户塔和物品向量。
  • 增量更新:做online learning更新模型参数,只更新ID Embedding。
    • 用户兴趣会随时发生变化,因此需要及时更新模型。
    • 实时收集线上数据,做流式处理,生成TFRecord文件。
    • 对模型做online learning,增量更新ID Embedding参数。
    • 发布用户ID Embedding(推荐时使用用户ID查询用户ID Embedding),供用户塔在线上计算用户向量。

全量更新不受一天中不同时段用户使用习惯差异的影响,随机打乱数据训练效果更好。而增量更新可以动态捕捉用户的兴趣变化。因此二者需要结合使用。

双塔模型+自监督学习

双塔模型学不好低曝光物品的向量表征:

  • 推荐系统的头部效应严重
    • 少部分物品占据大部分点击
    • 大部分物品点击次数不高
  • 高点击物品的表征学得好,长尾物品的表征学得不好。

通过自监督学习做data augmentation可以更好地学习长尾物品的向量表征:

  • 对每个物品做特征两类特征变换,并通过物品塔得到两个特征向量b'和b''。
  • 对于同一个物品的两个特征向量应使其相似度高。
  • 对于不同物品的特征向量应使其相似度低。

特征变换

对物品做特征变换时主要有几种方式:

  • Random Mask:随机选取一些离散特征(比如类目),把它们遮住。例如:

    • 某物品的类目特征是u={数码,摄影}。
    • mask后的类目特征变成u'={default}。
  • Dropout:随机丢弃某个多值离散特征50%的值。

    • 多值离散特征:可以有多个取值的特征,例如类目。
    • 例如某个物品的类目特征u={数码,摄影} dropout后变成了u'={美妆}。
  • 互补特征(complementary)

    • 假设物品一个有4种特征:{ID,类目,关键词,城市}。
    • 随机分成两组:{ID,关键词}和{类目,城市}。
    • 由{ID,default,关键词,default}计算得到物品表征1。
    • 由{default,类目,default,城市}计算得到物品表征2。
    • 应使物品表征1和物品表征2尽可能相似。
  • Mask一组关联的特征

    • 离线计算特征两两之间的关联,用互信息(mutual information)衡量: 其中p(u)表示某特征取值为u的概率,p(u,v)表示某两个特征分别取值u、v的概率。

    • 设一共有k种特征,则两两之间的MI构成k×k矩阵。

    • 随机选一个特征作为种子,mask种子及其相关的k/2种特征。

    • 效果好但成本高。

训练模型

首先对点击做随机抽样,得到n对用户-物品二元组,作为一个batch训练双塔。这种方式下热门物品抽到的概率更高。

接着从全体物品中均匀抽样,得到m个物品,作为一个batch,用来训练物品塔。这种方式下所有物品被抽到概率相同。对这些物品做两类特征变换,物品塔输出两组向量:

如图,取第一组中的向量,分别与第二组中的向量取余弦,要使正样本的余弦值尽可能接近1,其余尽可能接近0。使用交叉熵损失函数。

训练模型

如此得到了第i个物品的损失函数: 对m个物品的损失取平均作为自监督学习的损失: 双塔模型的损失和自监督学习的损失共同构成整个模型的损失函数,其中超参数α用来调节自监督的作用: