def _get_loss_gradients(self, x: "torch.Tensor", y: "torch.Tensor", perturbation: "torch.Tensor") -> "torch.Tensor":
        """
        Compute custom, framework-specific, regularized loss gradients.
        """
        import torch

        softmax = torch.nn.Softmax(dim=1).to(self.estimator.device)

        grads_batch = []

        for i in range(x.shape[0]):
            eps = torch.autograd.Variable(
                torch.zeros((1, x.shape[1], 1, 1, x.shape[4]), device=self.estimator.device), requires_grad=True
            )
            x_in = x[[i]] + torch.repeat_interleave(torch.repeat_interleave(eps, x.shape[2], dim=2), x.shape[3], dim=3)
            x_in = self._clip_and_round_pytorch(x_in)
            preds, _ = self.estimator._predict_framework(x=x_in)

            # calculate adversarial loss
            y_preds = softmax(preds)[0]
            y_mask = y[i].eq(1)
            label_prob = torch.masked_select(y_preds, y_mask)
            max_non_label_prob = torch.max(y_preds - y[i], dim=0)[0]

            l_1 = torch.zeros(1).to(self.estimator.device)
            l_m = (label_prob - max_non_label_prob) * (1 - 2 * int(self.targeted)) + self.loss_margin
            l_2 = (l_m**2) / self.loss_margin
            l_3 = l_m

            adversarial_loss = torch.max(l_1, torch.min(l_2, l_3)[0])[0]

            # calculate regularization terms
            # thickness - loss term
            perturbation_i = perturbation[[i]] + eps
            norm_reg = torch.mean(perturbation_i**2) + 1e-12
            perturbation_roll_right = torch.roll(perturbation_i, 1, dims=1)
            perturbation_roll_left = torch.roll(perturbation_i, -1, dims=1)

            # 1st order diff - loss term
            diff_norm_reg = torch.mean((perturbation_i - perturbation_roll_right) ** 2) + 1e-12

            # 2nd order diff - loss term
            laplacian_norm_reg = (
                torch.mean((-2 * perturbation_i + perturbation_roll_right + perturbation_roll_left) ** 2) + 1e-12
            )

            regularization_loss = self.beta_0 * (
                self.beta_1 * norm_reg + self.beta_2 * diff_norm_reg + self.beta_2 * laplacian_norm_reg
            )

            loss = adversarial_loss + regularization_loss

            self.estimator.model.zero_grad()

            # Compute gradients
            loss.backward()
            grads = eps.grad
            if grads is not None:
                grads_batch.append(grads[0, ...])
            else:
                raise ValueError("Received None instead of gradient tensor.")

        grads_batch_tensor = torch.stack(grads_batch)

        return grads_batch_tensor

        Compute custom, framework-specific, regularized loss gradients.
        
art/attacks/evasion/over_the_air_flickering/over_the_air_flickering_pytorch.py