Skip to content

Commit 2c80daf

Browse files
authored
Split benchmark for fused operators (#2676)
1 parent 2907c53 commit 2c80daf

7 files changed

Lines changed: 274 additions & 249 deletions
Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
from typing import Optional
2+
3+
import pytest
4+
import torch
5+
6+
import flag_gems
7+
from benchmark.attri_util import FLOAT_DTYPES
8+
from benchmark.performance_utils import GenericBenchmark
9+
10+
11+
class RopeBenchmark(GenericBenchmark):
12+
def set_more_shapes(self):
13+
# self.shapes is a list of tuples, each containing three elements:
14+
# (batch, num_heads, seq_len, head_size).
15+
return []
16+
17+
18+
def get_rope_cos_sin(max_seq_len, dim, dtype, base=10000, device=flag_gems.device):
19+
inv_freq = 1.0 / (base ** (torch.arange(0, dim, 2).float().to(device) / dim))
20+
t = torch.arange(max_seq_len, device=device, dtype=inv_freq.dtype)
21+
freqs = torch.outer(t, inv_freq)
22+
cos = freqs.cos().to(dtype)
23+
sin = freqs.sin().to(dtype)
24+
return cos, sin
25+
26+
27+
def rope_input_fn(shape, dtype, device):
28+
batch_size = 4
29+
q_heads = 8
30+
k_heads = 1
31+
head_dim = 64
32+
33+
seq_len = shape[0]
34+
q = torch.randn(
35+
(batch_size, seq_len, q_heads, head_dim), dtype=dtype, device=device
36+
)
37+
k = torch.randn(
38+
(batch_size, seq_len, k_heads, head_dim), dtype=dtype, device=device
39+
)
40+
cos, sin = get_rope_cos_sin(seq_len, head_dim, dtype, device=device)
41+
yield q, k, cos, sin
42+
43+
44+
# Copied from transformers.models.llama.modeling_llama.rotate_half
45+
# https://github.com/huggingface/transformers/blob/main/src/transformers/models/llama/modeling_llama.py
46+
def rotate_fn(x):
47+
"""Rotates half the hidden dims of the input."""
48+
x1 = x[..., : x.shape[-1] // 2]
49+
x2 = x[..., x.shape[-1] // 2 :]
50+
return torch.cat((-x2, x1), dim=-1)
51+
52+
53+
def torch_apply_rotary_pos_emb(
54+
q,
55+
k,
56+
cos,
57+
sin,
58+
position_ids: Optional[torch.Tensor] = None,
59+
rotary_interleaved: bool = False,
60+
):
61+
q = q.float()
62+
k = k.float()
63+
cos = cos[None, : q.size(-3), None, :]
64+
sin = sin[None, : q.size(-3), None, :]
65+
cos = torch.repeat_interleave(cos, 2, dim=-1) # [bs, seq_len, 1, dim]
66+
sin = torch.repeat_interleave(sin, 2, dim=-1) # [bs, seq_len, 1, dim]
67+
68+
q_embed = (q * cos) + (rotate_fn(q) * sin)
69+
k_embed = (k * cos) + (rotate_fn(k) * sin)
70+
71+
return q_embed, k_embed
72+
73+
74+
@pytest.mark.apply_rotary_pos_emb
75+
def test_apply_rotary_pos_emb():
76+
bench = RopeBenchmark(
77+
input_fn=rope_input_fn,
78+
op_name="apply_rotary_pos_emb",
79+
torch_op=torch_apply_rotary_pos_emb,
80+
gems_op=flag_gems.apply_rotary_pos_emb,
81+
dtypes=FLOAT_DTYPES,
82+
)
83+
bench.run()
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
import pytest
2+
import torch
3+
4+
import flag_gems
5+
from benchmark.attri_util import FLOAT_DTYPES
6+
from benchmark.performance_utils import GenericBenchmarkExcluse1D
7+
8+
9+
def _input_fn(shape, dtype, device):
10+
inp = torch.randn(shape, dtype=dtype, device=device)
11+
residual = torch.randn(shape, dtype=dtype, device=device)
12+
layer_shape = (shape[-1],)
13+
weight = torch.randn(layer_shape, dtype=dtype, device=device)
14+
yield inp, residual, layer_shape, weight, 1e-5
15+
16+
17+
def torch_op(x, residual, layer_shape, weight, eps):
18+
x = x + residual
19+
variance = x.pow(2).mean(-1, keepdim=True)
20+
hidden_states = x * torch.rsqrt(variance + eps)
21+
return weight * hidden_states
22+
23+
24+
@pytest.mark.fused_add_rms_norm
25+
def test_fused_add_rms_norm():
26+
bench = GenericBenchmarkExcluse1D(
27+
input_fn=_input_fn,
28+
op_name="fused_add_rms_norm",
29+
torch_op=torch_op,
30+
gems_op=flag_gems.fused_add_rms_norm,
31+
dtypes=FLOAT_DTYPES,
32+
)
33+
34+
bench.run()

benchmark/test_fused_perf.py

Lines changed: 0 additions & 249 deletions
This file was deleted.

benchmark/test_gelu_and_mul.py

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
import pytest
2+
import torch
3+
4+
import flag_gems
5+
from benchmark.attri_util import FLOAT_DTYPES
6+
from benchmark.performance_utils import GenericBenchmark, binary_input_fn
7+
8+
9+
@pytest.mark.gelu_and_mul
10+
def test_gelu_and_mul():
11+
def torch_op(x, y):
12+
return torch.mul(torch.nn.functional.gelu(x), y)
13+
14+
bench = GenericBenchmark(
15+
input_fn=binary_input_fn,
16+
op_name="gelu_and_mul",
17+
torch_op=torch_op,
18+
gems_op=flag_gems.gelu_and_mul,
19+
dtypes=FLOAT_DTYPES,
20+
)
21+
bench.run()

0 commit comments

Comments
 (0)