#!/usr/bin/env python3 """Test FMHA kernel with attention sink bias. Validates that the kernel's sink bias correction matches PyTorch reference: softmax([QK^T * scale, sink_bias])[:N] @ V Tests HD=64,128,256,512 with and without sinks. """ import torch import math import sys def reference_fmha_with_sink(q, k, v, scale, sink_bias=None): """PyTorch reference: softmax([QK^T * scale, sink_bias]) @ V. q: (n_h, T, hd), k: (1, N, hd), v: (1, N, hd) sink_bias: (n_h,) FP32 or None Returns: (n_h, T, hd) BF16 """ n_h, T, hd = q.shape N = k.shape[1] # QK^T: (n_h, T, N) scores = torch.matmul(q, k.transpose(-1, -2)) * scale # (n_h, T, N) if sink_bias is not None: # Concatenate sink as extra column: (n_h, T, N+1) sb = sink_bias.reshape(n_h, 1, 1).expand(-1, T, 1) combined = torch.cat([scores, sb], dim=-1) attn = torch.softmax(combined.float(), dim=-1)[:, :, :N] # drop sink column else: attn = torch.softmax(scores.float(), dim=-1) out = torch.matmul(attn.bfloat16(), v) # (n_h, T, hd) return out def test_fmha_sink(): from dsv4.kernels.attention.production import dsv4_attention torch.manual_seed(42) device = 'cuda' passed = 0 failed = 0 for hd in [64, 128, 256, 512]: for N in [9, 32, 128, 256]: for use_sink in [False, True]: n_h = 4 # small for speed T = 1 scale = 1.0 / math.sqrt(hd) q = torch.randn(n_h, T, hd, dtype=torch.bfloat16, device=device) k = torch.randn(1, N, hd, dtype=torch.bfloat16, device=device) v = torch.randn(1, N, hd, dtype=torch.bfloat16, device=device) sink = torch.randn(n_h, dtype=torch.float32, device=device) * 2 if use_sink else None # Production kernel try: o_kernel = dsv4_attention(q, k, v, scale=scale, sink_bias=sink) except Exception as e: print(f" FAIL hd={hd} N={N} sink={use_sink}: kernel error: {e}") failed += 1 continue # PyTorch reference o_ref = reference_fmha_with_sink(q, k, v, scale, sink) # Compare o_kf = o_kernel.float() o_rf = o_ref.float() cos = torch.nn.functional.cosine_similarity(o_kf.flatten().unsqueeze(0), o_rf.flatten().unsqueeze(0)).item() max_diff = (o_kf - o_rf).abs().max().item() status = "PASS" if cos > 0.999 else "FAIL" if status == "PASS": passed += 1 else: failed += 1 print(f" {status} hd={hd} N={N} sink={use_sink} cos={cos:.6f} max_diff={max_diff:.6f}") print(f"\n{'='*60}") print(f"Results: {passed} PASSED, {failed} FAILED") print(f"{'='*60}") return failed == 0 if __name__ == "__main__": success = test_fmha_sink() sys.exit(0 if success else 1)