首发于论文笔记
[论文笔记]PinSAGE——Graph Convolutional Neural Networks for Web-Scale Recommender Systems

[论文笔记]PinSAGE——Graph Convolutional Neural Networks for Web-Scale Recommender Systems

论文:《Graph Convolutional Neural Networks for Web-Scale Recommender Systems》:Pinterest公司在GraphSAGE等模型思路的基础上提出并应用于实际推荐业务场景的PinSAGE算法模型。

原文链接:arxiv.org/pdf/1806.0197

GraphSAGE阅读笔记:

ABSTRACT

在论文发表的2018年,虽然图神经网络已经成为了众所周知的研究热点,但针对实际生产环境中数十亿级别的item数量和上亿级别的user数量,缺少在推荐系统中实践的实例。

Pinterest在继承一些GCN思路和实现方法(random walk、图卷积)的基础上,开展了对采样方式和训练策略的改进,通过这些改进,Pinterest完成了在具有30亿个节点和180亿条边的图上的模型训练和落地。

INTRODUCTION

简单了解一下Pinterest——一款以兴趣为基础的社交网络,提供图片瀑布流的用户体验,论文发表的时候还没有上市,估值蛮高,现在的话市值200多亿刀。用户看到一个图片如果喜欢的话可以pin到自己的board中,好友可以repin(转发)。图片会有对应的主题,比如美食、穿搭、体育、美妆等等,自己的board也可以对pin在其中的图片分类。

Pinterest首页

接着说模型,可以认为PinSage是GCN在推荐领域的一个分支发展,GCN的核心思路是通过对图神经网络的不断迭代学习,从邻居节点上凝聚出图局部特征信息(aggregate feature information from local graph neighborhoods)。具体的实现可以看下图——左上角是我们拥有的一张图,A点是我们的目标节点,我们希望通过深度为2的图网络获得A点的Embedding信息,首先向下搜索A的所有一阶邻居(B、C、D)完成第一层搜索;接着分别对B、C、D做向下搜索,得到B点的一阶邻居(A、C)、C点的一阶邻居(A、B、E、F)和D点的一阶邻居(A),这时完成第二层搜索;反过来通过卷积核向上计算更新每一层的节点向量,最终回到A点,完成一轮更新。要完成整张图的更新,就需要对所有点执行对A点的操作(最下面的多个小图BATCH of NETWORKS)。

深度为2的图卷积网络示意图

如同GraphSAGE中提到的,GCN以往的计算在整张图上展开,来到上亿节点规模的图上,计算代价昂贵的同时也不能对新节点快速生成Embedding。PinSage就结合random walk对其做了改进(a random-walk-based GCN named PinSage)。原文枚举了算法的进步和优势——

  • 动态卷积(On-the-fly convolutions):主要通过限制搜索层数和每层节点数实现,避免了整张图上计算拉普拉斯矩阵的大额开销;
  • 小批量计算(Producer-consumer minibatch construction):协调CPU、GPU、内存间分工提升GPU计算效率,在CPU上完成局部卷积的定义,GPU上使用与训练模型计算更新模型参数;
  • MapReduce(Efficient MapReduce inference):管道化计算(pipeline);
  • RandomWalk(Constructing convolutions via random walks):短途随机游走(short random walk),为每个节点生成一个重要性得分,便于池化计算;
  • 重要性池化(Importance pooling):在上一步的重要性得分基础上,进行池化计算;
  • 强化训练机制(Curriculum training):采用越来越难的样本数据训练( fed harder-and-harder examples ),保证模型可以不断提升的训练机制;

RELATED WORK

这部分介绍了PinSage受到启发的基础,比较出名的word2vec、randomwalk、GCN等等,真的写过学术论文的话,dddd,一个意思换着法子反复讲。值得注意的是提到了GraphSAGE,文中指出了相比之下的改进之处:

  • 消除了在GPU中存储整图信息的限制;
  • 使用了低延迟的随机游走(low-latency random walks)进行采样;
  • MapReduce;

METHOD

PinSage内定义多个模块,每个模块学习如何从一个小的图邻域聚合信息,通过堆叠多个这样的模块,可以获得有关网络拓扑的信息。同时对局部采用的卷积核等模型组建进行共享,这样模型不会随着图尺寸的增大而训练困难。

最开始介绍了pin和boards的概念,文中所要构建的是pin的Embedding,这样就可以通过距离最近的方式以用户已经pin过的图片来推荐新图片。文中构建的图只包含pin和board两类节点,pin构成的节点集合为 I ,board构成的节点集合为 C ,称这样的图为二部图(bipartite graph consisting of nodes in two disjoint sets)。一直说pin和board感觉十分不好理解,自己看的时候把pin和board分别当作item和user,和其他推荐算法的使用便相似了很多,只不过board不是特定的用户个体而是用户定义的某一个集合(更细粒度上的用户),寻找pin的Embedding即为寻找item相关的Embedding。对于pin侧节点 u\in I 包含一些实际特征,比如文本content描述和图像特征,这也符合社交网络的实际生产环境。

模型结构 Model Architecture

1.前向传播(Forward propagation algorithm)

算法1介绍了单层卷积计算过程,节点 u 是计算Embedding的目标节点,用 z_{u} 表示Embedding向量,节点 u 的邻居节点集合为 N_{u} ,邻居节点的Embedding向量集合表示为 \left\{ z_{v}|v\in N_{u} \right\}

前向卷积池化计算

上面的Figure 1反映的就是算法1重复两次(深度为2)的实现流程——第一行中:将邻居节点置入全连接层(dense neural network)中,通过激活函数激活后,进行聚合池化操作, \gamma\left( activation, \alpha \right) 就是卷积核, \alpha 是邻居节点的权重系数, \gamma 是作用于向量元素上的平均或加权和算子,假设权重系数均匀(都为1),那么以平均核为例: n_{ui} = \left(\sum_{v}^{N\left( u \right)}{activation_{vi}} \right)/N_{u} ,经过池化操作后我们可以得到凝聚了邻居节点信息的向量 n_{u} ;第二行中:拼接 z_{u}n_{u} 后做一个基本的全连接层生成节点 u 新的Embedding向量 z_{u}^{NEW} ,文中指出了 CONCAT\left( z_{u}, n_{u} \right) 选择的拼接方式为串联( concatenation operation),取得了比平均更好的效果;第三行中:归一化,使训练更稳定。

2.基于重要性机制的邻居节点生成

关于 N\left( u \right) 集合的生成过程,PinSage采用了一种“重要性机制(Importance-based neighborhoods)”,在查找邻居节点时,算法模型希望能够找到对当前节点 u 影响最深远的邻居节点,在进行random walk随机游走的时候,对每个节点的访问次数进行计数(L1准则下),最终按计数大小排序找到Top N个节点放入邻居节点集合中。此处的计数值也就是算法1中的权重系数 \alpha ,文中称其为重要性池化(importance pooling)。

3.卷积层叠加(Stacking convolutions)

通过叠加算法1中的卷积层,可以加深聚合邻居节点的层数,更好的凝聚到局部图的拓扑信息。堆叠后的算法表示如算法2所示。

mini-batch下的采样-聚合过程

邻居节点采样深度为 KM 是全局图中大小为mini-batch的子图,要对整个 M 上的节点完成Embedding更新,因此第一行中: M 即为初识节点集合 S^{K} ;接着2-7行:逐层寻找上一层节点的相邻子节点,用并集的形式生成当前层的节点集合: S^{\left( k-1 \right)}\leftarrow S^{\left( k-1 \right)}\cup N\left( u \right) ;9-14行:从最底层开始,逐层向上完成卷积计算,更新节点向量;15-17行:完成卷积层计算后用全连接层做最后的更新。参考算法1,这里每一层的参数 Q^{k},q^{k},W^{k},w^{k} 是共享的,不同的只是层与层之间的参数。

4.损失函数

模型采用的损失函数是最大边界损失(max-margin-based loss function),理解上参考支持向量机的损失函数思路,模型计算出query的Embedding向量应当与正样本最大程度的重合且与负样本最大程度的远离,体现在向量内积上则为Embedding向量与正样本向量的内积尽可能大且与负样本的尽可能小,这样的模型能够“更好的区分出正负样本”:

P_{n}\left( q \right) 是目标querry的负样本集, i 是和querry相关的正样本, \Delta 为边界超参。

5.负样本采样

在每个mini-batch内,模型生成500个负样本。由果及因的想:既然选择使用的激活函数为最大边界,那么负样本的选择就变得尤为重要,否则“分离正负样本”就无从谈起了。文中提出了一种“强”负样本概念(hard negtive)——负样本需要与querry相关联(有边连接)但同时与正样本没有关联(没有边连接);同时文中还选择了PageRank排在2000-5000名的样本作为随机负样本。

querry、正样本、随机负样本、“强”负样本

上图是三种样本和querry的展示,感受直观一些。文中指出在模型训练策略上的设计为在第一个epoch中不给模型喂强负样本,这样模型可以快速的更新在参数空间中定位到一个较小的自空间;在其后的n-1个epoch中喂强负样本,实现性能提升。

