| |
| |
|
|
| import torch |
| from benchmark import benchmark_backward, benchmark_combined, benchmark_forward |
| from torch.nn import functional as F |
|
|
| from fla.ops.titans.naive import chunk_titans_linear_ref |
|
|
| |
|
|
|
|
| def time_fwd(func, *args, **kwargs): |
| time_fb = benchmark_forward(func, *args, **kwargs) |
| return time_fb[1].mean |
|
|
|
|
| def time_fwd_bwd(func, *args, **kwargs): |
| time_fb = benchmark_combined(func, *args, **kwargs) |
| return time_fb[1].mean |
|
|
|
|
| def time_bwd(func, *args, **kwargs): |
| time_fb = benchmark_backward(func, *args, **kwargs) |
| return time_fb[1].mean |
|
|
|
|
| repeats = 256 |
| device = "cuda" |
| dtype = torch.bfloat16 |
|
|
| bs_seqlen_vals = [(2, 1024), (2, 2048)] |
| causal_vals = [True] |
| headdim_vals = [4, 8] |
| dim = 16 |
| dropout_p = 0.0 |
|
|
| methods = ["naive_titans", "chunk_titans"] |
| time_f = {} |
| time_b = {} |
| time_f_b = {} |
| speed_f = {} |
| speed_b = {} |
| speed_f_b = {} |
| for causal in causal_vals: |
| for headdim in headdim_vals: |
| for B, seqlen in bs_seqlen_vals: |
| config = (causal, headdim, B, seqlen) |
| H = dim // headdim |
|
|
| q = torch.randn( |
| B, H, seqlen, headdim, device=device, requires_grad=True, dtype=dtype, |
| ) |
| k = F.normalize( |
| torch.randn(B, H, seqlen, headdim, device=device, dtype=dtype), |
| p=2, |
| dim=-1, |
| ).requires_grad_(True) |
| v = torch.randn( |
| B, H, seqlen, headdim, device=device, requires_grad=True, dtype=dtype, |
| ) |
| w = torch.randn(seqlen, headdim, device=device, requires_grad=True, dtype=dtype) |
| b = torch.randn(seqlen, headdim, device=device, requires_grad=True, dtype=dtype) |
| theta = torch.rand( |
| B, H, seqlen, 1, dtype=dtype, device=device, requires_grad=True, |
| ) |
| alpha = torch.rand( |
| B, H, seqlen, 1, dtype=dtype, device=device, requires_grad=True, |
| ) |
| eta = torch.rand( |
| B, H, seqlen, 1, dtype=dtype, device=device, requires_grad=True, |
| ) |
| o2, _ = chunk_titans_linear_ref( |
| q, k, v, w, b, theta, alpha, eta, chunk_size=16, use_chunk=False, |
| ) |
| o2.sum().backward(retain_graph=True) |
| f_b = time_fwd_bwd( |
| chunk_titans_linear_ref, |
| q, |
| k, |
| v, |
| w, |
| b, |
| theta, |
| alpha, |
| eta, |
| use_chunk=False, |
| verbose=False, |
| ) |
| time_f_b[config, "naive_titans"] = f_b |
|
|
| o3, _ = chunk_titans_linear_ref( |
| q, k, v, w, b, theta, alpha, eta, chunk_size=16, use_chunk=True, |
| ) |
| o3.sum().backward(retain_graph=True) |
| f_b = time_fwd_bwd( |
| chunk_titans_linear_ref, |
| q, |
| k, |
| v, |
| w, |
| b, |
| theta, |
| alpha, |
| eta, |
| chunk_size=16, |
| use_chunk=True, |
| verbose=False, |
| ) |
| time_f_b[config, "chunk_titans"] = f_b |
|
|
| print(f"### causal={causal}, headdim={headdim}, B={B}, seqlen={seqlen} ###") |
| for method in methods: |
| |
| print( |
| f"{method:>50} fwd + bwd:\t {time_f_b[config, method] * 1000:>6.4f} ms ", |
| ) |
|
|
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
|
|
| |
| |
|
|