Vulkan: how much of each LeRobot policy the Vulkan backend takes, and what blocks the rest

Ouverte
#24,688 0 commentaires 0 réactions 1 personne assignée Voir sur GitHub

Les mainteneurs répondent en général sous 1 jour

@SS-JIA y travaille déjà.

Depuis le 5/11/2026.

Évaluation

Cette issue n'a pas encore été évaluée.

Description

module: vulkan

This issue tracks LeRobot policies exported to ExecuTorch with its Vulkan GPU backend (VulkanPartitioner): how much of each policy Vulkan takes, whether the program exports, and what each project still needs to look at. Other backends have their own issues: TensorRT in #24353, OpenVINO in #24325, XNNPACK in #24667, Qualcomm in #24668, Core ML and MLX in #24669, the CUDA backend in #24684, and Arm in #24697.

Why this matters for LeRobot: Vulkan is a GPU path for boards with no CUDA and no NPU that ExecuTorch supports, for example the Arm Mali GPU on RK3588 boards. ExecuTorch's Vulkan backend is built mainly for Android GPUs, so a board running Linux is on the less tested path. It can also use the Adreno GPU in Qualcomm chips, which also have a Hexagon NPU (see #24668). On NVIDIA GPUs, TensorRT or the CUDA backend is the main path, so the H100 column here only checks correctness. No Mali or Adreno device has been tested yet.

Coverage

Policy Ops on Vulkan Heavy math on Vulkan Vulkan programs Exports to .pte H100 (correctness)
act 1556 / 1561 (100%) 100% 3 $\color{#2da44e}{\checkmark}$ $\color{#2da44e}{\checkmark}$ 88.7 (1.0x)
diffusion 534 / 619 (86%) 94% 50 $\color{#2da44e}{\checkmark}$ ❌
dm05 ⏳ ⏳ ⏳ ⏳ ⏳
eo1 20136 / 56586 (36%) 1% at least 1987 $\color{#d4a017}{\textsf{slow}}$ ⏳
evo1 13904 / 16601 (84%) 26% 61 $\color{#d4a017}{\textsf{slow}}$ ⏳
fastwam ⏳ ⏳ ⏳ ⏳ ⏳
fineart_vla 21670 / 21704 (100%) 100% 6 $\color{#d4a017}{\textsf{slow}}$ ❌
flux3 ⏳ ⏳ ⏳ ⏳ ⏳
gaussian_actor 114 / 127 (90%) 100% 5 $\color{#2da44e}{\checkmark}$ $\color{#2da44e}{\checkmark}$ 1.14 (1.9x)
groot ⏳ ⏳ ⏳ ⏳ ⏳
lawam 15409 / 18124 (85%) 44% at least 198 $\color{#d4a017}{\textsf{slow}}$ ⏳
lingbot_va 3998 / 10375 (39%) 10% at least 688 $\color{#d4a017}{\textsf{slow}}$ ⏳
lingbot_vla_v2 ⏳ ⏳ ⏳ ⏳ ⏳
molmoact2 ⏳ ⏳ ⏳ ⏳ ⏳
multi_task_dit 1460 / 1463 (100%) 100% 5 $\color{#2da44e}{\checkmark}$ $\color{#2da44e}{\checkmark}$ 774 (3.9x)
pi0 5624 / 5654 (99%) 100% 17 $\color{#2da44e}{\checkmark}$ ❌
pi05 ❌ ❌ ❌ ❌ -
pi0_fast 9059 / 9082 (100%) 100% 11 $\color{#2da44e}{\checkmark}$ ❌
smolvla 2933 / 7163 (41%) 16% 209 $\color{#2da44e}{\checkmark}$ ❌
tdmpc 5477 / 5895 (93%) 100% 140 $\color{#2da44e}{\checkmark}$ $\color{#2da44e}{\checkmark}$ 494 (0.9x)
vla_jepa 7049 / 10817 (65%) 6% 191 $\color{#d4a017}{\textsf{slow}}$ ⏳
vqbet 567 / 594 (95%) 23% 22 $\color{#2da44e}{\checkmark}$ $\color{#2da44e}{\checkmark}$ 1241 (0.02x)
wall_oss_05 36455 / 87088 (42%) 4% at least 2752 $\color{#d4a017}{\textsf{slow}}$ ⏳
wall_x ⏳ ⏳ ⏳ ⏳ ⏳
xvla 16565 / 16643 (100%) 99% 61 $\color{#d4a017}{\textsf{slow}}$ $\color{#2da44e}{\checkmark}$ 6568 (0.5x)

Legend:

  • "Ops on Vulkan": the graph ops that VulkanPartitioner() takes, out of all ops, over all programs of the policy. Ops are counted after to_edge, so a linear layer counts as a matmul and a transpose.
  • "Heavy math on Vulkan": the share of multiply-adds in matmuls, linear layers, convolutions and attention that Vulkan takes. A program counts as many times as one action chunk runs it (for example, once per denoising step).
  • "Vulkan programs": how many Vulkan partitions the policy is split into. Between 2 partitions, the data goes back to the CPU. "At least N" means partitioning itself did not finish within 15 minutes; N is the number of connected groups of ops that Vulkan takes, a lower bound.
  • "Exports to .pte": $\color{#2da44e}{\checkmark}$ means to_edge_transform_and_lower(...).to_executorch() finished with the default options. $\color{#d4a017}{\textsf{slow}}$ means the export did not finish within 15 minutes; a longer run is queued. ❌ means it fails; the cause is in the tables below.
  • "H100 (correctness)": the bundle run with lerobot-rollout --bundle.path on an H100 through its Vulkan driver, with PyTorch never loaded. $\color{#2da44e}{\checkmark}$ means it passed the export's own accuracy check and, for policies without a frame history, a 16-frame comparison against eager PyTorch. The number is milliseconds per action chunk (batch size 1, median). In brackets: how many times faster than eager PyTorch (lerobot-rollout --policy.path --device=cpu) on 16 CPU cores of the same machine, because a Vulkan bundle takes its inputs and returns its outputs on the CPU. Ops that Vulkan does not take run on ExecuTorch's portable CPU kernels, which are slow, so a bundle with heavy ops left on the CPU can be much slower than eager (vqbet).
  • -: not measured, because an earlier step fails.
  • ⏳: this cell is being measured (running or queued).

Notes:

  • The ExecuTorch 1.6.0 wheel has the Vulkan partitioner but not the Vulkan runtime. For the H100 column, ExecuTorch 1.6.0 was built from source with the Vulkan backend on (EXECUTORCH_BUILD_VULKAN=1, shaders compiled with glslc from conda-forge's shaderc, as ExecuTorch's CI does) and with the event tracer off (ExecuTorch table).
  • LeRobot has no Vulkan backend for lerobot-export yet (LeRobot table). So each policy is traced with the trace step of lerobot-export (same checkpoint, task and export flags as the XNNPACK rows of #24667 and the OpenVINO rows of #24325), and each traced program is lowered the way lerobot-export lowers for its ExecuTorch backends, with VulkanPartitioner() and its default options.
  • diffusion, dm05, eo1, fineart_vla, gaussian_actor, lingbot_vla_v2, molmoact2, multi_task_dit, tdmpc, vla_jepa, vqbet and wall_x use random weights, made by the same script and seed as in #24353. The other policies use their real weights.
  • With force_fp16 (run inside the backend in fp16), act, diffusion, gaussian_actor, multi_task_dit, pi0_fast, smolvla and vqbet also export. It does not change what the partitioner takes.
  • evo1 keeps its bf16 weights, so its vision-language part stays on the CPU (first ExecuTorch row).
  • pi0 and pi05 checkpoints use the SigLIP weight names of transformers before 5.22, which the branch cannot load yet (LeRobot table). The pi0 row uses the same pi0 weights re-saved under the new names, which does not change the graph. pi05 is not measured yet.

Built on

  • ExecuTorch: the official 1.6.0 CPU wheel (the final release). Its backends/vulkan Python code is what was measured. No source build and no patches.
  • torch 2.15.0, transformers 5.22.1.
  • LeRobot: the lerobot-export-stack branch of shoumikhin/lerobot, as it was on Nov 3 at 10:53 AM Pacific (see #24353).
  • GPU (for the correctness column): H100, NVIDIA driver 580, Vulkan 1.4.

Known issues

"Fix" is an open pull request unless it says merged. "Needs a decision" is a design question for the maintainers. "Needs an owner" means nobody is fixing it yet.

ExecuTorch
  • Pick up the rows marked "needs an owner". bf16 (first row) and batched convolutions (second row) cost the most heavy math.
  • Every row has a short repro below the table. Repros 1 to 4 need only the ExecuTorch 1.6.0 wheel and no GPU. Repros 5 and 6 need ExecuTorch built with Vulkan, and a GPU.
Problem Policies Fix Status
No bf16. torch.bfloat16 is not in the backend's dtype table (_VULKAN_DTYPES in backends/vulkan/utils.py), so every bf16 op stays on the CPU with "dtype not supported". evo1 (74% of its heavy math stays on the CPU), smolvla (84%), vla_jepa (94%), eo1 (99%), wall_oss_05 (96%) needs a decision: support bf16, or run bf16 programs in fp16 or fp32 inside the backend Repro ready (repro 1)
A 4D convolution is taken only with batch size 1 (check_conv_node in backends/vulkan/op_registry.py). Policies that encode 2 or more frames or cameras as one batch keep their image encoder on the CPU. vqbet (77% of its heavy math stays on the CPU), diffusion, xvla, multi_task_dit needs an owner Repro ready (repro 2)
No Vulkan kernel for elu, log1p (used by Mish through softplus), var, index_put, or transposed 1D convolution. Each one cuts the graph into more Vulkan programs. tdmpc (elu 181 times, log1p 150, var 36), diffusion (log1p 38, transposed conv1d 2), xvla (index_put 21) needs an owner Repro ready (repro 3)
Partitioning big graphs is very slow. VulkanPartitioner uses torch.fx's CapabilityBasedPartitioner, and its merge step grows much faster than the graph. tdmpc (5,895 ops) takes 603 s to partition and ends with 140 Vulkan programs, while its supported ops form only 41 connected groups. tdmpc, evo1, xvla, and the larger policies needs an owner Repro ready (repro 4): 200 blocks take 13 s, 400 blocks take 95 s
With the event tracer on, which the Python wheel's build preset turns on (tools/cmake/preset/pybind.cmake), the Vulkan runtime writes 2 GPU timestamps per dispatch into a query pool of 4,096 (VULKAN_QUERY_POOL_SIZE). A program with more than about 2,000 dispatches stops with "Vulkan QueryPool: Exceeded the maximum number of queries". act (from Python) needs an owner: use the query pool only when profiling is asked for, or let it grow Repro ready (repro 5): 1,000 steps run, 1,500 steps stop; with -DEXECUTORCH_ENABLE_EVENT_TRACER=OFF, 4,000 steps run
GroupNorm on a 3D input (batch, channels, length) gives wrong values with no error: the largest difference from eager PyTorch is 7.9 to 10.5 for the 5 shapes tried. The same GroupNorm on a 4D input is right. diffusion's 1D U-Net uses it in every denoising step. diffusion (on the H100 its export check gives 1.79, limit 2e-05; with GroupNorm kept on the CPU, its step program matches eager PyTorch to 3e-06) needs an owner: fix the kernel, or have the partitioner refuse 3D inputs until then Repro ready (repro 6)
x[idx] (aten.index.Tensor) on an int64 or int32 tensor is taken by the partitioner, but the runtime has no shader for it, so the program fails to load with Could not find ShaderInfo with name index_tensor_buffer_buffer_int32. The op is registered for float and int dtypes (register_index_tensor in backends/vulkan/op_registry.py), while index_tensor_buffer.yaml and index_tensor_texture.yaml build only half and float. pi0_fast (its prefill program does not load on the H100), fineart_vla (same, for its model program) needs an owner: add int variants of the shader, or register the op for float dtypes only Repro ready (repro 7)
A Vulkan program whose output is a copy of a constant returns zeros, or the data of another tensor, with no error. The backend's RemoveRedundantOpsTransform (backends/vulkan/_passes/remove_redundant_ops.py) removes the clone, so the constant itself becomes the program output, and it looks like the runtime never copies it into the output. This happens for bool, float32 and int32. pi0 (its first program returns an all-False attention mask, so the export check gives 1.07, limit 2e-05; every other pi0 program matches eager PyTorch to 4e-05) needs an owner: keep the copy when its input is a constant, or have the partitioner leave such a clone on the CPU Repro ready (repro 8)
The RMSNorm fusion (backends/vulkan/patterns/rms_norm.py) accepts any tensor as the scale, but the fused op needs a constant weight when the program loads. When the norm weight is bf16 and the input is fp32, the weight reaches the Vulkan program through a cast that stays on the CPU (bf16 is not supported), so it arrives as a plain input, and the program fails to load with (graph.val_is_tref(tensor_data)) is false in prepack_standard. smolvla (its language model program does not load on the H100) needs an owner: fuse only when the scale is a constant Repro ready (repro 9)
Repros (export only, ExecuTorch 1.6.0, torch 2.15.0)
import time

import torch
from executorch.backends.vulkan.partitioner.vulkan_partitioner import VulkanPartitioner
from executorch.exir import to_edge, to_edge_transform_and_lower


def lowered(model, *inputs):
    """How many Vulkan programs the model lowers to, and which ops stay on the CPU."""
    edge = to_edge_transform_and_lower(torch.export.export(model.eval(), inputs), partitioner=[VulkanPartitioner()])
    nodes = [n for n in edge.exported_program().graph.nodes if n.op == "call_function"]
    names = [getattr(n.target, "__name__", str(n.target)) for n in nodes]
    vulkan = names.count("executorch_call_delegate")
    cpu = sorted({name for name in names if name not in ("executorch_call_delegate", "getitem")})
    return vulkan, cpu


class Fn(torch.nn.Module):
    def __init__(self, fn):
        super().__init__()
        self.fn = fn

    def forward(self, x):
        return self.fn(x)


def case(label, model, *inputs):
    print(f"{label:44s} -> Vulkan programs, CPU ops: {lowered(model, *inputs)}")


# 1. bf16: no op is delegated.
case("Linear float32", torch.nn.Linear(64, 64), torch.randn(4, 64))
case("Linear bfloat16", torch.nn.Linear(64, 64).to(torch.bfloat16), torch.randn(4, 64, dtype=torch.bfloat16))

# 2. A 4D convolution is taken only with batch size 1.
case("Conv2d batch 1", torch.nn.Conv2d(3, 8, 3), torch.randn(1, 3, 32, 32))
case("Conv2d batch 2", torch.nn.Conv2d(3, 8, 3), torch.randn(2, 3, 32, 32))

# 3. Ops with no Vulkan kernel.
x = torch.randn(1, 16, 32)
case("ELU", torch.nn.ELU(), x)
case("Mish (softplus -> log1p)", torch.nn.Mish(), x)
case("var", Fn(lambda t: t.var(dim=-1, keepdim=True)), x)
case("ConvTranspose1d", torch.nn.ConvTranspose1d(16, 8, 4, stride=2, padding=1), x)


class Put(torch.nn.Module):
    def forward(self, t, idx):
        y = t.clone()
        y[idx] = 0.0
        return y


case("index_put (y[idx] = 0)", Put(), torch.randn(8, 32), torch.tensor([1, 3]))


# 4. Partitioning time grows fast with graph size when CPU ops sit on side branches.
class Blocks(torch.nn.Module):
    def __init__(self, n):
        super().__init__()
        self.layers = torch.nn.ModuleList(torch.nn.Linear(32, 32) for _ in range(n))

    def forward(self, x):
        for layer in self.layers:
            a = layer(x)
            x = a * torch.sigmoid(a) + torch.nn.functional.elu(a)  # elu stays on the CPU
        return x


for n in (50, 100, 200, 400):
    ep = to_edge(torch.export.export(Blocks(n).eval(), (torch.randn(1, 32),))).exported_program()
    start = time.time()
    tags = VulkanPartitioner().partition(ep).partition_tags
    print(f"{n:4d} blocks: {len(tags):4d} Vulkan partitions, partition() took {time.time() - start:6.1f} s")

Output:

Linear float32                               -> Vulkan programs, CPU ops: (1, [])
Linear bfloat16                              -> Vulkan programs, CPU ops: (0, ['aten.addmm.default', 'aten.permute_copy.default'])
Conv2d batch 1                               -> Vulkan programs, CPU ops: (1, [])
Conv2d batch 2                               -> Vulkan programs, CPU ops: (0, ['aten.convolution.default'])
ELU                                          -> Vulkan programs, CPU ops: (0, ['aten.elu.default'])
Mish (softplus -> log1p)                     -> Vulkan programs, CPU ops: (2, ['aten.log1p.default'])
var                                          -> Vulkan programs, CPU ops: (0, ['aten.var.correction'])
ConvTranspose1d                              -> Vulkan programs, CPU ops: (0, ['aten.convolution.default'])
index_put (y[idx] = 0)                       -> Vulkan programs, CPU ops: (1, ['aten.index_put.default'])
  50 blocks:   51 Vulkan partitions, partition() took    2.6 s
 100 blocks:  101 Vulkan partitions, partition() took    3.8 s
 200 blocks:  201 Vulkan partitions, partition() took   13.1 s
 400 blocks:  401 Vulkan partitions, partition() took   94.7 s
Repro 5 (needs ExecuTorch 1.6.0 built with Vulkan, and a GPU)
import sys

import torch
from executorch.backends.vulkan.partitioner.vulkan_partitioner import VulkanPartitioner
from executorch.exir import to_edge_transform_and_lower
from executorch.runtime import Runtime


class Many(torch.nn.Module):
    def __init__(self, n):
        super().__init__()
        self.n = n

    def forward(self, x):
        for i in range(self.n):
            x = x * 1.0001 + 0.001  # 2 dispatches per step
        return x


for n in [int(a) for a in sys.argv[1:]] or [500, 1000, 2000]:
    x = torch.randn(1, 64)
    et = to_edge_transform_and_lower(torch.export.export(Many(n), (x,)), partitioner=[VulkanPartitioner()]).to_executorch()
    method = Runtime.get().load_program(et.buffer).load_method("forward")
    try:
        out = method.execute([x])[0]
        print(n, "steps: ok, max abs diff", (out - Many(n)(x)).abs().max().item())
    except RuntimeError as error:
        print(n, "steps: RuntimeError:", str(error).split("\n")[0][:200])

Output on an H100:

# built with the event tracer on (the default of the Python wheel's build preset)
500 steps: ok, max abs diff 0.0
1000 steps: ok, max abs diff 0.0
1500 steps: RuntimeError: Exception raised from write_timestamp at .../backends/vulkan/runtime/vk_api/QueryPool.cpp:79: (num_queries_ < config_.max_query_count) is false! ...
2000 steps: RuntimeError: (same)
# built with -DEXECUTORCH_ENABLE_EVENT_TRACER=OFF
1500 steps: ok, max abs diff 0.0
4000 steps: ok, max abs diff 0.0
Repro 6 (needs ExecuTorch 1.6.0 built with Vulkan, and a GPU)
import torch
from executorch.backends.vulkan.partitioner.vulkan_partitioner import VulkanPartitioner
from executorch.exir import to_edge_transform_and_lower
from executorch.runtime import Runtime

torch.manual_seed(0)
for groups, channels, shape in [(8, 64, (1, 64, 16)), (8, 512, (1, 512, 16)), (8, 1024, (1, 1024, 8)), (8, 2048, (1, 2048, 4)),
                                (8, 512, (1, 512, 4, 4)), (32, 512, (1, 512, 16))]:
    m = torch.nn.GroupNorm(groups, channels).eval()
    with torch.no_grad():
        m.weight.normal_()
        m.bias.normal_()
    x = torch.randn(*shape)
    et = to_edge_transform_and_lower(torch.export.export(m, (x,)), partitioner=[VulkanPartitioner()]).to_executorch()
    out = Runtime.get().load_program(et.buffer).load_method("forward").execute([x])[0]
    ref = m(x)
    print(f"GroupNorm({groups}, {channels}) on {tuple(shape)}: max abs diff {(out - ref).abs().max().item():.2e}")

Output on an H100:

GroupNorm(8, 64) on (1, 64, 16): max abs diff 9.20e+00
GroupNorm(8, 512) on (1, 512, 16): max abs diff 1.05e+01
GroupNorm(8, 1024) on (1, 1024, 8): max abs diff 7.85e+00
GroupNorm(8, 2048) on (1, 2048, 4): max abs diff 8.08e+00
GroupNorm(8, 512) on (1, 512, 4, 4): max abs diff 9.54e-07
GroupNorm(32, 512) on (1, 512, 16): max abs diff 9.56e+00
Repro 7 (needs ExecuTorch 1.6.0 built with Vulkan, and a GPU)
import torch
from executorch.backends.vulkan.partitioner.vulkan_partitioner import VulkanPartitioner
from executorch.exir import to_edge_transform_and_lower
from executorch.runtime import Runtime


class Index(torch.nn.Module):
    def forward(self, x, idx):
        return x[idx]


for dtype in (torch.float32, torch.int64, torch.int32, torch.bool):
    x = (torch.randn(8, 16) * 10).to(dtype)
    idx = torch.tensor([1, 3, 5])
    try:
        edge = to_edge_transform_and_lower(torch.export.export(Index(), (x, idx)), partitioner=[VulkanPartitioner()])
        names = [getattr(n.target, "__name__", "") for n in edge.exported_program().graph.nodes if n.op == "call_function"]
        method = Runtime.get().load_program(edge.to_executorch().buffer).load_method("forward")
        out = method.execute([x, idx])[0]
        print(f"{str(dtype):14s} delegated={names.count('executorch_call_delegate')} ok={torch.equal(out, x[idx])}")
    except Exception as error:
        print(f"{str(dtype):14s} {type(error).__name__}: {str(error).splitlines()[0].split('!')[-1].strip()[:120]}")

Output on an H100:

torch.float32  delegated=1 ok=True
torch.int64    RuntimeError: Could not find ShaderInfo with name index_tensor_buffer_buffer_int32
torch.int32    RuntimeError: Could not find ShaderInfo with name index_tensor_buffer_buffer_int32
torch.bool     delegated=0 ok=True
Repro 8 (needs ExecuTorch 1.6.0 built with Vulkan, and a GPU)
import torch
from executorch.backends.vulkan.partitioner.vulkan_partitioner import VulkanPartitioner
from executorch.exir import to_edge_transform_and_lower
from executorch.runtime import Runtime


class Mask(torch.nn.Module):
    def __init__(self, dtype):
        super().__init__()
        self.register_buffer("mask", (torch.arange(12) % 3 != 0).reshape(1, 12).to(dtype))

    def forward(self, x):
        return self.mask.clone(), x + 1


for dtype in (torch.bool, torch.float32, torch.int32):
    m = Mask(dtype)
    x = torch.randn(1, 12)
    edge = to_edge_transform_and_lower(torch.export.export(m, (x,)), partitioner=[VulkanPartitioner()])
    names = [getattr(n.target, "__name__", "") for n in edge.exported_program().graph.nodes if n.op == "call_function"]
    out = Runtime.get().load_program(edge.to_executorch().buffer).load_method("forward").execute([x])[0]
    print(f"{str(dtype):14s} delegated={names.count('executorch_call_delegate')} got={out.int().tolist()[0]} want={m.mask.int().tolist()[0]}")

Output on an H100:

torch.bool     delegated=1 got=[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] want=[0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1]
torch.float32  delegated=1 got=[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] want=[0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1]
torch.int32    delegated=1 got=[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] want=[0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1]
Repro 9 (needs ExecuTorch 1.6.0 built with Vulkan, and a GPU)
import torch
from executorch.backends.vulkan.partitioner.vulkan_partitioner import VulkanPartitioner
from executorch.exir import to_edge_transform_and_lower
from executorch.runtime import Runtime


class Rms(torch.nn.Module):
    def __init__(self, scale):
        super().__init__()
        self.scale = scale
        self.weight = torch.nn.Parameter(torch.randn(64).to(torch.bfloat16 if scale == "bf16 weight" else torch.float32))

    def forward(self, x, s):
        norm = x * torch.rsqrt(x.pow(2).mean(-1, keepdim=True) + 1e-6)
        return norm * (s if self.scale == "input" else self.weight)


x, s = torch.randn(1, 8, 64), torch.randn(1, 8, 64)
for scale in ("fp32 weight", "bf16 weight", "input"):
    m = Rms(scale).eval()
    try:
        et = to_edge_transform_and_lower(torch.export.export(m, (x, s)), partitioner=[VulkanPartitioner()]).to_executorch()
        out = Runtime.get().load_program(et.buffer).load_method("forward").execute([x, s])[0]
        print(f"scale is {scale}: loads, max abs diff {(out - m(x, s)).abs().max().item():.2e}")
    except Exception as error:
        print(f"scale is {scale}: fails to load, {str(error).split('!')[0].split('Staging.cpp:')[-1][4:]}")

Output on an H100:

scale is fp32 weight: loads, max abs diff 2.38e-07
scale is bf16 weight: fails to load,  (graph.val_is_tref(tensor_data)) is false
scale is input: fails to load,  (graph.val_is_tref(tensor_data)) is false

LeRobot
  • Decide the rows marked "needs a decision".
Problem Policies Fix Status
lerobot-export has no Vulkan backend, so there is no Vulkan bundle for lerobot-rollout --bundle.path to run. all needs a decision: an executorch_vulkan backend in LeRobot, next to executorch_xnnpack and executorch_openvino Open
lerobot-export and the torch-free lerobot-rollout --bundle.path exist only on the lerobot-export-stack branch. all needs a decision: how to bring them upstream in reviewable pieces (same row as #24684) Open
With transformers 5.22, a pi0 or pi05 checkpoint saved with older SigLIP weight names does not load: model.safetensors does not hold model.paligemma_with_expert.paligemma.model.vision_tower.embeddings.patch_embedding.weight and 436 more. pi0, pi05 huggingface/lerobot#4775 Open

cc @SS-JIA @manuelcandales @digantdesai @cbilgin

Langage dominant
Python
Étoiles
5.2k
Forks
1.2k
Merge moyen
1 j 23 h
PR mergées (30 j)
696

Préparer son environnement

Par où commencer

  1. Lisez l'issue en entier, puis le guide de contribution du projet.
  2. Signalez en commentaire que vous la prenez — cela évite que deux personnes fassent le même travail.
  3. Forkez le dépôt et travaillez sur une branche.
  4. Ouvrez une pull request qui référence le numéro de l'issue.

Autres issues de pytorch/executorch

Toutes les issues de pytorch/executorch

Issues similaires

Plus d'issues Python

Recevez les nouvelles issues par e-mail

Un résumé court des issues GitHub adaptées aux débutants.