A lightweight PyTorch module for stabilizing hyperbolic embeddings in the Poincaré disk. Designed as a drop-in safeguard against runaway norms, invalid Möbius operations, and adversarial edge cases.
Hyperbolic space is excellent for encoding hierarchies, trees, and taxonomies, but it’s numerically fragile:
- 🚧 Points near the unit boundary (
‖z‖ → 1
) cause distance blowups - 🌀 Jacobians can collapse or explode
⚠️ Conjugations near the boundary amplify floating-point errors- 🎯 Boundary attractors can collapse into narrow angular beams
HyperbolicGuard
provides surgical safeguards to make hyperbolic embeddings usable in practice.
- ✅ Curvature-aware damping: soft boundary suppression
- ✅ Hyperbolic operator norm check: power-iteration estimate of Jacobian growth
- ✅ Stable conjugations: real-tensor Cayley transforms (disk ↔ upper half-plane)
- ✅ Angular entropy regularization: prevent beam-forming near the rim
- ✅ Horocycle stressors: adversarial pushes for robustness testing
- ✅ Numerical safety: guarded denominators, no complex literals
- ✅ Unit-tested Cayley roundtrips
git clone https://github.com/your-org/hyperbolic-guard.git
cd hyperbolic-guard
pip install -r requirements.txt
Dependencies:
torch >= 1.12
import torch
from hyperbolic_guard import HyperbolicGuard
guard = HyperbolicGuard(max_radius=0.95)
# Example batch of embeddings
z = torch.randn(16, 2) * 0.5
# Apply safeguards
z = project_to_radius(z, guard.max_radius) # your projection fn
z = guard.hyperbolic_damp(z) # curvature-aware damping
# Monitor stability
opnorm = guard.hyp_opnorm(lambda x: f(x), z) # f = your encoder/decoder
if opnorm.quantile(0.95) > guard.tau:
print("Warning: high operator norm detected!")
# Add angular entropy penalty to your training loss
loss = base_loss + guard.angular_entropy_penalty(z)
hyperbolic_damp(z, alpha=2.0)
→ curvature-aware damping near boundaryhyp_opnorm(f, z, iters=4)
→ per-sample hyperbolic operator norm estimatedisk_to_uhp(z)
/uhp_to_disk(w)
→ Cayley transforms (real-tensor)angular_entropy_penalty(z, n_bins=32, lam=1e-3)
→ regularizer for angular spreadhorocycle_perturb(z, alpha, u_dir)
→ push along horocycles for robustness tests
max_radius=0.95
→ soft wall margintau=0.99
→ operator norm thresholdr_crit=0.85
→ start angular entropy regularization
def test_cayley_roundtrip():
guard = HyperbolicGuard()
z = torch.randn(1000, 2) * 0.9 # inside disk
w = guard.disk_to_uhp(z)
z_recon = guard.uhp_to_disk(w)
err = (z - z_recon).norm(dim=-1).max()
print(f"Cayley roundtrip error: {err:.2e}")
assert err < 1e-6
class HyperbolicModel(nn.Module):
def __init__(self, f):
super().__init__()
self.guard = HyperbolicGuard(max_radius=0.95)
self.f = f # your encoder/decoder
def forward(self, z, base_loss=0.0):
z = project_to_radius(z, self.guard.max_radius)
z = self.guard.hyperbolic_damp(z)
opnorm = self.guard.hyp_opnorm(self.f, z)
if opnorm.quantile(0.95) > self.guard.tau:
print("Ricci flow smoothing may be needed")
loss = base_loss + self.guard.angular_entropy_penalty(z)
return self.f(z), loss
MIT License © 2025