spd_learn.modules.LogEig#
- class spd_learn.modules.LogEig(upper=True, flatten=True, autograd=False, device=None, dtype=None)[source]#
Bases:
ModuleLogarithmic Eigenvalue Layer (LogEig).
This layer maps SPD matrices to the tangent space at the identity via the Riemannian logarithm under the affine-invariant metric [Huang and Van Gool, 2017]. The output is then vectorized.
\[\log(X) = U \log(\Lambda) U^\top\]where \(X = U \Lambda U^\top\) is the eigendecomposition.
This operation embeds SPD matrices into the tangent space at the identity, which is a vector space, thereby enabling the use of standard Euclidean layers such as linear classifiers or fully connected networks for downstream tasks.
- Parameters:
See also
ExpEigInverse operation, maps from tangent space back to manifold.
ReEigEigenvalue rectification to ensure numerical stability before LogEig.
BiMapBilinear mapping for dimensionality reduction on SPD matrices.
matrix_log()Functional version of matrix logarithm.
log_euclidean_distance()Distance computation in log-domain.
Examples
>>> import torch >>> from spd_learn.modules import LogEig >>> layer = LogEig(upper=True) >>> X = torch.randn(2, 4, 4) >>> X = X @ X.mT + 0.1 * torch.eye(4) # Make SPD >>> Y = layer(X) >>> Y.shape torch.Size([2, 10])
import torch import numpy as np import matplotlib.pyplot as plt from spd_learn.modules import LogEig torch.manual_seed(42) # Create a 4x4 SPD matrix n = 4 A = torch.randn(n, n) X = A @ A.T + 0.1 * torch.eye(n) X = X.unsqueeze(0) # Apply LogEig logeig_full = LogEig(upper=False, flatten=False) logeig_vec = LogEig(upper=True, flatten=True) log_matrix = logeig_full(X) log_vector = logeig_vec(X) fig, axes = plt.subplots(1, 3, figsize=(14, 4)) # Input SPD matrix ax1 = axes[0] im1 = ax1.imshow(X[0].numpy(), cmap='RdBu_r', aspect='auto') ax1.set_title('Input SPD Matrix X') plt.colorbar(im1, ax=ax1, shrink=0.8) # Matrix logarithm ax2 = axes[1] im2 = ax2.imshow(log_matrix[0].numpy(), cmap='RdBu_r', aspect='auto') ax2.set_title(r'log(X) (Tangent Space)') plt.colorbar(im2, ax=ax2, shrink=0.8) # Vectorized output ax3 = axes[2] vec = log_vector[0].numpy() ax3.bar(range(len(vec)), vec, color='#2ecc71', alpha=0.8) ax3.set_xlabel('Vector index') ax3.set_ylabel('Value') ax3.set_title(f'Vectorized (dim={len(vec)})') ax3.grid(True, alpha=0.3) plt.suptitle('LogEig: SPD to Tangent Space Mapping', fontweight='bold') plt.tight_layout() plt.show()
- forward(X: Tensor) Tensor[source]#
Forward pass of the LogEig layer.
- Parameters:
X (torch.Tensor) – Input SPD matrix.
- Returns:
The vectorized output in the tangent space.
- Return type: