Skip to content

Conversation

AdrianLundell
Copy link
Collaborator

@AdrianLundell AdrianLundell commented Sep 12, 2025

  • Insert transposes for input/output iff the incoming/outgoing data is
    in channels first format.
  • For testing using tosa_reference_mode, transpose numpy arrays to and
    from correct data format since numpy doesn't have the concept of
    dim_order.
  • Remove checks for channels_first only input.
  • Remove check for not changing dim_order before to_tosa_memory_format
    pass since the behaviour of channel last tensors is non-predictable.
  • Add dim order testing of example networks and mv2
  • Add a section to the documentation about memory formats.

cc @digantdesai @freddan80 @per @zingo @oscarandersson8218

mergennachin and others added 2 commits September 11, 2025 15:32
Summary:
Pull Request resolved: pytorch#14191

Redoing pytorch#14111 with additional fixes

Reviewed By: digantdesai

Differential Revision: D82171193
- Insert transposes for input/output iff the incoming/outgoing data is
  in channels first format.
- For testing using tosa_reference_mode, transpose numpy arrays to and
  from correct data format since numpy doesn't have the concept of
  dim_order.
- Remove checks for channels_first only input.
- Remove check for not changing dim_order before to_tosa_memory_format
  pass since the behaviour of channel last tensors is non-predictable.
- Add dim order testing of example networks and mv2
- Add a section to the documentation about memory formats.

Signed-off-by: Adrian Lundell <[email protected]>
Change-Id: I05548b9f3b4671da6faad90a9dd7366fda4498d6
@AdrianLundell AdrianLundell added this to the 1.0.0 milestone Sep 12, 2025
@AdrianLundell AdrianLundell added the partner: arm For backend delegation, kernels, demo, etc. from the 3rd-party partner, Arm label Sep 12, 2025
@AdrianLundell AdrianLundell added ciflow/trunk release notes: arm Changes to the ARM backend delegate labels Sep 12, 2025
Copy link

pytorch-bot bot commented Sep 12, 2025

🔗 Helpful Links

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

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

❌ 3 New Failures, 1 Unrelated Failure

As of commit adec5aa with merge base cf6e895 (image):

NEW FAILURES - The following jobs have 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 Sep 12, 2025
@zingo
Copy link
Collaborator

zingo commented Sep 14, 2025

As #14191 has been merged I rebased this PR to "clean" out #14191 from the PR

@facebook-github-bot
Copy link
Contributor

@mergennachin has imported this pull request. If you are a Meta employee, you can view this in D82449155.

Copy link
Contributor

@digantdesai digantdesai left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review automatically exported from Phabricator review in Meta.

@@ -249,15 +249,6 @@ class EthosUBackend final : public ::executorch::runtime::BackendInterface {
handles.inputs->io[i].elem_size);
return Error::InvalidProgram;
}
supported = executorch::runtime::is_contiguous_dim_order(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this implies it can handle anything i.e. transpose op is inserted if it was needed. But what about asserting expectations. I.e. if user exported with NCHW and we inserted a transpose_to_nhwc AoT, what if now user supplied NHWC (instead of assumed NCHW), shouldn't we validate since we don't "check and optionally transpose" at runtime.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good point and I agree, however since we are past the branch cutoff date and we need this patch to unblock a major use case for us, may I ask to ignore this for now and fix this in a later PR?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No worries. I assumed that and stamped already :)

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does the stamp mean we can merge, or do we still wait och Meta to merge?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

haha good I was in the non-GA mode already where stamp --> you merge --> Internal failure --> we revert

But looking at the activity from @mergennachin he is, rightfully, still in GA mental mode for this GA critical PR. So if the internal CI is clean, he or I can merge this.

Copy link
Collaborator

@zingo zingo Sep 16, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, Im happy and you handle it fast so no problem, I just want to avoid an n"o one does it" situation 😆 as there might be a merge/sync to 1.0 coming up.

