docstr: Forward and update edge weights.
docstr_tok: ["Forward","and","update","edge","weights","."]
code: def _forward_and_gradient(
      self,
      x: Tensor,
      labels: Tensor,
      idx_attack: Optional[Tensor] = None,
      **kwargs,
  ) -> Tuple[Tensor, Tensor]:
      """Forward and update edge weights."""
      self.block_edge_weight.requires_grad = True
  
      self.model.reset_parameters()
  
      self.model.train()
      opt = Adam(
          self.model.parameters(), lr=lr, weight_decay=weight_decay
      )
  
      with higher.innerloop_ctx(self.model, opt) as (fmodel, diffopt):
          edge_index, edge_weight = self._get_modified_adj(
              self.edge_index,
              self.edge_weight,
              self.block_edge_index,
              self.block_edge_weight,
          )
  
          # Normalize only once (only relevant if model normalizes adj)
          if hasattr(fmodel, "norm"):
              edge_index, edge_weight = fmodel.norm(
                  edge_index,
                  edge_weight,
                  num_nodes=x.size(0),
                  add_self_loops=True,
              )
  
          for _ in range(n_epochs):
              pred = fmodel.forward(
                  x, edge_index, edge_weight, skip_norm=True
              )
              loss = F.cross_entropy(
                  pred[data.train_mask], data.y[data.train_mask]
              )
              diffopt.step(loss)
  
          pred = fmodel(x, edge_index, edge_weight)
          loss = self.loss(pred, labels, idx_attack)
  
          gradient = torch.autograd.grad(loss, self.block_edge_weight)[
              0
          ]
  
      # Clip gradient for stability:
      clip_norm = 0.5
      grad_len_sq = gradient.square().sum()
      if grad_len_sq > clip_norm:
          gradient *= clip_norm / grad_len_sq.sqrt()
  
      self.model.eval()
  
      return loss, gradient
  
file_path: pytorch_geometric/examples/contrib/rbcd_attack_poisoning.py
imports: import copy
  import os.path
  import sys
  from typing import Optional, Tuple
  import matplotlib.pyplot
  import torch
  import torch.nn.functional
  from rbcd_attack import GCN, metric, test, train
  from torch import Tensor
  from torch.optim import Adam
  import torch_geometric.transforms
  from torch_geometric.contrib.nn import PRBCDAttack
  from torch_geometric.datasets import Planetoid
label_desc: Use image node_id 2 for calling the PoisoningPRBCDAttack obj's underlying member method code with example usage: obj._forward_and_gradient(x, labels, idx_attack) and returns: loss,  gradient