Skip to content

Vulkan _convert_scalars_to_attrs lifts integer scalars as float32, breaking integer indexing#22365

Description

@AxelNoun

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    module: vulkanIssues related to the Vulkan delegate and code under backends/vulkan/

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions