Skip to content

Commit

Permalink
ReorgYolo reference implementation (openvinotoolkit#2384)
Browse files Browse the repository at this point in the history
* Align ReorgYolo to the spec (vector strides -> int stride)

* ReorgYolo ref impl

* ReorgYolo evaluate method

* ReorgYolo tests

* Tests update

* Style apply

* Add some coments

* Code refactor

* Comment update

* Style apply

* Build fix, mark evaluate as override

* Revert "Align ReorgYolo to the spec (vector strides -> int stride)"

* Use int_executable instead of evaluate

* Use char* instead of templates

* Code refactor

* Comment update

* Code review comment

* Add constructor aligned with spec

* Update shape validation

* Update attributes tests

* Add type_prop tests

* Update backend tests

* Add single layer tests

* Update the spec

* Remove wrong transformation test
  • Loading branch information
mitruska authored and mryzhov committed Dec 15, 2020
1 parent c437bcd commit c3bf59a
Show file tree
Hide file tree
Showing 15 changed files with 540 additions and 41 deletions.
6 changes: 3 additions & 3 deletions docs/ops/detection/ReorgYolo_1.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@

**Inputs**:

* **1**: 4D input tensor of any type and shape `[N, C, H, W]`. `H` and `W` should be divisible by `stride`. Required.
* **1**: 4D input tensor of any type and shape `[N, C, H, W]`. `H` and `W` should be divisible by `stride` and `C >= (stride*stride)`. **Required.**

**Outputs**:

Expand All @@ -31,7 +31,7 @@
**Example**

```xml
<layer id="89" name="ExtractImagePatches" type="ReorgYolo">
<layer id="89" name="reorg" type="ReorgYolo">
<data stride="2"/>
<input>
<port id="0">
Expand All @@ -50,4 +50,4 @@
</port>
</output>
</layer>
```
```
Original file line number Diff line number Diff line change
Expand Up @@ -19,38 +19,7 @@

using namespace testing;

TEST(TransformationTests, ConvertExtractImagePatchesToReorgYoloTests1) {
std::shared_ptr<ngraph::Function> f(nullptr), f_ref(nullptr);
{
auto input = std::make_shared<ngraph::opset1::Parameter>(ngraph::element::f32, ngraph::Shape{1, 3, 10, 10});

auto sizes = ngraph::Shape{5, 5};
auto strides = ngraph::Strides{5, 5};
auto rates = ngraph::Shape{1, 1};
ngraph::op::PadType auto_pad = ngraph::op::PadType::VALID;

auto eip = std::make_shared<ngraph::opset3::ExtractImagePatches>(input, sizes, strides, rates, auto_pad);

f = std::make_shared<ngraph::Function>(ngraph::NodeVector{eip}, ngraph::ParameterVector{input});

ngraph::pass::Manager manager;
manager.register_pass<ngraph::pass::InitNodeInfo>();
manager.register_pass<ngraph::pass::ConvertExtractImagePatchesToReorgYolo>();
manager.run_passes(f);
ASSERT_NO_THROW(check_rt_info(f));
}

{
auto input = std::make_shared<ngraph::opset1::Parameter>(ngraph::element::f32, ngraph::Shape{1, 3, 10, 10});
auto strides = ngraph::Strides{5, 5};
auto reorg_yolo = std::make_shared<ngraph::opset3::ReorgYolo>(input, strides);

f_ref = std::make_shared<ngraph::Function>(ngraph::NodeVector{reorg_yolo}, ngraph::ParameterVector{input});
}

auto res = compare_functions(f, f_ref);
ASSERT_TRUE(res.first) << res.second;
}
// TODO: bug 39971, remove ConvertExtractImagePatchesToReorgYolo transformation

TEST(TransformationTests, ConvertExtractImagePatchesToReorgYoloTestsNegative1) {
std::shared_ptr<ngraph::Function> f(nullptr), f_ref(nullptr);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
// Copyright (C) 2020 Intel Corporation
// SPDX-License-Identifier: Apache-2.0
//

#include <vector>

#include "single_layer_tests/reorg_yolo.hpp"
#include "common_test_utils/test_constants.hpp"

using namespace LayerTestsDefinitions;

const std::vector<ngraph::Shape> inShapes_caffe_yolov2 = {
{1, 64, 26, 26},
};

const std::vector<ngraph::Shape> inShapes = {
{1, 4, 4, 4},
{1, 8, 4, 4},
{1, 9, 3, 3},
{1, 24, 34, 62},
{2, 8, 4, 4},
};

const std::vector<size_t> strides = {
2, 3
};

const auto testCase_caffe_yolov2 = ::testing::Combine(
::testing::ValuesIn(inShapes_caffe_yolov2),
::testing::Values(strides[0]),
::testing::Values(InferenceEngine::Precision::FP32),
::testing::Values(CommonTestUtils::DEVICE_CPU)
);

const auto testCase_smallest = ::testing::Combine(
::testing::Values(inShapes[0]),
::testing::Values(strides[0]),
::testing::Values(InferenceEngine::Precision::FP32),
::testing::Values(CommonTestUtils::DEVICE_CPU)
);

const auto testCase_stride_2 = ::testing::Combine(
::testing::Values(inShapes[1]),
::testing::Values(strides[0]),
::testing::Values(InferenceEngine::Precision::FP32),
::testing::Values(CommonTestUtils::DEVICE_CPU)
);

const auto testCase_stride_3 = ::testing::Combine(
::testing::Values(inShapes[2]),
::testing::Values(strides[1]),
::testing::Values(InferenceEngine::Precision::FP32),
::testing::Values(CommonTestUtils::DEVICE_CPU)
);

const auto testCase_smaller_h = ::testing::Combine(
::testing::Values(inShapes[4]),
::testing::Values(strides[0]),
::testing::Values(InferenceEngine::Precision::FP32),
::testing::Values(CommonTestUtils::DEVICE_CPU)
);

const auto testCase_batch_2 = ::testing::Combine(
::testing::Values(inShapes[3]),
::testing::Values(strides[0]),
::testing::Values(InferenceEngine::Precision::FP32),
::testing::Values(CommonTestUtils::DEVICE_CPU)
);

INSTANTIATE_TEST_CASE_P(smoke_TestsReorgYolo_caffe_YoloV2, ReorgYoloLayerTest, testCase_caffe_yolov2, ReorgYoloLayerTest::getTestCaseName);
INSTANTIATE_TEST_CASE_P(smoke_TestsReorgYolo_stride_2_smallest, ReorgYoloLayerTest, testCase_smallest, ReorgYoloLayerTest::getTestCaseName);
INSTANTIATE_TEST_CASE_P(smoke_TestsReorgYolo_stride_2, ReorgYoloLayerTest, testCase_stride_2, ReorgYoloLayerTest::getTestCaseName);
INSTANTIATE_TEST_CASE_P(smoke_TestsReorgYolo_stride_3, ReorgYoloLayerTest, testCase_stride_3, ReorgYoloLayerTest::getTestCaseName);
INSTANTIATE_TEST_CASE_P(smoke_TestsReorgYolo_smaller_h, ReorgYoloLayerTest, testCase_smaller_h, ReorgYoloLayerTest::getTestCaseName);
INSTANTIATE_TEST_CASE_P(smoke_TestsReorgYolo_batch_2, ReorgYoloLayerTest, testCase_batch_2, ReorgYoloLayerTest::getTestCaseName);
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
// Copyright (C) 2019 Intel Corporation
// SPDX-License-Identifier: Apache-2.0
//

#pragma once

#include <tuple>
#include <string>
#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 ReorgYoloParamsTuple = typename std::tuple<
ngraph::Shape, // Input Shape
size_t, // stride
InferenceEngine::Precision, // Network precision
std::string>; // Device name

class ReorgYoloLayerTest : public testing::WithParamInterface<ReorgYoloParamsTuple>,
virtual public LayerTestsUtils::LayerTestsCommon {
public:
static std::string getTestCaseName(const testing::TestParamInfo<ReorgYoloParamsTuple> &obj);

protected:
void SetUp() override;
};

} // namespace LayerTestsDefinitions
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
// Copyright (C) 2020 Intel Corporation
// SPDX-License-Identifier: Apache-2.0
//

#include "ie_core.hpp"

#include "common_test_utils/common_utils.hpp"
#include "functional_test_utils/blob_utils.hpp"
#include "functional_test_utils/precision_utils.hpp"
#include "functional_test_utils/plugin_cache.hpp"
#include "functional_test_utils/skip_tests_config.hpp"

#include "single_layer_tests/reorg_yolo.hpp"

namespace LayerTestsDefinitions {

std::string ReorgYoloLayerTest::getTestCaseName(const testing::TestParamInfo<ReorgYoloParamsTuple> &obj) {
ngraph::Shape inputShape;
size_t stride;
InferenceEngine::Precision netPrecision;
std::string targetName;
std::tie(inputShape, stride, netPrecision, targetName) = obj.param;
std::ostringstream result;
result << "IS=" << inputShape << "_";
result << "stride=" << stride << "_";
result << "netPRC=" << netPrecision.name() << "_";
result << "targetDevice=" << targetName << "_";
return result.str();
}

void ReorgYoloLayerTest::SetUp() {
ngraph::Shape inputShape;
size_t stride;
InferenceEngine::Precision netPrecision;
std::tie(inputShape, stride, netPrecision, targetDevice) = this->GetParam();
auto ngPrc = FuncTestUtils::PrecisionUtils::convertIE2nGraphPrc(netPrecision);
auto param = std::make_shared<ngraph::op::Parameter>(ngraph::element::f32, inputShape);
auto reorg_yolo = std::make_shared<ngraph::op::v0::ReorgYolo>(param, stride);
function = std::make_shared<ngraph::Function>(std::make_shared<ngraph::opset1::Result>(reorg_yolo), ngraph::ParameterVector{param}, "ReorgYolo");
}

TEST_P(ReorgYoloLayerTest, CompareWithRefs) {
Run();
};

} // namespace LayerTestsDefinitions
5 changes: 4 additions & 1 deletion ngraph/core/include/ngraph/op/reorg_yolo.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,10 @@ namespace ngraph
/// \brief Constructs a ReorgYolo operation
///
/// \param input Input
/// \param strides Stride to reorganize input by
/// \param stride Stride to reorganize input by
ReorgYolo(const Output<Node>& input, const size_t stride);

// Constructor with `strides` for backward compatibility
ReorgYolo(const Output<Node>& input, const Strides& strides);

void validate_and_infer_types() override;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
//*****************************************************************************
// Copyright 2017-2020 Intel Corporation
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//*****************************************************************************

#pragma once

#include <cmath>
#include <cstddef>

#include "ngraph/shape.hpp"

namespace ngraph
{
namespace runtime
{
namespace reference
{
void reorg_yolo(const char* arg,
char* out,
const Shape& in_shape,
int64_t stride,
const size_t elem_size);
}
}
}
89 changes: 89 additions & 0 deletions ngraph/core/reference/src/runtime/reference/reorg_yolo.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
//*****************************************************************************
// Copyright 2017-2020 Intel Corporation
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//*****************************************************************************

#include <cmath>
#include <stdio.h>

#include "ngraph/runtime/reference/reorg_yolo.hpp"
#include "ngraph/shape.hpp"

using namespace ngraph;

namespace ngraph
{
namespace runtime
{
namespace reference
{
void reorg_yolo(const char* arg,
char* out,
const Shape& in_shape,
int64_t stride,
const size_t elem_size)
{
// [N, C, H, W]
size_t in_N = in_shape[0];
size_t in_C = in_shape[1];
size_t in_H = in_shape[2];
size_t in_W = in_shape[3];

// Inference output shape logic:
// in_shape [N,C,H,W] -> out_shape [N, C*(stride*stride), H/stride, W/stride]
// ReorgYolo implementation calculates new indices like for backprop:
// in_shape [N,C,H,W] -> out_shape [N, C/(stride*stride), H*stride, W*stride]

size_t impl_out_C = in_C / (stride * stride);
if (impl_out_C == 0)
{
throw ngraph_error(
"ReorgYolo. For [N, C, H, W] input shape, C >= (stride*stride) is "
"required.");
}
size_t impl_out_H = in_H * stride;
size_t impl_out_W = in_W * stride;

for (size_t n = 0; n < in_N; ++n)
{
for (size_t c = 0; c < in_C; ++c)
{
for (size_t h = 0; h < in_H; ++h)
{
for (size_t w = 0; w < in_W; ++w)
{
size_t offset = c / impl_out_C;
size_t impl_c = c % impl_out_C;
size_t impl_h = h * stride + offset / stride;
size_t impl_w = w * stride + offset % stride;

size_t arg_index =
((n * impl_out_C + impl_c) * impl_out_H + impl_h) * impl_out_W +
impl_w;
size_t dest_index = ((n * in_C + c) * in_H + h) * in_W + w;

arg_index *= elem_size;
dest_index *= elem_size;

std::copy(arg + arg_index,
arg + (arg_index + elem_size),
out + dest_index);
}
}
}
}
}
}
}
}
Loading

0 comments on commit c3bf59a

Please sign in to comment.