Skip to content

OpenVINO: fix wrong outputs when a partition returns a copy of its input - #24478

Open
pytorchbot wants to merge 1 commit into
cherry-pick-24396-by-pytorch_bot_bot_from
cherry-pick-24466-by-pytorch_bot_bot_
Open

pytorchbot wants to merge 1 commit into
cherry-pick-24396-by-pytorch_bot_bot_from
cherry-pick-24466-by-pytorch_bot_bot_

Conversation

@pytorchbot

Copy link
Copy Markdown
Collaborator

What is wrong today

When an OpenVINO partition returns a copy of one of its inputs, ExecuTorch gets stale memory back. For example:

class M(torch.nn.Module):
    def forward(self, x):
        y = x.clone()
        return y, torch.sin(y)

Lowered with OpenvinoPartitioner for CPU, y holds whatever its buffer held before, and torch.sin(y) is wrong too. OpenVINO can even overwrite x, so later ops that read x go wrong as well. The same happens for x.detach(), x[:, :], and chains like x.clone().clone(). This made a robot policy exported with LeRobot return wrong actions.

The cause is in OpenVINO. Its PyTorch frontend converts aten.clone and aten.alias_copy to nothing, so the converted model returns its input directly. ExecuTorch's runtime sets its output tensors after its input tensors. In that order the CPU plugin does not write such an output, and it can overwrite the input with the old contents of the output buffer. A plain OpenVINO script, without ExecuTorch, shows the same problem in every release tried, from 2025.2.0 to 2026.4.1 and a 2026.5 nightly.

What this change does

The partitioner leaves such a copy out of the partition when its result leaves the partition, so ExecuTorch's CPU kernel makes the copy. This covers aten.clone, aten.alias_copy, and dim_order_ops._clone_dim_order (which becomes aten.clone before conversion), including chains of them. A copy used only inside the partition stays there. OpenVINO skips it anyway, and taking it out could hand OpenVINO an input in a dim order it does not read.

Not touched here: the backend still reads and writes partition inputs and outputs in the default dim order, so a channels-last tensor at the partition edge can give wrong values.

Setting the output tensors first also avoids the bug, but only through an undocumented detail of the plugin, so this change does not rely on it.

With dim order turned off, a channels-last copy of an input that leaves the partition now fails at export instead of giving wrong values.

execute_layer_test gets an optional compile_config, to test lowering with dim order turned off, where a clone is aten.clone.

Testing

  • New tests in backends/openvino/tests/ops/test_copy.py. test_copy_of_input_as_output fails without the partitioner change and passes with it. test_copy_of_input_used_inside checks that a copy used only inside the partition stays there.
  • All OpenVINO op tests pass on Linux x86_64 with OpenVINO 2026.4.1.
  • The robot policy above now exports to OpenVINO and passes its accuracy check.

…put (#24466)

### What is wrong today

When an OpenVINO partition returns a copy of one of its inputs,
ExecuTorch gets stale memory back. For example:

```python
class M(torch.nn.Module):
    def forward(self, x):
        y = x.clone()
        return y, torch.sin(y)
```

Lowered with `OpenvinoPartitioner` for CPU, `y` holds whatever its
buffer held before, and `torch.sin(y)` is wrong too. OpenVINO can even
overwrite `x`, so later ops that read `x` go wrong as well. The same
happens for `x.detach()`, `x[:, :]`, and chains like
`x.clone().clone()`. This made a robot policy exported with LeRobot
return wrong actions.

The cause is in OpenVINO. Its PyTorch frontend converts `aten.clone` and
`aten.alias_copy` to nothing, so the converted model returns its input
directly. ExecuTorch's runtime sets its output tensors after its input
tensors. In that order the CPU plugin does not write such an output, and
it can overwrite the input with the old contents of the output buffer. A
plain OpenVINO script, without ExecuTorch, shows the same problem in
every release tried, from 2025.2.0 to 2026.4.1 and a 2026.5 nightly.

### What this change does

The partitioner leaves such a copy out of the partition when its result
leaves the partition, so ExecuTorch's CPU kernel makes the copy. This
covers `aten.clone`, `aten.alias_copy`, and
`dim_order_ops._clone_dim_order` (which becomes `aten.clone` before
conversion), including chains of them. A copy used only inside the
partition stays there. OpenVINO skips it anyway, and taking it out could
hand OpenVINO an input in a dim order it does not read.

Not touched here: the backend still reads and writes partition inputs
and outputs in the default dim order, so a channels-last tensor at the
partition edge can give wrong values.

Setting the output tensors first also avoids the bug, but only through
an undocumented detail of the plugin, so this change does not rely on
it.

With dim order turned off, a channels-last copy of an input that leaves
the partition now fails at export instead of giving wrong values.

`execute_layer_test` gets an optional `compile_config`, to test lowering
with dim order turned off, where a clone is `aten.clone`.

### Testing

- New tests in `backends/openvino/tests/ops/test_copy.py`.
`test_copy_of_input_as_output` fails without the partitioner change and
passes with it. `test_copy_of_input_used_inside` checks that a copy used
only inside the partition stays there.
- All OpenVINO op tests pass on Linux x86_64 with OpenVINO 2026.4.1.
- The robot policy above now exports to OpenVINO and passes its accuracy
check.

(cherry picked from commit 81a4666)
@pytorch-bot

pytorch-bot Bot commented Nov 3, 2026 •

Copy link
Copy Markdown

🔗 Helpful Links

🧪 See artifacts and rendered test results at hud.pytorch.org/pr/pytorch/executorch/24478

Note: Links to docs will display an error until the docs builds have been completed.

❌ 1 New Failure, 1 Unrelated Failure

As of commit 3a0b88c with merge base 4db778e (image):

NEW FAILURE - The following job has failed:

BROKEN TRUNK - The following job failed but were present on the merge base:

👉 Rebase onto the `viable/strict` branch to avoid these failures

This comment was automatically generated by Dr. CI and updates every 15 minutes.

@meta-cla meta-cla Bot added the CLA Signed This label is managed by the Facebook bot. Authors need to sign the CLA before a PR can be reviewed. label Nov 3, 2026

This branch was previously deployed

1 inactive deployment
cadence — 3a0b88c2 Deployed Nov 3, 2026 by pytorchbot via hifi-op-test / hifi4 #36139
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

CLA Signed This label is managed by the Facebook bot. Authors need to sign the CLA before a PR can be reviewed.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants