From 07a90738b45d36ce96e39bfbd89dc495601d457d Mon Sep 17 00:00:00 2001 From: Martin Klacer Date: Thu, 11 Jun 2026 11:17:20 +0100 Subject: [PATCH 1/4] Fixed failing KleidiAI NHWC failing unit tests * Fixed tests ConvFloat_UsesNhwcOnlyWithKleidi, FusedConvFloat_UsesNhwcOnlyWithKleidi * Added check to only test NHWC shape parameters if NHWC path was taken in graph optimisation Signed-off-by: Martin Klacer --- .../test/optimizer/nhwc_transformer_test.cc | 27 ++++++++++--------- 1 file changed, 15 insertions(+), 12 deletions(-) diff --git a/onnxruntime/test/optimizer/nhwc_transformer_test.cc b/onnxruntime/test/optimizer/nhwc_transformer_test.cc index b73929efab8a6..7fec7fb9f3b31 100644 --- a/onnxruntime/test/optimizer/nhwc_transformer_test.cc +++ b/onnxruntime/test/optimizer/nhwc_transformer_test.cc @@ -447,11 +447,13 @@ TEST(NhwcTransformerTests, ConvFloat_UsesNhwcOnlyWithKleidi) { auto check_nhwc_graph = [&](InferenceSessionWrapper& session) { auto op_to_count = CountOpsInGraph(session.GetGraph()); - const bool expect_nhwc = HasFloatNhwcNoTransposeSupport({1, 8, 7, 7}, {16, 8, 3, 3}, {1, 1, 1, 1}); - const int expected_nhwc_fused_conv = expect_nhwc ? 1 : 0; - const int expected_transposes = expect_nhwc ? 2 : 0; - EXPECT_EQ(op_to_count["com.microsoft.NhwcFusedConv"], expected_nhwc_fused_conv); - EXPECT_EQ(op_to_count["Transpose"], expected_transposes); + // Only validate NhwcFusedConv graph shape if that path was selected + if (op_to_count["com.microsoft.NhwcFusedConv"] == 0) { + return; + } + EXPECT_TRUE(HasFloatNhwcNoTransposeSupport({1, 8, 7, 7}, {16, 8, 3, 3}, {1, 1, 1, 1})); + EXPECT_EQ(op_to_count["com.microsoft.NhwcFusedConv"], 1); + EXPECT_EQ(op_to_count["Transpose"], 2); }; TransformerTester(build_test_case, @@ -515,12 +517,13 @@ TEST(NhwcTransformerTests, FusedConvFloat_UsesNhwcOnlyWithKleidi) { auto check_nhwc_graph = [&](InferenceSessionWrapper& session) { auto op_to_count = CountOpsInGraph(session.GetGraph()); - const bool expect_nhwc = HasFloatNhwcNoTransposeSupport( - {1, 8, 7, 7}, {16, 8, 3, 3}, {1, 1, 1, 1}, {1, 1}); - const int expected_nhwc_fused_conv = expect_nhwc ? 1 : 0; - const int expected_transposes = expect_nhwc ? 2 : 0; - EXPECT_EQ(op_to_count["com.microsoft.NhwcFusedConv"], expected_nhwc_fused_conv); - EXPECT_EQ(op_to_count["Transpose"], expected_transposes); + // Only validate NhwcFusedConv graph shape if that path was selected + if (op_to_count["com.microsoft.NhwcFusedConv"] == 0) { + return; + } + EXPECT_TRUE(HasFloatNhwcNoTransposeSupport({1, 8, 7, 7}, {16, 8, 3, 3}, {1, 1, 1, 1}, {1, 1})); + EXPECT_EQ(op_to_count["com.microsoft.NhwcFusedConv"], 1); + EXPECT_EQ(op_to_count["Transpose"], 2); }; TransformerTester(build_test_case, @@ -528,7 +531,7 @@ TEST(NhwcTransformerTests, FusedConvFloat_UsesNhwcOnlyWithKleidi) { TransformerLevel::Level2, TransformerLevel::Level3, /*opset_version*/ 12, - /*per_sample_tolerance*/ 1e-6, + /*per_sample_tolerance*/ 2e-6, /*relative_per_sample_tolerance*/ 1e-6); } From 795be01a29c9089b30e462e3f9e618560417681c Mon Sep 17 00:00:00 2001 From: Martin Klacer Date: Fri, 12 Jun 2026 14:27:38 +0100 Subject: [PATCH 2/4] Cleared up expected values and added fallback check to 2 NhwcTransformerTests * Affected tests: ConvFloat_UsesNhwcOnlyWithKleidi, FusedConvFloat_UsesNhwcOnlyWithKleidi Signed-off-by: Martin Klacer --- .../test/optimizer/nhwc_transformer_test.cc | 37 +++++++++++++++---- 1 file changed, 29 insertions(+), 8 deletions(-) diff --git a/onnxruntime/test/optimizer/nhwc_transformer_test.cc b/onnxruntime/test/optimizer/nhwc_transformer_test.cc index 7fec7fb9f3b31..48850491a0c22 100644 --- a/onnxruntime/test/optimizer/nhwc_transformer_test.cc +++ b/onnxruntime/test/optimizer/nhwc_transformer_test.cc @@ -447,12 +447,22 @@ TEST(NhwcTransformerTests, ConvFloat_UsesNhwcOnlyWithKleidi) { auto check_nhwc_graph = [&](InferenceSessionWrapper& session) { auto op_to_count = CountOpsInGraph(session.GetGraph()); - // Only validate NhwcFusedConv graph shape if that path was selected - if (op_to_count["com.microsoft.NhwcFusedConv"] == 0) { + + const bool kleidi_supported = HasFloatNhwcNoTransposeSupport({1, 8, 7, 7}, {16, 8, 3, 3}, {1, 1, 1, 1}); + const int nhwc_count = op_to_count["com.microsoft.NhwcFusedConv"]; + + // Other Level 3 layout optimizers may consume the Conv node in the graph before NhwcTransformer. + // If NHWC is selected, validate that it's only used with Arm® KleidiAI™ support and that + // the expected transpose-boundary graph shape is produced. Otherwise, don't validate the graph shape. + if (nhwc_count == 0) { + // When the Arm® KleidiAI™ NHWC Conv path is available but no NHWC ops were produced, + // ensure that some other optimiser run and consumed the Conv node instead + EXPECT_TRUE(!kleidi_supported || op_to_count["Conv"] == 0); return; } - EXPECT_TRUE(HasFloatNhwcNoTransposeSupport({1, 8, 7, 7}, {16, 8, 3, 3}, {1, 1, 1, 1})); - EXPECT_EQ(op_to_count["com.microsoft.NhwcFusedConv"], 1); + + EXPECT_TRUE(kleidi_supported); + EXPECT_EQ(nhwc_count, 1); EXPECT_EQ(op_to_count["Transpose"], 2); }; @@ -517,15 +527,26 @@ TEST(NhwcTransformerTests, FusedConvFloat_UsesNhwcOnlyWithKleidi) { auto check_nhwc_graph = [&](InferenceSessionWrapper& session) { auto op_to_count = CountOpsInGraph(session.GetGraph()); - // Only validate NhwcFusedConv graph shape if that path was selected - if (op_to_count["com.microsoft.NhwcFusedConv"] == 0) { + + const bool kleidi_supported = HasFloatNhwcNoTransposeSupport({1, 8, 7, 7}, {16, 8, 3, 3}, {1, 1, 1, 1}, {1, 1}); + const int nhwc_count = op_to_count["com.microsoft.NhwcFusedConv"]; + + // Other Level 3 layout optimizers may consume the FusedConv node in the graph before NhwcTransformer. + // If NHWC is selected, validate that it's only used with Arm® KleidiAI™ support and that + // the expected transpose-boundary graph shape is produced. Otherwise, don't validate the graph shape. + if (nhwc_count == 0) { + // When the Arm® KleidiAI™ NHWC Conv path is available but no NHWC ops were produced, + // ensure that some other optimiser run and consumed the FusedConv node instead + EXPECT_TRUE(!kleidi_supported || op_to_count["com.microsoft.FusedConv"] == 0); return; } - EXPECT_TRUE(HasFloatNhwcNoTransposeSupport({1, 8, 7, 7}, {16, 8, 3, 3}, {1, 1, 1, 1}, {1, 1})); - EXPECT_EQ(op_to_count["com.microsoft.NhwcFusedConv"], 1); + + EXPECT_TRUE(kleidi_supported); + EXPECT_EQ(nhwc_count, 1); EXPECT_EQ(op_to_count["Transpose"], 2); }; + // Different optimizer paths can change accumulation order, so allow a slightly larger absolute tolerance TransformerTester(build_test_case, check_nhwc_graph, TransformerLevel::Level2, From adf157b4c21c9dcc523f58f42836dd4f6ecc7863 Mon Sep 17 00:00:00 2001 From: Martin Klacer Date: Mon, 15 Jun 2026 09:47:41 +0100 Subject: [PATCH 3/4] Changed spelling of 'optimizer' for consistency Signed-off-by: Martin Klacer --- onnxruntime/test/optimizer/nhwc_transformer_test.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/onnxruntime/test/optimizer/nhwc_transformer_test.cc b/onnxruntime/test/optimizer/nhwc_transformer_test.cc index 48850491a0c22..2c5e4b0c2f38a 100644 --- a/onnxruntime/test/optimizer/nhwc_transformer_test.cc +++ b/onnxruntime/test/optimizer/nhwc_transformer_test.cc @@ -456,7 +456,7 @@ TEST(NhwcTransformerTests, ConvFloat_UsesNhwcOnlyWithKleidi) { // the expected transpose-boundary graph shape is produced. Otherwise, don't validate the graph shape. if (nhwc_count == 0) { // When the Arm® KleidiAI™ NHWC Conv path is available but no NHWC ops were produced, - // ensure that some other optimiser run and consumed the Conv node instead + // ensure that some other optimizer ran and consumed the Conv node instead EXPECT_TRUE(!kleidi_supported || op_to_count["Conv"] == 0); return; } @@ -536,7 +536,7 @@ TEST(NhwcTransformerTests, FusedConvFloat_UsesNhwcOnlyWithKleidi) { // the expected transpose-boundary graph shape is produced. Otherwise, don't validate the graph shape. if (nhwc_count == 0) { // When the Arm® KleidiAI™ NHWC Conv path is available but no NHWC ops were produced, - // ensure that some other optimiser run and consumed the FusedConv node instead + // ensure that some other optimizer ran and consumed the FusedConv node instead EXPECT_TRUE(!kleidi_supported || op_to_count["com.microsoft.FusedConv"] == 0); return; } From 35fbf6fb037d46d5765aa2812a0646caec202f70 Mon Sep 17 00:00:00 2001 From: Martin Klacer Date: Wed, 17 Jun 2026 12:44:59 +0100 Subject: [PATCH 4/4] Lower tolerance and add clearer comment to nhwc_transformer_test.cc * Added clearer comment with an explanation for the increased tolerance, and lowered increase from 2e-6 to 1.25e-6 in nhwc_transformer_test.cc FusedConvFloat_UsesNhwcOnlyWithKleidi test case Signed-off-by: Martin Klacer --- onnxruntime/test/optimizer/nhwc_transformer_test.cc | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/onnxruntime/test/optimizer/nhwc_transformer_test.cc b/onnxruntime/test/optimizer/nhwc_transformer_test.cc index 2c5e4b0c2f38a..29ad7fe972293 100644 --- a/onnxruntime/test/optimizer/nhwc_transformer_test.cc +++ b/onnxruntime/test/optimizer/nhwc_transformer_test.cc @@ -546,13 +546,14 @@ TEST(NhwcTransformerTests, FusedConvFloat_UsesNhwcOnlyWithKleidi) { EXPECT_EQ(op_to_count["Transpose"], 2); }; - // Different optimizer paths can change accumulation order, so allow a slightly larger absolute tolerance + // This compares a Level 3 layout-optimized FusedConv+Relu path with the Level 2 baseline, which can use a different FP accumulation order. + // The NCHWc-selected path showed deterministic FP rounding drift just over 1e-6, so use a slightly wider but still narrow margin. TransformerTester(build_test_case, check_nhwc_graph, TransformerLevel::Level2, TransformerLevel::Level3, /*opset_version*/ 12, - /*per_sample_tolerance*/ 2e-6, + /*per_sample_tolerance*/ 1.25e-6, /*relative_per_sample_tolerance*/ 1e-6); }