And I also dont expect any PR not 1.0 milestone tagged to be be merged. If so its just a bonus.

@AdrianLundell
Copy link
Collaborator Author

Failing arm-backend test is a very small numerical diff for backends/arm/test/ops/test_var.py::test_var_dim_tosa_INT[var_3d_dim_neg_1_no_keep_dim_biased] -> Flaky test, not related.

Other failures are non-arm specific.

@facebook-github-bot
Copy link
Contributor

@mergennachin has imported this pull request. If you are a Meta employee, you can view this in D82449155.

@mergennachin
Copy link
Contributor

The new tests are failing. Here's an example error message:

=================================== FAILURES ===================================
_________________ test_dim_order_u55_INT[channels_last_output] _________________

module = <class 'executorch.backends.arm.test.misc.test_dim_order.ChannelsLastOutput'>

    [@common](https://www.internalfb.com/intern/profile/common).XfailIfNoCorstone300
    [@common](https://www.internalfb.com/intern/profile/common).parametrize("module", test_modules)
    def test_dim_order_u55_INT(module):
        pipeline = EthosU55PipelineINT[input_t1](module(), module.inputs, [])
>       pipeline.run()

../buck-out/v2/gen/fbcode/6253fc99cd6e7a23/executorch/backends/arm/test/__dim_order__/dim_order#link-tree/executorch/backends/arm/test/misc/test_dim_order.py:116: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../buck-out/v2/gen/fbcode/6253fc99cd6e7a23/executorch/backends/arm/test/__dim_order__/dim_order#link-tree/executorch/backends/arm/test/tester/test_pipeline.py:281: in run
    raise e
../buck-out/v2/gen/fbcode/6253fc99cd6e7a23/executorch/backends/arm/test/__dim_order__/dim_order#link-tree/executorch/backends/arm/test/tester/test_pipeline.py:278: in run
    stage()
../buck-out/v2/gen/fbcode/6253fc99cd6e7a23/executorch/backends/arm/test/__dim_order__/dim_order#link-tree/executorch/backends/arm/test/tester/test_pipeline.py:89: in __call__
    self.func(*self.args, **self.kwargs)
../buck-out/v2/gen/fbcode/6253fc99cd6e7a23/executorch/backends/arm/test/__dim_order__/dim_order#link-tree/executorch/backends/arm/test/tester/arm_tester.py:491: in run_method_and_compare_outputs
    self._compare_outputs(
../buck-out/v2/gen/fbcode/6253fc99cd6e7a23/executorch/backends/arm/test/__dim_order__/dim_order#link-tree/executorch/backends/arm/test/tester/arm_tester.py:678: in _compare_outputs
    raise e
../buck-out/v2/gen/fbcode/6253fc99cd6e7a23/executorch/backends/arm/test/__dim_order__/dim_order#link-tree/executorch/backends/arm/test/tester/arm_tester.py:662: in _compare_outputs
    super()._compare_outputs(
../buck-out/v2/gen/fbcode/6253fc99cd6e7a23/executorch/backends/arm/test/__dim_order__/dim_order#link-tree/executorch/backends/test/harness/tester.py:423: in _compare_outputs
    Tester._assert_outputs_equal(
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

model_output = (tensor([[[[ 1.0034, 24.8351],
          [ 4.0138, 35.8729]],

         [[ 9.0310, 48.9177],
          [16.0550, 63.9692]]]]),)
ref_output = (tensor([[[[ 1.0034,  4.0138],
          [ 9.0310, 16.0550]],

         [[24.8351, 35.8729],
          [48.9177, 63.9692]]]]),)
atol = 0.2518597671985626, rtol = 0.001, statistics_callback = None

    [@staticmethod](https://www.internalfb.com/intern/profile/staticmethod)
    def _assert_outputs_equal(
        model_output,
        ref_output,
        atol=1e-03,
        rtol=1e-03,
        statistics_callback: Callable[[ErrorStatistics], None] | None = None,
    ):
        """
        Helper testing function that asserts that the model output and the reference output
        are equal with some tolerance. Due to numerical differences between eager mode and
        the XNNPACK's backend, we relax the detal such that absolute tolerance is 1e-3. and
        relative tolerance is 1e-3. In the event that the computation was quantized, we
        further relax the tolerance to one quantized step (equal to the quantization scale).
        This allows the quantized value to differ by 1 between the reference and model output.
        """
    
        assert len(model_output) == len(ref_output)
    
        for i in range(len(model_output)):
            model = model_output[i]
            ref = ref_output[i]
    
            error_stats = ErrorStatistics.from_tensors(model, ref)
            if statistics_callback is not None:
                statistics_callback(error_stats)
    
            assert (
                ref.shape == model.shape
            ), f"Output {i} shape {model.shape} does not match reference output shape {ref.shape}"
            if model.dtype == torch.bool:
                assert torch.equal(model, ref), (
                    f"Output {i} (bool tensor) does not match reference output.
"
                    f"\tShape: {model.shape}
"
                    f"\tMismatched count: {(model != ref).sum().item()} / {model.numel()}
"
                )
            else:
>               assert torch.allclose(
                    model,
                    ref,
                    atol=atol,
                    rtol=rtol,
                    equal_nan=True,
                ), (
                    f"Output {i} does not match reference output.
"
                    f"\tGiven atol: {atol}, rtol: {rtol}.
"
                    f"\tOutput tensor shape: {model.shape}, dtype: {model.dtype}
"
                    f"\tDifference: max: {torch.max(model-ref)}, abs: {torch.max(torch.abs(model-ref))}, mean abs error: {torch.mean(torch.abs(model-ref).to(torch.double))}.
"
                    f"\t-- Model vs. Reference --
"
                    f"\t Numel: {model.numel()}, {ref.numel()}
"
                    f"\tMedian: {model.median()}, {ref.median()}
"
                    f"\t  Mean: {model.to(torch.double).mean()}, {ref.to(torch.double).mean()}
"
                    f"\t   Max: {model.max()}, {ref.max()}
"
                    f"\t   Min: {model.min()}, {ref.min()}
"
                )
E               AssertionError: Output 0 does not match reference output.
E               	Given atol: 0.2518597671985626, rtol: 0.001.
E               	Output tensor shape: torch.Size([1, 2, 2, 2]), dtype: torch.float32
E               	Difference: max: 20.821361541748047, abs: 32.862632751464844, mean abs error: 13.420998275279999.
E               	-- Model vs. Reference --
E               	 Numel: 8, 8
E               	Median: 16.055025100708008, 16.055025100708008
E               	  Mean: 25.462266877293587, 25.462266877293587
E               	   Max: 63.969242095947266, 63.969242095947266
E               	   Min: 1.0034390687942505, 1.0034390687942505

../buck-out/v2/gen/fbcode/6253fc99cd6e7a23/executorch/backends/arm/test/__dim_order__/dim_order#link-tree/executorch/backends/test/harness/tester.py:378: AssertionError

@AdrianLundell
Copy link
Collaborator Author

@mergennachin The only thing that I can come up with that would cause this is that you need to update the way you run the tests internally to match the changes made in this PR. Would it be OK to disable the tests for now and put a ticket on you to fix this, or do you have any other solutions you prefer?

@digantdesai
Copy link
Contributor

yeah likely not a problem with this PR. Let me take a look.

@facebook-github-bot facebook-github-bot merged commit 5348ea9 into pytorch:main Sep 17, 2025
385 of 392 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
ciflow/trunk CLA Signed This label is managed by the Facebook bot. Authors need to sign the CLA before a PR can be reviewed. partner: arm For backend delegation, kernels, demo, etc. from the 3rd-party partner, Arm release notes: arm Changes to the ARM backend delegate
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants