-
Notifications
You must be signed in to change notification settings - Fork 493
【KernelGen】Add fmod operator #1737
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
bin913
merged 6 commits into
flagos-ai:master
from
Schopenhauer-loves-Hegel:auto-gen/fmod
May 11, 2026
Merged
Changes from 3 commits
Commits
Show all changes
6 commits
Select commit
Hold shift + click to select a range
59fdd32
feat: add fmod operator with tests and benchmark
factnn a00296b
Apply suggestion from @tengqm
bin913 e1dc6e6
Apply suggestions from code review
bin913 b0f51e5
Apply suggestions from code review
factnn 09b4177
Apply suggestions from code review
bin913 88ebb8a
Merge branch 'master' into auto-gen/fmod
bin913 File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,62 @@ | ||
| import pytest | ||
| import torch | ||
|
|
||
| from . import base, consts, utils | ||
|
|
||
|
|
||
| def _tensor_input_fn(shape, dtype, device): | ||
| inp1 = utils.generate_tensor_input(shape, dtype, device) | ||
| inp2 = utils.generate_tensor_input(shape, dtype, device) | ||
| inp2 = torch.where(inp2 == 0, torch.ones_like(inp2), inp2) | ||
| yield inp1, inp2 | ||
|
|
||
|
|
||
| def _scalar_input_fn(shape, dtype, device): | ||
| inp1 = utils.generate_tensor_input(shape, dtype, device) | ||
| yield inp1, 0.5 | ||
|
|
||
|
|
||
| @pytest.mark.fmod | ||
| def test_fmod_tensor(): | ||
| bench = base.GenericBenchmark( | ||
| input_fn=_tensor_input_fn, | ||
| op_name="fmod.Tensor", | ||
|
bin913 marked this conversation as resolved.
Outdated
|
||
| torch_op=torch.fmod, | ||
| dtypes=consts.FLOAT_DTYPES, | ||
| ) | ||
| bench.run() | ||
|
|
||
|
|
||
| @pytest.mark.fmod | ||
|
bin913 marked this conversation as resolved.
Outdated
|
||
| def test_fmod_scalar(): | ||
| bench = base.GenericBenchmark( | ||
| input_fn=_scalar_input_fn, | ||
| op_name="fmod.Scalar", | ||
|
bin913 marked this conversation as resolved.
Outdated
|
||
| torch_op=torch.fmod, | ||
| dtypes=consts.FLOAT_DTYPES, | ||
| ) | ||
| bench.run() | ||
|
|
||
|
|
||
| @pytest.mark.fmod | ||
|
bin913 marked this conversation as resolved.
Outdated
|
||
| def test_fmod_tensor_(): | ||
| bench = base.GenericBenchmark( | ||
| input_fn=_tensor_input_fn, | ||
| op_name="fmod_.Tensor", | ||
|
bin913 marked this conversation as resolved.
Outdated
|
||
| torch_op=torch.Tensor.fmod_, | ||
| dtypes=consts.FLOAT_DTYPES, | ||
| inplace=True, | ||
| ) | ||
| bench.run() | ||
|
|
||
|
|
||
| @pytest.mark.fmod | ||
|
bin913 marked this conversation as resolved.
Outdated
|
||
| def test_fmod_scalar_(): | ||
| bench = base.GenericBenchmark( | ||
| input_fn=_scalar_input_fn, | ||
| op_name="fmod_.Scalar", | ||
|
bin913 marked this conversation as resolved.
Outdated
|
||
| torch_op=torch.Tensor.fmod_, | ||
| dtypes=consts.FLOAT_DTYPES, | ||
| inplace=True, | ||
| ) | ||
| bench.run() | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,51 @@ | ||
| import logging | ||
|
|
||
| import triton | ||
| import triton.language as tl | ||
|
|
||
| from flag_gems.utils import pointwise_dynamic | ||
| from flag_gems.utils.triton_lang_extension import fmod as _fmod | ||
|
|
||
| logger = logging.getLogger(__name__) | ||
|
|
||
|
|
||
| @pointwise_dynamic(promotion_methods=[(0, 1, "DEFAULT")]) | ||
| @triton.jit | ||
| def fmod_func(x, y): | ||
| # Convert to float32 for computation to avoid libdevice float16/bfloat16 issues | ||
| dtype = x.dtype | ||
| x_fp32 = x.to(tl.float32) | ||
| y_fp32 = y.to(tl.float32) | ||
| result = _fmod(x_fp32, y_fp32) | ||
| return result.to(dtype) | ||
|
|
||
|
|
||
| @pointwise_dynamic(is_tensor=[True, False], promotion_methods=[(0, 1, "DEFAULT")]) | ||
| @triton.jit | ||
| def fmod_func_tensor_scalar(x, y): | ||
| # Convert to float32 for computation to avoid libdevice float16/bfloat16 issues | ||
| dtype = x.dtype | ||
| x_fp32 = x.to(tl.float32) | ||
| y_fp32 = y.to(tl.float32) | ||
| result = _fmod(x_fp32, y_fp32) | ||
| return result.to(dtype) | ||
|
|
||
|
|
||
| def fmod_tensor(A, B): | ||
| logger.debug("GEMS FMOD_TENSOR") | ||
| return fmod_func(A, B) | ||
|
|
||
|
|
||
| def fmod_scalar(A, B): | ||
| logger.debug("GEMS FMOD_SCALAR") | ||
| return fmod_func_tensor_scalar(A, B) | ||
|
|
||
|
|
||
| def fmod_tensor_(A, B): | ||
| logger.debug("GEMS FMOD_TENSOR_") | ||
| return fmod_func(A, B, out0=A) | ||
|
|
||
|
|
||
| def fmod_scalar_(A, B): | ||
| logger.debug("GEMS FMOD_SCALAR_") | ||
| return fmod_func_tensor_scalar(A, B, out0=A) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,74 @@ | ||
| import pytest | ||
| import torch | ||
|
|
||
| import flag_gems | ||
|
|
||
| from .accuracy_utils import ( | ||
| FLOAT_DTYPES, | ||
| POINTWISE_SHAPES, | ||
| SCALARS, | ||
| gems_assert_close, | ||
| to_reference, | ||
| ) | ||
|
|
||
|
|
||
| @pytest.mark.fmod | ||
|
factnn marked this conversation as resolved.
Outdated
bin913 marked this conversation as resolved.
Outdated
|
||
| @pytest.mark.parametrize("shape", POINTWISE_SHAPES) | ||
| @pytest.mark.parametrize("dtype", FLOAT_DTYPES) | ||
| def test_accuracy_fmod(shape, dtype): | ||
|
factnn marked this conversation as resolved.
Outdated
|
||
| inp1 = torch.randn(shape, dtype=dtype, device=flag_gems.device) | ||
| inp2 = torch.randn(shape, dtype=dtype, device=flag_gems.device) | ||
| inp2 = torch.where(inp2 == 0, torch.ones_like(inp2), inp2) | ||
| ref_inp1 = to_reference(inp1, True) | ||
| ref_inp2 = to_reference(inp2, True) | ||
| ref_out = torch.fmod(ref_inp1, ref_inp2) | ||
| with flag_gems.use_gems(): | ||
| res_out = torch.fmod(inp1, inp2) | ||
| gems_assert_close(res_out, ref_out, dtype) | ||
|
|
||
|
|
||
| @pytest.mark.fmod | ||
|
factnn marked this conversation as resolved.
Outdated
|
||
| @pytest.mark.parametrize("shape", POINTWISE_SHAPES) | ||
| @pytest.mark.parametrize("scalar", SCALARS) | ||
| @pytest.mark.parametrize("dtype", FLOAT_DTYPES) | ||
| def test_accuracy_fmod_tensor_scalar(shape, scalar, dtype): | ||
|
factnn marked this conversation as resolved.
Outdated
|
||
| inp1 = torch.randn(shape, dtype=dtype, device=flag_gems.device) | ||
| inp2 = scalar if scalar != 0 else 1.0 | ||
| ref_inp1 = to_reference(inp1, True) | ||
| ref_out = torch.fmod(ref_inp1, inp2) | ||
| with flag_gems.use_gems(): | ||
| res_out = torch.fmod(inp1, inp2) | ||
| atol = 1e-3 if abs(scalar) < 0.01 else 1e-4 | ||
| gems_assert_close(res_out, ref_out, dtype, atol=atol) | ||
|
|
||
|
|
||
| @pytest.mark.inplace | ||
| @pytest.mark.fmod_ | ||
|
factnn marked this conversation as resolved.
Outdated
|
||
| @pytest.mark.parametrize("shape", POINTWISE_SHAPES) | ||
| @pytest.mark.parametrize("dtype", FLOAT_DTYPES) | ||
| def test_accuracy_fmod_(shape, dtype): | ||
|
factnn marked this conversation as resolved.
Outdated
|
||
| inp1 = torch.randn(shape, dtype=dtype, device=flag_gems.device) | ||
| inp2 = torch.randn(shape, dtype=dtype, device=flag_gems.device) | ||
| inp2 = torch.where(inp2 == 0, torch.ones_like(inp2), inp2) | ||
| ref_inp1 = to_reference(inp1.clone(), True) | ||
| ref_inp2 = to_reference(inp2, True) | ||
| ref_out = ref_inp1.fmod_(ref_inp2) | ||
| with flag_gems.use_gems(): | ||
| res_out = inp1.fmod_(inp2) | ||
| gems_assert_close(res_out, ref_out, dtype) | ||
|
|
||
|
|
||
| @pytest.mark.inplace | ||
| @pytest.mark.fmod_ | ||
|
factnn marked this conversation as resolved.
Outdated
|
||
| @pytest.mark.parametrize("shape", POINTWISE_SHAPES) | ||
| @pytest.mark.parametrize("scalar", SCALARS) | ||
| @pytest.mark.parametrize("dtype", FLOAT_DTYPES) | ||
| def test_fmod_scalar_inplace(shape, scalar, dtype): | ||
| inp1 = torch.randn(shape, dtype=dtype, device=flag_gems.device) | ||
| inp2 = scalar if scalar != 0 else 1.0 | ||
| ref_inp1 = to_reference(inp1.clone(), True) | ||
| ref_out = ref_inp1.fmod_(inp2) | ||
| with flag_gems.use_gems(): | ||
| res_out = inp1.fmod_(inp2) | ||
| atol = 1e-3 if abs(scalar) < 0.01 else 1e-4 | ||
| gems_assert_close(res_out, ref_out, dtype, atol=atol) | ||
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.