我是靠谱客的博主 靓丽高山,最近开发中收集的这篇文章主要介绍2020.8.5 GAT代码解析【tensorflow】,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

init.py

from .gat import GAT#从gat.py里面引用GAT这个函数
from .sp_gat import SpGAT#spGAT表示的是稀疏GAT,也是一个引用

base_gattn.py

#attention层的损失函数和训练函数
import tensorflow as tf
class BaseGAttN:
def loss(logits, labels, nb_classes, class_weights):#损失函数的定义
"""tf.reduce_sum()用于计算张量tensor沿着某一维度的和,可以在求和后降维
tf.reduce_mean():计算tensor指定轴方向上的所有元素的平均;
tf.reduce_max():计算tensor指定轴方向上的各个元素的最大值;
tf.reduce_all():计算tensor指定轴方向上的各个元素的逻辑和(and运算);
tf.reduce_any():计算tensor指定轴方向上的各个元素的逻辑或(or运算);
tf.multiply()两个矩阵中对应元素各自相乘
tf.one_hot()函数是将input转化为one-hot类型数据输出,相当于将多个数值联合放在一起作为多个相同类型的向量,
可用于表示各自的概率分布,通常用于分类任务中作为最后的FC层的输出,有时翻译成“独热”编码。
indices = [0, 1, 2]
#输入数据(是个向量)需要编码的索引是[0,1,2]
depth = 3
tf.one_hot(indices, depth)
# output: [3 x 3]
# [[1., 0., 0.],
#
[0., 1., 0.],
#
[0., 0., 1.]]"""
sample_wts = tf.reduce_sum(tf.multiply(tf.one_hot(labels, nb_classes), class_weights), axis=-1)
xentropy = tf.multiply(tf.nn.sparse_softmax_cross_entropy_with_logits(
labels=labels, logits=logits), sample_wts)#计算稀疏softmax的交叉熵损失函数
return tf.reduce_mean(xentropy, name='xentropy_mean')
def training(loss, lr, l2_coef):
# weight decay权重衰减
vars = tf.trainable_variables()
"""返回只用trainable=true所创建的所有变量,variable()构造函数会自动将新变量添加到图形集合中去
tf.add_n()函数就是实现一个列表元素的相加,列表里面的元素可以是向量、矩阵等"""
lossL2 = tf.add_n([tf.nn.l2_loss(v) for v in vars if v.name not
in ['bias', 'gamma', 'b', 'g', 'beta']]) * l2_coef
"""L1范数损失函数,也被称为最小绝对值偏差(LAD),最小绝对值误差(LAE)。总的说来,它是把目标值(Yi)与估计值(f(xi))的绝对差值的总和(S)最小化:
L2范数损失函数,也被称为最小平方误差(LSE)。总的来说,它是把目标值(Yi)与估计值(f(xi))的差值的平方和(S)最小化:"""
# optimizer
adam优化器来优化学习率,使得学习率适当的增减
opt = tf.train.AdamOptimizer(learning_rate=lr)
# training op 通过minimize函数,用于最小化loss+lossL2(lossL2代表L2正则化的损失函数)
train_op = opt.minimize(loss+lossL2)
return train_op
def preshape(logits, labels, nb_classes):
new_sh_lab = [-1]
#原始的lable
new_sh_log = [-1, nb_classes]
#原始的logits
log_resh = tf.reshape(logits, new_sh_log)
#重新得到的logits
lab_resh = tf.reshape(labels, new_sh_lab) #重新得到的lable
"""tf.reshape(tensor,shape,name=None)函数的作用就是将tensor变换成参数shape的形式
其中shape为一个列表形式,特殊一点的是列表中可以存在-1,,,,其实也相当于升维,降维的意思"""
return log_resh, lab_resh
def confmat(logits, labels):
preds = tf.argmax(logits, axis=1)
#对于相应标签的预测
"""tf.argmax(input,axis)根据axis取值的不同返回每行或者每列最大值的索引(位置)
axis=0比较每一列,将其最大元素所在的索引记录下来,最后输出每一列最大元素所在的索引数组
axis=1比较每一行,将每一行最大元素的......."""
return tf.confusion_matrix(labels, preds)
#返回标签,以及相应标签的概率
##########################
# Adapted from tkipf/gcn
对16年的GCN进行的优化#
##########################
def masked_softmax_cross_entropy(logits, labels, mask):
"""Softmax cross-entropy loss with masking.带mask的softmax交叉熵损失函数定义
logits: 模型的输出,维度(B,C);B是样本量,C是输出维度
labels: 模型的标签,维度(B,C)
mask: 掩码,维度(B,)
logits 先softmax成为概率分布,再和labels计算交叉熵
losss 维度是(B,)"""
loss = tf.nn.softmax_cross_entropy_with_logits(logits=logits, labels=labels)
mask = tf.cast(mask, dtype=tf.float32)#tf.cast()类型转换函数,dtype就是转换目标类型
mask /= tf.reduce_mean(mask)#屏蔽掉某些样本的损失
loss *= mask#将mask与损失loss进行相乘即可
return tf.reduce_mean(loss)#返回平均损失
def masked_sigmoid_cross_entropy(logits, labels, mask):
"""sigmoid cross-entropy loss with masking.带mask的softmax交叉熵损失函数定义
logits:(B,C),模型输出;B是样本量,C是输出维度
labels:(B,C),真实标签
mask: 掩码,维度(B,)
分类的结果叫label;分割的结果叫mask。因为分割结果通常会半透明的覆盖在待分割目标上,所以就叫它掩膜吧。"""
labels = tf.cast(labels, dtype=tf.float32)
loss = tf.nn.sigmoid_cross_entropy_with_logits(logits=logits, labels=labels)
loss=tf.reduce_mean(loss,axis=1)
mask = tf.cast(mask, dtype=tf.float32)
mask /= tf.reduce_mean(mask)
loss *= mask
return tf.reduce_mean(loss)
def masked_accuracy(logits, labels, mask):
"""Accuracy with masking."""
"""equal,相等的意思。顾名思义,就是判断,x, y 是不是相等,它的判断方法不是整体判断,
而是逐个元素进行判断,如果相等就是True,不相等,就是False。
由于是逐个元素判断,所以x,y 的维度要一致"""
correct_prediction = tf.equal(tf.argmax(logits, 1), tf.argmax(labels, 1))
accuracy_all = tf.cast(correct_prediction, tf.float32)
mask = tf.cast(mask, dtype=tf.float32)
mask /= tf.reduce_mean(mask)
accuracy_all *= mask
#?为什么都要乘以一个mask呢?
return tf.reduce_mean(accuracy_all)
def micro_f1(logits, labels, mask):
"""评测指标 一般都有accuracy recall F1 macro-F1 micro-F1
这就表明直接将评估指标定义在这里面即可,再在相应的地方改改即可"""
predicted = tf.round(tf.nn.sigmoid(logits))
# Use integers to avoid any nasty FP behaviour使用整数来避免FP行为,这个不需要修改
predicted = tf.cast(predicted, dtype=tf.int32)
labels = tf.cast(labels, dtype=tf.int32)
mask = tf.cast(mask, dtype=tf.int32)
# expand the mask so that broadcasting works ([nb_nodes, 1])
mask = tf.expand_dims(mask, -1)
"""tf.expand_dims( input,axis=None,name=None, dim=None)
t2=[2,3,5]
tf.expand_dims(t2,axis=0) ->[1,2,3,5]
0其实代表第一个维度
tf.expand_dims(t2,axis=1) ->[2,1,3,5]
1其实代表第二个维度
tf.expand_dims(t2,axis=2) ->[2,3,1,5]
2其实代表第三个维度
)"""
# Count true positives, true negatives, false positives and false negatives.
#主要是为了计算评估指标,因此需要将tp,tn,fp,fn计算出来,以便后续处理
tp = tf.count_nonzero(predicted * labels * mask)
tn = tf.count_nonzero((predicted - 1) * (labels - 1) * mask)
fp = tf.count_nonzero(predicted * (labels - 1) * mask)
fn = tf.count_nonzero((predicted - 1) * labels * mask)
# Calculate accuracy, precision, recall and F1 score.
"""这里就是计算各种评估指标,accuracy,precision,recall ,F1 score
正确率(accuracy)是我们最常见的评价指标,accuracy = (TP+TN)/(P+N),
这个很容易理解,就是被分对的样本数除以所有的样本数,通常来说,正确率越高,分类器越好;
精度(precision)是精确性的度量,表示被分为正例的示例中实际为正例的比例,precision=TP/(TP+FP)"""
precision = tp / (tp + fp)
recall = tp / (tp + fn)
fmeasure = (2 * precision * recall) / (precision + recall)
fmeasure = tf.cast(fmeasure, tf.float32)
return fmeasure
"""这里列举几个分类指标
准确率,精确率,召回率 F1-score ROC
"""

gat,py

#这个就是GAT网络的框架
"""
将GAT的网络分为第一层网络,中间层网络,最后一层的网络
就是将每一层结构设置清楚即可,弄清楚其构造即可
"""
import numpy as np
import tensorflow as tf
from utils import layers
from models.base_gattn import BaseGAttN#从base_gattn.py 里面引用BaseGAttN
class GAT(BaseGAttN):
def inference(inputs, nb_classes, nb_nodes, training, attn_drop, ffd_drop,# inference代表推论
attn代表注意系数,ffd表示前馈神经网络
bias_mat, hid_units, n_heads, activation=tf.nn.elu, residual=False):#residual 残差
"""inputs:(B,N,D),B是batch_size,N是节点数,D是每个结点的原始特征维度数
nb_classes: 分类任务的类别数,设为C
nb_nodes: 节点个数,设为N
training: 标志”训练阶段“,”测试阶段“
通过==true or false来进行判别
attn_drop: 注意力矩阵的dropout率,防止过拟合
(dropout指在深度学习网络的训练过程中,对于神经网络单元,按照一定的概率将其暂时从网络中丢弃
经过交叉验证,隐含节点dropout率等于0.5的时候效果最好,原因是0.5的时候dropout随机生成的网络结构最多。
但是将dropout由固定值变为一个区间,可以提高效果)
ffd_drop: 输入的dropout率,防止过拟合
bias_mat: 一个(N,N)的矩阵,由邻接矩阵A变化而来,是注意力矩阵的掩码
hid_units: 列表,第i个元素是第i层的每个注意力头的隐藏单元数
n_heads: 列表,第i个元素是第i层的注意力头数
activation: 激活函数
residual: 是否进行残差连接
第一层,有H1个注意力头,每个头的输入都是(B,N,D),每头注意力输出(B,N,F1);
将所有注意力头的输出聚合,聚合为(B,N,F1*H1)"""
attns = []
#n_heads[0]=第一层注意力的头数,设为H1
for _ in range(n_heads[0]):
"""append()方法在被选元素的结尾(仍然在内部)插入指定内容
(selector).append(content),content是必需的,规定要插入的内容(可包含HTML标签)"""
attns.append(layers.attn_head(inputs, bias_mat=bias_mat,
out_sz=hid_units[0], activation=activation,
in_drop=ffd_drop, coef_drop=attn_drop, residual=False))
h_1 = tf.concat(attns, axis=-1)
"""concat表示拼接
axis=0代表在第0个维度拼接
axis=1代表在第1个维度拼接
负数在数组索引里面表示倒数(countdown),为-1表示在高维度进行拼接
中间层,层数是 len(hid_units)-1;
第i层有Hi个注意力头,输入是 (B,N,F1*H1),每头注意力输出是 (B,N,Fi);
每层均聚合所有头注意力,得到 (B,N,Fi*Hi)"""
# n_heads[i]=中间第i层的注意力头数,设为Hi
for i in range(1, len(hid_units)):
h_old = h_1
attns = []
for _ in range(n_heads[i]):
#与第一层注意力相比,中间层的input就是h_1
attns.append(layers.attn_head(h_1, bias_mat=bias_mat,
out_sz=hid_units[i], activation=activation,
in_drop=ffd_drop, coef_drop=attn_drop, residual=residual))
h_1 = tf.concat(attns, axis=-1)
"""最后一层,共n_heads[-1]头注意力,一般为1
输入:最后一个中间层的输出(B,N,Fi*Hi)
输出:(B,N,C),C是分类任务中的类别数"""
out = []
for i in range(n_heads[-1]):
out.append(layers.attn_head(h_1, bias_mat=bias_mat,
out_sz=nb_classes, activation=lambda x: x,
#只有最后一层输出才有激活函数,输出的尺寸就是分类的类别数
激活函数就是LeakyReLu
in_drop=ffd_drop, coef_drop=attn_drop, residual=False))
"""logits ——【batchsize,class_num】是未进入softmax的概率,一般是全连接层的输出,softmax的输入
将多头注意力的结果相加,并取平均"""
logits = tf.add_n(out) / n_heads[-1]
return logits
#这里返回的只是没有经过softmax的概率,我们将其称之为logits

最后

以上就是靓丽高山为你收集整理的2020.8.5 GAT代码解析【tensorflow】的全部内容,希望文章能够帮你解决2020.8.5 GAT代码解析【tensorflow】所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(43)

评论列表共有 0 条评论

立即
投稿
返回
顶部