[CPU] Added LogSoftmax-5 support (#2743)
authorAlexandra Sidorova <alexandra.sidorova@intel.com>
Fri, 6 Nov 2020 10:22:02 +0000 (13:22 +0300)
committerGitHub <noreply@github.com>
Fri, 6 Nov 2020 10:22:02 +0000 (13:22 +0300)
inference-engine/src/mkldnn_plugin/mkldnn_plugin.cpp
inference-engine/src/mkldnn_plugin/nodes/log_softmax.cpp
inference-engine/tests/functional/plugin/cpu/shared_tests_instances/single_layer_tests/log_softmax.cpp [new file with mode: 0644]
inference-engine/tests/functional/plugin/shared/include/single_layer_tests/log_softmax.hpp [new file with mode: 0644]
inference-engine/tests/functional/plugin/shared/include/single_layer_tests/softmax.hpp
inference-engine/tests/functional/plugin/shared/src/single_layer_tests/log_softmax.cpp [new file with mode: 0644]
ngraph/test/runtime/ie/unit_test.manifest

index 902b8a1..1f69e7b 100644 (file)
@@ -44,6 +44,7 @@
 #include <transformations/op_conversions/convert_space_to_batch.hpp>
 #include <transformations/op_conversions/convert_batch_to_space.hpp>
 #include <transformations/op_conversions/convert_mod.hpp>
+#include <transformations/op_conversions/log_softmax_decomposition.hpp>
 #include <transformations/convert_precision.hpp>
 #include <transformations/init_node_info.hpp>
 #include <transformations/rt_info/fused_names_attribute.hpp>
@@ -147,6 +148,7 @@ static void Transformation(ICNNNetwork::Ptr& clonedNetwork, const Config& conf)
     pass_config->disable<ngraph::pass::SoftPlusDecomposition>();
     pass_config->disable<ngraph::pass::HSigmoidDecomposition>();
     pass_config->disable<ngraph::pass::ConvertMod>();
+    pass_config->disable<ngraph::pass::LogSoftmaxDecomposition>();
 
     pass_config->enable<ngraph::pass::ConvertPadToGroupConvolution>();
 
index b79109d..3c3a32e 100644 (file)
@@ -60,37 +60,41 @@ public:
     StatusCode execute(std::vector<Blob::Ptr>& inputs, std::vector<Blob::Ptr>& outputs, ResponseDesc *resp) noexcept override {
         const float *src_data = inputs[0]->cbuffer().as<float *>() +
             inputs[0]->getTensorDesc().getBlockingDesc().getOffsetPadding();
-        float* dst_data = outputs[0]->cbuffer().as<float *>() +
+        float* dst_data = outputs[0]->buffer().as<float *>() +
             outputs[0]->getTensorDesc().getBlockingDesc().getOffsetPadding();
 
         if (is_last_dim) {
             parallel_for(axis_step, [&](size_t i) {
-                float reduce_prod = 0.0f;
                 const float *src_dataPtr = &src_data[i * reduced_axis_size];
+                float *dst_dataPtr = &dst_data[i * reduced_axis_size];
+
+                float reduce_prod = 0.0f;
+                const float max = *std::max_element(src_dataPtr, src_dataPtr + reduced_axis_size);
                 for (size_t j = 0; j < reduced_axis_size; ++j)
-                    reduce_prod += expf(src_dataPtr[j]);
+                    reduce_prod += expf(src_dataPtr[j] - max);
+
                 reduce_prod = logf(reduce_prod);
-                float *dst_dataPtr = reinterpret_cast<float*>(&dst_data[i * reduced_axis_size]);
                 for (size_t j = 0; j < reduced_axis_size; ++j)
-                    dst_dataPtr[j] = src_dataPtr[j] - reduce_prod;
+                    dst_dataPtr[j] = src_dataPtr[j] - max - reduce_prod;
             });
         } else {
             parallel_for2d(axis_step, reduced_axis_stride, [&](size_t k, size_t i) {
-                float reduce_prod = 0.0f;
                 const float *src_dataPtr = &src_data[k * reduced_axis_stride * reduced_axis_size + i];
+                float *dst_dataPtr = &dst_data[k * reduced_axis_stride * reduced_axis_size + i];
+
+                float reduce_prod = 0.0f;
+                float max = std::numeric_limits<float>::min();
                 for (size_t j = 0; j < reduced_axis_size; ++j) {
-                    reduce_prod += expf((*src_dataPtr));
-                    src_dataPtr += reduced_axis_stride;
+                    if (src_dataPtr[j * reduced_axis_stride] > max)
+                        max = src_dataPtr[j * reduced_axis_stride];
                 }
 
+                for (size_t j = 0; j < reduced_axis_size; ++j)
+                    reduce_prod += expf(src_dataPtr[j * reduced_axis_stride] - max);
+
                 reduce_prod = logf(reduce_prod);
-                src_dataPtr = &src_data[k * reduced_axis_stride * reduced_axis_size + i];
-                float *dst_dataPtr = reinterpret_cast<float*>(&dst_data[k * reduced_axis_stride * reduced_axis_size + i]);
-                for (size_t j = 0; j < reduced_axis_size; ++j) {
-                    (*dst_dataPtr) = (*src_dataPtr) - reduce_prod;
-                    src_dataPtr += reduced_axis_stride;
-                    dst_dataPtr += reduced_axis_stride;
-                }
+                for (size_t j = 0; j < reduced_axis_size; ++j)
+                    dst_dataPtr[j * reduced_axis_stride] = src_dataPtr[j * reduced_axis_stride] - max - reduce_prod;
             });
         }
 
diff --git a/inference-engine/tests/functional/plugin/cpu/shared_tests_instances/single_layer_tests/log_softmax.cpp b/inference-engine/tests/functional/plugin/cpu/shared_tests_instances/single_layer_tests/log_softmax.cpp
new file mode 100644 (file)
index 0000000..8c87da1
--- /dev/null
@@ -0,0 +1,76 @@
+// Copyright (C) 2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+//
+
+#include <vector>
+
+#include "single_layer_tests/log_softmax.hpp"
+#include "common_test_utils/test_constants.hpp"
+
+using namespace LayerTestsDefinitions;
+
+namespace {
+
+const std::vector<InferenceEngine::Precision> netPrecisions = {
+    InferenceEngine::Precision::FP32,
+};
+
+const std::vector<InferenceEngine::SizeVector> inputShapes2D = {
+    InferenceEngine::SizeVector {1, 100},
+    InferenceEngine::SizeVector {100, 1},
+    InferenceEngine::SizeVector {10, 10},
+};
+
+const std::vector<int64_t> axis2D = {
+    -2, -1, 0, 1
+};
+
+const auto params2D = testing::Combine(
+    testing::ValuesIn(netPrecisions),
+    testing::Values(InferenceEngine::Precision::UNSPECIFIED),
+    testing::Values(InferenceEngine::Precision::UNSPECIFIED),
+    testing::Values(InferenceEngine::Layout::ANY),
+    testing::Values(InferenceEngine::Layout::ANY),
+    testing::ValuesIn(inputShapes2D),
+    testing::ValuesIn(axis2D),
+    testing::Values(CommonTestUtils::DEVICE_CPU),
+    testing::Values(std::map<std::string, std::string>())
+);
+
+INSTANTIATE_TEST_CASE_P(
+        smoke_LogSoftmax2D,
+        LogSoftmaxLayerTest,
+        params2D,
+        LogSoftmaxLayerTest::getTestCaseName
+);
+
+const std::vector<InferenceEngine::SizeVector> inputShapes4D = {
+    InferenceEngine::SizeVector {1, 100, 1, 1},
+    InferenceEngine::SizeVector {1, 3, 4, 3},
+    InferenceEngine::SizeVector {2, 3, 4, 5},
+};
+
+const std::vector<int64_t> axis4D = {
+    -4, -3, -2, -1, 0, 1, 2, 3
+};
+
+const auto params4D = testing::Combine(
+    testing::ValuesIn(netPrecisions),
+    testing::Values(InferenceEngine::Precision::UNSPECIFIED),
+    testing::Values(InferenceEngine::Precision::UNSPECIFIED),
+    testing::Values(InferenceEngine::Layout::ANY),
+    testing::Values(InferenceEngine::Layout::ANY),
+    testing::ValuesIn(inputShapes4D),
+    testing::ValuesIn(axis4D),
+    testing::Values(CommonTestUtils::DEVICE_CPU),
+    testing::Values(std::map<std::string, std::string>())
+);
+
+INSTANTIATE_TEST_CASE_P(
+        smoke_LogSoftmax4D,
+        LogSoftmaxLayerTest,
+        params4D,
+        LogSoftmaxLayerTest::getTestCaseName
+);
+
+}  // namespace
diff --git a/inference-engine/tests/functional/plugin/shared/include/single_layer_tests/log_softmax.hpp b/inference-engine/tests/functional/plugin/shared/include/single_layer_tests/log_softmax.hpp
new file mode 100644 (file)
index 0000000..0c2231d
--- /dev/null
@@ -0,0 +1,41 @@
+// Copyright (C) 2020 Intel Corporation
+//
+// SPDX-License-Identifier: Apache-2.0
+//
+
+#pragma once
+
+#include <map>
+#include <memory>
+#include <string>
+#include <tuple>
+#include <vector>
+
+#include "functional_test_utils/layer_test_utils.hpp"
+#include "ngraph_functions/builders.hpp"
+#include "ngraph_functions/utils/ngraph_helpers.hpp"
+
+namespace LayerTestsDefinitions {
+
+using logSoftmaxLayerTestParams = std::tuple<
+        InferenceEngine::Precision,         // netPrecision
+        InferenceEngine::Precision,         // Input precision
+        InferenceEngine::Precision,         // Output precision
+        InferenceEngine::Layout,            // Input layout
+        InferenceEngine::Layout,            // Output layout
+        InferenceEngine::SizeVector,        // inputShape
+        int64_t,                            // axis
+        std::string,                        // targetDevice
+        std::map<std::string, std::string>  // config
+>;
+
+class LogSoftmaxLayerTest : public testing::WithParamInterface<logSoftmaxLayerTestParams>,
+                            virtual public LayerTestsUtils::LayerTestsCommon {
+public:
+    static std::string getTestCaseName(testing::TestParamInfo<logSoftmaxLayerTestParams> obj);
+
+protected:
+    void SetUp() override;
+};
+
+}  // namespace LayerTestsDefinitions
index 87dd395..47dbd0f 100644 (file)
@@ -19,10 +19,10 @@ namespace LayerTestsDefinitions {
 
 using softMaxLayerTestParams = std::tuple<
         InferenceEngine::Precision,         // netPrecision
-        InferenceEngine::Precision,        // Input precision
-        InferenceEngine::Precision,        // Output precision
-        InferenceEngine::Layout,           // Input layout
-        InferenceEngine::Layout,           // Output layout
+        InferenceEngine::Precision,         // Input precision
+        InferenceEngine::Precision,         // Output precision
+        InferenceEngine::Layout,            // Input layout
+        InferenceEngine::Layout,            // Output layout
         InferenceEngine::SizeVector,        // inputShape
         size_t,                             // axis
         std::string,                        // targetDevice
diff --git a/inference-engine/tests/functional/plugin/shared/src/single_layer_tests/log_softmax.cpp b/inference-engine/tests/functional/plugin/shared/src/single_layer_tests/log_softmax.cpp
new file mode 100644 (file)
index 0000000..9981571
--- /dev/null
@@ -0,0 +1,70 @@
+// Copyright (C) 2020 Intel Corporation
+//
+// SPDX-License-Identifier: Apache-2.0
+//
+
+#include "single_layer_tests/log_softmax.hpp"
+
+#include "common_test_utils/common_utils.hpp"
+#include "functional_test_utils/skip_tests_config.hpp"
+#include "functional_test_utils/layer_test_utils.hpp"
+
+#include "ie_core.hpp"
+
+#include <tuple>
+#include <string>
+#include <vector>
+#include <memory>
+
+namespace LayerTestsDefinitions {
+
+std::string LogSoftmaxLayerTest::getTestCaseName(testing::TestParamInfo<logSoftmaxLayerTestParams> obj) {
+    InferenceEngine::Precision netPrecision;
+    InferenceEngine::Precision inPrc, outPrc;
+    InferenceEngine::Layout inLayout, outLayout;
+    InferenceEngine::SizeVector inputShape;
+    int64_t axis;
+    std::string targetDevice;
+    std::map<std::string, std::string> config;
+    std::tie(netPrecision, inPrc, outPrc, inLayout, outLayout, inputShape, axis, targetDevice, config) = obj.param;
+
+    std::ostringstream result;
+    result << "netPRC=" << netPrecision.name() << "_";
+    result << "inPRC=" << inPrc.name() << "_";
+    result << "outPRC=" << outPrc.name() << "_";
+    result << "inL=" << inLayout << "_";
+    result << "outL=" << outLayout << "_";
+    result << "IS=" << CommonTestUtils::vec2str(inputShape) << "_";
+    result << "axis=" << axis << "_";
+    result << "trgDev=" << targetDevice;
+
+    return result.str();
+}
+
+void LogSoftmaxLayerTest::SetUp() {
+    InferenceEngine::SizeVector inputShape;
+    InferenceEngine::Precision netPrecision;
+    int64_t axis;
+
+    std::tie(netPrecision, inPrc, outPrc, inLayout, outLayout, inputShape, axis, targetDevice, configuration) = GetParam();
+    outLayout = inLayout;
+
+    const auto ngPrc = FuncTestUtils::PrecisionUtils::convertIE2nGraphPrc(netPrecision);
+
+    const auto params = ngraph::builder::makeParams(ngPrc, {inputShape});
+
+    const auto paramOuts =
+        ngraph::helpers::convert2OutputVector(ngraph::helpers::castOps2Nodes<ngraph::op::Parameter>(params));
+
+    const auto logSoftmax = std::make_shared<ngraph::op::v5::LogSoftmax>(paramOuts.at(0), axis);
+
+    const ngraph::ResultVector results {std::make_shared<ngraph::opset1::Result>(logSoftmax)};
+
+    function = std::make_shared<ngraph::Function>(results, params, "logSoftmax");
+}
+
+TEST_P(LogSoftmaxLayerTest, CompareWithRefs) {
+    Run();
+}
+
+}  // namespace LayerTestsDefinitions
index 559f684..76e96fc 100644 (file)
@@ -1140,13 +1140,6 @@ IE_CPU.onnx_resize11_scales_nearest_asymmetric_floor_dynamic_sizes
 # Input data precision not supported. Expected float.
 ctc_greedy_decoder_f16
 
-# Wrong output when axis 0
-IE_CPU.log_softmax_1d_single_value
-IE_CPU.log_softmax_2d_axis0
-IE_CPU.log_softmax_2d_axis_neg2
-IE_CPU.log_softmax_3d_axis_0
-IE_CPU.log_softmax_3d_axis_neg3
-
 #-------------------------------------------------------------------------------
 #
 #       Inference Engine GPU plugin excludes