Repository navigation
XNNPACK: read inputs with a non-default dim order in their memory layout - #24081
Conversation
🔗 Helpful Links🧪 See artifacts and rendered test results at hud.pytorch.org/pr/pytorch/executorch/24081
Note: Links to docs will display an error until the docs builds have been completed. ❌ 1 New FailureAs of commit bf19caf with merge base 4628b2b ( NEW FAILURE - The following job has failed:
This comment was automatically generated by Dr. CI and updates every 15 minutes. |
|
@claude please review |
|
those CI failures look likely to actually be related |
|
Claude finished @JakeStevens's task in 3m 34s —— View job The preprocess fix looks right for float inputs, but the new test feeds scrambled input data, so it fails in CI whether or not the fix works. It needs to be fixed and the coverage widened before this merges. Detailed reviewPR Review: #24081SummaryThe PR declares XNNPACK delegate inputs whose dim order is neither contiguous nor channels-last in memory order, then adds a static transpose at the start of the graph to restore the logical layout. The preprocess logic looks correct: the perm direction is right, the transpose prologue runs before other nodes, and external ids are kept. The main problems:
Code Quality
Testing
RecommendationRequest Changes The new test is wrong and fails on every CI platform, so the fix has no passing coverage yet. Fix the test input and add a non-self-inverse dim order. Also decide what happens to quantized inputs (partitioner rejection rather than a lowering-time |
|
I'm on it, addressing the incorrect test. |
|
Ok, the blocker with the incorrect input to the test is fixed together with other things. @JakeStevens, please check again. |
|
Rebase will resolve failing arm CI test. @JakeStevens could you review again? |
XNNExecutor reshapes every external input with its sizes listed in dim order, i.e. as the buffer is laid out in memory, but preprocess defined the input from its logical shape. An input recorded with, e.g., dim order (1, 0, 2) (a transposed example input) therefore failed shape propagation with xnn_status_invalid_parameter, or was read with its axes swapped. Define such inputs in memory order and transpose them back to the logical layout at the start of the graph. Channels-last inputs keep going through ChannelsLastTaggedReshapePass. pytorch#14735 was the constant-tensor side of this.
…rder Outputs get the same treatment as inputs: defined in memory order, with a static transpose from the logical layout at the end of the graph. Quantized externals keep their quant params (channel_dim remapped) instead of failing the lowering. Externals are matched by external id, the unread input_ids rewrite and the unused assert_default_dim_order are dropped, and the NHWC check is public. The test moves to ops/test_io_dim_order.py: it passed a reinterpreted input, which the bindings now copy into the exported layout. The new cases cover a non-self-inverse dim order, dynamic shapes, 4D, channels_last_3d, a mixed default/non-default pair, outputs and a QuantizeInputs int8 input.
9403718 to
d257d5d
Compare
|
Rebased onto main. |
|
Thanks for the update, the transpose directions and the dynamic-shape handling look right. Two problems with how the dim order is determined, though, and one of them is a regression: 1.
So preprocess declares the external as 2. Output dim orders are read after the XNNPACK passes have run. Smaller things:
Review drafted with Claude Code. |
…sses torch's dim_order() breaks size-1 ties differently from the emitter's dim_order_from_stride, and the passes can make a transposed output contiguous, so both are now read from the lowered program before the passes run. Quantized externals that need a transpose must be per-tensor.
|
Dim orders now come from |
JakeStevens
left a comment
There was a problem hiding this comment.
I checked the transpose directions and the runtime reshape and resize paths, and they look right. The one thing I'd like addressed before merging is a transposed input feeding a dynamically quantized op, which now aborts lowering (see the comment on line 154).
Review drafted with Claude Code.
| if quantized: | ||
| # Activations are quantized per tensor, so the transpose keeps the | ||
| # quant params as they are. | ||
| if not isinstance(union.quant_params, PerTensorQuant): |
There was a problem hiding this comment.
A transposed input that feeds a dynamically quantized op (the 8da4w/8da8w linear path) reaches this raise. For dynamic quant, get_quant_params returns PerTokenDynamicQuant, and XNNCompiler.cpp:410-418 requires that tensor to keep its external id. So the transpose can't be inserted in front of it, and clearing the id at line 163 would break it at runtime anyway.
The partitioner still claims these inputs, so to_edge_transform_and_lower now aborts where it used to lower and only misbehave at runtime. Could the partitioner decline inputs with a non-default dim order that feed a dynamic-quant op? Or could the transpose go before the dynamic-quant convert? If neither fits in this PR, please fix the message ("must be quantized per tensor" is misleading for a float input that is dynamically quantized) and add a test for this path.
There was a problem hiding this comment.
The external stays fp32: dynamic quant is an internal XNNConvert after the transpose (410-418 is the legacy dq_datatype path, never serialized). Added test_qd8_linear_permuted_input, which fails on main with invalid_parameter.
Also give symbolic-size externals an empty dim order instead of raising.
JakeStevens
left a comment
There was a problem hiding this comment.
thanks for taking in all the feedback! ping us if (when..) we forget to check back in on CI
Summary
A delegate input whose dim order is neither contiguous nor channels-last (e.g.
(1, 0, 2)from a transposed example input) is serialized with its logical sizes, butXNNExecutorreshapes it with sizes in dim order, so execution fails withxnn_status_invalid_parameteror reads swapped axes. Define such inputs in memory order and transpose back at the start of the graph. #14735 was the constant-tensor side of this.Test plan
New
ops/test_io_dim_order.pytests fail before, pass after.backends/xnnpack/test/{ops,passes,serialization}unchanged.cc @GregoryComer @digantdesai @cbilgin @JakeStevens @nil-is-all