Download benchmarks/benchmark.py from flashrt/adaptive-layernorm-producers: direct link, hf CLI and curl.
- Browser
- Download file 10.1 kB
-
https://huggingface.co/flashrt/adaptive-layernorm-producers/resolve/main/benchmarks/benchmark.py
- Command line
-
hf download hf://flashrt/adaptive-layernorm-producers/benchmarks/benchmark.py
-
curl -L -o benchmark.py https://huggingface.co/flashrt/adaptive-layernorm-producers/resolve/main/benchmarks/benchmark.py
10.1 kB
| #!/usr/bin/env python3 | |
| """Benchmark adaptive-layernorm-producers against eager producer chains.""" | |
| from __future__ import annotations | |
| import argparse | |
| import importlib | |
| import os | |
| import sys | |
| from pathlib import Path | |
| import torch | |
| ROOT = Path(__file__).resolve().parents[2] | |
| sys.path.insert(0, str(ROOT / "adaptive-layernorm-producers" / "tests")) | |
| from test_adaptive_layernorm_producers import ( # noqa: E402 | |
| _nvfp4_out, | |
| load_source_ops, | |
| make_case, | |
| quant_fp8, | |
| ref_adaln, | |
| ref_layer_norm_no_affine, | |
| ) | |
| def load_installed_ops(artifact: str | None): | |
| if artifact: | |
| sys.path.insert(0, artifact) | |
| try: | |
| return importlib.import_module("adaptive_layernorm_producers") | |
| finally: | |
| if artifact: | |
| sys.path.remove(artifact) | |
| def time_cuda(fn, iters: int = 200, warmup: int = 50) -> float: | |
| 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(iters): | |
| fn() | |
| end.record() | |
| torch.cuda.synchronize() | |
| return start.elapsed_time(end) * 1000.0 / iters | |
| def graph_time_cuda( | |
| fn, iters: int = 200, warmup: int = 50, launches_per_graph: int = 32 | |
| ) -> float: | |
| side = torch.cuda.Stream() | |
| side.wait_stream(torch.cuda.current_stream()) | |
| with torch.cuda.stream(side): | |
| for _ in range(3): | |
| fn() | |
| torch.cuda.current_stream().wait_stream(side) | |
| graph = torch.cuda.CUDAGraph() | |
| with torch.cuda.graph(graph): | |
| for _ in range(launches_per_graph): | |
| fn() | |
| return ( | |
| time_cuda(graph.replay, iters=iters, warmup=warmup) | |
| / launches_per_graph | |
| ) | |
| def load_native(): | |
| from torch.utils.cpp_extension import load | |
| major, minor = torch.cuda.get_device_capability() | |
| os.environ.setdefault( | |
| "TORCH_CUDA_ARCH_LIST", "12.0a" if major >= 12 else f"{major}.{minor}" | |
| ) | |
| package = ROOT / "adaptive-layernorm-producers" | |
| return load( | |
| name="adaptive_layernorm_producers_native_bench", | |
| sources=[ | |
| str(package / "benchmarks" / "native_binding.cpp"), | |
| str(package / "csrc" / "adaln_modulation6.cu"), | |
| ], | |
| extra_include_paths=[str(package / "csrc")], | |
| extra_cflags=["-O3"], | |
| extra_cuda_cflags=["-O3", "--expt-relaxed-constexpr"], | |
| verbose=False, | |
| ) | |
| def run_modulation6(ops, native, batch, sequence, dim, iters): | |
| params = torch.randn( | |
| (batch, sequence, 6, dim), device="cuda", dtype=torch.float32 | |
| ) | |
| modulation = torch.randn((6, dim), device="cuda", dtype=torch.float32) | |
| native_out = tuple( | |
| torch.empty( | |
| (batch, sequence, dim), device="cuda", dtype=torch.bfloat16 | |
| ) | |
| for _ in range(6) | |
| ) | |
| wrapper_out = tuple(torch.empty_like(native_out[0]) for _ in range(6)) | |
| def native_call(): | |
| native.adaln_modulation6( | |
| params.data_ptr(), modulation.data_ptr(), | |
| *(value.data_ptr() for value in native_out), | |
| batch, sequence, dim, | |
| ) | |
| def wrapper_call(): | |
| return ops.adaln_modulation6_bf16( | |
| params, modulation, out=wrapper_out | |
| ) | |
| def eager_call(): | |
| return tuple( | |
| (params[:, :, index, :] + modulation[index]).bfloat16() | |
| for index in range(6) | |
| ) | |
| compiled_call = torch.compile(eager_call, fullgraph=True) | |
| native_call() | |
| wrapper_call() | |
| for raw, wrapped in zip(native_out, wrapper_out, strict=True): | |
| torch.testing.assert_close(raw, wrapped, rtol=0, atol=0) | |
| native_us = time_cuda(native_call, iters=iters) | |
| wrapper_us = time_cuda(wrapper_call, iters=iters) | |
| eager_us = time_cuda(eager_call, iters=iters) | |
| compile_us = time_cuda(compiled_call, iters=iters) | |
| graph_native_us = graph_time_cuda(native_call, iters=iters) | |
| graph_wrapper_us = graph_time_cuda(wrapper_call, iters=iters) | |
| return ( | |
| native_us, wrapper_us, graph_native_us, graph_wrapper_us, | |
| eager_us, compile_us | |
| ) | |
| def run_case(ops, name: str, rows: int, dim: int, eps: float, iters: int) -> dict[str, float | str | int]: | |
| x, scale, shift, _inv_s, act_scale, _scale_fp8, _shift_fp8, _scale_deq, _shift_deq = make_case(rows, dim) | |
| out = torch.empty_like(x, dtype=torch.float8_e4m3fn) | |
| def fused(): | |
| ops.ada_layer_norm_quant_fp8_bf16(x, scale, shift, act_scale, eps, out=out) | |
| def eager(): | |
| quant_fp8(ref_adaln(x, scale, shift, eps), act_scale) | |
| no_affine_out = torch.empty_like(x, dtype=torch.float8_e4m3fn) | |
| def fused_no_affine(): | |
| ops.layer_norm_no_affine_quant_fp8_static_bf16(x, act_scale, eps, out=no_affine_out) | |
| def eager_no_affine(): | |
| quant_fp8(ref_layer_norm_no_affine(x, eps), act_scale) | |
| fused_us = time_cuda(fused, iters=iters) | |
| eager_us = time_cuda(eager, iters=iters) | |
| fused_no_affine_us = time_cuda(fused_no_affine, iters=iters) | |
| eager_no_affine_us = time_cuda(eager_no_affine, iters=iters) | |
| return { | |
| "shape": name, | |
| "rows": rows, | |
| "dim": dim, | |
| "ada_fp8_us": fused_us, | |
| "ada_eager_us": eager_us, | |
| "ada_speedup": eager_us / fused_us, | |
| "no_affine_fp8_us": fused_no_affine_us, | |
| "no_affine_eager_us": eager_no_affine_us, | |
| "no_affine_speedup": eager_no_affine_us / fused_no_affine_us, | |
| } | |
| def run_ptok_table(ops, name: str, rows: int, dim: int, eps: float, iters: int): | |
| chunks = 6 | |
| x = torch.randn((rows, dim), device="cuda", dtype=torch.bfloat16) | |
| temb = torch.randn( | |
| (rows, chunks, dim), device="cuda", dtype=torch.bfloat16 | |
| ) | |
| table = torch.randn((chunks, dim), device="cuda", dtype=torch.float32) | |
| out = torch.empty_like(x) | |
| packed, sf = _nvfp4_out(x) | |
| def fused_bf16(): | |
| return ops.ada_layer_norm_ptok_table_bf16( | |
| x, temb, table, 0, 1, eps, out=out | |
| ) | |
| def fused_nvfp4(): | |
| return ops.ada_layer_norm_quant_nvfp4_swizzled_ptok_table_bf16( | |
| x, temb, table, 0, 1, eps, packed=packed, sf_swizzled=sf | |
| ) | |
| def eager_bf16(): | |
| xf = x.float() | |
| mean = xf.mean(dim=-1, keepdim=True) | |
| var = (xf - mean).square().mean(dim=-1, keepdim=True) | |
| norm = (xf - mean) * torch.rsqrt(var + eps) | |
| shift = temb[:, 0].float() + table[0] | |
| scale = temb[:, 1].float() + table[1] | |
| return (norm * (1.0 + scale) + shift).to(torch.bfloat16) | |
| return { | |
| "shape": name, | |
| "rows": rows, | |
| "dim": dim, | |
| "bf16_us": time_cuda(fused_bf16, iters=iters), | |
| "eager_us": time_cuda(eager_bf16, iters=iters), | |
| "nvfp4_us": time_cuda(fused_nvfp4, iters=iters), | |
| } | |
| def main() -> None: | |
| parser = argparse.ArgumentParser() | |
| parser.add_argument("--backend", choices=["source", "installed"], default="source") | |
| parser.add_argument("--artifact", default=None) | |
| parser.add_argument("--iters", type=int, default=200) | |
| parser.add_argument("--markdown", default=None) | |
| args = parser.parse_args() | |
| if not torch.cuda.is_available(): | |
| raise SystemExit("CUDA is required") | |
| torch.manual_seed(2026) | |
| ops = load_source_ops() if args.backend == "source" else load_installed_ops(args.artifact) | |
| native = load_native() | |
| shapes = [ | |
| ("decode_action", 16, 2048), | |
| ("wan_video_short", 64, 3072), | |
| ("wan_video_ctx", 256, 3072), | |
| ("wan_video_2k", 2520, 3072), | |
| ("wan_video_4k", 4096, 3072), | |
| ] | |
| rows = [run_case(ops, name, r, d, 1e-5, args.iters) for name, r, d in shapes] | |
| table_rows = [ | |
| run_ptok_table(ops, name, r, d, 1e-5, args.iters) | |
| for name, r, d in [ | |
| ("video_short", 64, 3072), | |
| ("video_long", 2520, 3072), | |
| ] | |
| ] | |
| modulation_rows = [] | |
| for name, batch, sequence, dim in [ | |
| ("groot_dit", 1, 51, 1536), | |
| ("motus", 1, 2520, 3072), | |
| ("video_long", 1, 5070, 3072), | |
| ]: | |
| modulation_rows.append( | |
| (name, batch, sequence, dim) | |
| + run_modulation6(ops, native, batch, sequence, dim, args.iters) | |
| ) | |
| lines = [ | |
| "| Shape | Rows | Dim | AdaLN->FP8 us | Eager chain us | Speedup | LN->FP8 us | Eager LN chain us | Speedup |", | |
| "|---|---:|---:|---:|---:|---:|---:|---:|---:|", | |
| ] | |
| for row in rows: | |
| line = ( | |
| f"| {row['shape']} | {row['rows']} | {row['dim']} | " | |
| f"{row['ada_fp8_us']:.3f} | {row['ada_eager_us']:.3f} | {row['ada_speedup']:.2f}x | " | |
| f"{row['no_affine_fp8_us']:.3f} | {row['no_affine_eager_us']:.3f} | {row['no_affine_speedup']:.2f}x |" | |
| ) | |
| lines.append(line) | |
| print(line) | |
| lines.extend([ | |
| "", | |
| "| Per-token table shape | BF16 fused us | BF16 eager us | Speedup | NVFP4 fused us |", | |
| "|---|---:|---:|---:|---:|", | |
| ]) | |
| for row in table_rows: | |
| line = ( | |
| f"| {row['shape']} M{row['rows']} D{row['dim']} | " | |
| f"{row['bf16_us']:.3f} | {row['eager_us']:.3f} | " | |
| f"{row['eager_us'] / row['bf16_us']:.2f}x | {row['nvfp4_us']:.3f} |" | |
| ) | |
| lines.append(line) | |
| print(line) | |
| lines.extend( | |
| [ | |
| "", | |
| "| Modulation6 shape | Native us | Wrapper us | Graph native us | Graph wrapper us | Eager us | Compile us | Wrapper/native | Graph wrapper/native |", | |
| "|---|---:|---:|---:|---:|---:|---:|---:|---:|", | |
| ] | |
| ) | |
| for ( | |
| name, batch, sequence, dim, native_us, wrapper_us, graph_native_us, | |
| graph_wrapper_us, eager_us, compile_us | |
| ) in modulation_rows: | |
| line = ( | |
| f"| {name} B{batch} S{sequence} D{dim} | {native_us:.3f} | " | |
| f"{wrapper_us:.3f} | {graph_native_us:.3f} | " | |
| f"{graph_wrapper_us:.3f} | {eager_us:.3f} | {compile_us:.3f} | " | |
| f"{wrapper_us / native_us:.3f} | " | |
| f"{graph_wrapper_us / graph_native_us:.3f} |" | |
| ) | |
| lines.append(line) | |
| print(line) | |
| if args.markdown: | |
| Path(args.markdown).write_text("\n".join(lines) + "\n", encoding="utf-8") | |
| if __name__ == "__main__": | |
| main() | |