enable reference implementation in CTCGreedyDecoder single layer test (#2680)
authorPatryk Elszkowski <patryk.elszkowski@intel.com>
Mon, 26 Oct 2020 10:34:50 +0000 (11:34 +0100)
committerGitHub <noreply@github.com>
Mon, 26 Oct 2020 10:34:50 +0000 (13:34 +0300)
* enable reference implementation for CTCGreedyDecoder single layer tests

* update unit test to have blnak_index

* remove merge_repeated disable flag for CPU test because CPU impl always
merge

* add CTCGreedyDecoder single layer tests for CPU

* changes to match xPU implementations

* apply reviewers suggestions

Co-authored-by: Patryk Elszkowski <patryk.elszkowki@intel.com>
inference-engine/tests/functional/plugin/cpu/shared_tests_instances/single_layer_tests/ctc_greedy_decoder.cpp [new file with mode: 0644]
inference-engine/tests/functional/plugin/shared/include/single_layer_tests/ctc_greedy_decoder.hpp
inference-engine/tests/functional/plugin/shared/src/single_layer_tests/ctc_greedy_decoder.cpp
ngraph/core/reference/include/ngraph/runtime/reference/ctc_greedy_decoder.hpp
ngraph/test/backend/ctc_greedy_decoder.in.cpp

diff --git a/inference-engine/tests/functional/plugin/cpu/shared_tests_instances/single_layer_tests/ctc_greedy_decoder.cpp b/inference-engine/tests/functional/plugin/cpu/shared_tests_instances/single_layer_tests/ctc_greedy_decoder.cpp
new file mode 100644 (file)
index 0000000..e128cf3
--- /dev/null
@@ -0,0 +1,33 @@
+// Copyright (C) 2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+//
+
+#include <vector>
+#include "single_layer_tests/ctc_greedy_decoder.hpp"
+#include "common_test_utils/test_constants.hpp"
+
+using namespace LayerTestsDefinitions;
+using namespace ngraph::helpers;
+
+namespace {
+// Common params
+const std::vector<InferenceEngine::Precision> netPrecisions = {
+    InferenceEngine::Precision::FP32,
+    InferenceEngine::Precision::FP16
+};
+
+const auto basicCases = ::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::Values(std::vector<size_t>({ 10, 1, 16 }),
+                      std::vector<size_t>({ 20, 2, 8 })),
+    ::testing::Values(true/*, false - current implementation of CPU greedy decoder always merge_repeated */),
+    ::testing::Values(CommonTestUtils::DEVICE_CPU));
+
+INSTANTIATE_TEST_CASE_P(smoke_CTC_Greedy_decoder_Basic, CTCGreedyDecoderLayerTest,
+                        basicCases,
+                        CTCGreedyDecoderLayerTest::getTestCaseName);
+}  // namespace
index 7372446..d564f55 100644 (file)
@@ -50,7 +50,6 @@ protected:
     InferenceEngine::SizeVector sequenceLengths;
     bool mergeRepeated;
 
-    std::vector<std::vector<std::uint8_t>> CalculateRefs() override;
     void SetUp() override;
 };
 
index 4c6f91c..c759aeb 100644 (file)
@@ -51,83 +51,6 @@ std::string CTCGreedyDecoderLayerTest::getTestCaseName(
     return result.str();
 }
 
-std::vector<std::vector<std::uint8_t>> CTCGreedyDecoderLayerTest::CalculateRefs() {
-    std::vector<const float *> inRawData;
-    std::vector<InferenceEngine::Blob::Ptr> castedBlobs;
-    for (size_t i = 0; i < inputs.size(); i++) {
-        const auto precision = inputs[i]->getTensorDesc().getPrecision();
-        const auto layout = inputs[i]->getTensorDesc().getLayout();
-        const auto defLayout = InferenceEngine::TensorDesc::getLayoutByDims(inputs[i]->getTensorDesc().getDims());
-
-        if (precision == InferenceEngine::Precision::FP32 && layout == defLayout) {
-            inRawData.push_back(inputs[i]->cbuffer().template as<const float*>());
-        } else {
-            auto castedBlob = FuncTestUtils::copyBlobWithCast<InferenceEngine::Precision::FP32>(inputs[i]);
-            castedBlob = FuncTestUtils::convertBlobLayout(castedBlob, defLayout);
-            inRawData.push_back(castedBlob->cbuffer().template as<const float*>());
-            castedBlobs.push_back(castedBlob);
-        }
-    }
-
-    size_t T_ = inputShapes.at(0);
-    size_t N_ = inputShapes.at(1);
-    size_t C_ = inputShapes.at(2);
-    auto outSize = T_ * N_;
-    float a = 43;
-    const float* probabilities = inRawData[0];
-    const float* sequence_indicators = inRawData[1];
-    auto outBuf = std::vector<float>(outSize);
-    float* output_sequences = outBuf.data();
-
-    for (auto i = 0; i < outSize; i++)
-        output_sequences[i] = -1.0f;
-
-    for (size_t n = 0; n < N_; ++n) {
-        int prev_class_idx = -1;
-        size_t output_index = n * T_;
-
-        for (size_t t = 0; /* check at end */; ++t) {
-            // get maximum probability and its index
-            int max_class_idx = 0;
-
-            const float* probs = probabilities + t * C_ * N_ + n * C_;
-            float max_prob = probs[0];
-            ++probs;
-
-            for (size_t c = 1; c < C_; ++c, ++probs) {
-                if (*probs > max_prob) {
-                    max_class_idx = static_cast<int>(c);
-                    max_prob = *probs;
-                }
-            }
-
-            if (max_class_idx < static_cast<int>(C_) - 1 &&
-                max_class_idx != prev_class_idx) {
-                output_sequences[output_index] = static_cast<float>(max_class_idx);
-                output_index++;
-            }
-
-            prev_class_idx = max_class_idx;
-
-            if (t + 1 == T_ || sequence_indicators[(t + 1) * N_ + n] == 0) {
-                break;
-            }
-        }
-    }
-
-    // Be aligned with test utils ref calulcation method, which returns std::vector<std::vector<uint8_t>>...
-    std::vector<std::vector<uint8_t>> ret(1);
-    for (auto& val : outBuf) {
-        uint8_t* u8_val = reinterpret_cast<uint8_t*>(&val);
-        ret[0].push_back(u8_val[0]);
-        ret[0].push_back(u8_val[1]);
-        ret[0].push_back(u8_val[2]);
-        ret[0].push_back(u8_val[3]);
-    }
-
-    return ret;
-}
-
 void CTCGreedyDecoderLayerTest::SetUp() {
     auto netPrecision = InferenceEngine::Precision::UNSPECIFIED;
     std::tie(netPrecision, inPrc, outPrc, inLayout, outLayout, inputShapes, mergeRepeated, targetDevice) = GetParam();
@@ -146,7 +69,6 @@ void CTCGreedyDecoderLayerTest::SetUp() {
 }
 
 TEST_P(CTCGreedyDecoderLayerTest, CompareWithRefs) {
-    //std::vector<std::shared_ptr<float*>> CalculateRefs();
     Run();
 };
 }  // namespace LayerTestsDefinitions
index 40a9e3d..21eb99f 100644 (file)
@@ -35,9 +35,10 @@ namespace ngraph
                                     const Shape& out_shape,
                                     const bool ctc_merge_repeated)
             {
-                auto max_seq_len = data_shape[0];
-                auto batch_size = data_shape[1];
-                auto class_count = data_shape[2];
+                const auto max_seq_len = data_shape[0];
+                const auto batch_size = data_shape[1];
+                const auto class_count = data_shape[2];
+                const auto blank_index = class_count - 1;
 
                 CoordinateTransform out_transform = CoordinateTransform(out_shape);
                 CoordinateTransform data_transform = CoordinateTransform(data_shape);
@@ -59,18 +60,17 @@ namespace ngraph
                         auto mask_index = seq_masks_transform.index({seq_ind, batch_ind});
 
                         // first 0 marks the end of a sequence
-                        if (std::abs(static_cast<double>(sequence_masks[mask_index] -
-                                                         static_cast<T>(1))) >
-                            std::numeric_limits<double>::epsilon())
+                        if (seq_ind && sequence_masks[mask_index] == T{0})
                         {
-                            continue;
+                            break;
                         }
 
                         auto class_index = data + data_index;
                         auto class_max_element =
                             std::max_element(class_index, class_index + class_count);
                         unsigned int max_class_ind = std::distance(class_index, class_max_element);
-                        if (!(previous_class_index == max_class_ind && ctc_merge_repeated))
+                        if (!(previous_class_index == max_class_ind && ctc_merge_repeated) &&
+                            max_class_ind < blank_index)
                         {
                             tmp_out[out_index++] = max_class_ind;
                         }
index db52946..ae516d7 100644 (file)
@@ -49,7 +49,7 @@ NGRAPH_TEST(${BACKEND_NAME}, ctc_greedy_decoder)
 {
     const int T = 3;
     const int N = 1;
-    const int C = 2;
+    const int C = 3;
     const auto data_shape = Shape{T, N, C};
     const auto masks_shape = Shape{T, N};
 
@@ -59,7 +59,7 @@ NGRAPH_TEST(${BACKEND_NAME}, ctc_greedy_decoder)
     auto function = make_shared<Function>(decoder, ParameterVector{data, masks});
     auto test_case = test::TestCase<TestEngine>(function);
 
-    test_case.add_input<float>({0.1f, 0.2f, 0.4f, 0.3f, 0.5f, 0.6f});
+    test_case.add_input<float>({0.1f, 0.2f, 0.f, 0.4f, 0.3f, 0.f, 0.5f, 0.6f, 0.f});
     test_case.add_input<float>({1.0f, 1.0f, 1.0f});
     test_case.add_expected_output(Shape{N, T, 1, 1}, vector<float>{1.0f, 0.0f, 1.0f});
 
@@ -70,7 +70,7 @@ NGRAPH_TEST(${BACKEND_NAME}, ctc_greedy_decoder_f16)
 {
     const int T = 3;
     const int N = 1;
-    const int C = 2;
+    const int C = 3;
     const auto data_shape = Shape{T, N, C};
     const auto masks_shape = Shape{T, N};
 
@@ -80,7 +80,7 @@ NGRAPH_TEST(${BACKEND_NAME}, ctc_greedy_decoder_f16)
     auto function = make_shared<Function>(decoder, ParameterVector{data, masks});
     auto test_case = test::TestCase<TestEngine>(function);
 
-    test_case.add_input<float16>({0.1f, 0.2f, 0.4f, 0.3f, 0.5f, 0.6f});
+    test_case.add_input<float16>({0.1f, 0.2f, 0.f, 0.4f, 0.3f, 0.f, 0.5f, 0.6f, 0.f});
     test_case.add_input<float16>({1.0f, 1.0f, 1.0f});
     test_case.add_expected_output(Shape{N, T, 1, 1}, vector<float16>{1.0f, 0.0f, 1.0f});
 
@@ -91,7 +91,7 @@ NGRAPH_TEST(${BACKEND_NAME}, ctc_greedy_decoder_multiple_batches)
 {
     const int T = 3;
     const int N = 2;
-    const int C = 2;
+    const int C = 3;
     const auto data_shape = Shape{T, N, C};
     const auto masks_shape = Shape{T, N};
 
@@ -101,8 +101,24 @@ NGRAPH_TEST(${BACKEND_NAME}, ctc_greedy_decoder_multiple_batches)
     auto function = make_shared<Function>(decoder, ParameterVector{data, masks});
     auto test_case = test::TestCase<TestEngine>(function);
 
-    test_case.add_input<float>(
-        {0.1f, 0.2f, 0.15f, 0.25f, 0.4f, 0.3f, 0.45f, 0.35f, 0.5f, 0.6f, 0.55f, 0.65f});
+    test_case.add_input<float>({0.1f,
+                                0.2f,
+                                0.f,
+                                0.15f,
+                                0.25f,
+                                0.f,
+                                0.4f,
+                                0.3f,
+                                0.f,
+                                0.45f,
+                                0.35f,
+                                0.f,
+                                0.5f,
+                                0.6f,
+                                0.f,
+                                0.55f,
+                                0.65f,
+                                0.f});
 
     test_case.add_input<float>({1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f});
 
@@ -116,7 +132,7 @@ NGRAPH_TEST(${BACKEND_NAME}, ctc_greedy_decoder_single_batch_short_sequence)
 {
     const int T = 3;
     const int N = 1;
-    const int C = 2;
+    const int C = 3;
     const auto data_shape = Shape{T, N, C};
     const auto masks_shape = Shape{T, N};
 
@@ -126,7 +142,7 @@ NGRAPH_TEST(${BACKEND_NAME}, ctc_greedy_decoder_single_batch_short_sequence)
     auto function = make_shared<Function>(decoder, ParameterVector{data, masks});
     auto test_case = test::TestCase<TestEngine>(function);
 
-    test_case.add_input<float>({0.1f, 0.2f, 0.4f, 0.3f, 0.5f, 0.6f});
+    test_case.add_input<float>({0.1f, 0.2f, 0.f, 0.4f, 0.3f, 0.f, 0.5f, 0.6f, 0.f});
     test_case.add_input<float>({1.0f, 1.0f, 0.0f});
     test_case.add_expected_output(Shape{N, T, 1, 1}, vector<float>{1.0f, 0.0f, -1.0f});
 
@@ -137,7 +153,7 @@ NGRAPH_TEST(${BACKEND_NAME}, ctc_greedy_decoder_merge)
 {
     const int T = 3;
     const int N = 1;
-    const int C = 2;
+    const int C = 3;
     const auto data_shape = Shape{T, N, C};
     const auto masks_shape = Shape{T, N};
 
@@ -147,7 +163,7 @@ NGRAPH_TEST(${BACKEND_NAME}, ctc_greedy_decoder_merge)
     auto function = make_shared<Function>(decoder, ParameterVector{data, masks});
     auto test_case = test::TestCase<TestEngine>(function);
 
-    test_case.add_input<float>({0.1f, 0.2f, 0.3f, 0.4f, 0.6f, 0.5f});
+    test_case.add_input<float>({0.1f, 0.2f, 0.f, 0.3f, 0.4f, 0.f, 0.6f, 0.5f, 0.f});
     test_case.add_input<float>({1.0f, 1.0f, 1.0f});
     test_case.add_expected_output(Shape{N, T, 1, 1}, vector<float>{1.0f, 0.0f, -1.0f});
 
@@ -158,7 +174,7 @@ NGRAPH_TEST(${BACKEND_NAME}, ctc_greedy_decoder_single_no_merge)
 {
     const int T = 3;
     const int N = 1;
-    const int C = 2;
+    const int C = 3;
     const auto data_shape = Shape{T, N, C};
     const auto masks_shape = Shape{T, N};
 
@@ -168,7 +184,7 @@ NGRAPH_TEST(${BACKEND_NAME}, ctc_greedy_decoder_single_no_merge)
     auto function = make_shared<Function>(decoder, ParameterVector{data, masks});
     auto test_case = test::TestCase<TestEngine>(function);
 
-    test_case.add_input<float>({0.1f, 0.2f, 0.3f, 0.4f, 0.6f, 0.5f});
+    test_case.add_input<float>({0.1f, 0.2f, 0.f, 0.3f, 0.4f, 0.f, 0.6f, 0.5f, 0.f});
     test_case.add_input<float>({1.0f, 1.0f, 1.0f});
     test_case.add_expected_output(Shape{N, T, 1, 1}, vector<float>{1.0f, 1.0f, 0.0f});
 
@@ -179,7 +195,7 @@ NGRAPH_TEST(${BACKEND_NAME}, ctc_greedy_decoder_multiple_sequences)
 {
     const int T = 2;
     const int N = 2;
-    const int C = 2;
+    const int C = 3;
     const auto data_shape = Shape{T, N, C};
     const auto masks_shape = Shape{T, N};
 
@@ -189,7 +205,8 @@ NGRAPH_TEST(${BACKEND_NAME}, ctc_greedy_decoder_multiple_sequences)
     auto function = make_shared<Function>(decoder, ParameterVector{data, masks});
     auto test_case = test::TestCase<TestEngine>(function);
 
-    test_case.add_input<float>({0.1f, 0.2f, 0.4f, 0.3f, 0.5f, 0.6f, 0.7f, 0.8f});
+    test_case.add_input<float>(
+        {0.1f, 0.2f, 0.f, 0.4f, 0.3f, 0.f, 0.5f, 0.6f, 0.f, 0.7f, 0.8f, 0.f});
     test_case.add_input<float>({1.0f, 1.0f, 1.0f, 0.0f});
     test_case.add_expected_output(Shape{N, T, 1, 1}, vector<float>{1.0f, 1.0f, 0.0f, -1.0f});