PinSage:第一个基于GCN的工业级推荐系统

PinSage:第一个基于GCN的工业级推荐系统

论文:Graph Convolutional Neural Networks for Web-Scale Recommender Systems
作者:Rex Ying∗†, Ruining He
来源:KDD, 2018

0.概括

本文的理论基础为上一篇文章:GraphSAGE: GCN落地必读论文

斯坦福和Pinterest公司合作提出了第一个工业级别(数十亿节点和数百亿边)基于GCN的推荐系统,并在离线评估和AB实验选中取得了不错的效果。

斯坦福图这块非常厉害,Node2Vec和GraphSage都是出自这里,论文中GCN落地的技巧和创新非常值得借鉴。

1.问题设定

用户在Pinterest中 自己感兴趣的东西用图钉(pin)钉在钉板(broad),包扩10亿pin ,10亿board 以及180亿边(若pin在broad中,则它们之间存在一条边)。

目标是利用pin-broard二分图结构和属性(如描述文本、图片特征),生成pin的高质量的embedding用于推荐任务,如相关pin推荐,或者作为机器学习系统的输入特征。

2. PinSage框架

本章节描述PinSage 框架和训练细节,以及基于训练好的模型使用MapReduce高效生成每个节点的embedding。

2.1 局部图卷积

局部图卷积是本文的核心,通过对节点邻域子图进行多个卷积操作,以此聚合邻居特征的方式生成节点embedding。

每个卷积模块都学习如何聚合来自子图的信息,并堆叠起来,可以获得局部网络拓扑信息。并且卷积模块的参数在所有节点之间共享,大大减少复杂度,不受输入图尺寸的影响。

2.2 模型框架

本章介绍图卷积的前向传播算法:利用节点u的特征和其周围的图结构,生产节点的embedding z_u

2.2.1 卷积层

学习如何将u周围邻居信息聚合:

Q\q, W\w 是卷积层参数,对应weight/bias

输入:

  1. 节点u当前embedding z_u
  2. 邻居embedding \{z_v|v \in N(u)\} , N(u) 为u的邻居集合
  3. 邻居权重集合 \alpha
  4. 对邻居embedding进行聚合/pooling 的函数  \gamma(\cdot) :如简单平均、加权求和、最大。

输出:节点u新的embedding z_u^{NEW}

算法:

  1. 对每个邻居embedding进行线性变换后非线性输出,然后进行有权聚合/pooling。
  2. 拼接节点u自身embedding和邻居聚合embedding,再进行线性变换后非线性输出 (实践中拼接操作比平均操作效果更好)。
  3. 归一化,可以使训练更稳定,以及在近似查找最近邻的应用中更有效率。

2.2.2 邻居采样

问题:获得节点所有邻居(如二阶内)执行卷积,也会生成巨大的子图,计算复杂度大,需要采样。

对节点u的邻居采样:从节点u开始随机游走,统计每个节点的访问次数(L1正则化),取访问次数top的节点作为u的邻居 (引自《Pixie: A System for Recommending 3+ Billion Items to 200+ Million Users in Real-Time》)

2.2.3 堆叠多个卷积层

每次进行卷积时,得到一个节点新的表示,可以通过将卷积层堆叠起来,以聚合节点K跳邻居内的特征。下面算法是对于minibatch的节点集合M,如何通过堆叠卷积生成emebdding:

输入:minibatch 节点集合M, 深度K(卷积层数)、查找邻居函数N

输出:M内每个节点embedding z_u

算法(以K=2为例子):

1. 获得M中每个节点二跳邻居(基于随机游走抽样),并保存成三个集合:

  • S^{(2)} =自身节点
  • S^{(1)}=自身节点+一跳邻居
  • S^{(0)}= 自身节点+一跳邻居+二跳邻居

2.生成M中每个节点embedding:

  1. 初始化:设置二跳内任意节点的输入层为自身特征: h_u^{(0)}=x_u
  2. 进行两层卷积及叠加操作:
    1. 第一次卷积,生成S^{(1)} 中节点embeddinng,作为第二层卷积的输入。(这个操作等价为一次传播:将二跳邻居信息传播到一跳邻居上,以及将一跳邻居原有信息传播到自身节点。 不传播到二跳邻居原因是接下来不会用到二跳邻居信息了)
    2. 第二次卷积:以第一层卷积的输出作为输入,生成 S^{(0)} 中节点embedding (这个操作等价继续做一次传播)
  3. 全连接:将卷积结果输入到全连接层。


2.3 模型训练

2.3.1 标签定义

正例:若用户在点击item q后马上点了item i,可以认为i是q的好的推荐候选,即 (q,i) 是正例。

负例:在数十亿中item中,大概率与p不相似,故简单的方法是随机采样生成负例(后面会进一步做优化)

2.3.2 损失函数

训练损失使用max-margin ranking loss,基本想法是使最大化正例embedding之间相关性,与此同时要保证负例之间相关性通过某个预定义margin 小于正例子。

P_n(q) 为item q对应的负例分布, z_i 为对应节点i的embedding, \Delta 为超参(margin)

2.3.3 基于大的minibatch的多个GPU训练

  1. 前向传播:将minibatch等分,数量等于GPU数。然后每个GPU取minibatch中的一块,使用相同的参数执行FP操作。
  2. 反向传播:将每个GPU中参数梯度聚合在一起,同步执行SGD。
  3. batch 大小从512 到4096
  4. 使用warmup计划:在第一个epoch将学习率线性上升到最高,然后指数下降

2.3.4 生产者-消费者minibatch架构

问题:GPU前向传播计算,需要在CPU中查询全图邻接矩阵和节点特征矩阵(数十亿节点GPU存储不下),十分低效。

提出生产者-消费者模式,交替使用GPU和CPU:在CPU中抽取下一轮GPU计算所涉及的节点及邻居构成的子图G'(re-index)、所涉及的节点特征、负采样操作。

2.3.5 负采样
a.简单负样本

操作每个minibatch时,随机抽取500个items作为minibatch中所有正样本共享的负样本。

b. "hard"负样本

在实际场景中,对每个q 在20亿item中选择1000个相关的item,相当于模型需要在200个item中分辨出1个。但上面负样本的设置,使模型仅需从500个中分辨出1个,但这500个样本基于与q没有相关性,这会导致所训练到的模型可能无法区分与q略有相关的item,即负样本代表性不够。

即需要寻找到与q有些相关,但不是正例的“hard”负样本,具体的方法是通过定制化PageRank得到与q相关的排名在2000-5000的items进行随机采样认为是“hard”负样本(为什么是2000-5000?)

如图所示相比随机负样本,hard负样本与query q 更相似

2.4 基于MapReduce预测节点embedding

问题:如果采用训练时的方法进行全局预测节点embedding,会有大量重复计算,比如下图中对6个节点进行预测,绿色节点embedding虽然已经学习到了,但还是会重复计算。

在全局预测时重构成两个MapReduce 任务

  1. 计算所有pins的embedding。
  2. 将pins和对应的broads匹配,并对采样邻居pin的embedding进行pooling得到broad的embedding。

得到全量节点embedding后,导入到数据库中供下游应用查询。

2.5 最近邻查找

  • 近似KNN:《Near-optimal hashing algorithms for approximate nearest neighbor in high dimensions》)
  • 基于 Weak AND 操作的两级检索:《Near-optimal hashing algorithms for approximate nearest neighbor in high dimensions》

3.附技巧和创新

3.1 提升GCN可扩展性技巧

3.1.1 On-the-fly convolutions

问题:传统卷积操作是特征矩阵与全图拉普拉斯矩阵相乘( D^{-1/2}\tilde{A}D^{-1/2}X ),非常耗时。

在局部卷积基础上,采样目标节点的邻居做进一步优化:在目标节点及采样邻居构建的子图上进行卷积操作。

3.1.2 Producer-consumer minibatch construction

问题:GPU前向传播计算,需要在CPU中查询全图邻接矩阵和节点特征矩阵(数十亿节点GPU存储不下),十分低效。

提出生产者-消费者模式,交替使用GPU和CPU:在上一轮GPU计算时,并行进行CPU计算,抽取下一轮GPU计算所需的子图G‘和子图内节点特征(re-index)。

3.1.3 Efficient MapReduce inference

问题:在采用训练时的方法进行全局预测,会有大量重复计算,比如下图中对6个节点进行预测,绿色节点embedding虽然已经学习到了,但还是会重复计算。

在全局预测时重构成两个MapReduce 任务:

  1. 计算所有pins的embedding。
  2. 将pins和对应的broads匹配,并对采样邻居pin的embedding进行pooling得到broad的embedding。

3.2 训练技术和算法上创新

3.2.1 Constructing convolutions via random walks

问题:获得节点所有邻居(如二阶内)执行卷积,也会生成巨大的子图,计算复杂度大,需要采样。

节点u的邻居采样:从节点u开始随机游走,统计每个节点的访问次数(L1正则化),取访问次数top的节点作为u的邻居 (引自《Pixie: A System for Recommending 3+ Billion Items to 200+ Million Users in Real-Time》)。

3.2.2 Importance pooling

基于随机游走得到的相似度权重对邻居特征“加权聚合”,提升46%效果。

3.2.3 Curriculum training

在算法训练阶段逐步在模型中加入越来越难的负样本,提升12%效果。

编辑于 2019-04-22

文章被以下专栏收录