Skip to content

Commit f33d8b0

Browse files
zheng1claude
andcommitted
fix(ascend): correct flattened argmax semantics
Two issues on the dim=None path: 1. keepdim. The output was allocated with torch.empty([]) unconditionally, so keepdim=True was dropped. PyTorch returns shape [1] * inp.dim(). 2. Block size. block_size was derived only from sqrt(numel) with no upper bound. For large inputs it went past what the device handles on this path and the returned index pointed at an element that was not the maximum. It is now capped at 1024, the same bound argmin uses. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
1 parent 575d73a commit f33d8b0

2 files changed

Lines changed: 27 additions & 3 deletions

File tree

src/flag_gems/runtime/backend/_ascend/ops/argmax.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -113,13 +113,14 @@ def argmax(inp, dim=None, keepdim=False, *, dtype=None):
113113
M = inp.numel()
114114
if dtype is None:
115115
dtype = inp.dtype
116-
block_size = triton.next_power_of_2(math.ceil(math.sqrt(M)))
116+
block_size = min(1024, triton.next_power_of_2(math.ceil(math.sqrt(M))))
117117
mid_size = triton.cdiv(M, block_size)
118118
block_mid = triton.next_power_of_2(mid_size)
119119

120120
mid_value = torch.empty((mid_size,), dtype=dtype, device=inp.device)
121121
mid_index = torch.empty((mid_size,), dtype=torch.int64, device=inp.device)
122-
out = torch.empty([], dtype=torch.int64, device=inp.device)
122+
out_shape = [1] * inp.dim() if keepdim else []
123+
out = torch.empty(out_shape, dtype=torch.int64, device=inp.device)
123124

124125
with torch_device_fn.device(inp.device):
125126
argmax_kernel_1[(mid_size, 1, 1)](

tests/test_argmax.py

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
import torch
1717

1818
import flag_gems
19+
from flag_gems.runtime import torch_device_fn
1920

2021
from . import accuracy_utils as utils
2122
from . import conftest as cfg
@@ -60,9 +61,12 @@ def test_argmax(shape, dim, keepdim, dtype):
6061
else:
6162
inp = torch.randn(shape, dtype=dtype, device=flag_gems.device)
6263

63-
ref_inp = utils.to_reference(inp)
64+
use_cpu_ref = flag_gems.vendor_name == "ascend" and dim is None and keepdim
65+
ref_inp = inp.cpu() if use_cpu_ref else utils.to_reference(inp)
6466

6567
ref_out = torch.argmax(ref_inp, dim=dim, keepdim=keepdim)
68+
if use_cpu_ref and not cfg.TO_CPU:
69+
ref_out = ref_out.to(inp.device)
6670
with flag_gems.use_gems():
6771
res_out = torch.argmax(inp, dim=dim, keepdim=keepdim)
6872

@@ -87,3 +91,22 @@ def test_argmax_full_reduction_noncontiguous(dtype):
8791
res_out = torch.argmax(inp)
8892

8993
utils.gems_assert_equal(res_out, ref_out)
94+
95+
96+
@pytest.mark.argmax
97+
@pytest.mark.skipif(
98+
flag_gems.vendor_name != "ascend", reason="Ascend-specific regression test"
99+
)
100+
def test_argmax_large_flattened_block_size():
101+
# block_size was derived from sqrt(numel) with no upper bound. For an input
102+
# this large it went past what the device handles on the flattened path, and
103+
# the returned index pointed at an element that was not the maximum.
104+
for seed in (0, 2, 3, 9):
105+
torch_device_fn.manual_seed_all(seed)
106+
inp = torch.randn((200, 2560, 3), dtype=torch.bfloat16, device=flag_gems.device)
107+
ref_out = torch.argmax(inp.cpu())
108+
109+
with flag_gems.use_gems():
110+
res_out = torch.argmax(inp)
111+
112+
torch.testing.assert_close(res_out.cpu(), ref_out, atol=0, rtol=0)

0 commit comments

Comments
 (0)