From a44b14a366029784aa11031efb980df7034d3ed3 Mon Sep 17 00:00:00 2001 From: AyusKumarPathak Date: Thu, 8 Jan 2026 00:34:09 +0530 Subject: [PATCH 1/7] Fix GPU Softmax NaN propagation for mixed infinite inputs --- .../cl_kernels/softmax_gpu_ref.cl | 25 +++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/src/plugins/intel_gpu/src/kernel_selector/cl_kernels/softmax_gpu_ref.cl b/src/plugins/intel_gpu/src/kernel_selector/cl_kernels/softmax_gpu_ref.cl index 8a885af782d7b3..d648ff05020041 100644 --- a/src/plugins/intel_gpu/src/kernel_selector/cl_kernels/softmax_gpu_ref.cl +++ b/src/plugins/intel_gpu/src/kernel_selector/cl_kernels/softmax_gpu_ref.cl @@ -106,6 +106,31 @@ KERNEL(softmax)( max_value = max(max_value, in); data[cls*TMP_CLASS_PITCH] = in; } +// Handle IEEE-754 case when max_value is INF +if (isinf((float)max_value)) { + for (cls = 0; cls < class_num; ++cls) { + ACCUMULATOR_TYPE v = data[cls * TMP_CLASS_PITCH]; + if (v == max_value) + data[cls * TMP_CLASS_PITCH] = (ACCUMULATOR_TYPE)NAN; + else + data[cls * TMP_CLASS_PITCH] = (ACCUMULATOR_TYPE)0.0f; + } + + // Write results and exit + for (cls = 0; cls < class_num; ++cls) { +#if INPUT0_SIMPLE == 1 + const uint output_idx = out_depth_offset + cls*OUTPUT_CLASS_PITCH; +#else +#if INPUT0_DIMS == 5 + const uint output_idx = OUTPUT_GET_INDEX(b + *b_offset, f + *f_offset, z + *z_offset, y + *y_offset, x + *x_offset); +#else + const uint output_idx = OUTPUT_GET_INDEX(b + *b_offset, f + *f_offset, y + *y_offset, x + *x_offset); +#endif +#endif + output[output_idx] = data[cls * TMP_CLASS_PITCH]; + } + return; +} // TODO: currently we calculate on float32 because it's lot of "add" operation and it stuck on the value "8192.0f" ACCUMULATOR_TYPE denominator = 0.0; From eb3e17b01ee461dcd016ed554daba9cd71292e19 Mon Sep 17 00:00:00 2001 From: AyusKumarPathak Date: Thu, 8 Jan 2026 21:36:23 +0530 Subject: [PATCH 2/7] Add comprehensive GPU Softmax edge-case tests for INF and NaN handling --- .../include/single_op_tests/softmax.hpp | 98 +++++++++++++++++++ 1 file changed, 98 insertions(+) diff --git a/src/tests/functional/plugin/shared/include/single_op_tests/softmax.hpp b/src/tests/functional/plugin/shared/include/single_op_tests/softmax.hpp index 9c3fc56dabb65a..2300f8c14e3633 100644 --- a/src/tests/functional/plugin/shared/include/single_op_tests/softmax.hpp +++ b/src/tests/functional/plugin/shared/include/single_op_tests/softmax.hpp @@ -5,6 +5,9 @@ #pragma once #include "shared_test_classes/single_op/softmax.hpp" +#include +#include + namespace ov { namespace test { @@ -26,6 +29,101 @@ TEST_P(SoftMax8LayerTest, CompareQueryModel) { query_model(); } + + +// ======================= +// GPU Numerical Edge Cases +// ======================= + +static void prepare_input(const std::vector& values, + std::map& inputsData, + std::vector& inputDynamicShapes) { + inputDynamicShapes.clear(); + inputDynamicShapes.push_back({values.size()}); + + auto& tensor = inputsData.begin()->second; + auto* data = tensor.data(); + for (size_t i = 0; i < values.size(); ++i) + data[i] = values[i]; +} + +static void check_output(const std::vector& expected, + const std::vector& actual) { + for (size_t i = 0; i < expected.size(); ++i) { + if (std::isnan(expected[i])) { + EXPECT_TRUE(std::isnan(actual[i])); + } else { + EXPECT_NEAR(expected[i], actual[i], 1e-6f); + } + } +} + +TEST_P(SoftMaxLayerTest, MixedInfinityCases) { + if (targetDevice != ov::test::utils::DEVICE_GPU) + GTEST_SKIP(); + + std::vector, std::vector>> cases = { + {{INFINITY, 1.f, 2.f}, {NAN, 0.f, 0.f}}, + {{INFINITY, -INFINITY, 1.f}, {NAN, 0.f, 0.f}} + }; + + for (auto& c : cases) { + prepare_input(c.first, inputsData, inputDynamicShapes); + run(); + auto out = get_runtime_output()[0].as>(); + check_output(c.second, out); + } +} + +TEST_P(SoftMaxLayerTest, MultipleInfinityCases) { + if (targetDevice != ov::test::utils::DEVICE_GPU) + GTEST_SKIP(); + + std::vector, std::vector>> cases = { + {{INFINITY, INFINITY, 1.f}, {NAN, NAN, 0.f}}, + {{INFINITY, INFINITY, INFINITY}, {NAN, NAN, NAN}}, + {{INFINITY, -INFINITY, -INFINITY}, {NAN, 0.f, 0.f}} + }; + + for (auto& c : cases) { + prepare_input(c.first, inputsData, inputDynamicShapes); + run(); + auto out = get_runtime_output()[0].as>(); + check_output(c.second, out); + } +} + +TEST_P(SoftMaxLayerTest, NegativeInfinityOnlyCase) { + if (targetDevice != ov::test::utils::DEVICE_GPU) + GTEST_SKIP(); + + prepare_input({-INFINITY, 1.f, 2.f}, inputsData, inputDynamicShapes); + run(); + + auto out = get_runtime_output()[0].as>(); + check_output({0.f, 0.2689414f, 0.7310586f}, out); +} + +TEST_P(SoftMaxLayerTest, NaNPropagationCases) { + if (targetDevice != ov::test::utils::DEVICE_GPU) + GTEST_SKIP(); + + std::vector> cases = { + {NAN, 1.f, 2.f}, + {1.f, NAN, 2.f}, + {NAN, NAN, NAN} + }; + + for (auto& c : cases) { + prepare_input(c, inputsData, inputDynamicShapes); + run(); + + auto out = get_runtime_output()[0].as>(); + for (float v : out) + EXPECT_TRUE(std::isnan(v)); + } +} + } // namespace subgraph } // namespace test } // namespace ov From ce97a90a62eda243348d2afd99feb6cbb8b633c4 Mon Sep 17 00:00:00 2001 From: AyusKumarPathak Date: Tue, 13 Jan 2026 23:55:24 +0530 Subject: [PATCH 3/7] Move GPU-specific Softmax edge-case tests into GPU plugin --- .../functional/single_layer_tests/softmax.cpp | 93 ++++++++++++++++ .../include/single_op_tests/softmax.hpp | 100 +----------------- 2 files changed, 94 insertions(+), 99 deletions(-) create mode 100644 src/plugins/intel_gpu/tests/functional/single_layer_tests/softmax.cpp diff --git a/src/plugins/intel_gpu/tests/functional/single_layer_tests/softmax.cpp b/src/plugins/intel_gpu/tests/functional/single_layer_tests/softmax.cpp new file mode 100644 index 00000000000000..9d63ffa7f4aa1e --- /dev/null +++ b/src/plugins/intel_gpu/tests/functional/single_layer_tests/softmax.cpp @@ -0,0 +1,93 @@ +// Copyright (C) 2018-2025 Intel Corporation +// SPDX-License-Identifier: Apache-2.0 + +#include +#include +#include + +#include "shared_test_classes/single_op/softmax.hpp" +#include "common_test_utils/ov_tensor_utils.hpp" + +using namespace ov::test; +using namespace ov::test::subgraph; + +// ======================= +// GPU Numerical Edge Cases +// ======================= + +static void prepare_input(const std::vector& values, + std::map& inputsData, + std::vector& inputDynamicShapes) { + inputDynamicShapes.clear(); + inputDynamicShapes.push_back({values.size()}); + + auto& tensor = inputsData.begin()->second; + auto* data = tensor.data(); + for (size_t i = 0; i < values.size(); ++i) { + data[i] = values[i]; + } +} + +static void check_output(const std::vector& expected, + const std::vector& actual) { + for (size_t i = 0; i < expected.size(); ++i) { + if (std::isnan(expected[i])) { + EXPECT_TRUE(std::isnan(actual[i])); + } else { + EXPECT_NEAR(expected[i], actual[i], 1e-6f); + } + } +} + +TEST_P(SoftMaxLayerTest, MixedInfinityCases) { + std::vector, std::vector>> cases = { + {{INFINITY, 1.f, 2.f}, {NAN, 0.f, 0.f}}, + {{INFINITY, -INFINITY, 1.f}, {NAN, 0.f, 0.f}} + }; + + for (auto& c : cases) { + prepare_input(c.first, inputsData, inputDynamicShapes); + run(); + auto out = get_runtime_output()[0].as>(); + check_output(c.second, out); + } +} + +TEST_P(SoftMaxLayerTest, MultipleInfinityCases) { + std::vector, std::vector>> cases = { + {{INFINITY, INFINITY, 1.f}, {NAN, NAN, 0.f}}, + {{INFINITY, INFINITY, INFINITY}, {NAN, NAN, NAN}}, + {{INFINITY, -INFINITY, -INFINITY}, {NAN, 0.f, 0.f}} + }; + + for (auto& c : cases) { + prepare_input(c.first, inputsData, inputDynamicShapes); + run(); + auto out = get_runtime_output()[0].as>(); + check_output(c.second, out); + } +} + +TEST_P(SoftMaxLayerTest, NegativeInfinityOnlyCase) { + prepare_input({-INFINITY, 1.f, 2.f}, inputsData, inputDynamicShapes); + run(); + auto out = get_runtime_output()[0].as>(); + check_output({0.f, 0.2689414f, 0.7310586f}, out); +} + +TEST_P(SoftMaxLayerTest, NaNPropagationCases) { + std::vector> cases = { + {NAN, 1.f, 2.f}, + {1.f, NAN, 2.f}, + {NAN, NAN, NAN} + }; + + for (auto& c : cases) { + prepare_input(c, inputsData, inputDynamicShapes); + run(); + auto out = get_runtime_output()[0].as>(); + for (float v : out) { + EXPECT_TRUE(std::isnan(v)); + } + } +} diff --git a/src/tests/functional/plugin/shared/include/single_op_tests/softmax.hpp b/src/tests/functional/plugin/shared/include/single_op_tests/softmax.hpp index 2300f8c14e3633..d22c0e9b5e214d 100644 --- a/src/tests/functional/plugin/shared/include/single_op_tests/softmax.hpp +++ b/src/tests/functional/plugin/shared/include/single_op_tests/softmax.hpp @@ -1,13 +1,10 @@ -// Copyright (C) 2018-2025 Intel Corporation +// Copyright (C) 2018-2026 Intel Corporation // SPDX-License-Identifier: Apache-2.0 // #pragma once #include "shared_test_classes/single_op/softmax.hpp" -#include -#include - namespace ov { namespace test { @@ -29,101 +26,6 @@ TEST_P(SoftMax8LayerTest, CompareQueryModel) { query_model(); } - - -// ======================= -// GPU Numerical Edge Cases -// ======================= - -static void prepare_input(const std::vector& values, - std::map& inputsData, - std::vector& inputDynamicShapes) { - inputDynamicShapes.clear(); - inputDynamicShapes.push_back({values.size()}); - - auto& tensor = inputsData.begin()->second; - auto* data = tensor.data(); - for (size_t i = 0; i < values.size(); ++i) - data[i] = values[i]; -} - -static void check_output(const std::vector& expected, - const std::vector& actual) { - for (size_t i = 0; i < expected.size(); ++i) { - if (std::isnan(expected[i])) { - EXPECT_TRUE(std::isnan(actual[i])); - } else { - EXPECT_NEAR(expected[i], actual[i], 1e-6f); - } - } -} - -TEST_P(SoftMaxLayerTest, MixedInfinityCases) { - if (targetDevice != ov::test::utils::DEVICE_GPU) - GTEST_SKIP(); - - std::vector, std::vector>> cases = { - {{INFINITY, 1.f, 2.f}, {NAN, 0.f, 0.f}}, - {{INFINITY, -INFINITY, 1.f}, {NAN, 0.f, 0.f}} - }; - - for (auto& c : cases) { - prepare_input(c.first, inputsData, inputDynamicShapes); - run(); - auto out = get_runtime_output()[0].as>(); - check_output(c.second, out); - } -} - -TEST_P(SoftMaxLayerTest, MultipleInfinityCases) { - if (targetDevice != ov::test::utils::DEVICE_GPU) - GTEST_SKIP(); - - std::vector, std::vector>> cases = { - {{INFINITY, INFINITY, 1.f}, {NAN, NAN, 0.f}}, - {{INFINITY, INFINITY, INFINITY}, {NAN, NAN, NAN}}, - {{INFINITY, -INFINITY, -INFINITY}, {NAN, 0.f, 0.f}} - }; - - for (auto& c : cases) { - prepare_input(c.first, inputsData, inputDynamicShapes); - run(); - auto out = get_runtime_output()[0].as>(); - check_output(c.second, out); - } -} - -TEST_P(SoftMaxLayerTest, NegativeInfinityOnlyCase) { - if (targetDevice != ov::test::utils::DEVICE_GPU) - GTEST_SKIP(); - - prepare_input({-INFINITY, 1.f, 2.f}, inputsData, inputDynamicShapes); - run(); - - auto out = get_runtime_output()[0].as>(); - check_output({0.f, 0.2689414f, 0.7310586f}, out); -} - -TEST_P(SoftMaxLayerTest, NaNPropagationCases) { - if (targetDevice != ov::test::utils::DEVICE_GPU) - GTEST_SKIP(); - - std::vector> cases = { - {NAN, 1.f, 2.f}, - {1.f, NAN, 2.f}, - {NAN, NAN, NAN} - }; - - for (auto& c : cases) { - prepare_input(c, inputsData, inputDynamicShapes); - run(); - - auto out = get_runtime_output()[0].as>(); - for (float v : out) - EXPECT_TRUE(std::isnan(v)); - } -} - } // namespace subgraph } // namespace test } // namespace ov From 6a912b6d75d144921bd3a72ce4e750f500e46404 Mon Sep 17 00:00:00 2001 From: AyusKumarPathak Date: Fri, 16 Jan 2026 15:42:23 +0530 Subject: [PATCH 4/7] Address reviewer feedback on GPU softmax tests --- .../functional/single_layer_tests/softmax.cpp | 23 +++++++++++++------ 1 file changed, 16 insertions(+), 7 deletions(-) diff --git a/src/plugins/intel_gpu/tests/functional/single_layer_tests/softmax.cpp b/src/plugins/intel_gpu/tests/functional/single_layer_tests/softmax.cpp index 9d63ffa7f4aa1e..2849d2a99446b8 100644 --- a/src/plugins/intel_gpu/tests/functional/single_layer_tests/softmax.cpp +++ b/src/plugins/intel_gpu/tests/functional/single_layer_tests/softmax.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2018-2025 Intel Corporation +// Copyright (C) 2018-2026 Intel Corporation // SPDX-License-Identifier: Apache-2.0 #include @@ -8,8 +8,9 @@ #include "shared_test_classes/single_op/softmax.hpp" #include "common_test_utils/ov_tensor_utils.hpp" -using namespace ov::test; -using namespace ov::test::subgraph; +namespace ov { +namespace test { +namespace subgraph { // ======================= // GPU Numerical Edge Cases @@ -30,6 +31,8 @@ static void prepare_input(const std::vector& values, static void check_output(const std::vector& expected, const std::vector& actual) { + ASSERT_EQ(expected.size(), actual.size()); + for (size_t i = 0; i < expected.size(); ++i) { if (std::isnan(expected[i])) { EXPECT_TRUE(std::isnan(actual[i])); @@ -72,7 +75,9 @@ TEST_P(SoftMaxLayerTest, NegativeInfinityOnlyCase) { prepare_input({-INFINITY, 1.f, 2.f}, inputsData, inputDynamicShapes); run(); auto out = get_runtime_output()[0].as>(); - check_output({0.f, 0.2689414f, 0.7310586f}, out); + + std::vector expected = {0.f, 0.2689414f, 0.7310586f}; + EXPECT_THAT(out, ::testing::ElementsAreArray(expected)); } TEST_P(SoftMaxLayerTest, NaNPropagationCases) { @@ -86,8 +91,12 @@ TEST_P(SoftMaxLayerTest, NaNPropagationCases) { prepare_input(c, inputsData, inputDynamicShapes); run(); auto out = get_runtime_output()[0].as>(); - for (float v : out) { - EXPECT_TRUE(std::isnan(v)); - } + + std::vector expected(out.size(), std::numeric_limits::quiet_NaN()); + EXPECT_THAT(out, ::testing::ElementsAreArray(expected)); } } + +} // namespace subgraph +} // namespace test +} // namespace ov From 9c3ae649f3c2f8546e821586d75b74e43000ff5a Mon Sep 17 00:00:00 2001 From: AyusKumarPathak <150468678+AyusKumarPathak@users.noreply.github.com> Date: Fri, 16 Jan 2026 19:47:35 +0530 Subject: [PATCH 5/7] Update src/plugins/intel_gpu/tests/functional/single_layer_tests/softmax.cpp Co-authored-by: Pawel Raasz --- .../intel_gpu/tests/functional/single_layer_tests/softmax.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/plugins/intel_gpu/tests/functional/single_layer_tests/softmax.cpp b/src/plugins/intel_gpu/tests/functional/single_layer_tests/softmax.cpp index 2849d2a99446b8..a9d1d497523320 100644 --- a/src/plugins/intel_gpu/tests/functional/single_layer_tests/softmax.cpp +++ b/src/plugins/intel_gpu/tests/functional/single_layer_tests/softmax.cpp @@ -8,9 +8,7 @@ #include "shared_test_classes/single_op/softmax.hpp" #include "common_test_utils/ov_tensor_utils.hpp" -namespace ov { -namespace test { -namespace subgraph { +namespace ov::test { // ======================= // GPU Numerical Edge Cases From f5610332d3ed9c6164d4241784afe6d3240aa24c Mon Sep 17 00:00:00 2001 From: AyusKumarPathak <150468678+AyusKumarPathak@users.noreply.github.com> Date: Fri, 16 Jan 2026 19:50:11 +0530 Subject: [PATCH 6/7] updated --- .../intel_gpu/tests/functional/single_layer_tests/softmax.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/plugins/intel_gpu/tests/functional/single_layer_tests/softmax.cpp b/src/plugins/intel_gpu/tests/functional/single_layer_tests/softmax.cpp index a9d1d497523320..6677cca2521376 100644 --- a/src/plugins/intel_gpu/tests/functional/single_layer_tests/softmax.cpp +++ b/src/plugins/intel_gpu/tests/functional/single_layer_tests/softmax.cpp @@ -95,6 +95,5 @@ TEST_P(SoftMaxLayerTest, NaNPropagationCases) { } } -} // namespace subgraph -} // namespace test + } // namespace ov From c46613aeff2428fe26dff84ae6b0a513c6764924 Mon Sep 17 00:00:00 2001 From: AyusKumarPathak Date: Sat, 17 Jan 2026 00:42:22 +0530 Subject: [PATCH 7/7] Apply reviewer suggestions to GPU softmax tests --- .../functional/single_layer_tests/softmax.cpp | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/src/plugins/intel_gpu/tests/functional/single_layer_tests/softmax.cpp b/src/plugins/intel_gpu/tests/functional/single_layer_tests/softmax.cpp index 2849d2a99446b8..98e022281ec629 100644 --- a/src/plugins/intel_gpu/tests/functional/single_layer_tests/softmax.cpp +++ b/src/plugins/intel_gpu/tests/functional/single_layer_tests/softmax.cpp @@ -8,9 +8,7 @@ #include "shared_test_classes/single_op/softmax.hpp" #include "common_test_utils/ov_tensor_utils.hpp" -namespace ov { -namespace test { -namespace subgraph { +namespace ov::test::subgraph { // ======================= // GPU Numerical Edge Cases @@ -77,7 +75,10 @@ TEST_P(SoftMaxLayerTest, NegativeInfinityOnlyCase) { auto out = get_runtime_output()[0].as>(); std::vector expected = {0.f, 0.2689414f, 0.7310586f}; + + // Reviewer suggestion applied (both forms) EXPECT_THAT(out, ::testing::ElementsAreArray(expected)); + EXPECT_THAT(out, ::testing::ElementsAreArray(0.f, 0.2689414f, 0.7310586f)); } TEST_P(SoftMaxLayerTest, NaNPropagationCases) { @@ -93,10 +94,11 @@ TEST_P(SoftMaxLayerTest, NaNPropagationCases) { auto out = get_runtime_output()[0].as>(); std::vector expected(out.size(), std::numeric_limits::quiet_NaN()); + + // Reviewer suggestion applied EXPECT_THAT(out, ::testing::ElementsAreArray(expected)); + EXPECT_THAT(out, ::testing::Each(std::numeric_limits::quiet_NaN())); } } -} // namespace subgraph -} // namespace test -} // namespace ov +} // namespace ov::test::subgraph