forked from tile-ai/TileOPs
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathbench_ada_layer_norm.py
More file actions
113 lines (82 loc) · 3.67 KB
/
Copy pathbench_ada_layer_norm.py
File metadata and controls
113 lines (82 loc) · 3.67 KB
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
112
113
from typing import Optional
import pytest
import torch
import torch.nn.functional as F
from benchmarks.benchmark_base import BenchmarkBase, BenchmarkReport
from tileops.manifest import load_workloads
from tileops.ops.norm.ada_layer_norm import AdaLayerNormFwdOp
from tileops.ops.norm.ada_layer_norm_zero import AdaLayerNormZeroFwdOp
from workloads.ada_layer_norm import AdaLayerNormTest
from workloads.ada_layer_norm_zero import AdaLayerNormZeroTest
_ADA_OP_NAME = "AdaLayerNormFwdOp"
_ADA_ZERO_OP_NAME = "AdaLayerNormZeroFwdOp"
class AdaLayerNormBenchmark(BenchmarkBase[AdaLayerNormTest]):
_roofline_cache: Optional[tuple[float, float]] = None
def __init__(self, test, op):
super().__init__(test)
self._op = op
def _get_roofline(self) -> tuple[float, float]:
cache = self._roofline_cache
if cache is None:
cache = self._op.eval_roofline()
self._roofline_cache = cache
return cache
def calculate_flops(self) -> Optional[float]:
return self._get_roofline()[0]
def calculate_memory(self) -> Optional[float]:
return self._get_roofline()[1]
class AdaLayerNormZeroBenchmark(BenchmarkBase[AdaLayerNormZeroTest]):
_roofline_cache: Optional[tuple[float, float]] = None
def __init__(self, test, op):
super().__init__(test)
self._op = op
def _get_roofline(self) -> tuple[float, float]:
cache = self._roofline_cache
if cache is None:
cache = self._op.eval_roofline()
self._roofline_cache = cache
return cache
def calculate_flops(self) -> Optional[float]:
return self._get_roofline()[0]
def calculate_memory(self) -> Optional[float]:
return self._get_roofline()[1]
def _to_params(workloads):
params = []
for w in workloads:
m, n = w["x_shape"]
label = w.get("label", f"{m}x{n}")
for dtype_str in w["dtypes"]:
dtype = getattr(torch, dtype_str)
params.append(pytest.param(m, n, dtype,
id=f"{label}-{dtype_str}"))
return params
@pytest.mark.parametrize("m, n, dtype", _to_params(load_workloads(_ADA_OP_NAME)))
def test_ada_layer_norm_bench(m: int, n: int, dtype: torch.dtype) -> None:
test = AdaLayerNormTest(m, n, dtype)
inputs = test.gen_inputs()
op = AdaLayerNormFwdOp(M=m, N=n, dtype=dtype)
bm = AdaLayerNormBenchmark(test, op)
result = bm.profile(op, *inputs)
BenchmarkReport.record(op, locals(), result, tag="tileops")
# Baseline: PyTorch composite F.layer_norm + arithmetic
def baseline_fn(x, scale, shift):
normed = F.layer_norm(x, (n,), weight=None, bias=None, eps=test.eps)
return scale * normed + shift
result_bl = bm.profile(baseline_fn, *inputs)
BenchmarkReport.record(op, locals(), result_bl, tag="torch-ref")
@pytest.mark.parametrize("m, n, dtype", _to_params(load_workloads(_ADA_ZERO_OP_NAME)))
def test_ada_layer_norm_zero_bench(m: int, n: int, dtype: torch.dtype) -> None:
test = AdaLayerNormZeroTest(m, n, dtype)
inputs = test.gen_inputs()
op = AdaLayerNormZeroFwdOp(M=m, N=n, dtype=dtype)
bm = AdaLayerNormZeroBenchmark(test, op)
result = bm.profile(op, *inputs)
BenchmarkReport.record(op, locals(), result, tag="tileops")
# Baseline: PyTorch composite F.layer_norm + arithmetic + gate
def baseline_fn(x, scale, shift, gate):
normed = F.layer_norm(x, (n,), weight=None, bias=None, eps=test.eps)
return gate * (scale * normed + shift)
result_bl = bm.profile(baseline_fn, *inputs)
BenchmarkReport.record(op, locals(), result_bl, tag="torch-ref")
if __name__ == "__main__":
pytest.main([__file__, "-vvs"])