图节点嵌入相关算法学习笔记

引言

本篇笔记为coggle 2月打卡任务,正好也在学习cs224w,干脆就一起做了,以下是任务列表:

任务名称难度
任务1:图属性与图构造低、1
任务2:图查询与遍历低、2
任务3:节点中心性与应用中、2
任务4:图节点嵌入算法(DeepWalk/node2vec)高、3
任务5:图节点嵌入算法:LINE/SDNE高、3
任务6:图节点嵌入算法:GraphGAN高、3

task1 图属性与图构造

  • 步骤1:导入networkx
  • 步骤2:加载Wiki数据集,包含来自 19 个类别的 2405 个文档和它们之间的 17981个边。
  • 步骤3:使用networkx构造上述有向图
import pandas as pd
import numpy as np
import networkx as nx
import matplotlib.pyplot as plt

# 两列,分别为节点id,节点类别
group = pd.read_csv('http://mirror.coggle.club/dataset/graph-wiki/group.txt.zip', sep='\t', header=None)

# 两列,分别为出发节点id,目的节点id
graph = pd.read_csv('http://mirror.coggle.club/dataset/graph-wiki/graph.txt.zip', sep='\t', header=None)

g = nx.DiGraph()

# 只添加前100条边
g.add_edges_from(graph.values[:100])
nx.draw_spring(g)

# 添加所有数据
g = nx.DiGraph()
g.add_edges_from(graph.values[:])

在这里插入图片描述

task2 图查询与遍历

  1. 步骤1:使用networkx对Wiki数据集进行如下统计
    • 节点个数、边个数
    • 节点度平均
    • 存在指向自身节点的个数
  2. 步骤2:对节点1397进行深度和广度遍历,设置搜索最大深度为5
  3. 步骤3:判断节点1573与节点1397之间是否存在联通性
# 边个数 节点个数
g.number_of_edges(), g.number_of_nodes()

# 度均值
np.mean([x[1] for x in list(g.degree())])

# 对节点1397的深度5内进行深度和广度遍历
nx.dfs_tree(g, 1397, 5).nodes()
nx.bfs_tree(g, 1397, 5).nodes()

# 节点1573与节点1397之间的路径
list(nx.connectivity.node_disjoint_paths(g, 1573, 1397))
"""
[[1573, 2337, 489, 708, 1525, 1397],
 [1573, 280, 696, 1610, 1445, 1397],
 [1573, 445, 2395, 750, 1397],
 [1573, 933, 1455, 1401, 1412, 1397]]
"""

task3 节点中心性与应用

本task的数据为:

# 文章1
'''
一纸四季报,令芯片巨头英特尔一夜间股价重挫近6.5%,市值蒸发80亿美元,再度被AMD反超。

这份严重缩水的财报显示,英特尔在去年四季度营收大降32%至140亿美元,是2016年以来最低单季收入;净利润由三季度的10.2亿美元转为近7亿美元净亏损;毛利率更从2021年四季度的53.6%大幅下降至39.2%。

此番业绩“跳水”并非英特尔一家的一时失利,在全球PC出货量整体下滑的背景下,包括英特尔、AMD、英伟达、高通在内的芯片企业,均在过去一年里出现不同程度的收入与利润下滑,但英特尔的确是其中的重灾区。
'''

# 文章2
'''
2021年,成都地区生产总值已经超过1.99万亿元,距离2万亿门槛仅咫尺之间。在去年遭受多轮疫情冲击及高温限电冲击的不利影响下,2022年,成都市实现地区生产总值20817.5亿元,按可比价格计算,比上年增长2.8%。

成都因此成为第7个跨过GDP2万亿门槛的城市。目前,GDP万亿城市俱乐部中形成了4万亿、3万亿、2万亿和万亿这四个梯队。上海和北京在2021年跨过了4万亿,深圳2021年跨过了3万亿,重庆、广州、苏州和成都则是2万亿梯队。

在排名前十的城市中,预计武汉将超过杭州。武汉市政府工作报告称,预计2022年武汉地区生产总值达到1.9万亿元左右。而杭州市统计局公布的数据显示,杭州2022年地区生产总值为18753亿元。受疫情影响,武汉在2020年GDP排名退居杭州之后。
'''


