pytorch / pytorch/TensorRT

🐛 [Bug] execute_engine input checks name neither the engine nor the binding that failed

Open
#4,678 3 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
Python
Stars
3k
Forks
410
Avg merge
3d 18h
Merged PRs (30d)
78

Description

Bug Description

Every input check in execute_engine reports what disagreed and never which engine it
disagreed in. On a graph with more than one engine that is not enough to locate the problem,
and a refused engine writes none of its outputs, so what usually reaches the caller is an
unrelated error raised by whatever reads one of them.

core/runtime/execute_engine.cpp :: setup_input_tensors validates every input against the
binding it feeds and throws on the first disagreement:

TORCHTRT_CHECK(
    inputs[i].dtype() == binding.expected_type,
    "Expected input tensors to have type " << binding.expected_type
        << ", found type " << inputs[i].dtype());
...
TORCHTRT_CHECK(ctx->setInputShape(name.c_str(), dims), "Error while setting the input shape");

Neither message names the engine. The shape message additionally names neither the binding nor
the shape that was rejected — TensorRT itself reports both, and that report is discarded and
replaced with a fixed string:

IExecutionContext::setInputShape: Error Code 3: API Usage Error (Parameter check failed,
  condition: engineDims.d[i] == dims.d[i]. Static dimension mismatch while setting input shape
  for relu. Set dimensions are [8,17]. Expected dimensions are [8,16].)

torch.ops.tensorrt.set_logging_level(4) does not close the gap for the exception: the engine
name appears only in the LOG_DEBUG line that runs before the checks, so it is absent from
any log captured at the default level and absent from the exception in every case.

On a 14-engine model this made every runtime failure a search. These are all the diagnostics
a caller got:

Expected input tensors to have type Int, found type long int
Error while setting the input shape
CUDA out of memory. Tried to allocate 15.62 GiB.

and, when the refused engine's unwritten outputs were read further on:

a Tensor with 0 elements cannot be converted to Scalar

To Reproduce

docker run --rm --gpus all --ipc=host -v "$PWD":/w -w /w \
        nvcr.io/nvidia/pytorch:26.07-py3 python repro.py

repro.py

import torch
import torch.nn as nn
import torch_tensorrt

ROWS, COLS = 8, 16


class TwoEngines(nn.Module):
    """A graph split in two, so 'which engine?' is a real question."""

    def forward(self, x: torch.Tensor) -> torch.Tensor:
        a = x * 2.0
        b = torch.relu(a)  # pinned to Torch below, which splits the graph in two
        return torch.sigmoid(b + 1.0)


def engine_modules(gm: torch.fx.GraphModule) -> list[tuple[str, torch.nn.Module]]:
    """Returns the (name, module) pairs of ``gm``'s TensorRT submodules, in graph order."""
    return [
        (name, mod)
        for name, mod in gm.named_children()
        if getattr(mod, "serialized_engine", None) is not None
    ]


def message_for(call) -> str:
    """Runs ``call`` and returns the exception message it raises."""
    try:
        call()
    except Exception as exc:  # pylint: disable=broad-except
        return str(exc)
    raise RuntimeError("expected the call to fail, but it succeeded")


def main() -> None:
    model = TwoEngines().eval().cuda()
    x = torch.randn(ROWS, COLS, device="cuda")
    exported = torch.export.export(model, (x,))
    gm = torch_tensorrt.dynamo.compile(
        exported,
        inputs=(x,),
        min_block_size=1,
        pass_through_build_failures=True,
        # The only scaffolding here: it places an engine boundary so the graph holds two
        # engines. The diagnostics being reported are the same with one engine.
        torch_executed_ops={"torch.ops.aten.relu.default"},
    )
    engines = engine_modules(gm)
    print(f"engines in the graph: {[name for name, _ in engines]}")
    assert len(engines) > 1, "expected the partitioner to produce more than one engine"

    name, mod = engines[-1]
    mod.setup_engine()
    # The binding names are reachable only through the engine's __str__; the torchbind class
    # exposes no accessor for a binding's name, dtype or shape.
    binding_names = [b for b in str(mod.engine).split() if b.startswith("relu")]
    print(f"failing engine: {name}, input bindings: {binding_names}")

    cases = {
        "dtype check": lambda: torch.ops.tensorrt.execute_engine(
            [torch.zeros(ROWS, COLS, dtype=torch.int32, device="cuda")], mod.engine
        ),
        "shape check": lambda: torch.ops.tensorrt.execute_engine(
            [torch.zeros(ROWS, COLS + 1, device="cuda")], mod.engine
        ),
    }

    reproduced = False
    for label, call in cases.items():
        msg = message_for(call).strip()
        names_engine = name in msg
        names_binding = any(b in msg for b in binding_names)
        print(f"\n{label} raised:\n    " + msg.replace("\n", "\n    "))
        print(f"  names the engine ({name}): {names_engine}")
        print(f"  names a binding {binding_names}: {names_binding}")
        reproduced = reproduced or not names_engine

    print(f"\nreproduced: {reproduced}")
    if reproduced:
        print(
            "At least one check reports the disagreement without saying which engine it "
            "came from."
        )


if __name__ == "__main__":
    main()

output

engines in the graph: ['_run_on_acc_0', '_run_on_acc_2']
failing engine: _run_on_acc_2, input bindings: ['relu']

dtype check raised:
    [Error thrown at core/runtime/execute_engine.cpp:110] Expected inputs[i].dtype() == expected_type to be true but got false
    Expected input tensors to have type Float, found type int
  names the engine (_run_on_acc_2): False
  names a binding ['relu']: False
ERROR: [Torch-TensorRT] - IExecutionContext::setInputShape: Error Code 3: API Usage Error (Parameter check failed, condition: engineDims.d[i] == dims.d[i]. Static dimension mismatch while setting input shape for relu. Set dimensions are [8,17]. Expected dimensions are [8,16]. In setInputShape at /_src/runtime/api/executionContext.cpp:2295)

shape check raised:
    [Error thrown at core/runtime/execute_engine.cpp:149] Expected compiled_engine->exec_ctx->setInputShape(name.c_str(), dims) to be true but got false
    Error while setting the input shape
  names the engine (_run_on_acc_2): False
  names a binding ['relu']: False

reproduced: True
At least one check reports the disagreement without saying which engine it came from.

Expected behavior

Each check should name the engine and the binding, and the shape check should carry the shape
it rejected alongside the one that was declared. Concretely:

[_run_on_acc_2_engine] input 1 ("relu"): expected type Float, found type Int
[_run_on_acc_2_engine] input 1 ("relu"): rejected shape [8, 17], engine declares [8, 16]

Two related things would help alongside it:

  • The out-of-memory paths in the same function are worth catching for the same reason — a bare
    CUDA out of memory. Tried to allocate 15.62 GiB. says nothing about which engine asked for
    how much.
  • A binding's name, dtype and shape are currently reachable only by parsing the engine's
    __str__; the torchbind class exposes no accessor for them. An accessor would let callers
    diagnose this themselves.

Environment

Build information about Torch-TensorRT can be found by turning on debug messages

  • Pytorch NGC container : 26.07-py3

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start in core/runtime/execute_engine.cpp at setup_input_tensors and use repro.py to reproduce the dtype and shape failures. Trace the binding metadata and engine context used by each check. Done means the reported failures identify the engine and binding, and shape errors include rejected and declared shapes as described in the expected behavior.

Written by the indexing model from the issue text.

Assessment

Tech stack
cpp, python
Domain
compilers, machine-learning
Issue type
Bug
Difficulty
3/5
Estimated time
1-2 days
Activity status
Active
Clarity
Clearly specified
Newbie friendliness
70/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.