入门一个方向不仅要看论文(似懂非懂),还要搞清楚论文的代码才行
那就开始吧,逐句理解
首先设定可见的 GPU (我也想拥有…)
os.environ["CUDA_VISIBLE_DEVICES"] = "1,2,3"
然后慢慢给显存,但不会释放,所以会有碎片
config = tf.ConfigProto()
config.gpu_options.allow_growth = True
设置数据集 acm,featype 为下面的特征矩阵类型 现在是 fea,输出一段确认信息数据集和 featype
batch_size 为 1
nb_epoches 为 200(共 200 轮吗?)
patience 不知道
lr 学习率 0.005
l2_coef 权重衰减 0.001
hid_units = [8] 8 个隐藏单元
n_heads = [8, 1] 输出层的附加东西,8个到1个吗?
residual = False 是不设置残差吗?
nonlinearity = tf.nn.elu 非线性函数为 elu
model = HeteGAT_multi 模型为 heteGAT_multi (这个具体在 gat.py 文件里)
接着输出一系列确认信息
数据集、学习率、权重衰减
层数(这个输出是隐藏单元数?)、隐藏单元数、注意头数(n_heads ?)
残差、非线性函数、模型
创建一个 mask,下面 load_data 用得到
生成一个全是 false 的列表
对应 idx 位置设为 true
下面以 ACM3025 为例
用 scipy.io 的 sio 导入 mat 数据
导入后,可以看到 ‘PTP’、‘PLP’、'PAP‘、‘feature’、‘label’、‘train_idx’、'val_idx’ 、‘test_idx’ 索引
获取 label 和 feature,维度分别为 (3025, 3) 和 (3025, 1870)
样本个数 N,N 为 3025
data[‘PAP’] 和 data[‘PLP’] 都是 (3025, 3025)
rownetworks 是这两个矩阵减去单位矩阵,然后拼接
rownetworks = [data['PAP'] - np.eye(N), data['PLP'] - np.eye(N)]
记 label 为 y
train_idx、val_idx、test_idx 分别记录训练集、验证和测试的下标
维度各自为 (1, 600)、(1, 300)、(1, 2125)
测试集这么多?
然后用到上面的 mask
生成 train_mask、val_mask、test_mask
总长度是 3025,这些数据集对应的下标为 true
生成三个集对应的 y
先生成 3 个全空的 y 尺寸的矩阵(3025, 3)
然后把 y 上对应下标的值给到对应的三个集上,注意不是切片
这样 y_train 等三个集都还是 (3025, 3),对应下标都是 y 的值了,其他位置还是 0
输出一条确认信息,y_train 等和 train_idx 等的 shape
把特征复制 3 遍拼在一起 得到 truefeatures_list
最后,函数返回 rownetworks, truefeatures_list, y_train等,train_mask等
然后下面用 adj_list 接 rownetworks,fea_list 接 truefeatures_list
这里来了一句:试一试
如果 featype == ‘adj’,把 adj_list 当作fea_list
【所以 fea=fea,没有用到元路径信息?】
nb_nodes 为 3025
ft_size 为特征数目 1870
nb_classes 为分类数 3
下面对 fea_list、adj_list 等升维,用到了 np.newaxis
如 y_train 从 (3025, 3) 变成了 (1, 3025, 3)
把 adj(上面就是 ‘PAP’ 矩阵)进行处理,用到了 process.py 的 adj_to_bias
通过扩展到一个给定的邻域来准备邻接矩阵
biases_list = [process.adj_to_bias(adj, [nb_nodes], nhood=1) for adj in adj_list]
这里分析一下 adj_to_bias
def adj_to_bias(adj, sizes, nhood=1):
nb_graphs = adj.shape[0]
mt = np.empty(adj.shape)
for g in range(nb_graphs):
mt[g] = np.eye(adj.shape[1])
for _ in range(nhood):
mt[g] = np.matmul(mt[g], (adj[g] + np.eye(adj.shape[1])))
for i in range(sizes[g]):
for j in range(sizes[g]):
if mt[g][i][j] > 0.0:
mt[g][i][j] = 1.0
return -1e9 * (1.0 - mt)
这个 nb_graphs 挺奇怪,上面是 for 传入的 adj,又升过维,那应该就是 1 啊
生成 (1, 3025, 3025) 的全 1 张量
mt 的每个图 生成 (3025, 3025) 的单位矩阵,也就 1 个
对每个邻居,用 mt[g] 和 adj+单位矩阵 进行矩阵相乘,这个 nhood 可以设定
然后判定 mt,如果 mt[i][j] > 0
,那就设为 1.0 【不过这双重循环 3025 * 3025 看起来有点费时间?】
最后返回 -1e9 * (1.0 - mt)
,也即是
如果判定前 mt[i][j] 大于 0,最后是 0,如果小于等于 0,最后是一个很小的负数,如 -10000000000
这个就是用于后面的 bias 添加,只添加负的
设置默认图,命名空间为 input
with tf.Graph().as_default():
with tf.name_scope('input'):
生成 3(上面复制了 3 遍)个 (batch_size, 3025, 1870) 的特征 tensor
生成 2 (拼了 2 个路径)的 (batch_size, 3025, 1870) 的邻接 tensor
lbl_in (batch_size, 3015, 3) 标签 tensor
msk_in (batch_size, 3025) 的 mask tensor
这里调用了 model 的 inference,这个就另写一篇研究模型了
返回 logits(误差?)、final_emb、att_val
把 log、label、mask 传入 masked_softmax_cross_entropy 计算 loss
同时也传入得到 accuracy
这两个计算函数都在 baseGNN 里,也就是 GAT 的代码里,一模一样
调用 model 的 training
保存训练的模型
打包全局和局部初始化器,等会一起执行
200 轮
tr_step 是 batch 的步数
tr_size = 3025
lbl_in 放入 y_train 的 batch
msk_in 放入 train_mask 的 batch
attn_drop 为 0.6
ffd_drop 为 0.6
用 fd 字典把训练的特征、邻接、标签和mask 拼在一起
然后开始 run
对比 GAT 的 execute_cora.py 的训练,不同在于 feed_dict 的不同,具体是 fd1 和 fd2 的不同
其中 fd1 是 复制 3 遍的特征矩阵,而 fd2 是不同元路径的拼接矩阵
所以应该就是 fd2 的不同
fd1 = {i: d[tr_step * batch_size: (tr_step + 1) * batch_size]
for i, d in zip(ftr_in_list, fea_list)}
fd2 = {i: d[tr_step * batch_size: (tr_step + 1) * batch_size]
for i, d in zip(bias_in_list, biases_list)}
fd3 = {lbl_in: y_train[tr_step * batch_size: (tr_step + 1) * batch_size],
msk_in: train_mask[tr_step * batch_size: (tr_step + 1) * batch_size],
is_train: True,
attn_drop: 0.6,
ffd_drop: 0.6}
fd = fd1
fd.update(fd2)
fd.update(fd3)
_, loss_value_tr, acc_tr, att_val_train = sess.run([train_op, loss, accuracy, att_val],
feed_dict=fd)
GAT 的是
_, loss_value_tr, acc_tr = sess.run([train_op, loss, accuracy],
feed_dict={
ftr_in: features[tr_step*batch_size: (tr_step+1)*batch_size],
bias_in: biases[tr_step*batch_size: (tr_step+1)*batch_size],
lbl_in: y_train[tr_step*batch_size: (tr_step+1)*batch_size],
msk_in: train_mask[tr_step*batch_size: (tr_step+1)*batch_size],
is_train: True,
attn_drop: 0.6, ffd_drop: 0.6})
最后,通过两个自定义的 KNN 和 Kmeans 得到节点分类和节点聚类的指标
参考:https://blog.csdn.net/weixin_43301333/article/details/108854504
https://blog.csdn.net/u012436149/article/details/53837651
https://blog.csdn.net/nanhuaibeian/article/details/101862790
https://blog.csdn.net/qq_37591637/article/details/103408486