6.mini-batch

频繁使用GPU去访问CPU中的数据肯定会带来不必要的开销,所以文中提出了“重编码”(re-indexing)的操作,对每一个epoch所会使用的子图 G^{'} 内的节点做重新的编码,构建一个较小的特征矩阵在每个mini-batch生成时存入到GPU内,这样进行卷积计算时GPU不需要和CPU进行交互,性能提升。模型的训练在GPU内进行,特征提取、重编码和负样本生成在CPU内完成。每个GPU获取mini-batch的一部分,采用相同的参数完成前向计算,在反向传输更新后,聚合每个GPU所求得的参数,做一次随机梯度下降(SGD)。

7.MapReduce

我们可以思考算法1和算法2的实现过程,会存在一个节点计算重复发生的现象,比如图1右上最底层的卷积核 CONVOLVE^{\left( 1 \right)} 中点A被计算了3次,如果模型深度加深,相邻节点选择增多,这种重复运算也会跟着增加,此时便符合MapReduce的一些思想,如果能将重复运算压缩到一次,肯定是有益的。

MapReduce Pipeline

文中主要在两个地方使用了MapReduce:算法1的第一行,将pins映射到低维空间后聚合(group by,上图最左侧);把pin和board相关特征进行连接(join,上图join item)。通过MapReduce,PinSage可以只在较小的子图集上训练,最终对于完整图上所有节点的预测由上图的流水线完成。

EXPERIMENTS

分别从数据、离线评估、AB测和指标分析等做了说明。

数据

如果用户pin过两个帖子,则可以在两个帖子间创建边,互相是对方的正样本,相当于是以用户为枢纽,item-->user -->item的过程,这样的item对总共产生了12亿个。

每个pin所包含的特征是一个图像(4096维的Embedding)和一系列文字文本特征(比如标题、描述等等,256维的Embedding)。

其它Embedding方法、卷积核对比

各种方法比对

离线评估

对于测试集中的item对 \left( q,i \right) ,将 q 作为querry,生成Top K个最相近的邻居节点预测。hit-rit的定义为 i 是否在其中。MRR(Mean Reciprocal Rank)定义如下:

其中 R_{i, q}i 在Top K中的排名,排名越靠前 R_{i,q} 的值越小,反映在MRR上的收益越大,当排名靠后时, R_{i,q} 的变化不会对整体带来太多影响,比如排名400和500,最终的分值是1/4和1/5,而排名4和5,虽然只是相差一个,分值却是25和20。这样非线性的打分机制可以更加严格苛刻的评价模型优劣。

评价模型的另一个考虑点则是模型的Embedding在向量空间中的分布情况,怎样是好的分布呢?既然在推荐时经常采用距离最近的准则做筛选,以余弦距离为例,那首先希望的是Embedding可以在余弦距离为0的地方有较为稠密的分布,这是推荐模型要满足的最基本条件;但如果所有的向量都聚集在空间中很狭小的区域,也可以“欺骗”我们达到这样的效果,可是对于模型来说,还要做到很好的区分,让真正相关的向量聚集,不相关的向量远离,所以还应该有更广的覆盖区间。如图所示PinSage既可以在余弦距离为0处有很好的聚集效果,也覆盖了更广的空间。

用户反馈

上线后的反馈(个人理解),比较了集中方法的用户评价,如表2。

更直观的看一下图5,左侧图片是给模型的querry图,右侧是不同算法输出的推荐结果,能够感受到PinSage给出了更加细粒度的推荐体感。

还有一个很有趣的反映PinSage生成图模型结构性能的展示,图6中是一个简单的可视化展示,可以看到每张图片和相邻图片间都有着一定程度的相同点。(很好奇怎么画出来的,用最后的Embedding向量映射到二维坐标?)

调参讨论

测试了不同的batch size和neighbors数量。综合比较了每种情况下的训练时长、Hit-rate以及MRR。

结论就不写了,非常的不谦虚,毕竟应用到了实际生产,除了夸就是夸,没有给出值得改进的地方这些通常都会讲一讲的套话。

一些思考

在别的地方也看到过大家关于PinSage的讨论,很常提起的就是它和GraphSAGE到底有什么区别,说说自己的看法——落地。直白的看它没有对GraphSAGE在模型结构这些创新点上做出太多改进,但提供了一套完整的落地流程与验证。比如MapReduce的应用,GPU-CPU的合理分配使用,这些工作是需要时间的积累,大量工程实际的训练才可以得来的。

编辑于 2022-01-27 01:11