Download code/models/experimental/gr00t/benchmarks/mb1_eltwise.py from changh95/GR00T-N1.7-3B-p150: direct link, hf CLI and curl.
- Browser
- Download file 14.8 kB
-
https://huggingface.co/changh95/GR00T-N1.7-3B-p150/resolve/main/code/models/experimental/gr00t/benchmarks/mb1_eltwise.py
- Command line
-
hf download hf://changh95/GR00T-N1.7-3B-p150/code/models/experimental/gr00t/benchmarks/mb1_eltwise.py
-
curl -L -o mb1_eltwise.py https://huggingface.co/changh95/GR00T-N1.7-3B-p150/resolve/main/code/models/experimental/gr00t/benchmarks/mb1_eltwise.py
14.8 kB
| # SPDX-License-Identifier: Apache-2.0 | |
| """mb1_eltwise — layer_norm / rms_norm / gelu / add and fused ``ttnn.linear(activation=...)`` timings at GR00T shapes. | |
| Shapes (arch synthesis §1, perf-model-v2 §2.3): DiT activations [64, 1536] and [64, 6144]; LLM [S, 2048] and | |
| [S, 6144] for S in {128, 256, 512, 1024}; SigLIP ViT [M, 1152] / [M, 4304] and Qwen3-VL ViT [M, 1024] / [M, 4096] | |
| for M in {256, 352, 1792}. Every op is timed with ``--iters`` back-to-back calls (eager) and as a trace replay. | |
| Also measured: the per-op trace-replay floor (a [32, 32] ``ttnn.add`` — research §6 unknown 2 proxy) and the fused | |
| ``ttnn.linear(activation="gelu")`` vs ``ttnn.matmul`` + ``ttnn.gelu`` at the DiT ff1 and ViT fc1 shapes. | |
| Usage: | |
| with-device.sh python models/experimental/gr00t/benchmarks/mb1_eltwise.py --out results/mb1_eltwise.json | |
| """ | |
| from __future__ import annotations | |
| import argparse | |
| import math | |
| import os | |
| import sys | |
| import time | |
| from typing import Any, Dict, List | |
| sys.path.insert(0, os.path.dirname(os.path.abspath(__file__))) | |
| import mb1_common as C # noqa: E402 | |
| NORM_SHAPES = ( | |
| [("dit", 64, 1536)] | |
| + [("llm", S, 2048) for S in (128, 256, 512, 1024)] | |
| + [("siglip", M, 1152) for M in (256, 352, 1792)] | |
| + [("qwenvit", M, 1024) for M in (256, 352, 1792)] | |
| ) | |
| ACT_SHAPES = ( | |
| [("dit", 64, 6144)] | |
| + [("llm", S, 6144) for S in (128, 256, 512, 1024)] | |
| + [("siglip", M, 4304) for M in (256, 352, 1792)] | |
| + [("qwenvit", M, 4096) for M in (256, 352, 1792)] | |
| ) | |
| FUSED_SHAPES = [ | |
| ("dit_ff1", 64, 1536, 6144), | |
| ("siglip_fc1_1792", 1792, 1152, 4304), | |
| ("qwenvit_fc1_1792", 1792, 1024, 4096), | |
| ("siglip_fc1_352", 352, 1152, 4304), | |
| ] | |
| def time_op(ttnn, device, args, row: Dict[str, Any], fn) -> Dict[str, Any]: | |
| t = C.measure(ttnn, device, fn, iters=args.iters, warmup=3, reps=args.reps) | |
| row.update(eager_us=C.r(t.eager_us), trace_us=C.r(t.trace_us), error=t.error) | |
| print( | |
| f" {row.get('op'):>22s} {row.get('group', ''):>8s} {str(row.get('shape')):>16s} {row.get('mem', ''):>4s}: trace {row.get('trace_us')} us eager {row.get('eager_us')} us {row.get('error') or ''}" | |
| ) | |
| return row | |
| def main() -> int: | |
| ap = argparse.ArgumentParser(description=__doc__, formatter_class=argparse.RawDescriptionHelpFormatter) | |
| ap.add_argument("--out", default=os.path.join(C.default_out_dir(), "mb1_eltwise.json")) | |
| ap.add_argument("--iters", type=int, default=32) | |
| ap.add_argument("--reps", type=int, default=5) | |
| ap.add_argument("--quick", action="store_true") | |
| args = ap.parse_args() | |
| import torch | |
| import ttnn | |
| device = C.open_device(ttnn) | |
| result: Dict[str, Any] = { | |
| "env": C.env_report(), | |
| "device": C.device_report(ttnn, device), | |
| "args": vars(args), | |
| "rows": [], | |
| } | |
| rows = result["rows"] | |
| t0 = time.perf_counter() | |
| ck = C.compute_config(ttnn, "HiFi2", False) | |
| try: | |
| # ---- per-op replay floor | |
| a = ttnn.from_torch( | |
| torch.randn(1, 1, 32, 32), | |
| dtype=ttnn.bfloat16, | |
| layout=ttnn.TILE_LAYOUT, | |
| device=device, | |
| memory_config=ttnn.L1_MEMORY_CONFIG, | |
| ) | |
| b = ttnn.from_torch( | |
| torch.randn(1, 1, 32, 32), | |
| dtype=ttnn.bfloat16, | |
| layout=ttnn.TILE_LAYOUT, | |
| device=device, | |
| memory_config=ttnn.L1_MEMORY_CONFIG, | |
| ) | |
| rows.append( | |
| time_op( | |
| ttnn, | |
| device, | |
| args, | |
| dict(op="add_tiny_floor", group="floor", shape=[32, 32], mem="L1"), | |
| lambda: ttnn.add(a, b, memory_config=ttnn.L1_MEMORY_CONFIG), | |
| ) | |
| ) | |
| for iters in (8, 64, 256): | |
| if args.quick and iters > 64: | |
| continue | |
| tr = C.time_traced( | |
| ttnn, device, lambda: ttnn.add(a, b, memory_config=ttnn.L1_MEMORY_CONFIG), iters=iters, reps=args.reps | |
| ) | |
| rows.append( | |
| dict( | |
| op="add_tiny_floor", | |
| group="floor", | |
| shape=[32, 32], | |
| mem="L1", | |
| iters=iters, | |
| trace_us=C.r(tr["min"]), | |
| trace_us_mean=C.r(tr["mean"]), | |
| ) | |
| ) | |
| print(f" add [32,32] x{iters} per trace: {tr['min']:.2f} us/op") | |
| ttnn.deallocate(a) | |
| ttnn.deallocate(b) | |
| norm_shapes = NORM_SHAPES if not args.quick else NORM_SHAPES[:3] | |
| act_shapes = ACT_SHAPES if not args.quick else ACT_SHAPES[:3] | |
| for mem_name, mem in (("L1", ttnn.L1_MEMORY_CONFIG), ("DRAM", ttnn.DRAM_MEMORY_CONFIG)): | |
| if args.quick and mem_name == "DRAM": | |
| continue | |
| # ---- norms | |
| for group, M, D in norm_shapes: | |
| x = ttnn.from_torch( | |
| torch.randn(1, 1, M, D), | |
| dtype=ttnn.bfloat16, | |
| layout=ttnn.TILE_LAYOUT, | |
| device=device, | |
| memory_config=mem, | |
| ) | |
| res = ttnn.from_torch( | |
| torch.randn(1, 1, M, D), | |
| dtype=ttnn.bfloat16, | |
| layout=ttnn.TILE_LAYOUT, | |
| device=device, | |
| memory_config=mem, | |
| ) | |
| gamma = ttnn.from_torch( | |
| torch.randn(1, 1, 1, D), dtype=ttnn.bfloat16, layout=ttnn.TILE_LAYOUT, device=device | |
| ) | |
| beta = ttnn.from_torch( | |
| torch.randn(1, 1, 1, D), dtype=ttnn.bfloat16, layout=ttnn.TILE_LAYOUT, device=device | |
| ) | |
| # ROW_MAJOR affine params must be [1, 1, D/32, 32] (layernorm_device_operation.cpp:106; tt_transformers convention) | |
| gamma_rm = ttnn.from_torch( | |
| torch.randn(1, 1, D // 32, 32), dtype=ttnn.bfloat16, layout=ttnn.ROW_MAJOR_LAYOUT, device=device | |
| ) | |
| beta_rm = ttnn.from_torch( | |
| torch.randn(1, 1, D // 32, 32), dtype=ttnn.bfloat16, layout=ttnn.ROW_MAJOR_LAYOUT, device=device | |
| ) | |
| base = dict(group=group, shape=[M, D], mem=mem_name) | |
| rows.append( | |
| time_op( | |
| ttnn, | |
| device, | |
| args, | |
| dict(op="layer_norm(w,b tile)", **base), | |
| lambda: ttnn.layer_norm( | |
| x, weight=gamma, bias=beta, epsilon=1e-6, memory_config=mem, compute_kernel_config=ck | |
| ), | |
| ) | |
| ) | |
| rows.append( | |
| time_op( | |
| ttnn, | |
| device, | |
| args, | |
| dict(op="layer_norm(w,b rm)", **base), | |
| lambda: ttnn.layer_norm( | |
| x, weight=gamma_rm, bias=beta_rm, epsilon=1e-6, memory_config=mem, compute_kernel_config=ck | |
| ), | |
| ) | |
| ) | |
| rows.append( | |
| time_op( | |
| ttnn, | |
| device, | |
| args, | |
| dict(op="layer_norm(no affine)", **base), | |
| lambda: ttnn.layer_norm(x, epsilon=1e-6, memory_config=mem, compute_kernel_config=ck), | |
| ) | |
| ) | |
| rows.append( | |
| time_op( | |
| ttnn, | |
| device, | |
| args, | |
| dict(op="layer_norm(+residual)", **base), | |
| lambda: ttnn.layer_norm( | |
| x, | |
| residual_input_tensor=res, | |
| weight=gamma, | |
| bias=beta, | |
| epsilon=1e-6, | |
| memory_config=mem, | |
| compute_kernel_config=ck, | |
| ), | |
| ) | |
| ) | |
| rows.append( | |
| time_op( | |
| ttnn, | |
| device, | |
| args, | |
| dict(op="rms_norm(w)", **base), | |
| lambda: ttnn.rms_norm( | |
| x, weight=gamma, epsilon=1e-6, memory_config=mem, compute_kernel_config=ck | |
| ), | |
| ) | |
| ) | |
| rows.append( | |
| time_op( | |
| ttnn, | |
| device, | |
| args, | |
| dict(op="rms_norm(w rm)", **base), | |
| lambda: ttnn.rms_norm( | |
| x, weight=gamma_rm, epsilon=1e-6, memory_config=mem, compute_kernel_config=ck | |
| ), | |
| ) | |
| ) | |
| rows.append( | |
| time_op(ttnn, device, args, dict(op="add", **base), lambda: ttnn.add(x, res, memory_config=mem)) | |
| ) | |
| rows.append( | |
| time_op( | |
| ttnn, | |
| device, | |
| args, | |
| dict(op="mul_rowbcast", **base), | |
| lambda: ttnn.mul(x, gamma, memory_config=mem), | |
| ) | |
| ) | |
| rows.append( | |
| time_op( | |
| ttnn, | |
| device, | |
| args, | |
| dict(op="add_rowbcast", **base), | |
| lambda: ttnn.add(x, beta, memory_config=mem), | |
| ) | |
| ) | |
| for t_ in (x, res, gamma, beta, gamma_rm, beta_rm): | |
| ttnn.deallocate(t_) | |
| # ---- activations | |
| for group, M, D in act_shapes: | |
| x = ttnn.from_torch( | |
| torch.randn(1, 1, M, D), | |
| dtype=ttnn.bfloat16, | |
| layout=ttnn.TILE_LAYOUT, | |
| device=device, | |
| memory_config=mem, | |
| ) | |
| y = ttnn.from_torch( | |
| torch.randn(1, 1, M, D), | |
| dtype=ttnn.bfloat16, | |
| layout=ttnn.TILE_LAYOUT, | |
| device=device, | |
| memory_config=mem, | |
| ) | |
| base = dict(group=group, shape=[M, D], mem=mem_name) | |
| rows.append( | |
| time_op( | |
| ttnn, device, args, dict(op="gelu(Accurate)", **base), lambda: ttnn.gelu(x, memory_config=mem) | |
| ) | |
| ) | |
| rows.append( | |
| time_op( | |
| ttnn, | |
| device, | |
| args, | |
| dict(op="gelu(FastLut)", **base), | |
| lambda: ttnn.gelu(x, variant=ttnn.GeluVariant.FastLut, memory_config=mem), | |
| ) | |
| ) | |
| rows.append( | |
| time_op( | |
| ttnn, | |
| device, | |
| args, | |
| dict(op="gelu(Tanh)", **base), | |
| lambda: ttnn.gelu(x, variant=ttnn.GeluVariant.Tanh, memory_config=mem), | |
| ) | |
| ) | |
| rows.append( | |
| time_op(ttnn, device, args, dict(op="silu", **base), lambda: ttnn.silu(x, memory_config=mem)) | |
| ) | |
| rows.append( | |
| time_op(ttnn, device, args, dict(op="add", **base), lambda: ttnn.add(x, y, memory_config=mem)) | |
| ) | |
| rows.append( | |
| time_op(ttnn, device, args, dict(op="mul", **base), lambda: ttnn.mul(x, y, memory_config=mem)) | |
| ) | |
| ttnn.deallocate(x) | |
| ttnn.deallocate(y) | |
| C.write_json(args.out, result) | |
| # ---- fused linear activation vs separate | |
| for name, M, K, N in (FUSED_SHAPES if not args.quick else FUSED_SHAPES[:1]): | |
| mem = ttnn.L1_MEMORY_CONFIG if M <= 64 else ttnn.DRAM_MEMORY_CONFIG | |
| mem_name = "L1" if M <= 64 else "DRAM" | |
| a = ttnn.from_torch( | |
| torch.randn(1, 1, M, K) * 0.5, | |
| dtype=ttnn.bfloat16, | |
| layout=ttnn.TILE_LAYOUT, | |
| device=device, | |
| memory_config=mem, | |
| ) | |
| for w_dtype in ("bf16", "bfp8"): | |
| w = ttnn.from_torch( | |
| torch.randn(1, 1, K, N) / math.sqrt(K), | |
| dtype=C.ttnn_dtype(ttnn, w_dtype), | |
| layout=ttnn.TILE_LAYOUT, | |
| device=device, | |
| ) | |
| base = dict(group=name, shape=[M, K, N], mem=mem_name, w_dtype=w_dtype) | |
| rows.append( | |
| time_op( | |
| ttnn, | |
| device, | |
| args, | |
| dict(op="matmul", **base), | |
| lambda: ttnn.matmul(a, w, memory_config=mem, compute_kernel_config=ck), | |
| ) | |
| ) | |
| rows.append( | |
| time_op( | |
| ttnn, | |
| device, | |
| args, | |
| dict(op="linear(act=gelu)", **base), | |
| lambda: ttnn.linear(a, w, activation="gelu", memory_config=mem, compute_kernel_config=ck), | |
| ) | |
| ) | |
| rows.append( | |
| time_op( | |
| ttnn, | |
| device, | |
| args, | |
| dict(op="linear(act=silu)", **base), | |
| lambda: ttnn.linear(a, w, activation="silu", memory_config=mem, compute_kernel_config=ck), | |
| ) | |
| ) | |
| def mm_then_gelu(): | |
| h = ttnn.matmul(a, w, memory_config=mem, compute_kernel_config=ck) | |
| g = ttnn.gelu(h, memory_config=mem) | |
| ttnn.deallocate(h) | |
| return g | |
| rows.append(time_op(ttnn, device, args, dict(op="matmul+gelu(2 ops)", **base), mm_then_gelu)) | |
| ttnn.deallocate(w) | |
| ttnn.deallocate(a) | |
| C.write_json(args.out, result) | |
| finally: | |
| result["wall_s"] = round(time.perf_counter() - t0, 1) | |
| C.write_json(args.out, result) | |
| ttnn.close_device(device) | |
| C.print_table( | |
| rows, ["op", "group", "shape", "mem", "w_dtype", "trace_us", "eager_us", "error"], "elementwise / norm timings" | |
| ) | |
| return 0 | |
| if __name__ == "__main__": | |
| sys.exit(main()) | |