def METHOD_NAME(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