Instructions to use flashrt/gated-delta-attention with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- Kernels
How to use flashrt/gated-delta-attention with Kernels:
# !pip install kernels from kernels import get_kernel # a version (or an explicit revision) is required; see the "Files and versions" tab for the available ones kernel = get_kernel("flashrt/gated-delta-attention", version=1) - Notebooks
- Google Colab
- Kaggle
Download benchmarks/benchmark_sequence.py from flashrt/gated-delta-attention: direct link, hf CLI and curl.
- Browser
- Download file 3.7 kB
-
https://huggingface.co/flashrt/gated-delta-attention/resolve/main/benchmarks/benchmark_sequence.py
- Command line
-
hf download hf://flashrt/gated-delta-attention/benchmarks/benchmark_sequence.py
-
curl -L -o benchmark_sequence.py https://huggingface.co/flashrt/gated-delta-attention/resolve/main/benchmarks/benchmark_sequence.py
3.7 kB
| #!/usr/bin/env python3 | |
| """Benchmark the full recurrent scan against eager, compile, and native paths.""" | |
| from __future__ import annotations | |
| import argparse | |
| import importlib | |
| import sys | |
| from pathlib import Path | |
| import torch | |
| def elapsed_us(fn, warmup, iterations): | |
| for _ in range(warmup): | |
| fn() | |
| torch.cuda.synchronize() | |
| start = torch.cuda.Event(enable_timing=True) | |
| end = torch.cuda.Event(enable_timing=True) | |
| start.record() | |
| for _ in range(iterations): | |
| fn() | |
| end.record() | |
| end.synchronize() | |
| return start.elapsed_time(end) * 1000.0 / iterations | |
| def main(): | |
| parser = argparse.ArgumentParser() | |
| parser.add_argument("--backend", choices=("source", "installed"), default="source") | |
| parser.add_argument("--artifact") | |
| parser.add_argument("--sequence", type=int, default=65) | |
| parser.add_argument("--heads", type=int, default=4) | |
| parser.add_argument("--warmup", type=int, default=10) | |
| parser.add_argument("--iterations", type=int, default=100) | |
| args = parser.parse_args() | |
| tests = Path(__file__).resolve().parents[1] / "tests" | |
| sys.path.insert(0, str(tests)) | |
| from test_gated_delta_attention import ( | |
| InstalledOps, | |
| load_source_ops, | |
| ref_sequence_f32state, | |
| ) | |
| if args.backend == "source": | |
| ops = load_source_ops() | |
| raw_ops = ops._ops | |
| else: | |
| if args.artifact: | |
| sys.path.insert(0, args.artifact) | |
| ops = InstalledOps(importlib.import_module("gated_delta_attention")) | |
| raw_ops = ops._mod.ops | |
| s, h, d = args.sequence, args.heads, 128 | |
| q = (torch.randn((s, h, d), device="cuda") * 0.05).bfloat16() | |
| k = (torch.randn((s, h, d), device="cuda") * 0.05).bfloat16() | |
| v = (torch.randn((s, h, d), device="cuda") * 0.05).bfloat16() | |
| g = (torch.randn((s, h), device="cuda") * 0.02).bfloat16() | |
| beta = torch.sigmoid(torch.randn((s, h), device="cuda")).bfloat16() | |
| state_initial = torch.zeros((h, d, d), device="cuda", dtype=torch.bfloat16) | |
| state = state_initial.clone() | |
| legacy_state = state_initial.unsqueeze(0).clone() | |
| output = torch.empty_like(q) | |
| def eager(): | |
| return ref_sequence_f32state(q, k, v, g, beta, state_initial) | |
| compiled = torch.compile(eager, fullgraph=True) | |
| def wrapper(): | |
| state.copy_(state_initial) | |
| return ops.sequence(q, k, v, g, beta, state, out=output) | |
| def raw_native_sequence(): | |
| state.copy_(state_initial) | |
| raw_ops.gated_delta_recurrent_sequence_bf16( | |
| q, k, v, g, beta, state, output, True | |
| ) | |
| def legacy_per_token_native(): | |
| legacy_state.copy_(state_initial.unsqueeze(0)) | |
| for index in range(s): | |
| ops.recurrent( | |
| q[index:index + 1], k[index:index + 1], v[index:index + 1], | |
| g[index:index + 1], beta[index:index + 1], legacy_state, | |
| ) | |
| expected, _ = eager() | |
| actual = wrapper() | |
| diff = (actual.float() - expected.float()).abs() | |
| assert float(torch.quantile(diff.flatten(), 0.99)) <= 0.03125 | |
| values = { | |
| "torch_eager_us": elapsed_us(eager, args.warmup, args.iterations), | |
| "torch_compile_us": elapsed_us(compiled, args.warmup, args.iterations), | |
| "legacy_per_token_native_us": elapsed_us( | |
| legacy_per_token_native, args.warmup, args.iterations | |
| ), | |
| "hub_wrapper_us": elapsed_us(wrapper, args.warmup, args.iterations), | |
| "raw_native_sequence_us": elapsed_us( | |
| raw_native_sequence, args.warmup, args.iterations | |
| ), | |
| } | |
| print(f"shape=S{s}_H{h}_D{d}") | |
| for name, value in values.items(): | |
| print(f"{name}={value:.3f}") | |
| if __name__ == "__main__": | |
| main() | |