Repository navigation
[MLAS][KleidiAI] Integrate Depthwise 3x3 Conv Kernel - #29441
Jonathan Clohessy (JonathanC-ARM) wants to merge 10 commits into
Conversation
There was a problem hiding this comment.
Pull request overview
This PR integrates an Arm® KleidiAI™ SME2-backed FP32 depthwise 3x3 convolution path into MLAS, wires it into the existing KleidiAI CPU convolution routing (Depthwise → IGemm → SGemmFallback → NoKleidiAi), and enables NHWC graph transformation when the new depthwise channels-last capability is available. It also adds an MLAS unit test to validate both the direct KleidiAI depthwise entrypoint and end-to-end routing through MlasConv in channels-last mode.
Changes:
- Added a new KleidiAI FP32 depthwise convolution implementation and ukernel selection plumbing.
- Integrated a new
ConvRoute::Depthwiseinto KleidiAI conv prepare/dispatch and enabled NHWC transform gating for supported depthwise shapes. - Added MLAS unit tests covering direct depthwise invocation and
MlasConvchannels-last routing.
Reviewed changes
Copilot reviewed 9 out of 9 changed files in this pull request and generated 1 comment.
Show a summary per file
| File | Description |
|---|---|
| onnxruntime/test/mlas/unittest/test_dwconv_kleidiai.cpp | Adds unit tests for KleidiAI depthwise conv (direct call and MlasConv NHWC path). |
| onnxruntime/core/optimizer/nhwc_transformer.cc | Extends NHWC transform filtering to consider depthwise channels-last support constraints. |
| onnxruntime/core/mlas/lib/kleidiai/mlasi_kleidiai.h | Adds depthwise support/entrypoint declarations and introduces ConvRoute::Depthwise selection. |
| onnxruntime/core/mlas/lib/kleidiai/dw_conv_kleidiai.cpp | Implements the FP32 depthwise 3x3 kernel path, including layout conversions and packing. |
| onnxruntime/core/mlas/lib/kleidiai/convolve_kleidiai.cpp | Wires depthwise routing into KleidiAI conv prepare/dispatch and refactors IGEMM capability checks. |
| onnxruntime/core/mlas/lib/kai_ukernel_interface.h | Generalizes the ukernel wrapper type and adds a depthwise ukernel wrapper typedef and accessor. |
| onnxruntime/core/mlas/lib/kai_ukernel_interface.cpp | Registers the SME2 depthwise ukernel and exposes it via GetKleidiAIDepthwiseConvUKernel(). |
| onnxruntime/core/mlas/lib/convolve.cpp | Enables MlasConvSupportsDepthwiseChannelsLast2DFloatKernel for KleidiAI-supported shapes to unlock NHWC transforms. |
| cmake/onnxruntime_mlas.cmake | Adds the new depthwise source file to the KleidiAI MLAS build. |
Review —
|
9a52413 to
80524ec
Compare
Head branch was pushed to by a user without write access
There was a problem hiding this comment.
🟡 Changes recommended
The new route has disabled-backend correctness issues, regresses symbolic dense transformation, and leaves an SME2 optimizer test stale.
Get a fresh assessment by requesting another Copilot review.
Review details
- Files reviewed: 11/11 changed files
- Comments generated: 3
- Review effort level: Balanced
| const bool depthwise_nhwc_fastpath = | ||
| wants_channels_last && !sum_present && MlasConvSupportsDepthwiseChannelsLast2DFloatKernel(kernel_rank, narrow<size_t>(N), group_count, input_channels_per_group, input_shape_size_t.data(), kernel_shape_size_t.data(), dilations_size_t.data(), pads_size_t.data(), strides_size_t.data(), filter_count_per_group, | ||
| /*Beta*/ 0.0f); |
| parameters.StrideShape[dim] = StrideShape[dim]; | ||
| } | ||
|
|
||
| return ArmKleidiAI::DepthwiseConvKleidiAISupported(¶meters); |
| !TryGetDimValueAsSizeT(*input_shape, 2, input_spatial_shape[0]) || | ||
| !TryGetDimValueAsSizeT(*input_shape, 3, input_spatial_shape[1]) || | ||
| !TryGetDimValueAsSizeT(*weight_shape, 0, total_filter_count) || | ||
| !TryGetDimValueAsSizeT(*weight_shape, 1, input_channels_per_group) || |
|
After threading added , threaded vs non threaded version is benchmarked: Apple M4 Pro Machine:
Android X300 Device
|
|
All points in the review are addressed. |
There was a problem hiding this comment.
🟡 Changes recommended
Finite clamping changes convolution results, and the updated transformer test fails when NCHWc takes precedence.
5 open issues
This marks the input as a native NHWC fast path even whensession.disable_kleidiai=1. For a… Preserve infinite and overflow results in depthwise Conv · New Disable NCHWc transformation in NHWC capability test · New Requiring weight dimension 1 here regresses the existing dense NHWC route: a legal dense Conv with… This newly makes the SME2-supported{1,8,7,7}/{8,1,3,3}, group-8 case return true, but…
Review effort: Balanced
| -std::numeric_limits<float>::max(), | ||
| std::numeric_limits<float>::max(), |
| const bool expect_nhwc = HasFloatNhwcNoTransposeSupport({1, 8, 7, 7}, {8, 1, 3, 3}, {}, {}, {}, 8); | ||
| EXPECT_EQ(op_to_count["Conv"] + op_to_count["com.microsoft.nchwc.Conv"], expect_nhwc ? 0 : 1); | ||
| EXPECT_EQ(op_to_count["com.microsoft.NhwcFusedConv"], expect_nhwc ? 1 : 0); | ||
| EXPECT_EQ(op_to_count["Transpose"], expect_nhwc ? 2 : 0); |
There was a problem hiding this comment.
🟡 Changes recommended
The selected KleidiAI kernel converts a quiet-NaN bias to negative infinity in eligible depthwise convolutions, requiring a NaN-preserving path and regression coverage.
6 open issues
This marks the input as a native NHWC fast path even whensession.disable_kleidiai=1. For a… Preserve NaN bias in eligible depthwise Conv kernel · New Disable NCHWc transformation in NHWC capability test Preserve infinite and overflow results in depthwise Conv Requiring weight dimension 1 here regresses the existing dense NHWC route: a legal dense Conv with… This newly makes the SME2-supported{1,8,7,7}/{8,1,3,3}, group-8 case return true, but…
Review effort: Balanced
| -std::numeric_limits<float>::infinity(), | ||
| std::numeric_limits<float>::infinity(), |
There was a problem hiding this comment.
fallback provided in the last commit. Done
There was a problem hiding this comment.
🟡 Changes recommended
The fallback still permits incorrect NaN handling for biasless inputs, weights, and invalid arithmetic, while the threaded test unconditionally fails in standalone MLAS builds without a thread pool.
8 open issues
NaNs in inputs and accumulation bypass the SME2 fallback · New This marks the input as a native NHWC fast path even whensession.disable_kleidiai=1. For a… Standalone tests fail when the MLAS thread pool is unavailable · New Preserve NaN bias in eligible depthwise Conv kernel Disable NCHWc transformation in NHWC capability test Preserve infinite and overflow results in depthwise Conv Requiring weight dimension 1 here regresses the existing dense NHWC route: a legal dense Conv with… This newly makes the SME2-supported{1,8,7,7}/{8,1,3,3}, group-8 case return true, but…
Review effort: Balanced
| auto backend_kernel_selector_config = mlas_backend_kernel_selector_config_; | ||
| #if defined(USE_KLEIDIAI) && defined(MLAS_TARGET_ARM64) | ||
| const bool is_depthwise_multiplier_one = input_channels_per_group == 1 && filter_count_per_group == 1; | ||
| if (backend_kernel_selector_config.use_kleidiai && is_depthwise_multiplier_one && B != nullptr) { |
There was a problem hiding this comment.
NaN preserving clamping provided, fallback removed. Done
| } | ||
|
|
||
| TEST(MlasKleidiDepthwiseTest, ThreadedRowTilesWithTailNhwc) { | ||
| ASSERT_NE(GetMlasThreadPool(), nullptr); |
Signed-off-by: Jonathan Clohessy <Jonathan.Clohessy@arm.com>
Signed-off-by: melkap01 <melike.kaptan@arm.com>
…ts, refactor cleaned Signed-off-by: melkap01 <melike.kaptan@arm.com>
Signed-off-by: melkap01 <melike.kaptan@arm.com>
Signed-off-by: melkap01 <melike.kaptan@arm.com>
Signed-off-by: melkap01 <melike.kaptan@arm.com>
Signed-off-by: melkap01 <melike.kaptan@arm.com>
Signed-off-by: melkap01 <melike.kaptan@arm.com>
3e8b1ea to
a43c69d
Compare
There was a problem hiding this comment.
🔵 Needs a closer look
The SME2 integration requires hardware-backed validation of row/channel tails, packed-weight vector-length handling, and NaN-preserving clamp behavior that this source-only review could not verify.
8 open issues
NaNs in inputs and accumulation bypass the SME2 fallback This marks the input as a native NHWC fast path even whensession.disable_kleidiai=1. For a… Standalone tests fail when the MLAS thread pool is unavailable Preserve NaN bias in eligible depthwise Conv kernel Disable NCHWc transformation in NHWC capability test Preserve infinite and overflow results in depthwise Conv Requiring weight dimension 1 here regresses the existing dense NHWC route: a legal dense Conv with… This newly makes the SME2-supported{1,8,7,7}/{8,1,3,3}, group-8 case return true, but…
Review effort: Balanced
Signed-off-by: melkap01 <melike.kaptan@arm.com>


Description
This PR adds a Arm® KleidiAI™ backed f32 depthwise convolution path in MLAS and wires it into the CPU/KleidiAI convolution routing flow.
The new path targets eligible depthwise convolutions using the KleidiAI SME2 depthwise ukernel. It is integrated as a first-class KleidiAI convolution route so depthwise dispatch is handled consistently with the existing IGEMM / SGEMM fallback routing.
Changes
onnxruntime/core/mlas/lib/kleidiai/dw_conv_kleidiai.cppConvRoute::Depthwise.DepthwiseIGemmSGemmFallbackNoKleidiAiSupported depthwise shape envelope
The current KleidiAI depthwise route supports f32 depthwise convolution with:
3x3kernelThe implementation handles NHWC directly and can fall back to internal NCHW to NHWC conversion when needed.
Example Performance Results
mobilenet_v1_f32.onnxmobilenetv1_ssd_f32.onnxretinaface_f32.onnxdeeplabv3_mobilenetv2_f32.onnxde_efficientnetlitev3_f32.onnx