Skip to content

Commit 7386695

Browse files
factnnclaude
andcommitted
feat: add rsub operator implementation, tests and benchmark
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
1 parent 201171c commit 7386695

5 files changed

Lines changed: 116 additions & 0 deletions

File tree

benchmark/test_rsub_perf.py

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
import pytest
2+
import torch
3+
4+
from benchmark.attri_util import FLOAT_DTYPES
5+
from benchmark.performance_utils import GenericBenchmark, generate_tensor_input
6+
7+
8+
def rsub_tensor_input_fn(shape, cur_dtype, device):
9+
inp1 = generate_tensor_input(shape, cur_dtype, device)
10+
inp2 = generate_tensor_input(shape, cur_dtype, device)
11+
yield inp1, inp2
12+
13+
14+
def rsub_scalar_input_fn(shape, cur_dtype, device):
15+
inp1 = generate_tensor_input(shape, cur_dtype, device)
16+
yield inp1, 0.5
17+
18+
19+
@pytest.mark.rsub
20+
def test_perf_rsub_tensor():
21+
bench = GenericBenchmark(
22+
input_fn=rsub_tensor_input_fn,
23+
op_name="rsub.Tensor",
24+
torch_op=torch.rsub,
25+
dtypes=FLOAT_DTYPES,
26+
)
27+
bench.run()
28+
29+
30+
@pytest.mark.rsub
31+
def test_perf_rsub_scalar():
32+
bench = GenericBenchmark(
33+
input_fn=rsub_scalar_input_fn,
34+
op_name="rsub.Scalar",
35+
torch_op=torch.rsub,
36+
dtypes=FLOAT_DTYPES,
37+
)
38+
bench.run()

src/flag_gems/__init__.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -384,6 +384,8 @@ def torch_ge(v):
384384
("rrelu_with_noise_backward", rrelu_with_noise_backward),
385385
("rsqrt", rsqrt),
386386
("rsqrt_", rsqrt_),
387+
("rsub.Scalar", rsub_scalar),
388+
("rsub.Tensor", rsub_tensor),
387389
("scaled_softmax_backward", scaled_softmax_backward),
388390
("scaled_softmax_forward", scaled_softmax_forward),
389391
("scatter.reduce", scatter),

src/flag_gems/ops/__init__.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -258,6 +258,7 @@
258258
from flag_gems.ops.round import round, round_, round_out
259259
from flag_gems.ops.rrelu_with_noise_backward import rrelu_with_noise_backward
260260
from flag_gems.ops.rsqrt import rsqrt, rsqrt_
261+
from flag_gems.ops.rsub import rsub_scalar, rsub_tensor
261262
from flag_gems.ops.scaled_softmax import scaled_softmax_backward, scaled_softmax_forward
262263
from flag_gems.ops.scatter import scatter, scatter_
263264
from flag_gems.ops.scatter_add_ import scatter_add_
@@ -647,6 +648,8 @@
647648
"rrelu_with_noise_backward",
648649
"rsqrt",
649650
"rsqrt_",
651+
"rsub_scalar",
652+
"rsub_tensor",
650653
"scaled_dot_product_attention",
651654
"scaled_dot_product_attention_backward",
652655
"scaled_dot_product_attention_forward",

src/flag_gems/ops/rsub.py

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
import logging
2+
3+
import triton
4+
5+
from flag_gems.utils import pointwise_dynamic
6+
7+
logger = logging.getLogger(__name__)
8+
9+
10+
@pointwise_dynamic(is_tensor=[True, True, False], promotion_methods=[(0, 1, "DEFAULT")])
11+
@triton.jit
12+
def rsub_func(x, y, alpha):
13+
return y - x * alpha
14+
15+
16+
@pointwise_dynamic(
17+
is_tensor=[True, False, False], promotion_methods=[(0, 1, "DEFAULT")]
18+
)
19+
@triton.jit
20+
def rsub_func_tensor_scalar(x, y, alpha):
21+
return y - x * alpha
22+
23+
24+
def rsub_tensor(A, B, *, alpha=1):
25+
logger.debug("GEMS RSUB TENSOR")
26+
return rsub_func(A, B, alpha)
27+
28+
29+
def rsub_scalar(A, B, alpha=1):
30+
logger.debug("GEMS RSUB SCALAR")
31+
return rsub_func_tensor_scalar(A, B, alpha)

tests/test_rsub.py

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
import pytest
2+
import torch
3+
4+
import flag_gems
5+
6+
from .accuracy_utils import (
7+
FLOAT_DTYPES,
8+
POINTWISE_SHAPES,
9+
gems_assert_close,
10+
to_reference,
11+
)
12+
13+
14+
@pytest.mark.rsub
15+
@pytest.mark.parametrize("shape", POINTWISE_SHAPES)
16+
@pytest.mark.parametrize("dtype", FLOAT_DTYPES)
17+
def test_accuracy_rsub_tensor(shape, dtype):
18+
inp1 = torch.randn(shape, dtype=dtype, device=flag_gems.device)
19+
inp2 = torch.randn(shape, dtype=dtype, device=flag_gems.device)
20+
ref_inp1 = to_reference(inp1)
21+
ref_inp2 = to_reference(inp2)
22+
23+
ref_out = torch.rsub(ref_inp1, ref_inp2)
24+
with flag_gems.use_gems():
25+
res_out = torch.rsub(inp1, inp2)
26+
27+
gems_assert_close(res_out, ref_out, dtype)
28+
29+
30+
@pytest.mark.rsub
31+
@pytest.mark.parametrize("shape", POINTWISE_SHAPES)
32+
@pytest.mark.parametrize("dtype", FLOAT_DTYPES)
33+
def test_accuracy_rsub_scalar(shape, dtype):
34+
inp1 = torch.randn(shape, dtype=dtype, device=flag_gems.device)
35+
ref_inp1 = to_reference(inp1)
36+
inp2 = 0.5
37+
38+
ref_out = torch.rsub(ref_inp1, inp2)
39+
with flag_gems.use_gems():
40+
res_out = torch.rsub(inp1, inp2)
41+
42+
gems_assert_close(res_out, ref_out, dtype)

0 commit comments

Comments
 (0)