# 文章3
'''
据报道,美国证券交易委员会(SEC)与特斯拉首席执行官埃隆·马斯克之间又起波澜。SEC正对马斯克展开调查,主要审查内容是,马斯克是否参与了关于特斯拉自动驾驶软件的不恰当宣传。

据知情人士透露,该机构正在调查马斯克是否就驾驶辅助技术发表了不恰当的前瞻声明。

特斯拉在2014年首次发布了其自动驾驶辅助功能,公司声称该功能可以让汽车在车道内自动转向、加速和刹车。目前所有特斯拉车辆都内置了该软件。
'''

步骤1:筛选度最大的Top10个节点,并对节点深度1以内的节点进行可视化;

# 筛选度最大的Top10个节点,并对节点深度1以内的节点进行可视化;
g_degree = pd.DataFrame(g.degree()).sort_values(by=1)
g_degree = g_degree.iloc[-10:]

selected_nodes = []
for node in g_degree[0].values:
    selected_nodes += list(nx.dfs_tree(g, node, 1).nodes())

nx.draw_spring(g.subgraph(selected_nodes), node_size=3)

在这里插入图片描述


步骤2:使用PageRank筛选Top10个节点,并对节点深度1以内的节点进行可视化;

# 使用PageRank筛选Top10个节点,并对节点深度1以内的节点进行可视化
g_pagerank = pd.DataFrame.from_dict(nx.pagerank(g), orient='index')
g_pagerank = g_pagerank.sort_values(by=0)

g_pagerank = g_pagerank.iloc[-10:]
selected_nodes = []
for node in g_pagerank[0].index:
    selected_nodes += list(nx.dfs_tree(g, node, 1).nodes())

nx.draw_spring(g.subgraph(selected_nodes), node_size=3)

在这里插入图片描述

步骤3:文本关键词提取算法RAKE

这里以文章一为例,先将上述文章1的内容规整一下:

content = "一纸四季报,令芯片巨头英特尔一夜间股价重挫近6.5%,市值蒸发80亿美元,再度被AMD反超。这份严重缩水的财报显示,英特尔在去年四季度营收大降32%至140亿美元,是2016年以来最低单季收入;净利润由三季度的10.2亿美元转为近7亿美元净亏损;毛利率更从2021年四季度的53.6%大幅下降至39.2%。此番业绩“跳水”并非英特尔一家的一时失利,在全球PC出货量整体下滑的背景下,包括英特尔、AMD、英伟达、高通在内的芯片企业,均在过去一年里出现不同程度的收入与利润下滑,但英特尔的确是其中的重灾区。"

然后使用RAKE算法对上述内容进行提取,并计算单词打分 wordDegree (w) / wordFrequency (w),以及统计每个文章Top10关键词:

import jieba
from collections import Counter

g2 = nx.Graph()
words = jieba.lcut(content)
words = [x for x in words if len(x) > 1]
for i in range(len(words)-2):
    for j in range(i-2, i+2):
        if i == j:
            continue
        g2.add_edge(words[i], words[j])

g2_node_gree = dict(g2.degree())
word_counter = dict(Counter(words))

g2_node_gree = pd.DataFrame.from_dict(g2_node_gree, orient='index')
g2_node_gree.columns = ['degree']

g2_node_gree['freq'] = g2_node_gree.index.map(word_counter)
g2_node_gree['score'] = g2_node_gree['degree'] / g2_node_gree['freq']

g2_node_gree.sort_values(by='score').index[-10:]

"""
['32%', '140', '2016', '以来', '最低', '单季', '收入', '利润', '缩水', '净利润']
"""

其余两个就不再详述,这里贴出结果为:

