Jure的图深度学习课: http://web.stanford.edu/class/cs224w/index.html#content
除此之外Embedding甚至还具有数学运算的关系,比如 Embedding(马德里)-Embedding(西班牙)+Embedding(法国)≈Embedding(巴黎)
从另外一个空间表达物体,甚至揭示了物体间的潜在关系,从某种意义上来说,Embedding方法甚至具备了一些本体论的哲学意义。
在word2vec诞生之后,embedding的思想迅速从NLP领域扩散到几乎所有机器学习的领域,既然可以对一个序列中的词进行embedding,那自然可以对用户购买序列中的一个商品,用户观看序列中的一个电影进行embedding。而广告、推荐、搜索等领域用户数据的稀疏性几乎必然要求在构建DNN之前对user和item进行embedding后才能进行有效的训练。
具体来讲,如果item存在于一个序列中,item2vec的方法与word2vec没有任何区别。而如果我们摒弃序列中item的空间关系,在原来的目标函数基础上,自然是不存在时间窗口的概念了,取而代之的是item set中两两之间的条件概率。
资料来源:https://blog.csdn.net/osuperman12345/article/details/65444832
图来源:Jizhe Wang, Pipei Huang, Huan Zhao, Zhibo Zhang, Binqiang Zhao, Dik Lun Lee. "Billion-scale Commodity Embedding for E-commerce Recommendation in Alibaba." SIGKDD explorations Udisk (2018). Download
给定一个图$G=(V,E)$,以及部分标注的社会网络$G_L=(V,E,X,Y)$,其中,$X\in \mathbb{R}^{|V|\times S}$是节点属性,$S$是每个属性向量的特征空间的大小,$Y\in \mathbb{R}^{|V|\times |y|}$是节点的标签。论文的工作就是独立于标签$Y$的值,学习出$X_E \in \mathbb{R}^{|V|\times d}$的表示,$d$是一个极小的隐空间维度。学习出来的社会化表示具有以下特点:
选取随机游走序列,作为DeepWalk的输入。原因有:
于是问题变成了最优化如下式子 $minimize_\Phi −logPr(\{v_{i−w},...,v_{i+w}\}\setminus v_i|\phi(v_i))$
这里$\setminus v_i$是去除、不包括$v_i$的意思。
#pip install deepwalk
#pip install python-Levenshtein
from gensim.models import Word2Vec
import networkx as nx
# 定义随机游走策略
from deepwalk import DeepWalk
# 加载网络数据
G = nx.read_adjlist('karate.adjlist')
deepwalk = DeepWalk(G, num_walks=10, walk_length=80, window=5, workers=4)
# 训练模型
model = deepwalk.fit(window=5, min_count=1)
# 获取节点嵌入向量
embedding = model.wv.vectors
# 检索与相似度最高的节点对
similarity_matrix = np.dot(embedding, np.transpose(embedding))
non_edges = list(nx.non_edges(G))
scores = []
for (i, j) in non_edges:
scores.append((i, j, similarity_matrix[i][j]))
# 按相似度分数从高到低排序
scores = sorted(scores, key=lambda x: x[-1], reverse=True)
# 输出前10个预测的新链接和相似度分数
print("Top 10 predicted new links:")
for i, (u, v, score) in enumerate(scores[:10]):
print(f"{i + 1}. ({u}, {v}) - {score}")
## Deepwalk
import numpy as np
import random
from tqdm import tqdm
import warnings
warnings.filterwarnings('ignore')
from sklearn.decomposition import PCA
import networkx as nx
import matplotlib.pyplot as plt
import pandas as pd
from gensim.models import Word2Vec
%matplotlib inline
df_data = pd.read_csv("./data/space_data.tsv", sep = "\t")
df_data.head()
g = nx.from_pandas_edgelist(df_data, "source", "target", edge_attr=True, create_using=nx.Graph())
def get_random_walk(node, pathlength):
random_walk = [node]
for i in range(pathlength-1):
tmp = list(g.neighbors(node))
tmp = list(set(tmp) - set(random_walk))
if len(tmp) == 0:
break
ran_node = random.choice(tmp)
random_walk.append(ran_node)
node = ran_node
return random_walk
allnodes = list(g.nodes())
walks_list_random = []
for n in tqdm(allnodes):
for i in range(5):
walks_list_random.append(get_random_walk(n,10))
# count of sequences
len(walks_list_random)
model = Word2Vec(window = 4, sg = 1, hs = 0,
negative = 9,
alpha=0.04, min_alpha=0.0005,seed = 20)
model.build_vocab(walks_list_random, progress_per=2)
model.train(walks_list_random, total_examples = model.corpus_count, epochs=20, report_delay=1)
model.wv.most_similar('artificial intelligence',topn=10)
u
与 s1
节点。而“结构性”指的是结构相似的网络节点中需要具有相似的embedding表达,例如u
与s6
节点。为了表达图网络的结构性,我们应该采用「BFS」 (Breadth First Search,宽度优先搜索) 的方法来进行采样。这是因为BFS可以扫描局部的结构。同时为了表达图结构的同质性,我们采用「DFS」 (Depth First Search,深度优先搜索) 的方法来进行扫描。通过调整随机游走的概率,其扫描过程可以在BFS和DFS之间进行权衡,我们下面将详细讲述。该数据集由 cora.cites 与 cora.content 两个文件组成。
<paper_id> <word_attributes> <class_label>
数据示例:1061127 0 0 0 0 0 0 0 1 ... 0 1 0 Rule_Learning
.cites文件包含语料库的引用关系‘图’。每行(其实就是图的一条边)用以下格式描述一个引用关系:<被引论文编号> <引论文编号>
数据示例: 35 103482
其中$\pi_{vx}$为是节点$v$和节点$x$的非归一化转移概率,$Z$为归一化常数。
pip install node2vec
import networkx as nx
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
%matplotlib inline
from sklearn.manifold import TSNE
from node2vec import Node2Vec
# 加载Cora数据集
cora = pd.read_csv('data/cora.content', sep='\t', header=None)
cited_in = pd.read_csv('data/cora.cites', sep='\t', header=None,
names=['target', 'source'])
nodes, features = cora.iloc[:, :-1], cora.iloc[:, -1]
# 定义函数:构造基于Cora数据集的图结构
def create_graph(nodes, features, cited_in):
nodes.index = nodes.index.map(str)
graph = nx.from_pandas_edgelist(cited_in,
source='source',
target='target')
for index, row in nodes.iterrows():
node_id = str(row[0])
features = row.drop(labels=[0])
node_attrs = {f'attr_{i}': float(x) for i, x in enumerate(features)}
if graph.has_node(node_id) == True:
temp = graph.nodes[node_id]
temp.update(node_attrs)
graph.add_nodes_from([(node_id, temp)])
else:
graph.add_nodes_from([(node_id, node_attrs)])
return graph
# 构建图
graph = create_graph(nodes, features, cited_in)
# 定义函数:创建基于Cora数据集的嵌入
def create_embeddings(graph):
# 初始化node2vec实例,指定相关超参数
n2v = Node2Vec(graph, dimensions=64, walk_length=4,
num_walks=10, p=1, q=1, weight_key='attr_weight')
# 基于指定参数训练得到嵌入向量表达式
model = n2v.fit(window=10, min_count=1, batch_words=4)
# 获得所有图中节点的嵌入向量
embeddings = pd.DataFrame(model.wv.vectors)
ids = list(map(str, model.wv.index_to_key))
# 将原有的特征和id与新获取到的嵌入向量按行合并
lookup_table = nodes.set_index(0).join(embeddings.set_index(embeddings.index))
return np.array(lookup_table.dropna().iloc[:, -64:]), np.array(list(range(1, lookup_table.shape[0] + 1)))
# 创建嵌入向量
cora_embeddings, cora_labels = create_embeddings(graph)
from sklearn import svm, model_selection, metrics
# 使用支持向量机作为示范的分类器
svm_model = svm.SVC(kernel='rbf', C=1, gamma=0.01)
# 进行交叉验证和分类训练
scores = model_selection.cross_val_score(
svm_model, cora_embeddings, cora_labels, cv=5)
print(scores.mean())
# 定义函数:可视化Nodes2Vec的结果
def visualize_results(embeddings, labels):
# 使用t-SNE对数据进行降维并绘图
tsne = TSNE(n_components=2, verbose=1, perplexity=40, n_iter=300)
tsne_results = tsne.fit_transform(embeddings)
plt.figure(figsize=(10, 5))
plt.scatter(tsne_results[:,0], tsne_results[:,1], c=labels)
plt.colorbar()
plt.show()
# 可视化结果
visualize_results(cora_embeddings, cora_labels)
一句话概括图神经网络(Graphic Nuaral Network,GNN):将一个数据(一个图)输入到网络(GNN)中,会得到一个输出数据(同样是图),输出的图和输入的图相比,顶点、边、以及全局信息会发生一些改变。(注意,顶点之间的连接情况不会变)
GNN历史
一些参考资料
对这篇文章的解读:https://zhuanlan.zhihu.com/p/538914712
内容参考:https://blog.csdn.net/weixin_43702653/article/details/123779738?spm=1001.2014.3001.5502
Kipf, Welling, 2017, SEMI-SUPERVISED CLASSIFICATION WITH GRAPH CONVOLUTIONAL NETWORKS, ICLR 2017
b站UP主 望舒同学 讲解GCN:https://www.bilibili.com/video/BV1z14y1A7JX/
原文链接:https://blog.csdn.net/weixin_43702653/article/details/123850998
此卷积非彼卷积,完全不是一码事,只是说GCN也可以做多层罢了。。。如下图:
① 邻接矩阵的改变
② 度矩阵的改变
首先对度矩阵的行和列进行了归一化(具体格式看下图),为什么这么做呢?行归一化系数代表着节点自身的一个变化程度,关联的节点越少,系数越大,越容易随波主流,更易受别人影响。而列归一化系数,代表关联节点对当前节点的影响程度,关系网越复杂的节点,它对其他节点的作用就越小,比如我认识一个亿万富翁,但富翁认识很多人,我们也就是一面之缘,那么能说因为我和他认识,我就是个百万富翁了嘛,显然有点草率了。通过行和列归一化系数,相互制衡。
同时,归一化的系数还开了根号,就是因为考虑到归一化后的行和列系数都加权给了节点特征,均衡一点。
③ Attention机制
接下来重复step1~3,每重复一次算一层,GCN正常只需要3–5层即可,这里就和CNN、RNN很不一样。因为节点每更新一次,感受野就变大一些,如果网络太深,那么每个节点就会受无关节点的影响,效果反而下降。
正如六度分割空间理论——“只需6个人,你就可以认识全世界”,见下图所示: