本文介绍 Structural Deep Network Embedding ,以下简称 SDNE,以半监督的方式用深度神经网络来做图嵌入。

模型解读

论文指出学习网络表示具有三大难点:

  1. 高度非线性:网络结构是高度非线性的,使用浅层网络无法捕捉高度非线性的网络结构。
  2. 结构捕捉:同时捕捉到局部结构与全局结构。
  3. 稀疏性:大部分真实的网络都是稀疏的,仅仅利用网络中的部分连接关系建模效果还不够好。

SDNE 的目标是设计一个可以学习到一阶相似度与二阶相似度的模型。一阶相似度与二阶相似度的概念与之前博客【图嵌入】Graph Embedding 方法之 LINE 原理解读中描述的相同:

  • 一阶相似度:描述边相连的节点对之间具有的相似性。
  • 二阶相似度:拥有共同邻居但是不直接向相连的两个节点具有的相似性。

也就是说一阶相似度主要反映了 Graph 的局部特征, 二阶相似度反映了 Graph 的全局特征。

为此,作者设计的模型如下图所示:

二阶相似度学习(无监督学习部分)

先看图中的左半部分:

其输入是 xix_ixi 输出是 x^i\hat x_ix^i ,这实际上是一种自编码器,其目标是学习一种函数映射:
f(x)≈xf(x) \approx x f(x)x
自编码器没有标签数据,所以是一种非监督学习,前半部分为编码器,后半部分为解码器。在实际应用中通常会使用自编码器的前半部分,即输入 xix_ixi 到得到 yi(K)y_i^{(K)}yi(K) 的部分,此部分的公式为:
yi(1)=σ(W(1)xi+b(1))yi(k)=σ(W(k)yi(k−1)+b(k)),k=2,...,Ky_i^{(1)}=\sigma{(W^{(1)}x_i+b^{(1)})} \\ y_i^{(k)}=\sigma{(W^{(k)}y_i^{(k-1)}+b^{(k)})}, k=2,...,K yi(1)=σ(W(1)xi+b(1))yi(k)=σ(W(k)yi(k1)+b(k)),k=2,...,K
其中,xix_ixi 为输入值,本质是节点 iii 的邻接矩阵(后面会解释)。上面公式中的 yi(k)y_i^{(k)}yi(k) 为第 kkk 层的第 iii 个节点的输出值,而 W(k)W^{(k)}W(k) 为第 k 层的参数矩阵,bkb^{k}bk 为第 k 层的偏置项。最终经过编码得到节点的 Embedding 向量 yi(K)y_i^{(K)}yi(K)之后,再经过与编码器对称的网络结构得到输出值 x^i\hat x_ix^i

自编码器的目标是最小化输入与输出的重构误差,所以损失函数为:
L=∑i=1n∣∣xi^−xi∣∣22\mathcal{L}=\sum_{i=1}^n{||\hat{x_i}-x_i||^2_2} L=i=1nxi^xi22
这里存在的一个问题是由于图的稀疏性,邻接矩阵S中的非零元素是远远少于零元素的,那么对于神经网络来说只要全部输出0也能取得一个不错的效果,这不是我们想要的。文章给出的一个方法是使用带权损失函数,对于非零元素具有更高的惩罚系数:
L2nd=∑i=1n∣∣(xi^−xi)⊙bi∣∣22\mathcal{L_{2nd}}=\sum_{i=1}^n||(\hat{x_i}-x_i)\odot{b_i}||^2_2 L2nd=i=1n(xi^xi)bi22
公式中 ⊙\odot 为哈马达乘积,表示对应位置元素相乘。bi={bi,j}j=1nb_i=\{b_{i,j}\}^n_{j=1}bi={bi,j}j=1n,邻接矩阵中的 0 元素对应 b=1b=1b=1,非 0 元素的 b>1b>1b>1,这意味着如果将非 0 元素预测错了,将面临更大的惩罚。

