Vulkan _convert_scalars_to_attrs lifts integer scalars as float32, breaking integer indexing
馃悰 Describe the bug
The bug reproduces with a bare VulkanQuantizer(): no set_global, no quantization config. transform_for_annotation still rewrites integer scalars to float32 buffers, and an int64 add used as an index then fails with IndexError: tensors used as indices must be long, int, byte or bool tensors.
backends/vulkan/quantizer/vulkan_quantizer_utils.py _convert_scalars_to_attrs promotes every scalar operand of aten.add.Tensor / aten.mul.Tensor with torch.tensor(float(args[i])). That forces torch.float32, ignoring n.meta["val"].dtype.
This is the same helper body as the XNNPACK copy reported in #22062. The open fix #22065 touches only:
backends/xnnpack/quantizer/xnnpack_quantizer_utils.py
backends/xnnpack/test/quantizer/test_xnnpack_quantizer.py
It does not change backends/vulkan/.
backends/vulkan/quantizer/ contains vulkan_quantizer.py, vulkan_quantizer_utils.py, and BUCK. There is no existing test file for this quantizer.
Measured on commit 6755ea388ce6d2249d26f568c286a153ccba4883 (OSS layout, not a claim about Meta-internal jobs):
pytest.ini testpaths lists backends/xnnpack/test and does not list backends/vulkan/.
.github/workflows/pull.yml and vulkan.yml invoke Vulkan Python tests by name only: python -m unittest backends/vulkan/test/test_vulkan_delegate.py -k "*pt2e*" (and *torchao*).
The repro below is a synthetic nn.Module (Linear + integer index). No production model was exported or measured as broken.
Local ExecuTorch install is incomplete (pybindings._C and exir/_serialize/program.fbs are missing), so this was run against a source checkout rather than an installed wheel. Once ExecuTorch is installed, the script below is the repro.
Reproduction
import traceback
import torch
from executorch.backends.vulkan.quantizer.vulkan_quantizer import (
VulkanQuantizer,
get_symmetric_quantization_config,
)
from torchao.quantization.pt2e.quantize_pt2e import prepare_pt2e
class Tiny(torch.nn.Module):
def __init__(self):
super().__init__()
self.fc = torch.nn.Linear(4, 4)
def forward(self, x):
return self.fc(x)[:, torch.arange(4) + 0]
m, ex = Tiny().eval(), (torch.randn(2, 4),)
def inspect_and_run(label, q):
print(f"\n=== {label} ===")
exported = torch.export.export(m, ex).module()
p = prepare_pt2e(exported, q)
consts = {
n: getattr(p, n).dtype
for n in dir(p)
if n.startswith("_tensor_constant")
}
print("lifted dtypes:", consts)
try:
print(p(*ex).shape)
except IndexError:
traceback.print_exc()
inspect_and_run("bare VulkanQuantizer()", VulkanQuantizer())
inspect_and_run("with set_global", VulkanQuantizer().set_global(get_symmetric_quantization_config()))
Output of that script on unpatched 6755ea388ce6d2249d26f568c286a153ccba4883:
=== bare VulkanQuantizer() ===
lifted dtypes: {'_tensor_constant_0': torch.float32}
Traceback (most recent call last):
File "repro.py", line 34, in inspect_and_run
print(p(*ex).shape)
^^^^^^
File ".../torch/fx/graph_module.py", line 949, in call_wrapped
return self._wrapped_call(self, *args, **kwargs)
File ".../torch/fx/graph_module.py", line 461, in __call__
raise e
File ".../torch/fx/graph_module.py", line 447, in __call__
return super(self.cls, obj).__call__(*args, **kwargs)
File ".../torch/nn/modules/module.py", line 1778, in _wrapped_call_impl
return self._call_impl(*args, **kwargs)
File ".../torch/nn/modules/module.py", line 1789, in _call_impl
return forward_call(*args, **kwargs)
File "<eval_with_key>.18", line 12, in forward
index = torch.ops.aten.index.Tensor(linear, [None, add]); linear = add = None
File ".../torch/_ops.py", line 871, in __call__
return self._op(*args, **kwargs)
IndexError: tensors used as indices must be long, int, byte or bool tensors
=== with set_global ===
lifted dtypes: {'_tensor_constant_0': torch.float32}
Traceback (most recent call last):
File "repro.py", line 34, in inspect_and_run
print(p(*ex).shape)
^^^^^^
File ".../torch/fx/graph_module.py", line 949, in call_wrapped
return self._wrapped_call(self, *args, **kwargs)
File ".../torch/fx/graph_module.py", line 461, in __call__
raise e
File ".../torch/fx/graph_module.py", line 447, in __call__
return super(self.cls, obj).__call__(*args, **kwargs)
File ".../torch/nn/modules/module.py", line 1778, in _wrapped_call_impl
return self._call_impl(*args, **kwargs)
File ".../torch/nn/modules/module.py", line 1789, in _call_impl
return forward_call(*args, **kwargs)
File "<eval_with_key>.29", line 13, in forward
index = torch.ops.aten.index.Tensor(linear, [None, add]); linear = add = None
File ".../torch/_ops.py", line 871, in __call__
return self._op(*args, **kwargs)
IndexError: tensors used as indices must be long, int, byte or bool tensors
Expected: lifted scalar keeps torch.int64; prepare_pt2e / module execution returns a [2, 4] tensor.
A one-line fix aligned with #22065 already exists; a PR follows.
Versions
collect_env.py was not run (incomplete local ExecuTorch install: no pybindings._C, no exir/_serialize/program.fbs). Measured environment:
- OS: Windows 11,
10.0.26200, AMD64
- SHA:
6755ea388ce6d2249d26f568c286a153ccba4883 (commit the measurements were taken on; not current origin/main)
- Python: 3.12.10
- torch: 2.12.0+cpu (CUDA: no)
- torchao: 0.17.0+git02105d46c
Related: #22062 (XNNPACK), #22065 (XNNPACK patch, still open, does not cover Vulkan).
Related observation on the XNNPACK twin
pytest.ini addopts includes --ignore=backends/xnnpack/test/quantizer/test_xnnpack_quantizer.py. A search of .github/workflows for test_xnnpack_quantizer returned no hits. The default OSS pytest job (.ci/scripts/unittest-linux-cmake.sh) is pytest -n auto, which reads that ini.
Not measured: whether any non-Actions runner (including the Buck target test_xnnpack_quantizer in backends/xnnpack/test/BUCK) executes that XNNPACK file. This issue does not claim it never runs outside GitHub Actions.
cc @SS-JIA @manuelcandales @digantdesai @cbilgin
Vulkan
_convert_scalars_to_attrslifts integer scalars as float32, breaking integer indexing馃悰 Describe the bug
The bug reproduces with a bare
VulkanQuantizer(): noset_global, no quantization config.transform_for_annotationstill rewrites integer scalars tofloat32buffers, and anint64add used as an index then fails withIndexError: tensors used as indices must be long, int, byte or bool tensors.backends/vulkan/quantizer/vulkan_quantizer_utils.py_convert_scalars_to_attrspromotes every scalar operand ofaten.add.Tensor/aten.mul.Tensorwithtorch.tensor(float(args[i])). That forcestorch.float32, ignoringn.meta["val"].dtype.This is the same helper body as the XNNPACK copy reported in #22062. The open fix #22065 touches only:
backends/xnnpack/quantizer/xnnpack_quantizer_utils.pybackends/xnnpack/test/quantizer/test_xnnpack_quantizer.pyIt does not change
backends/vulkan/.backends/vulkan/quantizer/containsvulkan_quantizer.py,vulkan_quantizer_utils.py, andBUCK. There is no existing test file for this quantizer.Measured on commit
6755ea388ce6d2249d26f568c286a153ccba4883(OSS layout, not a claim about Meta-internal jobs):pytest.initestpathslistsbackends/xnnpack/testand does not listbackends/vulkan/..github/workflows/pull.ymlandvulkan.ymlinvoke Vulkan Python tests by name only:python -m unittest backends/vulkan/test/test_vulkan_delegate.py -k "*pt2e*"(and*torchao*).The repro below is a synthetic
nn.Module(Linear+ integer index). No production model was exported or measured as broken.Local ExecuTorch install is incomplete (
pybindings._Candexir/_serialize/program.fbsare missing), so this was run against a source checkout rather than an installed wheel. Once ExecuTorch is installed, the script below is the repro.Reproduction
Output of that script on unpatched
6755ea388ce6d2249d26f568c286a153ccba4883:Expected: lifted scalar keeps
torch.int64;prepare_pt2e/ module execution returns a[2, 4]tensor.A one-line fix aligned with #22065 already exists; a PR follows.
Versions
collect_env.pywas not run (incomplete local ExecuTorch install: nopybindings._C, noexir/_serialize/program.fbs). Measured environment:10.0.26200, AMD646755ea388ce6d2249d26f568c286a153ccba4883(commit the measurements were taken on; not currentorigin/main)Related: #22062 (XNNPACK), #22065 (XNNPACK patch, still open, does not cover Vulkan).
Related observation on the XNNPACK twin
pytest.iniaddoptsincludes--ignore=backends/xnnpack/test/quantizer/test_xnnpack_quantizer.py. A search of.github/workflowsfortest_xnnpack_quantizerreturned no hits. The default OSS pytest job (.ci/scripts/unittest-linux-cmake.sh) ispytest -n auto, which reads that ini.Not measured: whether any non-Actions runner (including the Buck target
test_xnnpack_quantizerinbackends/xnnpack/test/BUCK) executes that XNNPACK file. This issue does not claim it never runs outside GitHub Actions.cc @SS-JIA @manuelcandales @digantdesai @cbilgin