spd_learn.functional.spd_rpgd_attack#

spd_learn.functional.spd_rpgd_attack(model: Module, x: Tensor, y: Tensor, eps: float, criterion: Module, n_iterations: int = 100, step_size: float = 0.01)[source]#

Riemannian Projected Gradient Descent attack on the SPD manifold under AIRM metric.

This attack generates adversarial examples by performing gradient ascent on the loss function while constraining perturbations to lie within a geodesic ball of radius eps on the Riemannian manifold of SPD matrices [Timoz et al., 2026].

Problem description: Given an input SPD matrix \(X \in \mathcal{S}^{++}_n\) with its true label \(y\), the goal is to find an adversarial example \(X_{adv}\) such that:

\[\max_{X_{adv} \in \mathcal{S}^{++}_n} \mathcal{L}(f(X_{adv}), y) \quad \text{s.t.} \quad d_{AIRM}(X, X_{adv}) \leq \epsilon\]

The algorithm outline:

  1. Initialize the adversarial example as the original input.

  2. For a fixed number of iterations:

  1. Compute the gradient of the loss w.r.t. the current adversarial example.

  2. Convert the Euclidean gradient to a Riemannian gradient.

  3. Take a step along the Riemannian gradient.

  4. Project back onto the geodesic ball of radius eps.

Parameters:
  • model (torch.nn.Module or object) – The model to attack. Should accept SPD matrices as input. If an object with a module_ attribute (e.g. skorch) is passed, the underlying module is used.

  • eps (float, default=0.2) – Maximum AIRM distance for adversarial perturbations.

  • criterion (callable, optional) – Loss function to maximize. If None, uses torch.nn.CrossEntropyLoss().

Examples

>>> import torch
>>> from spd_learn.attacks import RiemannianPGDAttack
>>> from spd_learn.models import SPDNet
>>> model = SPDNet(n_channels=3, n_classes=2)
>>> attack = RiemannianPGDAttack(
...     estimator=model,
...     eps=0.1,
...     criterion=torch.nn.CrossEntropyLoss()
... )
>>> x = torch.randn(5, 3, 10, 10)
>>> x = x @ x.transpose(-1, -2) + torch.eye(10)
>>> y = torch.randint(0, 2, (5,))
>>> x_adv = attack.generate(x, y, n_iterations=50, step_size=0.01)

Notes

The stepsize and number of iterations should be chosen carefully to balance attack strength and computational cost.

See also

geodesic_distance_spdairm()

Distance under affine-invariant metric.