[CPU][ARM] Int8 conv swish fq fusion#34931
Open
Passavee-Losripat wants to merge 23 commits into
Open
Conversation
Passavee-Losripat
force-pushed
the
int8-conv-swish-fq-fusion
branch
from
March 25, 2026 16:54
25f294b to
c3d0c62
Compare
Passavee-Losripat
force-pushed
the
int8-conv-swish-fq-fusion
branch
from
May 28, 2026 15:00
3ea426d to
d8eb502
Compare
Passavee-Losripat
force-pushed
the
int8-conv-swish-fq-fusion
branch
from
June 29, 2026 17:41
653e0c4 to
fa7be2b
Compare
Passavee-Losripat
force-pushed
the
int8-conv-swish-fq-fusion
branch
from
June 29, 2026 18:04
fa7be2b to
d2b04d6
Compare
Passavee-Losripat
marked this pull request as ready for review
June 29, 2026 18:05
Contributor
There was a problem hiding this comment.
Pull request overview
This PR updates the Intel CPU plugin’s ARM/ACL low-precision convolution flow to recognize and fuse a Conv -> (Mul/Add bias/scale) -> Activation -> FakeQuantize pattern (notably Swish), re-enables relevant ARM convolution transformations, and extends the ACL convolution executor to handle an activation + FakeQuantize post-op chain and direct-to-F32 output paths.
Changes:
- Extend ARM pattern matching / transformation plumbing to optionally include an activation node between
AddandFakeQuantizeand propagate an optional “activation” anchor through affected passes. - Update ACL convolution execution constraints and configuration to support up to two post-ops (Activation + FakeQuantize) and add an i8→f32 direct output configuration.
- Add/extend ARM subgraph tests and test target wiring for ARM-specific custom subgraph suites.
Reviewed changes
Copilot reviewed 14 out of 14 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
| src/plugins/intel_cpu/tests/functional/custom/subgraph_tests/src/arm/conv_fq.cpp | Adds optional Swish into the Conv→FQ test graph and instantiates a Swish test suite. |
| src/plugins/intel_cpu/tests/functional/cmake/target_per_test.cmake | Adds an ARM subgraph test target directory for per-test targets. |
| src/plugins/intel_cpu/src/transformations/utils.hpp | Declares a new ARM matcher helper for Conv→Swish→FQ chains. |
| src/plugins/intel_cpu/src/transformations/utils.cpp | Implements Conv→Swish→FQ matcher used to skip FakeQuantize decomposition on ARM. |
| src/plugins/intel_cpu/src/transformations/transformation_pipeline.cpp | Extends the ARM callback to avoid FakeQuantize decomposition for Swish chains. |
| src/plugins/intel_cpu/src/transformations/snippets/aarch64/pass/snippets_mark_skipped.cpp | Marks Conv→Swish→FQ chains as skipped for snippets on ARM. |
| src/plugins/intel_cpu/src/transformations/cpu_opset/arm/pass/fallback_unsupported_lp_conv_to_fp16.cpp | Propagates optional activation anchor handling during fallback-to-FP16 transformation. |
| src/plugins/intel_cpu/src/transformations/cpu_opset/arm/pass/convert_conv_bias.cpp | Updates bias-conversion transformation to handle optional activation presence. |
| src/plugins/intel_cpu/src/transformations/cpu_opset/arm/pass/conv_mul_add_fq_block.cpp | Extends the block pattern to optionally include an activation (Swish/Relu) between Add and FQ. |
| src/plugins/intel_cpu/src/nodes/executors/convolution_implementations.cpp | Adds an ACL lowp type mapping for i8→f32 conv. |
| src/plugins/intel_cpu/src/nodes/executors/acl/acl_conv.hpp | Adds flags for i8/u8 direct-to-f32 paths. |
| src/plugins/intel_cpu/src/nodes/executors/acl/acl_conv.cpp | Iterates post-ops (up to 2), adjusts supports() checks, and wires direct-to-f32 ACL configuration parameters. |
| src/plugins/intel_cpu/src/nodes/conv.cpp | Extends fusion eligibility rules to allow post-op chaining with Activation + FakeQuantize (but contains a Swish-specific fusion blocker). |
| src/plugins/intel_cpu/src/dnnl_extension_utils.cpp | Adds Swish to the set of unary post-ops supported under ACL builds. |
Comment on lines
+588
to
+591
| if (any_of(convInPrc, ov::element::u8, ov::element::i8) && | ||
| fusedWith.back()->getAlgorithm() == Algorithm::EltwiseSwish) { | ||
| return false; | ||
| } |
Comment on lines
+197
to
+205
| // After ConvertConvolutionBias swaps Mul and Add: | ||
| // Conv -> Add(bias) -> Mul(scales) -> Swish -> FQ | ||
| auto conv = wrap_type<ov::op::v1::Convolution>(); | ||
| auto add = wrap_type<ov::op::v1::Add>({conv, any_input()}); | ||
| auto mul = wrap_type<ov::op::v1::Multiply>({add, any_input()}); | ||
| auto swish = wrap_type<ov::op::v4::Swish>({mul}); | ||
| auto fq = wrap_type<ov::op::v0::FakeQuantize>( | ||
| {swish, any_input(), any_input(), any_input(), any_input()}); | ||
|
|
Comment on lines
+227
to
232
| ::testing::Combine(::testing::ValuesIn(inputShapes), | ||
| ::testing::Values(element::f32), | ||
| ::testing::ValuesIn(quantizationParams), | ||
| ::testing::Values(true), //withBias | ||
| ::testing::Values(true), //withSwish | ||
| ::testing::Values(ov::test::utils::DEVICE_CPU)), |
Comment on lines
+142
to
+152
| const bool isQuantizedU8 = srcDesc->getPrecision() == ov::element::u8 && | ||
| any_of(weiDesc->getPrecision(), ov::element::u8, ov::element::i8) && | ||
| dstDesc->getPrecision() == ov::element::u8 && hasQuantizationPostOp; | ||
| const bool isQuantizedI8 = srcDesc->getPrecision() == ov::element::i8 && | ||
| weiDesc->getPrecision() == ov::element::i8 && | ||
| dstDesc->getPrecision() == ov::element::i8 && hasQuantizationPostOp; | ||
| const bool isQuantizedI8DstF32 = srcDesc->getPrecision() == ov::element::i8 && | ||
| weiDesc->getPrecision() == ov::element::i8 && | ||
| dstDesc->getPrecision() == ov::element::f32; | ||
|
|
||
| VERIFY(isQuantizedU8 || isQuantizedI8 || isQuantizedI8DstF32, UNSUPPORTED_BY_EXECUTOR); |
v-Golubev
reviewed
Jul 1, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Details:
ConvolutionTransformationon ARM by removingCPU_DISABLE_PASS_ARMintransformation_pipeline.cppConvMulAddFQBlockpattern matcher to optionally match an activation node betweenAddandFakeQuantize, enabling recognition ofConv -> Mul -> Add -> Activation -> FQin addition to the existingConv -> Mul -> Add -> FQ. Currently supportsSwishandReluviawrap_type<Swish, Relu>ConvertConvolutionBiasandFallbackUnsupportedLPConvToFP16to retrieve and handle the optional activation anchor without breaking existing patternsACLConvolutionExecutorto accept Activation + FakeQuantize as simultaneous post-ops, replacing the hard single-post-op limit with an iteration loopcanFuse()inconv.cppto allow FakeQuantize fusion after a single Eltwise activation is already fused, enabling the full post-op chain to reach the ACL executorisI8DstF32/isU8DstF32flags anduse_direct_i8_s8_f32/use_direct_u8_u8_f32paths inACLConvolutionExecutorso Conv can output F32 directly, letting the activation run in floating point before FQ requantizesKnown Issues
Tickets:
AI Assistance: