论文
图注意力网络来自 Graph Attention Networks,ICLR 2018. https://arxiv.org/abs/1710.10903
GAT层
输入
N为节点的个数,F为feature的个数,这表示输入为N个节点的每个节点的F个feature
输出
表示对这N个节点的 F' 个输出,输出位N个节点的每个节点的F'个feature
注意力机制
GAT.py
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 |
import tensorflow as tf from tensorflow import keras from tensorflow.python.keras import activations from tensorflow.python.keras import constraints from tensorflow.python.keras import initializers from tensorflow.python.keras import regularizers class GraphAttentionLayer(keras.layers.Layer): def compute_output_signature(self, input_signature): pass def __init__(self, input_dim, output_dim, adj, nodes_num, dropout_rate=0.0, activation=None, use_bias=True, kernel_initializer='glorot_uniform', bias_initializer='zeros', kernel_regularizer=None, bias_regularizer=None, activity_regularizer=None, kernel_constraint=None, bias_constraint=None, coef_dropout=0.0, **kwargs): """ :param input_dim: 输入的维度 :param output_dim: 输出的维度,不等于input_dim :param adj: 具有自环的tuple类型的邻接表[coords, values, shape], 可以采用sp.coo_matrix生成 :param nodes_num: 点数量 :param dropout_rate: 丢弃率,防过拟合,默认0.5 :param activation: 激活函数 :param use_bias: 偏移,默认True :param kernel_initializer: 权值初始化方法 :param bias_initializer: 偏移初始化方法 :param kernel_regularizer: 权值正则化 :param bias_regularizer: 偏移正则化 :param activity_regularizer: 输出正则化 :param kernel_constraint: 权值约束 :param bias_constraint: 偏移约束 :param coef_dropout: 互相关系数丢弃,默认0.0 :param kwargs: """ super(GraphAttentionLayer, self).__init__() self.activation = activations.get(activation) self.use_bias = use_bias self.kernel_initializer = initializers.get(kernel_initializer) self.bias_initializer = initializers.get(bias_initializer) self.kernel_regularizer = regularizers.get(kernel_regularizer) self.bias_regularizer = regularizers.get(bias_regularizer) self.kernel_constraint = constraints.get(kernel_constraint) self.bias_constraint = constraints.get(bias_constraint) self.input_dim = input_dim self.output_dim = output_dim self.support = [tf.SparseTensor(indices=adj[0][0], values=adj[0][1], dense_shape=adj[0][2])] self.dropout_rate = dropout_rate self.coef_drop = coef_dropout self.nodes_num = nodes_num self.kernel = None self.mapping = None self.bias = None def build(self, input_shape): """ 只执行一次 """ self.kernel = self.add_weight(shape=(self.input_dim, self.output_dim), initializer=self.kernel_initializer, regularizer=self.kernel_regularizer, constraint=self.kernel_constraint, trainable=True) if self.use_bias: self.bias = self.add_weight(shape=(self.nodes_num, self.output_dim), initializer=self.kernel_initializer, regularizer=self.kernel_regularizer, constraint=self.kernel_constraint, trainable=True) print('[GAT LAYER]: GAT W & b built.') def call(self, inputs, training=True): # 完成输入到输出的映射关系 # inputs = tf.nn.l2_normalize(inputs, 1) raw_shape = inputs.shape inputs = tf.reshape(inputs, shape=(1, raw_shape[0], raw_shape[1])) # (1, nodes_num, input_dim) mapped_inputs = keras.layers.Conv1D(self.output_dim, 1, use_bias=False)(inputs) # (1, nodes_num, output_dim) # mapped_inputs = tf.nn.l2_normalize(mapped_inputs) sa_1 = keras.layers.Conv1D(1, 1)(mapped_inputs) # (1, nodes_num, 1) sa_2 = keras.layers.Conv1D(1, 1)(mapped_inputs) # (1, nodes_num, 1) con_sa_1 = tf.reshape(sa_1, shape=(raw_shape[0], 1)) # (nodes_num, 1) con_sa_2 = tf.reshape(sa_2, shape=(raw_shape[0], 1)) # (nodes_num, 1) con_sa_1 = tf.cast(self.support[0], dtype=tf.float32) * con_sa_1 # (nodes_num, nodes_num) W_hi con_sa_2 = tf.cast(self.support[0], dtype=tf.float32) * tf.transpose(con_sa_2, [1, 0]) # (nodes_num, nodes_num) W_hj weights = tf.sparse.add(con_sa_1, con_sa_2) # concatenation weights_act = tf.SparseTensor(indices=weights.indices, values=tf.nn.leaky_relu(weights.values), dense_shape=weights.dense_shape) # 注意力互相关系数 attention = tf.sparse.softmax(weights_act) # 输出注意力机制 inputs = tf.reshape(inputs, shape=raw_shape) if self.coef_drop > 0.0: attention = tf.SparseTensor(indices=attention.indices, values=tf.nn.dropout(attention.values, self.coef_dropout), dense_shape=attention.dense_shape) if training and self.dropout_rate > 0.0: inputs = tf.nn.dropout(inputs, self.dropout_rate) if not training: print("[GAT LAYER]: GAT not training now.") attention = tf.sparse.reshape(attention, shape=[self.nodes_num, self.nodes_num]) value = tf.matmul(inputs, self.kernel) value = tf.sparse.sparse_dense_matmul(attention, value) if self.use_bias: ret = tf.add(value, self.bias) else: ret = tf.reshape(value, (raw_shape[0], self.output_dim)) return self.activation(ret) |
参考
https://blog.csdn.net/weixin_36474809/article/details/89401552
https://github.com/PetarV-/GAT