class_docstr: A Graph Attention layer (GAT) from the paper
  
  > [Graph Attention Networks](https://arxiv.org/abs/1710.10903)<br>
  > Petar Veličković et al.
  
  **Mode**: single, disjoint, mixed, batch.
  
  **This layer expects dense inputs when working in batch mode.**
  
  This layer computes a convolution similar to `layers.GraphConv`, but
  uses the attention mechanism to weight the adjacency matrix instead of
  using the normalized Laplacian:
  $$
      \X' = \mathbf{\alpha}\X\W + \b
  $$
  where
  $$
      \mathbf{\alpha}_{ij} =\frac{ \exp\left(\mathrm{LeakyReLU}\left(
      \a^{\top} [(\X\W)_i \, \| \, (\X\W)_j]\right)\right)}{\sum\limits_{k
      \in \mathcal{N}(i) \cup \{ i \}} \exp\left(\mathrm{LeakyReLU}\left(
      \a^{\top} [(\X\W)_i \, \| \, (\X\W)_k]\right)\right)}
  $$
  where \(\a \in \mathbb{R}^{2F'}\) is a trainable attention kernel.
  Dropout is also applied to \(\alpha\) before computing \(\Z\).
  Parallel attention heads are computed in parallel and their results are
  aggregated by concatenation or average.
  
  **Input**
  
  - Node features of shape `([batch], n_nodes, n_node_features)`;
  - Binary adjacency matrix of shape `([batch], n_nodes, n_nodes)`;
  
  **Output**
  
  - Node features with the same shape as the input, but with the last
  dimension changed to `channels`;
  - if `return_attn_coef=True`, a list with the attention coefficients for
  each attention head. Each attention coefficient matrix has shape
  `([batch], n_nodes, n_nodes)`.
  
  **Arguments**
  
  - `channels`: number of output channels;
  - `attn_heads`: number of attention heads to use;
  - `concat_heads`: bool, whether to concatenate the output of the attention
   heads instead of averaging;
  - `dropout_rate`: internal dropout rate for attention coefficients;
  - `return_attn_coef`: if True, return the attention coefficients for
  the given input (one n_nodes x n_nodes matrix for each head).
  - `add_self_loops`: if True, add self loops to the adjacency matrix.
  - `activation`: activation function;
  - `use_bias`: bool, add a bias vector to the output;
  - `kernel_initializer`: initializer for the weights;
  - `attn_kernel_initializer`: initializer for the attention weights;
  - `bias_initializer`: initializer for the bias vector;
  - `kernel_regularizer`: regularization applied to the weights;
  - `attn_kernel_regularizer`: regularization applied to the attention kernels;
  - `bias_regularizer`: regularization applied to the bias vector;
  - `activity_regularizer`: regularization applied to the output;
  - `kernel_constraint`: constraint applied to the weights;
  - `attn_kernel_constraint`: constraint applied to the attention kernels;
  - `bias_constraint`: constraint applied to the bias vector.
class_docstr_tok: ["A","Graph","Attention","layer","(","GAT",")","from","the","paper",">","[","Graph","Attention","Networks","]","(","https",":","\/\/arxiv.org\/abs\/1710.10903",")","<","br",">",">","Petar","Veli\u010dkovi\u0107","et","al",".","*","*","Mode","*","*",":","single",",","disjoint",",","mixed",",","batch",".","*","*","This","layer","expects","dense","inputs","when","working","in","batch","mode",".","*","*","This","layer","computes","a","convolution","similar","to","`","layers.GraphConv","`",",","but","uses","the","attention","mechanism","to","weight","the","adjacency","matrix","instead","of","using","the","normalized","Laplacian",":","$","$","\\X","'","=","\\mathbf","{","\\alpha","}","\\X\\W","+","\\b","$","$","where","$","$","\\mathbf","{","\\alpha","}","_","{","ij","}","=\\frac","{","\\exp\\left","(","\\mathrm","{","LeakyReLU","}","\\left","(","\\a^","{","\\top","}","[","(","\\X\\W",")","_i","\\",",","\\|","\\",",","(","\\X\\W",")","_j","]","\\right",")","\\right",")","}","{","\\sum\\limits_","{","k","\\in","\\mathcal","{","N","}","(","i",")","\\cup","\\","{","i","\\","}","}","\\exp\\left","(","\\mathrm","{","LeakyReLU","}","\\left","(","\\a^","{","\\top","}","[","(","\\X\\W",")","_i","\\",",","\\|","\\",",","(","\\X\\W",")","_k","]","\\right",")","\\right",")","}","$","$","where","\\","(","\\a","\\in","\\mathbb","{","R","}","^","{","2F","'","}","\\",")","is","a","trainable","attention","kernel",".","Dropout","is","also","applied","to","\\","(","\\alpha\\",")","before","computing","\\","(","\\Z\\",")",".","Parallel","attention","heads","are","computed","in","parallel","and","their","results","are","aggregated","by","concatenation","or","average",".","*","*","Input","*","*","-","Node","features","of","shape","`","(","[","batch","]",",","n_nodes",",","n_node_features",")","`",";","-","Binary","adjacency","matrix","of","shape","`","(","[","batch","]",",","n_nodes",",","n_nodes",")","`",";","*","*","Output","*","*","-","Node","features","with","the","same","shape","as","the","input",",","but","with","the","last","dimension","changed","to","`","channels","`",";","-","if","`","return_attn_coef=True","`",",","a","list","with","the","attention","coefficients","for","each","attention","head",".","Each","attention","coefficient","matrix","has","shape","`","(","[","batch","]",",","n_nodes",",","n_nodes",")","`",".","*","*","Arguments","*","*","-","`","channels","`",":","number","of","output","channels",";","-","`","attn_heads","`",":","number","of","attention","heads","to","use",";","-","`","concat_heads","`",":","bool",",","whether","to","concatenate","the","output","of","the","attention","heads","instead","of","averaging",";","-","`","dropout_rate","`",":","internal","dropout","rate","for","attention","coefficients",";","-","`","return_attn_coef","`",":","if","True",",","return","the","attention","coefficients","for","the","given","input","(","one","n_nodes","x","n_nodes","matrix","for","each","head",")",".","-","`","add_self_loops","`",":","if","True",",","add","self","loops","to","the","adjacency","matrix",".","-","`","activation","`",":","activation","function",";","-","`","use_bias","`",":","bool",",","add","a","bias","vector","to","the","output",";","-","`","kernel_initializer","`",":","initializer","for","the","weights",";","-","`","attn_kernel_initializer","`",":","initializer","for","the","attention","weights",";","-","`","bias_initializer","`",":","initializer","for","the","bias","vector",";","-","`","kernel_regularizer","`",":","regularization","applied","to","the","weights",";","-","`","attn_kernel_regularizer","`",":","regularization","applied","to","the","attention","kernels",";","-","`","bias_regularizer","`",":","regularization","applied","to","the","bias","vector",";","-","`","activity_regularizer","`",":","regularization","applied","to","the","output",";","-","`","kernel_constraint","`",":","constraint","applied","to","the","weights",";","-","`","attn_kernel_constraint","`",":","constraint","applied","to","the","attention","kernels",";","-","`","bias_constraint","`",":","constraint","applied","to","the","bias","vector","."]
code: def _call_single(self, x, a):
      # Reshape kernels for efficient message-passing
      kernel = tf.reshape(
          self.kernel, (-1, self.attn_heads * self.channels)
      )
      attn_kernel_self = ops.transpose(self.attn_kernel_self, (2, 1, 0))
      attn_kernel_neighs = ops.transpose(
          self.attn_kernel_neighs, (2, 1, 0)
      )
  
      # Prepare message-passing
      indices = a.indices
      N = tf.shape(x, out_type=indices.dtype)[-2]
      if self.add_self_loops:
          indices = ops.add_self_loops_indices(indices, N)
      targets, sources = indices[:, 1], indices[:, 0]
  
      # Update node features
      x = K.dot(x, kernel)
      x = tf.reshape(x, (-1, self.attn_heads, self.channels))
  
      # Compute attention
      attn_for_self = tf.reduce_sum(x * attn_kernel_self, -1)
      attn_for_self = tf.gather(attn_for_self, targets)
      attn_for_neighs = tf.reduce_sum(x * attn_kernel_neighs, -1)
      attn_for_neighs = tf.gather(attn_for_neighs, sources)
  
      attn_coef = attn_for_self + attn_for_neighs
      attn_coef = tf.nn.leaky_relu(attn_coef, alpha=0.2)
      attn_coef = ops.unsorted_segment_softmax(attn_coef, targets, N)
      attn_coef = self.dropout(attn_coef)
      attn_coef = attn_coef[..., None]
  
      # Update representation
      output = attn_coef * tf.gather(x, sources)
      output = tf.math.unsorted_segment_sum(output, targets, N)
  
      return output, attn_coef
  
file_path: spektral/spektral/layers/convolutional/gat_conv.py
imports: import tensorflow
  from tensorflow.keras import backend
  from tensorflow.keras import constraints, initializers, regularizers
  from tensorflow.keras.layers import Dropout
  from spektral.layers import ops
  from spektral.layers.convolutional.conv import Conv
  from spektral.layers.ops import modes
label_desc: Use image node_id 4 for calling the GATConv obj's underlying member method code with example usage: obj._call_single(x, a) and returns: output,  attn_coef