Repository navigation
Wire batch-norm fusion into CpuBackend.preprocess (#24193) - #24193
Conversation
🔗 Helpful Links🧪 See artifacts and rendered test results at hud.pytorch.org/pr/pytorch/executorch/24193
Note: Links to docs will display an error until the docs builds have been completed. ❌ 2 New Failures, 50 PendingAs of commit 63d563f with merge base 5723674 ( NEW FAILURES - The following jobs have failed:
This comment was automatically generated by Dr. CI and updates every 15 minutes. |
|
@JakeStevens has exported this pull request. If you are a Meta employee, you can view the originating Diff in D126784606. |
digantdesai
left a comment
There was a problem hiding this comment.
Review automatically exported from Phabricator review in Meta.
This PR needs a
|
Summary: Run the shared `FuseBatchNormWithConvPass` and `FuseBatchNormWithLinearPass` in `CpuBackend.preprocess`. Unfused `_native_batch_norm_legit_no_training` already executes through the reference provider, but as a separate kernel with its own serialized weight and stats; folding it into the preceding conv/linear removes that kernel from the delegate. The passes are listed in `CPU_PREPROCESS_PASSES` (mirroring `XNNPACKPassManager.passes`) so every lowering flow gets them from one extension point. Fusion introduces `get_attr` constants, so preprocess follows with `lift_constant_tensor_pass` (the native serializer rejects unlifted constants), then drops parameter/buffer/constant inputs left without users. Without that step the delegate serialized the original weights and batch norm stats next to the fused ones. Authored with Claude Code. Reviewed By: digantdesai Differential Revision: D126784606
3ea6045 to
0f5523a
Compare
Summary: Run the shared `FuseBatchNormWithConvPass` and `FuseBatchNormWithLinearPass` in `CpuBackend.preprocess`. Unfused `_native_batch_norm_legit_no_training` already executes through the reference provider, but as a separate kernel with its own serialized weight and stats; folding it into the preceding conv/linear removes that kernel from the delegate. The passes are listed in `CPU_PREPROCESS_PASSES` (mirroring `XNNPACKPassManager.passes`) so every lowering flow gets them from one extension point. Fusion introduces `get_attr` constants, so preprocess follows with `lift_constant_tensor_pass` (the native serializer rejects unlifted constants), then drops parameter/buffer/constant inputs left without users. Without that step the delegate serialized the original weights and batch norm stats next to the fused ones. Authored with Claude Code. Reviewed By: digantdesai Differential Revision: D126784606
Summary: Run the shared `FuseBatchNormWithConvPass` and `FuseBatchNormWithLinearPass` in `CpuBackend.preprocess`. Unfused `_native_batch_norm_legit_no_training` already executes through the reference provider, but as a separate kernel with its own serialized weight and stats; folding it into the preceding conv/linear removes that kernel from the delegate. The passes are listed in `CPU_PREPROCESS_PASSES` (mirroring `XNNPACKPassManager.passes`) so every lowering flow gets them from one extension point. Fusion introduces `get_attr` constants, so preprocess follows with `lift_constant_tensor_pass` (the native serializer rejects unlifted constants), then drops parameter/buffer/constant inputs left without users. Without that step the delegate serialized the original weights and batch norm stats next to the fused ones. Authored with Claude Code. Reviewed By: digantdesai Differential Revision: D126784606
Summary: CPU partitioning and delegate I/O required every tensor to be FP32, leaving indices, masks and integer outputs outside the delegate. Accept static uint8, int8, int16, int32, int64 and bool tensors, and validate runtime I/O against the serialized dtype. Existing allocation and ET kernel routes preserve the values without conversion through FP32. Integer delegation also exposes `index.Tensor`/`index_put`, whose indices are `Tensor?[]`. Native serialization emits a plain tensor list when every index is present, but ET's kernels unbox a list of optional tensors. Mark those Reference routes with `optional_tensor_lists` so the CPU runtime binds optional lists for them; the shared serializer and the other Native engines are unchanged. Add exact runtime regressions for integer precision, indices, mixed outputs, constants and optional index lists. Dynamic shapes/scalars and quantized execution remain separate. The Native schema and storage contract do not change. Authored with AI assistance using Codex and Claude Code. Reviewed By: digantdesai Differential Revision: D123332329
Summary: Adds `FuseBatchNormWithLinearPass` to `backends/transforms`, the linear counterpart of `FuseBatchNormWithConvPass`. It folds an inference batch norm into the preceding `aten.linear` weight and bias using `torch.nn.utils.fusion.fuse_linear_bn_weights`, so backends can drop the BN without serializing extra weights. Fusion only happens when it is numerically equivalent: the linear output must be rank 2 (the only case where BN's channel dim is linear's output dim), every weight/bias/running-stat input must be a constant parameter, BN must only be consumed through `getitem(0)`, and training-mode `native_batch_norm` is skipped. Authored with Claude Code. Reviewed By: digantdesai Differential Revision: D125532471
Summary: Run the shared `FuseBatchNormWithConvPass` and `FuseBatchNormWithLinearPass` in `CpuBackend.preprocess`. Unfused `_native_batch_norm_legit_no_training` already executes through the reference provider, but as a separate kernel with its own serialized weight and stats; folding it into the preceding conv/linear removes that kernel from the delegate. The passes are listed in `CPU_PREPROCESS_PASSES` (mirroring `XNNPACKPassManager.passes`) so every lowering flow gets them from one extension point. Fusion introduces `get_attr` constants, so preprocess follows with `lift_constant_tensor_pass` (the native serializer rejects unlifted constants), then drops parameter/buffer/constant inputs left without users. Without that step the delegate serialized the original weights and batch norm stats next to the fused ones. Authored with Claude Code. Reviewed By: digantdesai Differential Revision: D126784606
Summary: Run the shared `FuseBatchNormWithConvPass` and `FuseBatchNormWithLinearPass` in `CpuBackend.preprocess`. Unfused `_native_batch_norm_legit_no_training` already executes through the reference provider, but as a separate kernel with its own serialized weight and stats; folding it into the preceding conv/linear removes that kernel from the delegate. The passes are listed in `CPU_PREPROCESS_PASSES` (mirroring `XNNPACKPassManager.passes`) so every lowering flow gets them from one extension point. Fusion introduces `get_attr` constants, so preprocess follows with `lift_constant_tensor_pass` (the native serializer rejects unlifted constants), then drops parameter/buffer/constant inputs left without users. Without that step the delegate serialized the original weights and batch norm stats next to the fused ones. Authored with Claude Code. Reviewed By: digantdesai Differential Revision: D126784606
77f8a3b to
42720b9
Compare
Summary: Run the shared `FuseBatchNormWithConvPass` and `FuseBatchNormWithLinearPass` in `CpuBackend.preprocess`. Unfused `_native_batch_norm_legit_no_training` already executes through the reference provider, but as a separate kernel with its own serialized weight and stats; folding it into the preceding conv/linear removes that kernel from the delegate. The passes are listed in `CPU_PREPROCESS_PASSES` (mirroring `XNNPACKPassManager.passes`) so every lowering flow gets them from one extension point. Fusion introduces `get_attr` constants, so preprocess follows with `lift_constant_tensor_pass` (the native serializer rejects unlifted constants), then drops parameter/buffer/constant inputs left without users. Without that step the delegate serialized the original weights and batch norm stats next to the fused ones. Authored with Claude Code. Reviewed By: digantdesai Differential Revision: D126784606
Summary: Run the shared `FuseBatchNormWithConvPass` and `FuseBatchNormWithLinearPass` in `CpuBackend.preprocess`. Unfused `_native_batch_norm_legit_no_training` already executes through the reference provider, but as a separate kernel with its own serialized weight and stats; folding it into the preceding conv/linear removes that kernel from the delegate. The passes are listed in `CPU_PREPROCESS_PASSES` (mirroring `XNNPACKPassManager.passes`) so every lowering flow gets them from one extension point. Fusion introduces `get_attr` constants, so preprocess follows with `lift_constant_tensor_pass` (the native serializer rejects unlifted constants), then drops parameter/buffer/constant inputs left without users. Without that step the delegate serialized the original weights and batch norm stats next to the fused ones. Authored with Claude Code. Reviewed By: digantdesai Differential Revision: D126784606
Summary: Run the shared `FuseBatchNormWithConvPass` and `FuseBatchNormWithLinearPass` in `CpuBackend.preprocess`. Unfused `_native_batch_norm_legit_no_training` already executes through the reference provider, but as a separate kernel with its own serialized weight and stats; folding it into the preceding conv/linear removes that kernel from the delegate. The passes are listed in `CPU_PREPROCESS_PASSES` (mirroring `XNNPACKPassManager.passes`) so every lowering flow gets them from one extension point. Fusion introduces `get_attr` constants, so preprocess follows with `lift_constant_tensor_pass` (the native serializer rejects unlifted constants), then drops parameter/buffer/constant inputs left without users. Without that step the delegate serialized the original weights and batch norm stats next to the fused ones. Authored with Claude Code. Reviewed By: digantdesai Differential Revision: D126784606
Summary: Run the shared `FuseBatchNormWithConvPass` and `FuseBatchNormWithLinearPass` in `CpuBackend.preprocess`. Unfused `_native_batch_norm_legit_no_training` already executes through the reference provider, but as a separate kernel with its own serialized weight and stats; folding it into the preceding conv/linear removes that kernel from the delegate. The passes are listed in `CPU_PREPROCESS_PASSES` (mirroring `XNNPACKPassManager.passes`) so every lowering flow gets them from one extension point. Fusion introduces `get_attr` constants, so preprocess follows with `lift_constant_tensor_pass` (the native serializer rejects unlifted constants), then drops parameter/buffer/constant inputs left without users. Without that step the delegate serialized the original weights and batch norm stats next to the fused ones. Authored with Claude Code. Reviewed By: digantdesai Differential Revision: D126784606
`backends/transforms/targets.bzl` defines the `fuse_batch_norm_with_linear` `python_library` twice (lines 138 and 152). The first copy comes from #24192. The second came in with the squash of #24193, whose branch picked up the block again when it was merged with `main`. Buck refuses to register the same target twice, so any command that loads `//backends/transforms/...` fails: ``` error: Attempted to register target root//backends/transforms:fuse_batch_norm_with_linear twice ``` This breaks `unittest-buck` on `main` and on open PRs. This change deletes the second, identical definition. No other targets in the file are duplicated. ### Test plan - Checked that `targets.bzl` now defines each target name once. - CI: `unittest-buck` should get past the `buck2 query` step.
…torch#24193) Summary: Run the shared `FuseBatchNormWithConvPass` and `FuseBatchNormWithLinearPass` in `CpuBackend.preprocess`. Unfused `_native_batch_norm_legit_no_training` already executes through the reference provider, but as a separate kernel with its own serialized weight and stats; folding it into the preceding conv/linear removes that kernel from the delegate. The passes are listed in `CPU_PREPROCESS_PASSES` (mirroring `XNNPACKPassManager.passes`) so every lowering flow gets them from one extension point. Fusion introduces `get_attr` constants, so preprocess follows with `lift_constant_tensor_pass` (the native serializer rejects unlifted constants), then drops parameter/buffer/constant inputs left without users. Without that step the delegate serialized the original weights and batch norm stats next to the fused ones. Authored with Claude Code. Reviewed By: digantdesai Differential Revision: D126784606
`backends/transforms/targets.bzl` defines the `fuse_batch_norm_with_linear` `python_library` twice (lines 138 and 152). The first copy comes from pytorch#24192. The second came in with the squash of pytorch#24193, whose branch picked up the block again when it was merged with `main`. Buck refuses to register the same target twice, so any command that loads `//backends/transforms/...` fails: ``` error: Attempted to register target root//backends/transforms:fuse_batch_norm_with_linear twice ``` This breaks `unittest-buck` on `main` and on open PRs. This change deletes the second, identical definition. No other targets in the file are duplicated. ### Test plan - Checked that `targets.bzl` now defines each target name once. - CI: `unittest-buck` should get past the `buck2 query` step.
Summary:
Run the shared
FuseBatchNormWithConvPassandFuseBatchNormWithLinearPassinCpuBackend.preprocess. Unfused_native_batch_norm_legit_no_trainingalready executes through the reference provider, but as a separate kernel with its own serialized weight and stats; folding it into the preceding conv/linear removes that kernel from the delegate. The passes are listed inCPU_PREPROCESS_PASSES(mirroringXNNPACKPassManager.passes) so every lowering flow gets them from one extension point.Fusion introduces
get_attrconstants, so preprocess follows withlift_constant_tensor_pass(the native serializer rejects unlifted constants), then drops parameter/buffer/constant inputs left without users. Without that step the delegate serialized the original weights and batch norm stats next to the fused ones.Authored with Claude Code.
Reviewed By: digantdesai
Differential Revision: D126784606