# ['增长', '2.8%', '成都', '2020', '成为', '超过', 'GDP2', '目前', '可比价格', '因此']
# ['主要', '审查', '内容', '参与', '关于', '软件', '所有', '宣传', '人士', '恰当']

步骤4:文本关键词提取算法TextRank

这里跟步骤三一样,直接给出代码为:

g2 = nx.Graph()

words = jieba.lcut(content)
words = [x for x in words if len(x) > 1]
for i in range(len(words)-2):
    for j in range(i-2, i+2):
        if i == j:
            continue
        g2.add_edge(words[i], words[j])

g2_node_gree = pd.DataFrame.from_dict(nx.pagerank(g2), orient='index')
g2_node_gree.columns = ['degree']
g2_node_gree = g2_node_gree.sort_values(by='degree')

三篇文章提取统计的结果为:

# ['39.2%', '四季', '一纸', 'AMD', '下滑', '四季度', '收入', '芯片', '亿美元', '英特尔']
# ['万亿元', '成都', '地区', '2021', '城市', '杭州', '武汉', '2022', '生产总值', '万亿']
# ['功能', '是否', '辅助', '调查', '恰当', 'SEC', '驾驶', '自动', '马斯克', '特斯拉']

下图是task任务下插入的一张图,但我不太清楚这张图怎么画的,就以上信息好像不怎么够,提取出来的6个关键词列表好像除了根据算法认定的词权重外似乎是没多大关系?之后再研究一下:
在这里插入图片描述

当然,这里我尝试了一些简单的方式,比如我看到有直接用相关性的,这里我大概修改了一下代码,为:

G = nx.Graph()

keywords_list = [
    ['39.2%', '四季', '一纸', 'AMD', '下滑', '四季度', '收入', '芯片', '亿美元', '英特尔'],
    ['功能', '是否', '辅助', '调查', '恰当', 'SEC', '驾驶', '自动', '马斯克', '特斯拉'],
    ['万亿元', '成都', '地区', '2021', '城市', '杭州', '武汉', '2022', '生产总值', '万亿'],
    ['32%', '140', '2016', '以来', '最低', '单季', '收入', '利润', '缩水', '净利润'],
    ['增长', '2.8%', '成都', '2020', '成为', '超过', 'GDP2', '目前', '可比价格', '因此'],
    ['主要', '审查', '内容', '参与', '关于', '软件', '所有', '宣传', '人士', '恰当']
]

# 定义一个函数来计算两个关键词列表之间的相关性
def similarity(list1, list2):
    # 计算两个列表之间的交集和并集
    intersection = set(list1) & set(list2)
    union = set(list1) | set(list2)
    
    # 计算交集与并集之比作为相关性度量
    return len(intersection) / len(union)

# 添加节点和边
for keywords in keywords_list:
    G.add_nodes_from(keywords)
for i in range(len(keywords_list)-1):
    for j in range(i+1, len(keywords_list)):
        # 计算两个关键词列表之间的相关性,并作为边的权重
        weight = similarity(keywords_list[i], keywords_list[j])
        # 只有当相关性大于0时才添加边
        if weight > 0:
            G.add_edge(keywords_list[i][0], keywords_list[j][0], weight=weight)

nx.draw(G, with_labels=True, font_weight='bold',
        node_color='skyblue',
        edge_color='gray')
plt.show()

有些丑,没有上图好看,就不贴出来献丑了,emmm,可以自己跑跑试试,因为我是两个算法针对三段文章提取出来的,所以就直接取交并,而没有用到分词出来的权重,虽然结果感觉上差不多,还是需要词之间的相关性,这个不知道怎么定义。

task4 图节点嵌入算法:DeepWalk/node2vec

这里两个算法的原理,我已经在前面两篇文章中做了详细推导与说明,为:

CS224W课程学习笔记(三):DeepWalk算法原理与说明

CS224W课程学习笔记(四):node2vec算法原理与说明

deepwalk

首先写出随机游走的采样序列算法:

import random
def deepwalk(G, walk_length):
    nodes = G.nodes()
    history_walks = []

    # 对于每个节点
    for node in nodes:

        # 从当前节点开始
        random_walk_length = [node]

        # 开始游走
        for i in range(walk_length-1):

            # 找到节点邻居
            neighbors = list(G.neighbors(node))

            # 排除已经游走的邻居
            neighbors = list(set(neighbors) - set(random_walk_length))    
            if len(neighbors) == 0:
                break

            # 随机挑选邻居
            random_neighbor = random.choice(neighbors)            
            random_walk_length.append(random_neighbor)

            # 从下一个邻居继续游走
            node = random_neighbor

        # 此节点的游走路径
        history_walks.append(random_walk_length)

    return history_walks

然后我们加载wiki数据集,并用50维做嵌入,生成节点类别:

g = nx.DiGraph()
# 构件图
g.add_edges_from(graph.values[:])
# 游走
history_walks = deepwalk(g, 100)

from gensim.models import Word2Vec
# 训练word2vec
w2v = Word2Vec(history_walks, vector_size=50, window=5)
# 节点类别,因为word2vec有单独节点次序
node_group = group.iloc[list(w2v.wv.key_to_index.keys())][1].values
"""
array([18, 18,  4, ..., 11,  2, 17])
"""

根据上面得到的节点类别做降维与使用TSNE算法可视化,对于TSNE算法,我在deepwalk笔记中对该概念和PCA降维进行了对比,具体可以看上述我引用出来的第三篇,这里不再详述,那代码为:

from sklearn.manifold import TSNE

tsne = TSNE(n_components=2)
tsne_data = tsne.fit_transform(w2v.wv.vectors)

import matplotlib.cm as cm
x = np.arange(20)
ys = [i+x+(i*x)**2 for i in range(20)]
colors = cm.rainbow(np.linspace(0, 1, len(ys)))

plt.scatter(
    tsne_data[:, 0], 
    tsne_data[:, 1],
    color=colors[node_group]
)

在这里插入图片描述

然后我们可以使用节点嵌入向量 + 逻辑回归进行训练,并记录验证集准确率:

from sklearn.model_selection import train_test_split
from sklearn.linear_model import LogisticRegression

# 划分数据集
x_tr, x_val, y_tr, y_val = train_test_split(
    w2v.wv.vectors, node_group, test_size=0.2, stratify=node_group
)

# 模型训练与验证,准确率0.535
model = LogisticRegression()
model.fit(x_tr, y_tr)
model.score(x_val, y_val)
"""
0.5642023346303502
"""

还行,比预先版本的0.535要高0.03,因为逻辑回归没有给默认参数,这点随机性可以理解,毕竟分高了,emmm。

node2vec

node2vec是一种综合考虑DFS邻域和BFS邻域的graph embedding方法。简单来说,可以看作是deepwalk的一种扩展,是结合了DFS和BFS随机游走的deepwalk。node2vec依然采用随机游走的方式获取顶点的近邻序列,不同的是node2vec采用的是一种有偏的随机游走。

这里将上述的labels和graph改动一下格式,因为原来是以zip文件转格式而来并且是以制表符为分隔,先wget下载文件后,解压运行如下代码:

import pandas as pd

df = pd.read_table("graph.txt", sep="\t")
df2 = pd.read_table("label.txt", sep="\t")

# 将制表符替换成空格
df = df.replace("\t", " ")
df.to_csv("train.txt",sep=" ",index=False)
df.to_csv("test.txt",sep=" ",index=False)

然后根据我上面第四篇笔记中,浅梦大佬开发的ge包进行训练,代码改为:

import numpy as np

from ge.classify import read_node_label, Classifier
from ge import Node2Vec
from sklearn.linear_model import LogisticRegression

import matplotlib.pyplot as plt
import networkx as nx
from sklearn.manifold import TSNE


def evaluate_embeddings(embeddings):
    # group = pd.read_csv('http://mirror.coggle.club/dataset/graph-wiki/group.txt.zip', sep='\t', header=None)
    X, Y = read_node_label('test.txt')
    tr_frac = 0.8
    print("Training classifier using {:.2f}% nodes...".format(
        tr_frac * 100))
    clf = Classifier(embeddings=embeddings, clf=LogisticRegression())
    clf.split_train_evaluate(X, Y, tr_frac)


def plot_embeddings(embeddings,):
    X, Y = read_node_label('test.txt')

    emb_list = []
    for k in X:
        emb_list.append(embeddings[k])
    emb_list = np.array(emb_list)

    model = TSNE(n_components=2)
    node_pos = model.fit_transform(emb_list)

    color_idx = {}
    for i in range(len(X)):
        color_idx.setdefault(Y[i][0], [])
        color_idx[Y[i][0]].append(i)

    for c, idx in color_idx.items():
        plt.scatter(node_pos[idx, 0], node_pos[idx, 1], label=c)
    plt.legend()
    plt.show()

在这里插入图片描述

使用逻辑回归进行测试,得到的分数为0.5883,即:

{'micro': 0.5883575883575883, 'macro': 0.459881682897527, 'samples': 0.5883575883575883, 'weighted': 0.5816291785521392, 'acc': 0.5883575883575883}

task5 图节点嵌入算法:LINE/SDNE

步骤1:使用LINE对Wiki数据集节点嵌入,维度为50维
步骤2:每个group中20%的节点作为验证集,剩余的作为训练集
步骤3:使用节点嵌入向量 + 逻辑回归进行训练,并记录验证集准确率
步骤4:使用SDNE重复上述操作
步骤5:使用t-SNE将节点的LINE/SDNE特征降维,绘制散点图,节点颜色使用group进行区分

关于LINE和SDNE,后者可以说是前者的延伸,SDNE使用一个自动编码器结构来同时优化1阶和2阶相似度(LINE是分别优化的),学习得到的向量表示能够保留局部和全局结构,并且对稀疏网络具有鲁棒性。

之后考虑会与deepwalk和node2vec一样出篇博客好好总结一下这两种算法,如果有必要,这里还是用浅梦大佬的ge包,它把这些算法接口封装得太棒了。

LINE

import numpy as np

from ge.classify import read_node_label, Classifier
from ge import LINE
from sklearn.linear_model import LogisticRegression

import matplotlib.pyplot as plt
import networkx as nx
from sklearn.manifold import TSNE


def evaluate_embeddings(embeddings):
    X, Y = read_node_label('test.txt')
    tr_frac = 0.8
    print("Training classifier using {:.2f}% nodes...".format(
        tr_frac * 100))
    clf = Classifier(embeddings=embeddings, clf=LogisticRegression())
    clf.split_train_evaluate(X, Y, tr_frac)


def plot_embeddings(embeddings,):
    X, Y = read_node_label('test.txt')

    emb_list = []
    for k in X:
        emb_list.append(embeddings[k])
    emb_list = np.array(emb_list)

    model = TSNE(n_components=2)
    node_pos = model.fit_transform(emb_list)

    color_idx = {}
    for i in range(len(X)):
        color_idx.setdefault(Y[i][0], [])
        color_idx[Y[i][0]].append(i)

    for c, idx in color_idx.items():
        plt.scatter(node_pos[idx, 0], node_pos[idx, 1], label=c)
    plt.legend()
    plt.show()


if __name__ == "__main__":
    G = nx.read_edgelist('train.txt',
                         create_using=nx.DiGraph(), nodetype=None, data=[('weight', int)])

    model = LINE(G, embedding_size=128, order='second')
    model.train(batch_size=1024, epochs=50, verbose=2)
    embeddings = model.get_embeddings()

    evaluate_embeddings(embeddings)
    plot_embeddings(embeddings)

在这里插入图片描述
然后精度结果为:

{'micro': 0.6195426195426196, 'macro': 0.5044817581137855, 'samples': 0.6195426195426196, 'weighted': 0.614818511410618, 'acc': 0.6195426195426196}

