背景
目前很多机器学习算法都是针对于结构化数据,即每个样本的特征数都固定,这样可将数据按照预定的模式去学习,但也有不少学习场景中,还存在大量的关联性数据,如用户的购买赠送行为,用户的社交关系等等,这些数据很难直接应用目前的算法。
Graph representations 学习是一种通过图来学习节点表示向量的方法,通过将其转化为结构化的数据,进而应用我们已有的大量学习算法进行学习。首先将深度学习应用在图表示学习中的是DeepWalk,利用随机游走生成序列,然后利用类似Word2vec的技术,将其转化为向量,后面又出现Line,Node2Vec等大量的学习方法。
DeepWalk
当我们构建好关联图后,迭代每一个节点,随机游走,采样固定长度的序列,比如5,如图所示:
将采集到的这些序列使用Word2Vec的技术,如CBOW或Skip-Gram,为每个节点训练得到一个节点向量;论文里作者使用SkipGram, 以及Hierarchical Softmax(算法复杂度由O(|V|)到O(log|V|)),以及SGD进行求解。
该方法还以进行在线学习,并行化,应用于网络分类,异常检测等
算法流程如下:
其他:
- 在node2vec提到,使用Hierarchical softmax相比于negative sampling并不有效。
- Line中提到其没有明确的目标函数,能够清楚知道什么网络属性被保留下来。
- DeepWalk适用于无权网络
Line
相比于DeepWalk,Line定义了明确的学习函数,同时考虑了一阶相似度和二阶相似度。
优势:
- 更具扩展性: 无向,有向图,或者权重图
- 一阶学习local网络结构,二阶学习到更global结构,如6和7:一阶代表两者相连,二阶代表具有相同朋友的节点往往也具有某种相似性,如5和6。
优化目标
对于一阶:
节点 v i v_i vi和 v j v_j vj之间的联合概率分布 p 1 ( v i , v j ) p_1(v_i, v_j) p1(vi,vj)与其经验分布 p ^ 1 ( v i , v j ) \hat p_1(v_i, v_j) p^1(vi,vj)的差距最小,即设KL散度目标最小
O 1 = d ( p ^ 1 ( ⋅ , ⋅ ) , p 1 ( ⋅ , ⋅ ) ) O_1 = d(\hat p_1(\cdot, \cdot), p_1(\cdot, \cdot)) O1=d(p^1(⋅,⋅),p1(⋅,⋅))
其中 p ^ 1 ( v i , v j ) = w i j ∑ ( i , j ) ∈ E w i j \hat p_1(v_i, v_j) = \frac{w_{ij}}{\sum\limits_{(i,j)\in E}w_{ij}} p^1(vi,vj)=(i,j)∈E∑wijwij, p 1 ( v i , v j ) = 1 1 + e x p ( − u → i T ⋅ u → j ) p_1(v_i, v_j)=\frac{1}{1+exp(-\overrightarrow u_i^T \cdot \overrightarrow u_j)} p1(vi,vj)=1+exp(−uiT⋅uj)1,其中 u → i \overrightarrow u_i ui为节点 v i v_i vi的向量表示。
继续化简 O 1 O_1 O1,得到:
O 1 = − ∑ ( i , j ) ∈ E w i j l o g p 1 ( ( v i , v j ) ) O_1 = - \sum\limits_{(i,j)\in E }w_{ij} log p_1((v_i, v_j)) O1=−(i,j)∈E∑wijlogp1((vi,vj))
对于二阶:
直接写成目标函数
O 2 = − ∑ ( i , j ) ∈ E w i j l o g p 2 ( v j ∣ v i ) O_2 = -\sum\limits_{(i,j)\in E} w_{ij}log p_2(v_j|v_i) O2=−(i,j)∈E∑wijlogp2(vj∣vi)
代码部分
注:在实现上,为每个节点生成两个向量:
作者:浅梦
链接:https://zhuanlan.zhihu.com/p/56478167
来源:知乎
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
ef line_loss(y_true, y_pred):
return -K.mean(K.log(K.sigmoid(y_true*y_pred)))
def create_model(numNodes, embedding_size, order='second'):
v_i = Input(shape=(1,))
v_j = Input(shape=(1,))
first_emb = Embedding(numNodes, embedding_size, name='first_emb')
second_emb = Embedding(numNodes, embedding_size, name='second_emb')
context_emb = Embedding(numNodes, embedding_size, name='context_emb')
v_i_emb = first_emb(v_i)
v_j_emb = first_emb(v_j)
v_i_emb_second = second_emb(v_i)
v_j_context_emb = context_emb(v_j)
first = Lambda(lambda x: tf.reduce_sum(
x[0]*x[1], axis=-1, keep_dims=False), name='first_order')([v_i_emb, v_j_emb])
second = Lambda(lambda x: tf.reduce_sum(
x[0]*x[1], axis=-1, keep_dims=False), name='second_order')([v_i_emb_second, v_j_context_emb])
if order == 'first':
output_list = [first]
elif order == 'second':
output_list = [second]
else:
output_list = [first, second]
model = Model(inputs=[v_i, v_j], outputs=output_list)
其他:
- 采用了Negative sampling
- Alias sampling
时间复杂度为O(1)的抽样算法,普通的算法为O(N)或者为O(logN), Alias 通过维护两个数组,达到采样时间复杂度为O(1)。用于离散数据的采样。
alias sampling
=>乘以 N
=>前两个多出来的部分补到后面两个缺失的部分中,但Alias Method一定要保证:每列中最多只放两个事件,所以此时需要讲1中的补满3中去:
=>
- 将整个概率拉平1*N的长方形 Alias Table,构建上述图,储存两个数组,
一个是i列对于的面积百分比即 p r o b = [ 2 3 , 1 , 1 3 , 1 3 ] prob =[\frac23,1,\frac13,\frac13] prob=[32,