Skip to content

[Vulkan] Missing int32 -> uint8 view_convert variant: lowers cleanly, aborts at run time#22320

Description

@msluszniak

馃悰 Describe the bug

The view_convert shader combo lists generate uint8 -> int32 but not the reverse, so a graph containing an int32 -> uint8 view_convert lowers cleanly through VulkanPartitioner and then aborts at run time:

libc++abi: terminating due to uncaught exception of type vkcompute::vkapi::Error:
Exception raised from get_shader_info at backends/vulkan/runtime/api/ShaderRegistry.cpp:54:
(it != listings_.end()) is false! Could not find ShaderInfo with name view_convert_buffer_int32_uint8

backends/vulkan/runtime/graph/ops/glsl/view_convert_buffer.yaml (and the _texture twin):

        - parameter_values: [uint8, float]
        - parameter_values: [uint8, half]
        - parameter_values: [uint8, int32]     # <- present
        - parameter_values: [float, int32]     # <- no [int32, uint8]

Repro. Lower sentence-transformers/all-MiniLM-L6-v2 with VulkanPartitioner and run it. The conversion arrives through the attention mask:

import torch, torch.nn as nn, torch.nn.functional as F
from transformers import AutoModel
from executorch.backends.vulkan.partitioner.vulkan_partitioner import VulkanPartitioner
from executorch.exir import to_edge_transform_and_lower, EdgeCompileConfig

class Emb(nn.Module):
    def __init__(self):
        super().__init__()
        self.model = AutoModel.from_pretrained(
            "sentence-transformers/all-MiniLM-L6-v2", attn_implementation="eager")
    def forward(self, input_ids, attention_mask):
        tok = self.model(input_ids=input_ids, attention_mask=attention_mask)[0]
        mask = attention_mask.unsqueeze(-1).expand(tok.size()).float()
        summed = torch.sum(tok * mask, 1, keepdim=True)
        counts = torch.sum(mask, 1, keepdim=True).clamp(min=1e-9)
        return F.normalize((summed / counts).squeeze(1), p=2, dim=1)

ep = torch.export.export(
    Emb().eval(),
    (torch.zeros(1, 128, dtype=torch.int64), torch.ones(1, 128, dtype=torch.int64)))
prog = to_edge_transform_and_lower(
    {"forward": ep}, partitioner=[VulkanPartitioner()],
    compile_config=EdgeCompileConfig(
        _core_aten_ops_exception_list=[torch.ops.aten.linear.default])).to_executorch()
open("minilm_vulkan.pte", "wb").write(prog.buffer)

Lowering reports a clean 2-blob partition; executor_runner then aborts on device.

Expected behavior

Either generate the variant, or have the partitioner decline the node so it stays on host. Silently accepting at AOT and aborting at run time is the worst of the three, because the failure only appears on a device.

Fix

view_convert is a plain elementwise OUT_T(t_inp[...]) cast, so the pair needs nothing beyond being listed. Verified on a Galaxy S26 Ultra (Adreno 840): with the variant generated, all-MiniLM-L6-v2 runs and its embedding matches the eager reference to cosine 0.99999726 (max abs deviation 4.0e-04), bit-identical across 90 in-process replays.

PR: #22321

Versions

ExecuTorch main @ c27baa8. Android arm64-v8a, NDK 27.1, Galaxy S26 Ultra (Adreno 840). Python 3.10, torch 2.13.0.

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