| #!/usr/bin/env python3 | |
| """GPU-scale independent audit of finite-temperature attention metastability. | |
| This uses the stochastic self-attention process SA_P from Eq. (5.3) of | |
| arXiv:2508.09628. It checks the constant-step first phase on an equilateral | |
| configuration satisfying the paper's geometric hypotheses, then measures | |
| first-exit times from the singleton-cluster epsilon neighborhoods used by | |
| Theorem 5.4. All particles update simultaneously and each query samples an | |
| independent categorical key from its finite-beta attention weights. | |
| """ | |
| from __future__ import annotations | |
| import json | |
| import math | |
| import platform | |
| import time | |
| import torch | |
| SEED = 809704 | |
| def regular_polygon(count: int, radius: float, device: torch.device) -> torch.Tensor: | |
| angles = torch.arange(count, device=device, dtype=torch.float32) * (2.0 * math.pi / count) | |
| return radius * torch.stack((torch.cos(angles), torch.sin(angles)), dim=1) | |
| def stochastic_step( | |
| state: torch.Tensor, | |
| beta: float, | |
| gamma: float, | |
| generator: torch.Generator, | |
| ) -> torch.Tensor: | |
| """One vectorized SA_P step for state shaped (replicas, particles, 2).""" | |
| scores = torch.einsum("rid,rjd->rij", state, state) | |
| probabilities = torch.softmax(float(beta) * scores, dim=2) | |
| uniforms = torch.rand( | |
| (*state.shape[:2], 1), | |
| dtype=state.dtype, | |
| device=state.device, | |
| generator=generator, | |
| ) | |
| indices = (uniforms > torch.cumsum(probabilities, dim=2)).sum(dim=2) | |
| indices.clamp_(max=state.shape[1] - 1) | |
| selected = torch.gather(state, 1, indices[..., None].expand(-1, -1, state.shape[2])) | |
| return (1.0 - gamma) * state + gamma * selected | |
| def first_phase(device: torch.device, generator: torch.Generator) -> dict[str, object]: | |
| vertices = regular_polygon(3, 1.0, device) | |
| interiors = 0.25 * vertices | |
| initial = torch.cat((vertices, interiors), dim=0) | |
| beta = 1_000_000.0 | |
| gamma = 0.1 | |
| c0 = 1.5 | |
| diameter = math.sqrt(3.0) | |
| initial_distance = 0.75 | |
| tau = min(c0 / (2.0 * diameter), math.sqrt(2.0 * c0) / 2.0, (1.0 - gamma) * initial_distance) | |
| t1 = math.floor(math.log(tau / initial_distance) / math.log(1.0 - gamma)) | |
| replicas = 262_144 | |
| state = initial.expand(replicas, -1, -1).clone() | |
| for _ in range(t1): | |
| state = stochastic_step(state, beta, gamma, generator) | |
| vertex_ok = torch.all( | |
| torch.linalg.vector_norm(state[:, :3] - vertices[None, :, :], dim=2) <= beta ** (-0.25) + 1e-6, | |
| dim=1, | |
| ) | |
| interior_ok = torch.all( | |
| torch.linalg.vector_norm(state[:, 3:] - vertices[None, :, :], dim=2) <= 1.1 * tau + 1e-6, | |
| dim=1, | |
| ) | |
| success = vertex_ok & interior_ok | |
| sweep: list[dict[str, float]] = [] | |
| sweep_replicas = 65_536 | |
| for local_beta in (2.0, 4.0, 8.0, 16.0, 32.0, 64.0): | |
| local = initial.expand(sweep_replicas, -1, -1).clone() | |
| for _ in range(t1): | |
| local = stochastic_step(local, local_beta, gamma, generator) | |
| labels = torch.argmax(torch.einsum("rid,kd->rik", local[:, 3:], vertices), dim=2) | |
| target = torch.arange(3, device=device)[None, :] | |
| correct = torch.mean((labels == target).to(torch.float64)).item() | |
| distance = torch.mean(torch.linalg.vector_norm(local[:, 3:] - vertices[None, :, :], dim=2)).item() | |
| sweep.append( | |
| { | |
| "beta": local_beta, | |
| "correct_cell_fraction": correct, | |
| "mean_distance_to_assigned_vertex": distance, | |
| } | |
| ) | |
| return { | |
| "beta": beta, | |
| "gamma": gamma, | |
| "T1": t1, | |
| "tau": tau, | |
| "tested_C": 1.1, | |
| "replicas": replicas, | |
| "successes": int(success.sum().item()), | |
| "empirical_success_probability": float(success.to(torch.float64).mean().item()), | |
| "paper_lower_bound": 1.0 - beta ** (-0.125), | |
| "moderate_beta_sweep_replicas": sweep_replicas, | |
| "moderate_beta_sweep": sweep, | |
| } | |
| def first_exit_sweep(device: torch.device, generator: torch.Generator) -> dict[str, object]: | |
| vertices = regular_polygon(3, 0.5, device) | |
| gamma = 0.02 | |
| diameter = math.sqrt(3.0) * 0.5 | |
| epsilon = 2.0 * diameter * gamma | |
| c0 = 0.375 | |
| replicas = 16_384 | |
| max_steps = 25_000 | |
| beta_values = (4.0, 8.0, 12.0, 16.0, 20.0, 24.0) | |
| rows: list[dict[str, float | int]] = [] | |
| total_particle_updates = 0 | |
| for beta in beta_values: | |
| state = vertices.expand(replicas, -1, -1).clone() | |
| alive = torch.ones(replicas, dtype=torch.bool, device=device) | |
| exits = torch.full((replicas,), max_steps + 1, dtype=torch.int64, device=device) | |
| steps_executed = 0 | |
| for step in range(1, max_steps + 1): | |
| state = stochastic_step(state, beta, gamma, generator) | |
| distance = torch.linalg.vector_norm(state - vertices[None, :, :], dim=2) | |
| newly_exited = alive & torch.any(distance > epsilon + 1e-6, dim=1) | |
| exits[newly_exited] = step | |
| alive &= ~newly_exited | |
| steps_executed = step | |
| total_particle_updates += replicas * 3 | |
| if not torch.any(alive): | |
| break | |
| uncensored = exits[exits <= max_steps].to(torch.float64) | |
| if uncensored.numel() == 0: | |
| median = float(max_steps + 1) | |
| mean = float(max_steps + 1) | |
| q10 = float(max_steps + 1) | |
| q90 = float(max_steps + 1) | |
| else: | |
| median = float(torch.quantile(uncensored, 0.5).item()) | |
| mean = float(uncensored.mean().item()) | |
| q10 = float(torch.quantile(uncensored, 0.1).item()) | |
| q90 = float(torch.quantile(uncensored, 0.9).item()) | |
| row = { | |
| "beta": beta, | |
| "replicas": replicas, | |
| "steps_executed": steps_executed, | |
| "median_exit_time_uncensored": median, | |
| "mean_exit_time_uncensored": mean, | |
| "q10_exit_time_uncensored": q10, | |
| "q90_exit_time_uncensored": q90, | |
| "censored_fraction": float((exits > max_steps).to(torch.float64).mean().item()), | |
| "empirical_survival_at_t5": float((exits >= 5).to(torch.float64).mean().item()), | |
| } | |
| rows.append(row) | |
| print("METASTABILITY_ROW=" + json.dumps(row, sort_keys=True), flush=True) | |
| betas = torch.tensor([float(row["beta"]) for row in rows], dtype=torch.float64) | |
| log_medians = torch.log( | |
| torch.tensor([float(row["median_exit_time_uncensored"]) for row in rows], dtype=torch.float64) | |
| ) | |
| design = torch.stack((betas, torch.ones_like(betas)), dim=1) | |
| coeff = torch.linalg.lstsq(design, log_medians).solution | |
| predicted = design @ coeff | |
| residual = torch.sum((log_medians - predicted) ** 2) | |
| total = torch.sum((log_medians - torch.mean(log_medians)) ** 2) | |
| r_squared = float((1.0 - residual / total).item()) | |
| return { | |
| "geometry": "three singleton clusters at an equilateral triangle of radius 0.5", | |
| "gamma": gamma, | |
| "epsilon": epsilon, | |
| "epsilon_over_gamma": epsilon / gamma, | |
| "required_minimum_2diameter": 2.0 * diameter, | |
| "c0": c0, | |
| "replicas_per_beta": replicas, | |
| "max_steps": max_steps, | |
| "total_particle_updates": total_particle_updates, | |
| "log_median_exit_vs_beta_slope": float(coeff[0].item()), | |
| "log_linear_fit_r_squared": r_squared, | |
| "rows": rows, | |
| } | |
| def main() -> None: | |
| if not torch.cuda.is_available(): | |
| raise RuntimeError("This audit requires a CUDA GPU; refusing a silent CPU fallback.") | |
| device = torch.device("cuda") | |
| # Monte Carlo category sampling is insensitive to fp64 roundoff, while | |
| # fp32 uses the accelerator's native high-throughput path. | |
| torch.set_default_dtype(torch.float32) | |
| generator = torch.Generator(device=device) | |
| generator.manual_seed(SEED) | |
| start = time.perf_counter() | |
| gpu = torch.cuda.get_device_properties(device) | |
| result = { | |
| "schema_version": 1, | |
| "paper": "Attention's forward pass and Frank-Wolfe", | |
| "openreview_id": "zrn7rRuvhW", | |
| "arxiv_id": "2508.09628", | |
| "seed": SEED, | |
| "implementation": "independent PyTorch vectorization of stochastic SA_P Eq. (5.3)", | |
| "simulation_dtype": "float32", | |
| "software": { | |
| "python": platform.python_version(), | |
| "torch": torch.__version__, | |
| "cuda_runtime": torch.version.cuda, | |
| }, | |
| "hardware": { | |
| "gpu_name": gpu.name, | |
| "gpu_memory_bytes": gpu.total_memory, | |
| "device_count": torch.cuda.device_count(), | |
| }, | |
| } | |
| result["theorem_5_2_first_phase"] = first_phase(device, generator) | |
| result["theorem_5_4_metastability"] = first_exit_sweep(device, generator) | |
| torch.cuda.synchronize() | |
| result["wall_time_seconds"] = time.perf_counter() - start | |
| first = result["theorem_5_2_first_phase"] | |
| meta = result["theorem_5_4_metastability"] | |
| result["checks"] = { | |
| "first_phase_exceeds_paper_lower_bound": ( | |
| first["empirical_success_probability"] >= first["paper_lower_bound"] | |
| ), | |
| "exit_time_log_linear_r_squared_above_0_99": meta["log_linear_fit_r_squared"] > 0.99, | |
| "positive_exponential_slope": meta["log_median_exit_vs_beta_slope"] > 0.0, | |
| } | |
| print("RESULT_JSON=" + json.dumps(result, sort_keys=True), flush=True) | |
| if __name__ == "__main__": | |
| main() | |
Xet Storage Details
- Size:
- 9.38 kB
- Xet hash:
- c0f124d149cbc9fba75e28cd07c8a65fc032a7e1d2689f23050a66fd3859a31b
·
Xet efficiently stores files, intelligently splitting them into unique chunks and accelerating uploads and downloads. More info.