讲到这还有个问题,输入的数据 xix_ixi 到底是什么?假设用 S 表示邻接矩阵集合:
S={s1,s2,...,sn}si={sij}j=1n,sij>0S = \{ s_1, s_2,...,s_n \} \\ s_i = \{ s_{ij}\}^n_{j=1}, s_{ij}>0 S={s1,s2,...,sn}si={sij}j=1n,sij>0
其中,n 表示节点的个数,sis_isi 表示 {si1,si2,...,sin}\{s_{i1},s_{i2},...,s_{in} \}{si1,si2,...,sin} 中与节点 iii 相邻的节点的边的集合。令最终输入的 xi=six_i = s_ixi=si,则输入每一个 xix_ixi 都包含了顶点 iii 的邻居结构信息。因此结构相似的顶点可以学习到相似的 embedding 向量,不断优化代价函数来捕捉全局结构特征,即二阶相似度。

一阶相似度学习(有监督部分)

一开始文章提到 SDNE 是半监督学习模型,那么监督学习的部分体现在何处?再来观察整个网络的结构:

模型的两侧的输入了有边相连的节点 i,ji, ji,j 的信息可以学习全局特征,但是这还不够,相连的两个节点具有一阶相似性,即节点 i,ji, ji,j 应该有相似的向量表示。于是借用拉普拉斯特征映射的思想(在图中相连的点,在降维后的空间中尽可能的靠近。 ),定义如下损失函数:
L1st=∑i,j=1nsi,j∣∣yi(K)−yj(K)∣∣22=∑i.j=1nsi,j∣∣yi−yj∣∣22\begin{aligned} \mathcal{L_{1st}}&=\sum_{i,j=1}^n{s_{i,j}||y_i^{(K)}-y_j^{(K)}||^2_2}\\ &=\sum_{i.j=1}^n{s_{i,j}||y_i-y_j||^2_2} \end{aligned} L1st=i,j=1nsi,jyi(K)yj(K)22=i.j=1nsi,jyiyj22

该损失函数可以利用边的约束作用使得相邻顶点保持一阶相似度,当相似的顶点在嵌入空间中映射得很远时,就会产生惩罚。

补充:

论文对这个损失函数进行了进一步的变换,根据拉普拉斯矩阵的性质有(参考:拉普拉斯矩阵,谱聚类方法推导和对拉普拉斯矩阵的理解):
L1st=∑i.j=1nsi,j∣∣yi−yj∣∣22=2tr(YTLY)\begin{aligned} \mathcal{L_{1st}}&=\sum_{i.j=1}^n{s_{i,j}||y_i-y_j||^2_2} \\ &=2tr(Y^TLY) \end{aligned} L1st=i.j=1nsi,jyiyj22=2tr(YTLY)

L=D−SL = D - S L=DS

其中,Y 表示节点的 embedding 向量,L为拉普拉斯矩阵,D是节点的度,S是邻接矩阵。

最终整个模型的的损失函数定义如下:
Lmix=L2nd+αL1st+νLreg=∑i=1n∣∣(xi^−xi)⊙bi∣∣22+α∑i.j=1nsi,j∣∣yi−yj∣∣22+νLreg\begin{aligned} \mathcal{L_{mix}}&=\mathcal{L_{2nd}+\alpha{\mathcal{L_{1st}}}}+\nu{\mathcal{L_{reg}}} \\ &=\sum_{i=1}^n||(\hat{x_i}-x_i)\odot{b_i}||^2_2+\alpha{\sum_{i.j=1}^n{s_{i,j}||y_i-y_j||^2_2}}+\nu{\mathcal{L_{reg}}} \end{aligned} Lmix=L2nd+αL1st+νLreg=i=1n(xi^xi)bi22+αi.j=1nsi,jyiyj22+νLreg

其中 α,ν\alpha, \nuα,ν 为超参数,LregL_{reg}LregL2L_2L2 正则项用于防止过拟合:

Lreg=12∑k=1k(∣∣W(k)∣∣F2+∣∣W^k∣∣F2)\mathcal{L_{reg}}=\frac{1}{2}\sum_{k=1}^k({||W^{(k)}||^2_F+||\hat{W}^{k}||_F^2}) Lreg=21k=1k(W(k)F2+W^kF2)

在模型优化方面,SDNE 使用反向传播来更新网络参数,但由于模型高度非线性,参数空间中可能存在许多局部最优。因此,为了得到全局最优,作者使用深度信念网络(Deep Belief Network,以下简称 DBN)对参数进行预训练。

关键源码解读

这部分主要参考了https://github.com/xiaohan2012/sdne-keras。

损失函数定义

定义函数 build_reconstruction_loss 作为二阶相似度对应的损失函数,参数 beta 控制非零元素的惩罚力度。

def build_reconstruction_loss(beta):def reconstruction_loss(true_y, pred_y):diff = K.square(true_y - pred_y)weight = true_y * (beta - 1) + 1weighted_diff = diff * weightreturn K.mean(K.sum(weighted_diff, axis=1))  # mean sqaure errorreturn reconstruction_loss

定义函数 edge_wise_loss 作为一阶相似度对应的损失函数,参数 true_y 并未使用,embedding_diff 表示相邻的节点iii 与节点 jjj 的 embedding 向量的差值,此函数就是利用差值求均方误差。

def edge_wise_loss(true_y, embedding_diff):return K.mean(K.sum(K.square(embedding_diff), axis=1))  # mean sqaure error

模型定义

关键代码如下:

# INPUT
# 边的一个顶点 a
input_a = Input(shape=(1,), name='input-a', dtype='int32')
# 边的另一个顶点 b
input_b = Input(shape=(1,), name='input-b', dtype='int32')
edge_weight = Input(shape=(1,), name='edge_weight', dtype='float32')# 定义编码器、解码器的层数组
encoding_layers = []
decoding_layers = []# 用 embedding_layer 保持邻接矩阵
embedding_layer = Embedding(output_dim=self.N, input_dim=self.N,trainable=False, input_length=1, name='nbr-table')
# if you don't do this, the next step won't work
embedding_layer.build((None,))
embedding_layer.set_weights([self.adj_mat])encoding_layers.append(embedding_layer)
encoding_layers.append(Reshape((self.N,)))# 构造编码器
encoding_layer_dims = [encode_dim]for i, dim in enumerate(encoding_layer_dims):layer = Dense(dim, activation='sigmoid',kernel_regularizer=regularizers.l2(l2_param),name='encoding-layer-{}'.format(i))encoding_layers.append(layer)# 构造解码器
decoding_layer_dims = encoding_layer_dims[::-1][1:] + [self.N]
for i, dim in enumerate(decoding_layer_dims):activation = 'sigmoid'layer = Dense(dim, activation=activation,kernel_regularizer=regularizers.l2(l2_param),name='decoding-layer-{}'.format(i))decoding_layers.append(layer)# 构造整个网络
all_layers = encoding_layers + decoding_layers# 取出节点 a 与节点 b 的 embedding 向量
# reduce 函数将 input_a 作为数组 encoding_layers 中每一个 Layer 的输入
# 然后将每个 layer 的输出值作为下一个 layer 的输入,直到编码器层结束
encoded_a = reduce(lambda arg, f: f(arg), encoding_layers, input_a)
encoded_b = reduce(lambda arg, f: f(arg), encoding_layers, input_b)# 得到节点的重构矩阵
decoded_a = reduce(lambda arg, f: f(arg), all_layers, input_a)
decoded_b = reduce(lambda arg, f: f(arg), all_layers, input_b)# 将两个节点的 embedding 向量做减法
embedding_diff = Subtract()([encoded_a, encoded_b])# 为差值添加权重
embedding_diff = Lambda(lambda x: x * edge_weight)(embedding_diff)# 构建模型
self.model = Model([input_a, input_b, edge_weight],[decoded_a, decoded_b, embedding_diff])# 构建损失函数
reconstruction_loss = build_reconstruction_loss(beta)# 构建模型
self.model.compile(optimizer='adadelta',loss=[reconstruction_loss, reconstruction_loss, edge_wise_loss],loss_weights=[1, 1, alpha]) # 损失函数权重
# 构建模型
self.encoder = Model(input_a, encoded_a)# 构建模型
self.decoder = Model(input_a, decoded_a)
self.decoder.compile(optimizer='adadelta',loss=reconstruction_loss)

关于 reduce 的更多说明如下:

reduce(function, sequence[, initial]) -> value

Apply a function of two arguments cumulatively to the items of a sequence,
from left to right, so as to reduce the sequence to a single value.
For example, reduce(lambda x, y: x+y, [1, 2, 3, 4, 5]) calculates
((((1+2)+3)+4)+5). If initial is present, it is placed before the items
of the sequence in the calculation, and serves as a default when the
sequence is empty.

行业应用

在购物的过程中,经常遇到满减活动,例如满400减50,当购物车商品金额不足400时,就需要进行凑单。在2018年的时候,阿里公开了他们的凑单算法:

阿里的凑单算法框架图如上图所示,其中一部分就用到了 SDNE 模型。比较传统的协同过滤算法也能发掘共同购买关系,为什么还需要构造 graph?

由于 graph 具有传播能力,它不仅能有效的提取出来节点之间的直接关联,而且可以通过游走策略,挖掘出来二度、三度的关系。朋友的朋友,也是朋友,也存在一定的弱关联,有效的利用这种传播能力,能解决购买数据的稀疏性,达到提升覆盖的效果。

整个算法流程的步骤大致如下:

(1)构建 Graph

基于用户购买行为构建 graph,节点是商品,边是商品间同时购买的行为,权重是可以是两个商品同时购买的次数、时间、金额等。

为什么需要带权重的Graph?商品的数量繁多,绝大多数是冷门商品。在对图进行采样的过程中,如果使用 random walk 策略,那么采样出来的序列就包含很多冷门商品。但是在引入权重后,可以基于边的权重进行游走(weighted walk),这样采样出来的序列就能包含更受用户欢迎的热门商品。

(2)采样

假如有了下图所示的带权商品图:

假设游走2步,从节点A出发,随机取下一个邻居节点时,如果是random walk算法,它会等概率的游走到B或C节点,但是weighted walk算法会以7/8的概率取节点C,再会以8/12的概率游走到节点D,最终很大概率上会采出来一条序walk=(A,C,D),对于原始graph,A和D是没有关联的,但是通过weighted walk,能够有效的挖掘出A和D的关系。

(3)嵌入

将基于weighted walk采出来的序,构造成item-item的pair对,送给embedding模型:

每一对商品都输出一个 score,上线之后,取出 topN 个 score 较高的关联商品进行推荐。

参考文章:

【论文笔记】Structural Deep Network Embedding

SDNE:《Structral Deep Network Embedding》阅读笔记

【Embedding】SDNE:深度学习在图嵌入领域的应用

大话深度信念网络(DBN)

阿里凑单算法首次公开!基于Graph Embedding的打包购商品挖掘系统解析

