QuSpect
Initial Hugging Face release
47709ed
Raw History Blame Contribute Delete
4.54 kB
#!/usr/bin/env python3
"""Static GPU tests for the QH-024 true replacement module."""
from __future__ import annotations
import json
import sys
from pathlib import Path
import torch
from torch import nn
PROJECT = Path(__file__).resolve().parents[2]
sys.path.insert(0, str(PROJECT / "code/src"))
from quantum_qwen38.hyqut_replacement import HybridValueReplacement, QH024Config
def make(kind: str, config: QH024Config, dense: nn.Linear) -> HybridValueReplacement:
return HybridValueReplacement.from_dense(dense, config, core_kind=kind)
def grad_vector(module: nn.Module) -> torch.Tensor:
return torch.cat([
p.grad.detach().flatten().float()
for p in module.parameters()
if p.requires_grad and p.grad is not None
])
def main() -> None:
if not torch.cuda.is_available():
raise RuntimeError("QH-024 static tests are GPU-only")
device = torch.device("cuda:0")
torch.manual_seed(20260838)
config = QH024Config(
hidden_size=64, output_size=16, svd_rank=8,
n_qubits=4, depth=2, gamma_init=0.1,
)
dense = nn.Linear(64, 16, bias=False, device=device, dtype=torch.float32)
qh, dq = make("quantum", config, dense), make("dequantized", config, dense)
cc, noent = make("classical", config, dense), make("no_entanglement", config, dense)
dq.load_state_dict(qh.state_dict(), strict=True)
expected = 64 * 8 + 16 * 4 + 3 * 4 * 2 + 1
counts = {
"qh024": qh.trainable_parameter_count(), "dq024": dq.trainable_parameter_count(),
"cc024": cc.trainable_parameter_count(), "qh024_noent": noent.trainable_parameter_count(),
}
if set(counts.values()) != {expected}:
raise AssertionError(f"matched parameter count failed: {counts}")
x_qh = torch.randn(2, 3, 64, device=device, requires_grad=True)
x_dq = x_qh.detach().clone().requires_grad_(True)
y_qh, y_dq = qh.student_forward(x_qh), dq.student_forward(x_dq)
forward_error = float((y_qh - y_dq).abs().max())
y_qh.square().mean().backward()
y_dq.square().mean().backward()
input_gradient_error = float((x_qh.grad - x_dq.grad).abs().max())
parameter_gradient_error = float((grad_vector(qh) - grad_vector(dq)).abs().max())
if forward_error > 2e-6 or input_gradient_error > 2e-6 or parameter_gradient_error > 2e-5:
raise AssertionError("QH-024/DQ-024 equivalence failed")
gradient_groups = {
"down": float(qh.down.weight.grad.abs().max()),
"up": float(qh.up.weight.grad.abs().max()),
"theta": float(qh.core.theta.grad.abs().max()),
"gamma": float(qh.gamma.grad.abs()),
}
if any(value <= 0 or not torch.isfinite(torch.tensor(value)) for value in gradient_groups.values()):
raise AssertionError(f"missing/nonfinite gradient: {gradient_groups}")
qh.set_capture_teacher_only(True)
teacher = qh(torch.randn(1, 2, 64, device=device))
captured_x, captured_target = qh.take_capture()
if float((teacher - captured_target).abs().max()) != 0.0 or captured_x.shape != (1, 2, 64):
raise AssertionError("teacher capture failed")
qh.set_capture_teacher_only(False)
qh.strip_teacher()
if qh.teacher_weight is not None:
raise AssertionError("teacher buffer was not stripped")
cpu_module = make("quantum", config, nn.Linear(64, 16, bias=False))
try:
cpu_module.student_forward(torch.randn(1, 1, 64))
cpu_rejected = False
except RuntimeError as error:
cpu_rejected = "CUDA-only" in str(error)
if not cpu_rejected:
raise AssertionError("QH-024 CPU execution was not rejected")
payload = {
"status": "ok",
"expected_trainable_parameters": expected,
"matched_trainable_parameter_counts": counts,
"audit": qh.audit(),
"qh_dq_equivalence": {
"forward_max_abs_error": forward_error,
"input_gradient_max_abs_error": input_gradient_error,
"parameter_gradient_max_abs_error": parameter_gradient_error,
"exactly_dequantizable_within_tolerance": True,
},
"gradient_groups": gradient_groups,
"teacher_buffer_stripped": True,
"cpu_execution_rejected": cpu_rejected,
"claim_ceiling": "quantum-executable layer replacement; exactly dequantized on the tested map",
}
output = PROJECT / "artifacts/qh024-gpu-validation.json"
output.write_text(json.dumps(payload, indent=2), encoding="utf-8")
print(json.dumps(payload, indent=2))
if __name__ == "__main__":
main()