Repository navigation
Conversation
…ow-rank broadcast operands Profiling a conv encoder-decoder (MI-GAN inpainting, fp16) showed the graph split into 7-8 XNNPACK partitions around portable upsample_nearest2d ops and ~25% of the time spent in NCHW<->NHWC transposes. upsample_nearest2d.vec with an exact x2 scale on a static 4D input is now partitioned and lowered as concatenate4 of the input along channels followed by depth_to_space_2d(block_size=2). XNNPACK has no nearest resize and its static_broadcast is not implemented at run time. This adds an XNNDepthToSpace2d node to the flatbuffer schemas and XNNCompiler. Static quantization is supported: the quantizer annotates the op with shared input/output qparams and the intermediate value carries them. Other scales, including an explicit scale_factors that is not exactly 2.0, stay portable. In ChannelsLastTaggedReshapePass, single-element operands of add/sub/mul/div/maximum/minimum (a lifted Python scalar such as the gain in x * 1.4142) no longer take part in the layout decision, and rank < 4 operands that broadcast over the trailing dims (a [H, W] map added to [N, C, H, W]) are reshaped to 4D with leading ones so they follow the NHWC operand instead of dragging the activation back to NCHW. Dequantized operands keep their rank, since a view between the dequantize and the op would carry no quant params.
🔗 Helpful Links🧪 See artifacts and rendered test results at hud.pytorch.org/pr/pytorch/executorch/24113
Note: Links to docs will display an error until the docs builds have been completed.
|
|
@pytorchbot label "release notes: xnnpack" |
|
sorry, can we split this into two PRs? to keep the changes atomic per pr instead of squishing them together. the upsample changes are additive and lower risk. that being said, a lower-rank operand with symbolic dims breaks lowering with these changes. Before, a dynamic-shape model with |
I will look into that tomorrow |
|
Done, split in two: this PR now only lowers Thanks for the dynamic-shape report, reproduced it: |
Summary
Profiling the MI-GAN inpainting model (a conv encoder-decoder, fp16) on XNNPACK showed the graph split into 7-8 delegate partitions around portable
upsample_nearest2dops. This PR lowersupsample_nearest2dx2.XNNPACK has no nearest resize, and its
static_broadcastis defined but returnsxnn_status_unsupported_parameterat reshape time. Nearest x2 is instead lowered asconcatenate4of the input with itself along channels ([N, H, W, 4C]), followed bydepth_to_space_2d(block_size=2). This adds anXNNDepthToSpace2dnode, appended at the end of theXNodeUnioninschema.fbs/runtime_schema.fbsso existing node IDs don't change, plusdefineDepthToSpace2dNodeinXNNCompiler.cpp.UpsampleNearest2dConfigonly partitions static 4D inputs with an exact x2 output. An explicitscale_factorsthat is not exactly 2.0 stays portable as well: PyTorch indexes with the given scale rather than the size ratio, soscale_factor=2.004doubles the size but picks different pixels. Static quantization is supported: the quantizer annotates the op with input/output shared qparams, and the intermediate value carries them, since neither node changes values.The
ChannelsLastTaggedReshapePasschange that was originally part of this PR (keeping NHWC across scalar and low-rank broadcast operands) moved to its own PR at review request, together with the fix for the dynamic-shape low-rank operand case reported below.Measured on MI-GAN 256/512 fp16 with the host runtime, together with that pass change, on an ExecuTorch 1.4.1-based branch: XNNPACK partitions went from 7/8 to 1, the delegated share of run time from 87/82% to 98/95%, and
Method::executedropped by 29%/28%. The output was unchanged (max abs diff 2e-3, fp16 noise).The new node needs an updated runtime. A program that uses it fails to load on an older runtime.
Review order: the serialization schema and
XNNCompiler.cpp, thenop_upsample_nearest2d.pywithUpsampleNearest2dConfigand the quantizer annotator, then the tests.Test plan
Tested on macOS arm64, with pybindings built from this branch (
cmake --preset pybind, targetportable_lib) so that the run-on-delegate stages use the new runtime node.backends/xnnpack/test/ops/test_upsample_nearest2d.pycovers x2 by scale and by size, fp16, fp32 and qs8 conv-upsample-conv lowered to one partition, and x3 andscale_factor=2.004staying portable.python -m pytest backends/xnnpack/test/ops/test_upsample_nearest2d.py backends/xnnpack/test/passes/test_channels_last_tagged_reshape.py backends/xnnpack/test/test_xnnpack_partitioner.py # 35 passedlintrunnerreports no issues on the changed files.