class_docstr: Graph attention layer from `Graph Attention Network
  <https://arxiv.org/pdf/1710.10903.pdf>`__, with the sparse aggregation
  accelerated by cugraph-ops.
  
  Parameters
  ----------
  in_feats : int or tuple
      Input feature size. A pair denotes feature sizes of source and
      destination nodes.
  out_feats : int
      Output feature size.
  num_heads : int
      Number of heads in multi-head attention.
  feat_drop : float, optional
      Dropout rate on feature. Defaults: ``0``.
  concat : bool, optional
      If False, the multi-head attentions are averaged instead of concatenated.
      Default: ``True``.
  edge_feats : int, optional
      Edge feature size. Default: ``None``.
  negative_slope : float, optional
      LeakyReLU angle of negative slope. Defaults: ``0.2``.
  residual : bool, optional
      If True, use residual connection. Defaults: ``False``.
  allow_zero_in_degree : bool, optional
      If there are 0-in-degree nodes in the graph, output for those nodes will
      be invalid since no message will be passed to those nodes. This is
      harmful for some applications causing silent performance regression.
      This module will raise a DGLError if it detects 0-in-degree nodes in
      input graph. By setting ``True``, it will suppress the check and let the
      users handle it by themselves. Defaults: ``False``.
  bias : bool, optional
      If True, learns a bias term. Defaults: ``True``.
  
  Examples
  --------
  >>> import dgl
  >>> import torch
  >>> from cugraph_dgl.nn import GATConv
  ...
  >>> device = 'cuda'
  >>> g = dgl.graph(([0,1,2,3,2,5], [1,2,3,4,0,3])).to(device)
  >>> g = dgl.add_self_loop(g)
  >>> feat = torch.ones(6, 10).to(device)
  >>> conv = GATConv(10, 2, num_heads=3).to(device)
  >>> res = conv(g, feat)
  >>> res
  tensor([[[ 0.2340,  1.9226],
          [ 1.6477, -1.9986],
          [ 1.1138, -1.9302]],
          [[ 0.2340,  1.9226],
          [ 1.6477, -1.9986],
          [ 1.1138, -1.9302]],
          [[ 0.2340,  1.9226],
          [ 1.6477, -1.9986],
          [ 1.1138, -1.9302]],
          [[ 0.2340,  1.9226],
          [ 1.6477, -1.9986],
          [ 1.1138, -1.9302]],
          [[ 0.2340,  1.9226],
          [ 1.6477, -1.9986],
          [ 1.1138, -1.9302]],
          [[ 0.2340,  1.9226],
          [ 1.6477, -1.9986],
          [ 1.1138, -1.9302]]], device='cuda:0', grad_fn=<ViewBackward0>)
code: def __init__(
      self,
      in_feats: Union[int, Tuple[int, int]],
      out_feats: int,
      num_heads: int,
      feat_drop: float = 0.0,
      concat: bool = True,
      edge_feats: Optional[int] = None,
      negative_slope: float = 0.2,
      residual: bool = False,
      allow_zero_in_degree: bool = False,
      bias: bool = True,
  ):
      super().__init__()
      self.in_feats = in_feats
      self.out_feats = out_feats
      self.in_feats_src, self.in_feats_dst = dgl.utils.expand_as_pair(
          in_feats
      )
      self.num_heads = num_heads
      self.feat_drop = nn.Dropout(feat_drop)
      self.concat = concat
      self.edge_feats = edge_feats
      self.negative_slope = negative_slope
      self.allow_zero_in_degree = allow_zero_in_degree
  
      if isinstance(in_feats, int):
          self.lin = nn.Linear(
              in_feats, num_heads * out_feats, bias=False
          )
      else:
          self.lin_src = nn.Linear(
              self.in_feats_src, num_heads * out_feats, bias=False
          )
          self.lin_dst = nn.Linear(
              self.in_feats_dst, num_heads * out_feats, bias=False
          )
  
      if edge_feats is not None:
          self.lin_edge = nn.Linear(
              edge_feats, num_heads * out_feats, bias=False
          )
          self.attn_weights = nn.Parameter(
              torch.Tensor(3 * num_heads * out_feats)
          )
      else:
          self.register_parameter("lin_edge", None)
          self.attn_weights = nn.Parameter(
              torch.Tensor(2 * num_heads * out_feats)
          )
  
      if bias and concat:
          self.bias = nn.Parameter(torch.Tensor(num_heads, out_feats))
      elif bias and not concat:
          self.bias = nn.Parameter(torch.Tensor(out_feats))
      else:
          self.register_buffer("bias", None)
  
      self.residual = (
          residual and self.in_feats_dst != out_feats * num_heads
      )
      if self.residual:
          self.lin_res = nn.Linear(
              self.in_feats_dst, num_heads * out_feats, bias=bias
          )
      else:
          self.register_buffer("lin_res", None)
  
      self.reset_parameters()
  
imports: from typing import Optional, Tuple, Union
  from cugraph_dgl.nn.conv.base import BaseConv, SparseGraph
  from cugraph.utilities.utils import import_optional
label_desc: Use image node_id 1 to create a new GATConv object from inherited base classes: BaseConv with example: obj = GATConv(in_feats, out_feats, num_heads, feat_drop, concat, edge_feats, negative_slope, residual, allow_zero_in_degree, bias)