SDNE: 阿里应用深度学习进行图嵌入,构造凑单算法模型相关推荐

  1. 图深度学习——复杂图嵌入:异质图,二分图,多维图,超图,符号图,动态图

    复杂图嵌入 复杂图更适合于现实的应用 大部分针对复杂图设计的方法和针对简单图的算法是相似的. 复杂图简介 异质图 异质图除了边和节点的集合外,还包含两个映射函数.因为在异质图中,节点和边的种类是有不同 ...

  2. 深度学习:词嵌入之word2vec

    http://blog.csdn.net/pipisorry/article/details/76147604 word2vec简介 深度学习在自然语言处理中第一个应用:训练词嵌入.Google 的 ...

  3. 「云服务」阿里云服务学习路径图总结

    阿里云服务学习路径图总结 开始探索阿里云的产品和服务,可以发现无限的可能性. 云服务器 ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 ...

  4. 深度学习静态图和静态图的区别以及优缺点是什么?

    深度学习静态图和静态图的区别以及优缺点是什么? 不论是动态图还是静态图,它们都属于计算图.计算图是用来描述运算的有向无环图,它有两个主要元素:结点(Node)和边(Edge).结点表示数据,如向量.矩 ...

  5. 【深度学习】图网络——悄然兴起的深度学习新浪潮

    [深度学习]图网络--悄然兴起的深度学习新浪潮 https://mp.weixin.qq.com/s/mOZDN9u7YCdtYs6DbUml0Q 现实世界中的大量问题都可以抽象成图模型(Graph ...

  6. 【人工智能与深度学习】图卷积网络 I

    [人工智能与深度学习]图卷积网络 I 传统卷积神经网络 什么是维度诅咒? 有关卷积神经网络的主要假设:: 图域 数据域 图域 图域的启发性示例 图的定义和特征 传统卷积网络中的卷积 卷积 我们如何定义 ...

  7. 阿里云深度学习存储解决方案

    介绍 现如今在谈论数据的价值的时候,经常提到的概念之一就是深度学习,或者更广泛的说是人工智能.深度学习系统通常通过大规模的数据集和神经网络算法来训练和完善应用模型,这就需要强大的计算集群,高性能可扩展 ...

  8. 深度学习目标检测系列:RCNN系列算法图解

    在生活中,经常会遇到这样的一种情况,上班要出门的时候,突然找不到一件东西了,比如钥匙.手机或者手表等.这个时候一般在房间翻一遍各个角落来寻找不见的物品,最后突然一拍大脑,想到在某一个地方,在整个过程中 ...

  9. PGL图学习之图神经网络ERNIESage、UniMP进阶模型[系列八]

    PGL图学习之图神经网络ERNIESage.UniMP进阶模型[系列八] 原项目链接:fork一下即可:https://aistudio.baidu.com/aistudio/projectdetai ...

最新文章

  1. 学python的好处-python语言的优点和缺点
  2. 监控软件nagios之安装
  3. 利用python爬虫(part6)--用Xpath匹配带来的数据合并问题
  4. 纯JavaScript实现的调用设备摄像头并拍照的功能
  5. 计算机在制造业中的应用,计算机技术在机械制造中的应用
  6. SPOJ Qtree系列
  7. Atitti 固化数据库表结构方案
  8. Go专栏“改善Go语言编程质量的50个有效实践”上线了
  9. Android 图片高斯模糊处理
  10. 阿里云P10技术专家褚霸:我是一个程序员
  11. coherence-based label propagation over time series for accelerated active learning
  12. 2011年6个微博营销趋势
  13. 转 Java编程规范
  14. php中调用css设置表格,CSS表格设置实例
  15. 华为语音解锁设置_华为手机语音转文字怎么设置,如何完成音频在线转换
  16. 详解Jetpack Compose中的Modifier修饰符
  17. TDengine集群搭建
  18. 淘宝代购系统|代购网站建设|代购系统开发代码对接教程
  19. 【云原生】了解微服务低代码平台
  20. 复旦微电子fpga数据手册_专注FPGA图像加速领域 深维科技跨入发展快车道

热门文章

  1. Django-HttpResponse、render,、redirect(转载)
  2. DataGrip导入csv数据并把第一行作为列名
  3. java 存储cookie_java设置cookie,存储和读取 | 学步园
  4. 问题: springboot返回登录失败
  5. linux cvs服务,Linux环境下轻松搭建CVS服务器
  6. (十四)java版spring cloud+spring boot 社交电子商务平台-使用spring cloud Bus刷新配置...
  7. 推荐一个非常好用的Chrome扩展应用,用于美化Json字符串 1
  8. Spark-core(核心)的基本介绍
  9. 在windows中手动安装第三方模块
  10. TCP/IP 2.5浮动静态路由