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
File size: 3,698 Bytes
5b852c4 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 | #!/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()
|