def loss_gradient(self, x: np.ndarray, y: list[dict[str, np.ndarray | "torch.Tensor"]], **kwargs) -> np.ndarray:
        """
        Compute the gradient of the loss function w.r.t. `x`.

        :param x: Samples of shape (nb_samples, height, width, nb_channels).
        :param y: Target values of format `list[dict[Tensor]]`, one for each input image. The
                  fields of the dict are as follows:

                  - boxes (FloatTensor[N, 4]): the predicted boxes in [x1, y1, x2, y2] format, with values \
                    between 0 and H and 0 and W.
                  - labels (Int64Tensor[N]): the predicted labels for each image.
                  - scores (Tensor[N]): the scores or each prediction.
        :return: Loss gradients of the same shape as `x`.
        """
        grad_list = []

        for i in range(x.shape[0]):

            x_i = x[[i]]
            y_i = [y[i]]

            output, _, image_tensor_list_grad = self._get_losses(x=x_i, y=y_i)

            # Compute the gradient and return
            loss = None
            for loss_name in self.attack_losses:
                if loss is None:
                    loss = output[loss_name]
                else:
                    loss = loss + output[loss_name]

            # Clean gradients
            self._model.zero_grad()

            # Compute gradients
            loss.backward(retain_graph=True)  # type: ignore

            for img in image_tensor_list_grad:
                if img.grad is not None:
                    gradients = img.grad.cpu().numpy().copy()
                else:
                    gradients = None
                grad_list.append(gradients)

        grads = np.array(grad_list)

        if grads.shape[0] == 1:
            grads_ = np.empty(len(grads), dtype=object)
            grads_[:] = list(grads)
            grads = grads_

        if not self.all_framework_preprocessing:
            grads = self._apply_preprocessing_gradient(x, grads)

        if x.dtype != object:
            grads = np.array([i for i in grads], dtype=x.dtype)  # pylint: disable=unnecessary-comprehension
            assert grads.shape == x.shape and grads.dtype == x.dtype

        return grads

        Compute the gradient of the loss function w.r.t. `x`.

        :param x: Samples of shape (nb_samples, height, width, nb_channels).
        :param y: Target values of format `list[dict[Tensor]]`, one for each input image. The
                  fields of the dict are as follows:

                  - boxes (FloatTensor[N, 4]): the predicted boxes in [x1, y1, x2, y2] format, with values                     between 0 and H and 0 and W.
                  - labels (Int64Tensor[N]): the predicted labels for each image.
                  - scores (Tensor[N]): the scores or each prediction.
        :return: Loss gradients of the same shape as `x`.
        
art/estimators/object_tracking/pytorch_goturn.py