这里LINE算法是0.62,因为我跑了50个epochs,并且batch是1024,前面node2vec只给了五次随机游走,并且其它参数是小的,如果同等参数下,肯定node2vec更强,这是毫无争议的,并且时间优化也快。

SDNE

SDNE使用自动编码器(AutoEncoder)和拉普拉斯特征映射(Laplacian Eigenmaps)来学习网络的局部结构信息和全局结构信息。它主要由以下几个部分组成:

  • 输入层:将网络中的节点表示为一个稀疏向量,其中第 i i i个元素为1,其他元素为0。
  • 编码层:将输入层的向量通过多层非线性变换映射到一个低维空间,得到节点的嵌入向量。
  • 解码层:将嵌入向量通过多层非线性变换重构出输入层的向量,得到节点的重构向量。
  • 损失函数:定义了两个损失项,分别是一阶相似性损失和二阶相似性损失。一阶相似性损失用于保持节点之间的邻接关系,二阶相似性损失用于保持节点之间的结构关系。
import numpy as np

from ge.classify import read_node_label, Classifier
from ge import SDNE
from sklearn.linear_model import LogisticRegression

import matplotlib.pyplot as plt
import networkx as nx
from sklearn.manifold import TSNE


def evaluate_embeddings(embeddings):
    X, Y = read_node_label('test.txt')
    tr_frac = 0.8
    print("Training classifier using {:.2f}% nodes...".format(
        tr_frac * 100))
    clf = Classifier(embeddings=embeddings, clf=LogisticRegression())
    clf.split_train_evaluate(X, Y, tr_frac)


def plot_embeddings(embeddings,):
    X, Y = read_node_label('test.txt')

    emb_list = []
    for k in X:
        emb_list.append(embeddings[k])
    emb_list = np.array(emb_list)

    model = TSNE(n_components=2)
    node_pos = model.fit_transform(emb_list)

    color_idx = {}
    for i in range(len(X)):
        color_idx.setdefault(Y[i][0], [])
        color_idx[Y[i][0]].append(i)

    for c, idx in color_idx.items():
        plt.scatter(node_pos[idx, 0], node_pos[idx, 1],
                    label=c)  # c=node_colors)
    plt.legend()
    plt.show()


if __name__ == "__main__":
    G = nx.read_edgelist('train.txt',
                         create_using=nx.DiGraph(), nodetype=None, data=[('weight', int)])

    model = SDNE(G, hidden_size=[256, 128],)
    model.train(batch_size=3000, epochs=40, verbose=2)
    embeddings = model.get_embeddings()

    evaluate_embeddings(embeddings)
    plot_embeddings(embeddings)

task6 图节点嵌入算法:GraphGAN

  • 步骤1:使用GraphGAN对Wiki数据集节点嵌入,维度为50维
  • 步骤2:每个group中20%的节点作为验证集,剩余的作为训练集
  • 步骤3:使用节点嵌入向量 + 逻辑回归进行训练,并记录验证集准确率
  • 步骤4:使用t-SNE将节点的GraphGAN特征降维,绘制散点图,节点颜色使用group进行区分

这个算法搞了一下午,从刚开始懵逼,到晚上还是懵逼,并且产生了一种“我是谁,我在哪,我在干什么”的感觉,下面讲述一下心路历程。

首先在GitHub上逛了一圈,发现只有作者本人发布的graphGAN复现的标星比较高,但可能那时候脑子发抽,突然想特立独行,然后就去找标星少的跑,即如下两个链接:

https://github.com/liutongyang/GraphGAN-pytorch

https://github.com/yikaiw/NRL-implement

基本没了,因为graphGAN在10个以上star的排除作者本人的就俩,但不跑不知道,一跑吓一跳,感觉bug太多了,上面第一个链接是由原tensorflow复现的graphGAN转pytorch,然后同样是国人,加了自己的翻译,readme.md直接拷贝的,但代码没有翻译完,根本跑不起,第二个是在原作基础上加了很多自己的修改,比如说记载数据方式,以及评估函数,训练函数都有不同程度的修改,具体在后面展开。

关于作者本人的graphGAN的链接是:

https://github.com/hwwang55/GraphGAN

这个也是一言难尽,所以先讲讲论文吧,代码方面我感觉一笔带过了。于是我就跑去看了该作者的论文,地址为:https://arxiv.org/pdf/1711.08267.pdf,但还别说,论文的数据倒是非常漂亮。

min ⁡ θ G max ⁡ θ D V ( G , D ) = ∑ c = 1 V ( E v ∼ p true  ( ⋅ ∣ v c ) [ log ⁡ D ( v , v c ; θ D ) ] + E v ∼ G ( ⋅ ∣ v c ; θ G ) [ log ⁡ ( 1 − D ( v , v c ; θ D ) ) ] ) . \begin{array}{c} \min _{\theta_{G}} \max _{\theta_{D}} V(G, D)=\sum_{c=1}^{V}\left(\mathbb{E}_{v \sim p_{\text {true }}\left(\cdot \mid v_{c}\right)}\left[\log D\left(v, v_{c} ; \theta_{D}\right)\right]\right. \\ \left.+\mathbb{E}_{v \sim G\left(\cdot \mid v_{c} ; \theta_{G}\right)}\left[\log \left(1-D\left(v, v_{c} ; \theta_{D}\right)\right)\right]\right) . \end{array} minθGmaxθDV(G,D)=c=1V(Evptrue (vc)[logD(v,vc;θD)]+EvG(vc;θG)[log(1D(v,vc;θD))]).

G是一个生成器,它试图近似真实的边连接分布 ( v ∣ v c ) (v|vc) (vvc),D是一个判别器,它的目的是判断顶点对(v, vc)之间是否有边连接。 D ( v , v c ; θ D ) D(v, vc; θD) D(v,vc;θD)输出一个标量,那这基本就是GAN的两个基本变量了,然后论文中后面就是对上述的进行推导优化,以及加入softmax,这里的框架流程为:
在这里插入图片描述
然后给出一些假设与一些定义后,开始推导:
在这里插入图片描述

然后再带softmax,简化,后面又等价代换等等操作后,终于给出了作者的测试结果:

在这里插入图片描述

合着这一顿操作,一阶加二阶优化器一起上,还加上了GAN的变量,就提升了0.01?另外就是它还需要提供预训练的图向量,但论文行文确实漂亮。让人有复现的欲望?大坑,非常坑。

然后我就知其所以然,而不知其所止的去了。结果坑了我自己。这里讲下大致过程吧,不准备回头解决问题了。

GitHub中官方代码拉下来后,需要改动的数据集大致如下:

train_filename = "../../data/" + app + "/" + dataset + "_train.txt"
test_filename = "../../data/" + app + "/" + dataset + "_test.txt"
test_neg_filename = "../../data/" + app + "/" + dataset + "_test_neg.txt"
pretrain_emb_filename_d = "../../pre_train/" + app + "/" + dataset + "_pre_train.emb"
pretrain_emb_filename_g = "../../pre_train/" + app + "/" + dataset + "_pre_train.emb"
emb_filenames = ["../../results/" + app + "/" + dataset + "_gen_.emb",
                 "../../results/" + app + "/" + dataset + "_dis_.emb"]
result_filename = "../../results/" + app + "/" + dataset + ".txt"
cache_filename = "../../cache/" + dataset + ".pkl"
model_log = "../../log/"

我看了一下,发现我除了上面的train外,其它基本没有,然后就基于上述node2vec的节点把训练的图向量保存下来,可以填补pretrain_filename,那还有test_filename直接根据上述的train进行划分,代码为:

# 导入相关库
import numpy as np
import networkx as nx
import pandas as pd

# 两列,分别为出发节点id,目的节点id
graph = pd.read_csv('http://mirror.coggle.club/dataset/graph-wiki/graph.txt.zip', sep='\t', header=None)

G = nx.DiGraph()
G.add_edges_from(graph.values[:])

# 读取图数据
# G = nx.read_edgelist('graph.txt', create_using=nx.Graph(), nodetype=int)

nodes = list(G.nodes())
edges = list(G.edges())
print(nodes)
print(edges)
# 设置测试边的比例
test_ratio = 0.2

np.random.shuffle(edges)
num_test_edges = int(len(edges) * test_ratio)
test_edges = edges[:num_test_edges]
train_edges = edges[num_test_edges:]

train_G = nx.Graph()
train_G.add_nodes_from(nodes)
train_G.add_edges_from(train_edges)

test_G = nx.Graph()
test_G.add_nodes_from(nodes)
test_G.add_edges_from(test_edges)

# 保存训练图和测试图
nx.write_edgelist(train_G, 'train_graph.txt')
nx.write_edgelist(test_G, 'test_graph.txt')

那就只有test_neg_filename 没有了,但这个我就不知道怎么造了,所以我划分完数据集后并没有跑,而是去复现了一下,大概跑了10个epochs,发现一件比较好玩的事情:

@:/home/program/test/GraphGAN-master/results/link_prediction# cat CA-GrQc.txt
gen:0.7598343685300207
dis:0.7598343685300207
gen:0.5659075224292616
dis:0.7405106970324362
gen:0.759144237405107
dis:0.7598343685300207
gen:0.5652173913043478
dis:0.7425810904071773
gen:0.52311939268461
dis:0.673567977915804
gen:0.5044858523119393
dis:0.6652864044168392
gen:0.7598343685300207
dis:0.7598343685300207
gen:0.7598343685300207

我们可以发现初始是有0.76,但是后续越跑越低?emmm,这作者给的参数都已经很低了,但我看到issue里有一个提问,是它跑完了,越跑越低,然后作者干脆把他issue关了。。。

具体问题参照:如何看待有些AI研究员所有的工作都不公布code?

那我对于graphGAN的研究就到此为止了,浪费了大半天吧,除了论文漂亮,代码写得冗余,以及复现不了,都感觉没啥意义了,然后我又回看了NRL-implement,即上述第二个引用链接,它采用的是腾讯数据集,有大概几十万的节点,我看了下一个epochs要跑9个小时就放弃了,然后我也替换成了自己数据集试下,它针对数据预处理的改动是需要换成npy,所以这里还需要改动下格式:

import numpy as np

dd = np.genfromtxt("train_graph.txt")
x = np.delete(dd, 2, axis=1)
np.save("train_graph.npy", x)

然后它的配置为:

lr_dis = 1e-4  # learning rate for discriminator
lr_gen = 1e-3  # learning rate for discriminator

max_epochs = 20  # outer loop number
max_epochs_gen = 30  # loop number for generator
max_epochs_dis = 30  # loop number for discriminator

gen_for_d_iters = 10  # iteration numbers for generate new data for discriminator
model_log = '../log/iteration/'

load_model = False  # if load the model for continual training
gen_update_iter = 200
window_size = 3
random_state = np.random.randint(0, 100000)
train_filename = '/home/program/test/NRL-implement/test/train_graph.npy'
test_filename = '/home/program/test/NRL-implement/test/test_graph.npy'
# train_filename = '../data/tencent/train_edges.npy'
# test_filename = '../data/tencent/test_edges.npy'

# test_neg_filename = 'data/tencent/test_edges_false.npy'
emb_filenames = ['results/tencent/GraphGAN/embeds_gen.csv', 'results/tencent/GraphGAN/embeds_dis.csv']



result_filename = 'results/GraphGAN/result.csv'
embed_dim = 50
node_num = 2405
modes = ['dis', 'gen']

这配置感觉比原作者靠谱,至少我发现它很多东西没有,那可能真按照GAN生成了,但当我把我的数据该进去后,跑是跑了一个epochs,然后就停止了,感觉是tensorflow版本问题,该作者没有详述需要版本,那task6,我就只能到此为止了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

submarineas

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值