#!/usr/bin/env python3 """Test CUDA RoPE kernel correctness. Compare CUDA kernel output vs PyTorch reference. Must achieve cos >= 0.999998 for production. """ import torch import math import sys def build_rope_cache(max_pos, rope_dim, device, theta=10000.): freqs = 1. / (theta ** (torch.arange(0, rope_dim, 2, dtype=torch.float32) / rope_dim)) angles = torch.outer(torch.arange(max_pos, dtype=torch.float32), freqs) return torch.cos(angles).to(device), torch.sin(angles).to(device) def apply_rope_ref(x, pos, cos, sin, rope_dim, inverse=False): """PyTorch reference — the current _apply_rope implementation.""" T, nh, hd = x.shape nope = hd - rope_dim c, s = cos[pos].unsqueeze(1), sin[pos].unsqueeze(1) xr = x[:, :, nope:] # view ev = xr[..., 0::2].clone() od = xr[..., 1::2] if inverse: xr[..., 0::2] = (ev * c + od * s).bfloat16() xr[..., 1::2] = (-ev * s + od * c).bfloat16() else: xr[..., 0::2] = (ev * c - od * s).bfloat16() xr[..., 1::2] = (ev * s + od * c).bfloat16() return x def test_rope_cuda(): from dsv4.ops.rope_cuda import apply_rope device = "cuda:0" rope_dim = 64 hd = 512 n_h = 128 T = 1 # decode max_pos = 4096 cos, sin = build_rope_cache(max_pos, rope_dim, device) # Test forward RoPE torch.manual_seed(42) x_ref = torch.randn(T, n_h, hd, dtype=torch.bfloat16, device=device) x_cuda = x_ref.clone() positions = torch.tensor([100], dtype=torch.long, device=device) apply_rope_ref(x_ref, positions, cos, sin, rope_dim, inverse=False) apply_rope(x_cuda, positions, cos, sin, rope_dim, inverse=False) cos_sim = torch.nn.functional.cosine_similarity( x_ref.flatten().float(), x_cuda.flatten().float(), dim=0 ).item() max_diff = (x_ref.float() - x_cuda.float()).abs().max().item() print(f"Forward RoPE (T=1, n_h=128, hd=512):") print(f" Cosine: {cos_sim:.8f}") print(f" Max diff: {max_diff:.8f}") if cos_sim < 0.999998: print(f" ❌ FAIL: cosine < 0.999998") return False print(f" ✅ PASS") # Test inverse RoPE x_ref_inv = x_ref.clone() x_cuda_inv = x_cuda.clone() apply_rope_ref(x_ref_inv, positions, cos, sin, rope_dim, inverse=True) apply_rope(x_cuda_inv, positions, cos, sin, rope_dim, inverse=True) cos_sim_inv = torch.nn.functional.cosine_similarity( x_ref_inv.flatten().float(), x_cuda_inv.flatten().float(), dim=0 ).item() print(f"\nInverse RoPE (T=1, n_h=128, hd=512):") print(f" Cosine: {cos_sim_inv:.8f}") if cos_sim_inv < 0.999998: print(f" ❌ FAIL") return False print(f" ✅ PASS") # Test round-trip (forward + inverse should be identity) x_rt = torch.randn(T, n_h, hd, dtype=torch.bfloat16, device=device) x_orig = x_rt.clone() apply_rope(x_rt, positions, cos, sin, rope_dim, inverse=False) apply_rope(x_rt, positions, cos, sin, rope_dim, inverse=True) rt_cos = torch.nn.functional.cosine_similarity( x_orig.flatten().float(), x_rt.flatten().float(), dim=0 ).item() print(f"\nRound-trip (forward + inverse):") print(f" Cosine: {rt_cos:.8f}") if rt_cos < 0.9999: print(f" ❌ FAIL: round-trip error too large") return False print(f" ✅ PASS") # Test multi-token T2 = 8 x_ref2 = torch.randn(T2, n_h, hd, dtype=torch.bfloat16, device=device) x_cuda2 = x_ref2.clone() pos2 = torch.arange(T2, dtype=torch.long, device=device) apply_rope_ref(x_ref2, pos2, cos, sin, rope_dim, inverse=False) apply_rope(x_cuda2, pos2, cos, sin, rope_dim, inverse=False) cos_sim2 = torch.nn.functional.cosine_similarity( x_ref2.flatten().float(), x_cuda2.flatten().float(), dim=0 ).item() print(f"\nMulti-token forward (T=8, n_h=128, hd=512):") print(f" Cosine: {cos_sim2:.8f}") if cos_sim2 < 0.999998: print(f" ❌ FAIL") return False print(f" ✅ PASS") return True if __name__ == "__main__": torch.manual_seed(42) success = test_rope_cuda() sys.exit(0 if success else 1)