| import torch |
|
|
| from kernels.benchmark import Benchmark |
|
|
|
|
| def _extract_output(result): |
| if isinstance(result, tuple): |
| return result[0] |
| return result |
|
|
|
|
| def _reference_attention(query, key, value, causal=False): |
| """Reference SDPA on (B, S, H, D) inputs (matches kernels' util).""" |
| query, key, value = (x.transpose(1, 2).contiguous() for x in (query, key, value)) |
| with torch.nn.attention.sdpa_kernel(torch.nn.attention.SDPBackend.MATH): |
| out = torch.nn.functional.scaled_dot_product_attention( |
| query, key, value, is_causal=causal |
| ) |
| return out.transpose(1, 2).contiguous() |
|
|
|
|
| class AttentionHelionBenchmark(Benchmark): |
| """Mirrors kernels.benchmarks.attention.FlashAttentionBenchmark. |
| |
| Uses the (B, S, H, D) flash-attn layout and calls ``flash_attn_func`` so |
| the same workloads apply to this Helion kernel and to flash-attn3. |
| """ |
|
|
| seed: int = 42 |
|
|
| def setup_small(self): |
| B, S, H, D = 2, 128, 8, 64 |
| self.q = torch.randn(B, S, H, D, device="cuda", dtype=torch.float16) |
| self.k = torch.randn(B, S, H, D, device="cuda", dtype=torch.float16) |
| self.v = torch.randn(B, S, H, D, device="cuda", dtype=torch.float16) |
| self.out = torch.empty(B, S, H, D, device="cuda", dtype=torch.float16) |
|
|
| def benchmark_small(self): |
| self.out = _extract_output( |
| self.kernel.flash_attn_func(self.q, self.k, self.v, causal=False) |
| ) |
|
|
| def verify_small(self) -> torch.Tensor: |
| return _reference_attention(self.q, self.k, self.v, causal=False) |
|
|
| def setup_medium(self): |
| B, S, H, D = 4, 512, 16, 64 |
| self.q = torch.randn(B, S, H, D, device="cuda", dtype=torch.float16) |
| self.k = torch.randn(B, S, H, D, device="cuda", dtype=torch.float16) |
| self.v = torch.randn(B, S, H, D, device="cuda", dtype=torch.float16) |
| self.out = torch.empty(B, S, H, D, device="cuda", dtype=torch.float16) |
|
|
| def benchmark_medium(self): |
| self.out = _extract_output( |
| self.kernel.flash_attn_func(self.q, self.k, self.v, causal=False) |
| ) |
|
|
| def verify_medium(self) -> torch.Tensor: |
| return _reference_attention(self.q, self.k, self.v, causal=False) |
|
|
| def setup_large(self): |
| B, S, H, D = 8, 1024, 32, 128 |
| self.q = torch.randn(B, S, H, D, device="cuda", dtype=torch.float16) |
| self.k = torch.randn(B, S, H, D, device="cuda", dtype=torch.float16) |
| self.v = torch.randn(B, S, H, D, device="cuda", dtype=torch.float16) |
| self.out = torch.empty(B, S, H, D, device="cuda", dtype=torch.float16) |
|
|
| def benchmark_large(self): |
| self.out = _extract_output( |
| self.kernel.flash_attn_func(self.q, self.k, self.v, causal=False) |
| ) |
|
|
| def verify_large(self) -> torch.Tensor: |
| return _reference_attention(self.q, self.k, self.v, causal=False) |
|
|