diff --git a/inference-engine/src/transformations/src/transformations/op_conversions/convert_broadcast3.cpp b/inference-engine/src/transformations/src/transformations/op_conversions/convert_broadcast3.cpp index 581a9f12820..2b251c3ef46 100644 --- a/inference-engine/src/transformations/src/transformations/op_conversions/convert_broadcast3.cpp +++ b/inference-engine/src/transformations/src/transformations/op_conversions/convert_broadcast3.cpp @@ -41,7 +41,11 @@ void ngraph::pass::ConvertBroadcast3::convert_broadcast3() { } else if (broadcast_type == op::BroadcastType::BIDIRECTIONAL) { auto constant_one = std::make_shared(input.get_element_type(), Shape({1}), std::vector{1}); auto broadcast_ones = std::make_shared(constant_one, target_shape, op::AutoBroadcastType::NUMPY); - last_node = std::make_shared(input, broadcast_ones); + if (input.get_element_type() == element::boolean) { + last_node = std::make_shared(input, broadcast_ones); + } else { + last_node = std::make_shared(input, broadcast_ones); + } ngraph::copy_runtime_info(broadcast, {last_node, broadcast_ones, constant_one}); } diff --git a/inference-engine/tests/functional/plugin/cpu/shared_tests_instances/single_layer_tests/broadcast.cpp b/inference-engine/tests/functional/plugin/cpu/shared_tests_instances/single_layer_tests/broadcast.cpp new file mode 100644 index 00000000000..89655ac8030 --- /dev/null +++ b/inference-engine/tests/functional/plugin/cpu/shared_tests_instances/single_layer_tests/broadcast.cpp @@ -0,0 +1,174 @@ +// Copyright (C) 2019 Intel Corporation +// SPDX-License-Identifier: Apache-2.0 +// + +#include + +#include "single_layer_tests/broadcast.hpp" +#include "common_test_utils/test_constants.hpp" + +using namespace LayerTestsDefinitions; + +namespace { + +const std::vector inputPrecisions = { + InferenceEngine::Precision::FP32, + InferenceEngine::Precision::I32, + InferenceEngine::Precision::BOOL +}; + +// NUMPY MODE + +std::vector> inShapesNumpy = { + {3, 1}, + {1, 4, 1} +}; + +std::vector> targetShapesNumpy = { + {2, 3, 6}, + {1, 4, 4} +}; + +const auto numpyBroadcastParams1 = ::testing::Combine( + ::testing::Values(targetShapesNumpy[0]), + ::testing::Values(ngraph::AxisSet{}), //not used in numpy mode + ::testing::Values(ngraph::op::BroadcastType::NUMPY), + ::testing::Values(inShapesNumpy[0]), + ::testing::ValuesIn(inputPrecisions), + ::testing::Values(CommonTestUtils::DEVICE_CPU) +); + +INSTANTIATE_TEST_CASE_P( + TestNumpyBroadcast1, + BroadcastLayerTest, + numpyBroadcastParams1, + BroadcastLayerTest::getTestCaseName +); + +const auto numpyBroadcastParams2 = ::testing::Combine( + ::testing::Values(targetShapesNumpy[1]), + ::testing::Values(ngraph::AxisSet{}), //not used in numpy mode + ::testing::Values(ngraph::op::BroadcastType::NUMPY), + ::testing::Values(inShapesNumpy[1]), + ::testing::ValuesIn(inputPrecisions), + ::testing::Values(CommonTestUtils::DEVICE_CPU) +); + +INSTANTIATE_TEST_CASE_P( + TestNumpyBroadcast2, + BroadcastLayerTest, + numpyBroadcastParams2, + BroadcastLayerTest::getTestCaseName +); + +// BIDIRECTIONAL MODE + +std::vector> inShapesBidi = { + {4, 1}, + {1, 4, 1}, + {4, 1, 1} +}; + +std::vector> targetShapesBidi = { + {2, 1, 4}, + {1, 4, 4}, + {1, 1, 2, 2} +}; + +const auto bidirectionalBroadcastParams1 = ::testing::Combine( + ::testing::Values(targetShapesBidi[0]), + ::testing::Values(ngraph::AxisSet{}), //not used in bidirectional mode + ::testing::Values(ngraph::op::BroadcastType::BIDIRECTIONAL), + ::testing::Values(inShapesBidi[0]), + ::testing::ValuesIn(inputPrecisions), + ::testing::Values(CommonTestUtils::DEVICE_CPU) +); + +INSTANTIATE_TEST_CASE_P( + TestBidirectionalBroadcast1, + BroadcastLayerTest, + bidirectionalBroadcastParams1, + BroadcastLayerTest::getTestCaseName +); + +const auto bidirectionalBroadcastParams2 = ::testing::Combine( + ::testing::Values(targetShapesBidi[1]), + ::testing::Values(ngraph::AxisSet{}), //not used in bidirectional mode + ::testing::Values(ngraph::op::BroadcastType::BIDIRECTIONAL), + ::testing::Values(inShapesBidi[1]), + ::testing::ValuesIn(inputPrecisions), + ::testing::Values(CommonTestUtils::DEVICE_CPU) +); + +INSTANTIATE_TEST_CASE_P( + TestBidirectionalBroadcast2, + BroadcastLayerTest, + bidirectionalBroadcastParams2, + BroadcastLayerTest::getTestCaseName +); + +const auto bidirectionalBroadcastParams3 = ::testing::Combine( + ::testing::Values(targetShapesBidi[2]), + ::testing::Values(ngraph::AxisSet{}), //not used in bidirectional mode + ::testing::Values(ngraph::op::BroadcastType::BIDIRECTIONAL), + ::testing::Values(inShapesBidi[2]), + ::testing::ValuesIn(inputPrecisions), + ::testing::Values(CommonTestUtils::DEVICE_CPU) +); + +INSTANTIATE_TEST_CASE_P( + TestBidirectionalBroadcast3, + BroadcastLayerTest, + bidirectionalBroadcastParams3, + BroadcastLayerTest::getTestCaseName +); + +// EXPLICIT MODE + +std::vector> inShapesExplicit = { + {3, 1}, + {2, 4} +}; + +std::vector> targetShapesExplicit = { + {2, 3, 1}, + {2, 3, 4} +}; + +std::vector axes = { + {1, 2}, + {0, 2} +}; + +const auto explicitBroadcastParams1 = ::testing::Combine( + ::testing::Values(targetShapesExplicit[0]), + ::testing::Values(axes[0]), + ::testing::Values(ngraph::op::BroadcastType::EXPLICIT), + ::testing::Values(inShapesExplicit[0]), + ::testing::ValuesIn(inputPrecisions), + ::testing::Values(CommonTestUtils::DEVICE_CPU) +); + +INSTANTIATE_TEST_CASE_P( + TestExplicitBroadcast1, + BroadcastLayerTest, + explicitBroadcastParams1, + BroadcastLayerTest::getTestCaseName +); + +const auto explicitBroadcastParams2 = ::testing::Combine( + ::testing::Values(targetShapesExplicit[1]), + ::testing::Values(axes[1]), + ::testing::Values(ngraph::op::BroadcastType::EXPLICIT), + ::testing::Values(inShapesExplicit[1]), + ::testing::ValuesIn(inputPrecisions), + ::testing::Values(CommonTestUtils::DEVICE_CPU) +); + +INSTANTIATE_TEST_CASE_P( + TestExplicitBroadcast2, + BroadcastLayerTest, + explicitBroadcastParams2, + BroadcastLayerTest::getTestCaseName +); +} // namespace \ No newline at end of file diff --git a/inference-engine/tests/functional/plugin/shared/include/single_layer_tests/broadcast.hpp b/inference-engine/tests/functional/plugin/shared/include/single_layer_tests/broadcast.hpp new file mode 100644 index 00000000000..3634fc0d39b --- /dev/null +++ b/inference-engine/tests/functional/plugin/shared/include/single_layer_tests/broadcast.hpp @@ -0,0 +1,35 @@ +// Copyright (C) 2019 Intel Corporation +// SPDX-License-Identifier: Apache-2.0 +// + +#pragma once + +#include +#include +#include +#include + +#include "functional_test_utils/layer_test_utils.hpp" +#include "ngraph_functions/builders.hpp" +#include "ngraph_functions/utils/ngraph_helpers.hpp" + +namespace LayerTestsDefinitions { + +using BroadcastParamsTuple = typename std::tuple< + InferenceEngine::SizeVector, // target shape + ngraph::AxisSet, // axes mapping + ngraph::op::BroadcastType, // broadcast mode + InferenceEngine::SizeVector, // Input shape + InferenceEngine::Precision, // Network precision + std::string>; // Device name + +class BroadcastLayerTest : public testing::WithParamInterface, + virtual public LayerTestsUtils::LayerTestsCommon { +public: + static std::string getTestCaseName(const testing::TestParamInfo &obj); + +protected: + void SetUp() override; +}; + +} // namespace LayerTestsDefinitions \ No newline at end of file diff --git a/inference-engine/tests/functional/plugin/shared/src/single_layer_tests/broadcast.cpp b/inference-engine/tests/functional/plugin/shared/src/single_layer_tests/broadcast.cpp new file mode 100644 index 00000000000..e42a8f00938 --- /dev/null +++ b/inference-engine/tests/functional/plugin/shared/src/single_layer_tests/broadcast.cpp @@ -0,0 +1,49 @@ +// Copyright (C) 2020 Intel Corporation +// SPDX-License-Identifier: Apache-2.0 +// + +#include "single_layer_tests/broadcast.hpp" + + +namespace LayerTestsDefinitions { +std::string BroadcastLayerTest::getTestCaseName(const testing::TestParamInfo& obj) { + InferenceEngine::SizeVector targetShape; + ngraph::AxisSet axesMapping; + ngraph::op::BroadcastType mode; + InferenceEngine::SizeVector inputShape; + InferenceEngine::Precision networkPrecision; + std::string deviceName; + std::tie(targetShape, axesMapping, mode, inputShape, networkPrecision, deviceName) = obj.param; + + std::ostringstream result; + result << "targetShape=" << CommonTestUtils::vec2str(targetShape) << "_"; + result << "axesMapping=" << CommonTestUtils::set2str(axesMapping) << "_"; + result << "mode=" << mode << "_"; + result << "inShape=" << CommonTestUtils::vec2str(inputShape) << "_"; + result << "inNPrec=" << networkPrecision << "_"; + result << "trgDev=" << deviceName; + return result.str(); +} + +void BroadcastLayerTest::SetUp() { + InferenceEngine::SizeVector targetShape; + ngraph::AxisSet axesMapping; + ngraph::op::BroadcastType mode; + InferenceEngine::SizeVector inputShape; + InferenceEngine::Precision networkPrecision; + std::tie(targetShape, axesMapping, mode, inputShape, networkPrecision, targetDevice) = this->GetParam(); + auto ngPrc = FuncTestUtils::PrecisionUtils::convertIE2nGraphPrc(networkPrecision); + + auto target_shape_const = ngraph::opset3::Constant::create(ngraph::element::i64, {targetShape.size()}, targetShape); + auto params = ngraph::builder::makeParams(ngPrc, {inputShape}); + + auto broadcast = ngraph::builder::makeBroadcast(params[0], target_shape_const, mode, axesMapping); + ngraph::ResultVector results{std::make_shared(broadcast)}; + function = std::make_shared(results, params, "BroadcastInference"); +} + +TEST_P(BroadcastLayerTest, CompareWithRefs) { + Run(); +} + +} // namespace LayerTestsDefinitions \ No newline at end of file diff --git a/inference-engine/tests/ngraph_functions/include/ngraph_functions/builders.hpp b/inference-engine/tests/ngraph_functions/include/ngraph_functions/builders.hpp index 284aca1a9e6..cc445d77535 100644 --- a/inference-engine/tests/ngraph_functions/include/ngraph_functions/builders.hpp +++ b/inference-engine/tests/ngraph_functions/include/ngraph_functions/builders.hpp @@ -70,6 +70,11 @@ std::shared_ptr makeConstant(const element::Type &type, const std::vector< std::shared_ptr makeInputLayer(const element::Type& type, ngraph::helpers::InputLayerType inputType, const std::vector& shape); +std::shared_ptr makeBroadcast(const ngraph::Output &in, + const ngraph::Output &target_shape, + const ngraph::op::BroadcastType& mode, + const ngraph::AxisSet& axis_set = {}); + std::shared_ptr makeConvolution(const ngraph::Output &in, const element::Type &type, const std::vector &filterSize, diff --git a/inference-engine/tests/ngraph_functions/src/broadcast.cpp b/inference-engine/tests/ngraph_functions/src/broadcast.cpp new file mode 100644 index 00000000000..5da37fe8211 --- /dev/null +++ b/inference-engine/tests/ngraph_functions/src/broadcast.cpp @@ -0,0 +1,29 @@ +// Copyright (C) 2020 Intel Corporation +// SPDX-License-Identifier: Apache-2.0 +// + +#include +#include + +#include "ngraph_functions/builders.hpp" + +namespace ngraph { +namespace builder { +std::shared_ptr makeBroadcast(const ngraph::Output &in, + const ngraph::Output &target_shape, + const ngraph::op::BroadcastType& mode, + const ngraph::AxisSet& axisSet) { + if (mode == ngraph::op::BroadcastType::NONE) { + auto axisSetConst = ngraph::opset5::Constant::create(ngraph::element::i64, {axisSet.size()}, axisSet.to_vector()); + return std::make_shared(in, + target_shape, + axisSetConst, + mode); + } else { // numpy/bidiractional modes + return std::make_shared(in, + target_shape, + mode); + } +} +} // namespace builder +} // namespace ngraph diff --git a/ngraph/core/include/ngraph/op/util/broadcast_base.hpp b/ngraph/core/include/ngraph/op/util/broadcast_base.hpp index 28d01ed39c8..225a4550460 100644 --- a/ngraph/core/include/ngraph/op/util/broadcast_base.hpp +++ b/ngraph/core/include/ngraph/op/util/broadcast_base.hpp @@ -71,7 +71,6 @@ namespace ngraph const std::pair pair_broadcast_axes, const Shape output_shape) const; - template bool evaluate(const HostTensorPtr& arg0, const HostTensorPtr& out, const AxisSet& broadcast_axes) const; diff --git a/ngraph/core/reference/include/ngraph/runtime/opt_kernel/broadcast.hpp b/ngraph/core/reference/include/ngraph/runtime/opt_kernel/broadcast.hpp deleted file mode 100644 index 7380a6cd34f..00000000000 --- a/ngraph/core/reference/include/ngraph/runtime/opt_kernel/broadcast.hpp +++ /dev/null @@ -1,218 +0,0 @@ -//***************************************************************************** -// 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 -#include - -#include "ngraph/runtime/reference/broadcast.hpp" -#include "ngraph/shape_util.hpp" -#include "ngraph/util.hpp" - -namespace ngraph -{ - namespace runtime - { - namespace opt_kernel - { - template - void broadcast_2d( - const T* in, T* out, const Shape& in_shape, const Shape& out_shape, size_t out_axis) - { - size_t index[2]; - size_t& in_index = index[out_axis]; - auto out_strides = row_major_strides(out_shape); - for (index[0] = 0; index[0] < out_shape[0]; ++index[0]) - { - for (index[1] = 0; index[1] < out_shape[1]; ++index[1]) - { - // clang-format off - out[index[0] * out_strides[0] + - index[1]] = - in[in_index]; - // clang-format on - } - } - } - - // #define PARALLEL - template - void broadcast_3d( - const T* in, T* out, const Shape& in_shape, const Shape& out_shape, size_t out_axis) - { - size_t index[3]; - size_t& in_index = index[out_axis]; - auto out_strides = row_major_strides(out_shape); - for (index[0] = 0; index[0] < out_shape[0]; ++index[0]) - { - for (index[1] = 0; index[1] < out_shape[1]; ++index[1]) - { - for (index[2] = 0; index[2] < out_shape[2]; ++index[2]) - { - // clang-format off - out[index[0] * out_strides[0] + - index[1] * out_strides[1] + - index[2]] = - in[in_index]; - // clang-format on - } - } - } - } - - template - void broadcast_4d( - const T* in, T* out, const Shape& in_shape, const Shape& out_shape, size_t out_axis) - { - size_t index[4]; - size_t& in_index = index[out_axis]; - auto out_strides = row_major_strides(out_shape); - for (index[0] = 0; index[0] < out_shape[0]; ++index[0]) - { - for (index[1] = 0; index[1] < out_shape[1]; ++index[1]) - { - for (index[2] = 0; index[2] < out_shape[2]; ++index[2]) - { - for (index[3] = 0; index[3] < out_shape[3]; ++index[3]) - { - // clang-format off - out[index[0] * out_strides[0] + - index[1] * out_strides[1] + - index[2] * out_strides[2] + - index[3]] = - in[in_index]; - // clang-format on - } - } - } - } - } - - template - void broadcast_5d( - const T* in, T* out, const Shape& in_shape, const Shape& out_shape, size_t out_axis) - { - size_t index[5]; - size_t& in_index = index[out_axis]; - auto out_strides = row_major_strides(out_shape); - for (index[0] = 0; index[0] < out_shape[0]; ++index[0]) - { - for (index[1] = 0; index[1] < out_shape[1]; ++index[1]) - { - for (index[2] = 0; index[2] < out_shape[2]; ++index[2]) - { - for (index[3] = 0; index[3] < out_shape[3]; ++index[3]) - { - for (index[4] = 0; index[4] < out_shape[4]; ++index[4]) - { - // clang-format off - out[index[0] * out_strides[0] + - index[1] * out_strides[1] + - index[2] * out_strides[2] + - index[3] * out_strides[3] + - index[4]] = - in[in_index]; - // clang-format on - } - } - } - } - } - } - - template - void broadcast_6d( - const T* in, T* out, const Shape& in_shape, const Shape& out_shape, size_t out_axis) - { - size_t index[6]; - size_t& in_index = index[out_axis]; - auto out_strides = row_major_strides(out_shape); - for (index[0] = 0; index[0] < out_shape[0]; ++index[0]) - { - for (index[1] = 0; index[1] < out_shape[1]; ++index[1]) - { - for (index[2] = 0; index[2] < out_shape[2]; ++index[2]) - { - for (index[3] = 0; index[3] < out_shape[3]; ++index[3]) - { - for (index[4] = 0; index[4] < out_shape[4]; ++index[4]) - { - for (index[5] = 0; index[5] < out_shape[5]; ++index[5]) - { - // clang-format off - out[index[0] * out_strides[0] + - index[1] * out_strides[1] + - index[2] * out_strides[2] + - index[3] * out_strides[3] + - index[4] * out_strides[4] + - index[5]] = - in[in_index]; - // clang-format on - } - } - } - } - } - } - } - - template - void broadcast(const T* in, - T* out, - const Shape& in_shape, - const Shape& out_shape, - const AxisSet& broadcast_axes) - { - if (is_scalar(in_shape)) - { - for (size_t i = 0; i < shape_size(out_shape); ++i) - { - out[i] = in[0]; - } - } - else if (in_shape.size() == 1) - { - size_t output_axis = 0; - for (size_t i = 0; i < out_shape.size(); i++) - { - if (broadcast_axes.count(i) == 0) - { - output_axis = i; - break; - } - } - switch (out_shape.size()) - { - case 2: broadcast_2d(in, out, in_shape, out_shape, output_axis); break; - case 3: broadcast_3d(in, out, in_shape, out_shape, output_axis); break; - case 4: broadcast_4d(in, out, in_shape, out_shape, output_axis); break; - case 5: broadcast_5d(in, out, in_shape, out_shape, output_axis); break; - case 6: broadcast_6d(in, out, in_shape, out_shape, output_axis); break; - default: - runtime::reference::broadcast( - in, out, in_shape, out_shape, broadcast_axes); - break; - } - } - else - { - runtime::reference::broadcast(in, out, in_shape, out_shape, broadcast_axes); - } - } - } - } -} diff --git a/ngraph/core/reference/include/ngraph/runtime/reference/broadcast.hpp b/ngraph/core/reference/include/ngraph/runtime/reference/broadcast.hpp index 8c324fb845d..02ed992d51b 100644 --- a/ngraph/core/reference/include/ngraph/runtime/reference/broadcast.hpp +++ b/ngraph/core/reference/include/ngraph/runtime/reference/broadcast.hpp @@ -16,10 +16,8 @@ #pragma once -#include - -#include "ngraph/coordinate_transform.hpp" -#include "ngraph/shape_util.hpp" +#include "ngraph/axis_set.hpp" +#include "ngraph/shape.hpp" namespace ngraph { @@ -27,42 +25,12 @@ namespace ngraph { namespace reference { - template - void broadcast(const T* arg, - T* out, + void broadcast(const char* arg, + char* out, const Shape& in_shape, const Shape& out_shape, - const AxisSet& broadcast_axes) - { - // Remove all broadcast axes from in_shape - Shape adjusted_in_shape; - for (auto length : in_shape) - { - if (length != 1) - { - adjusted_in_shape.push_back(length); - } - } - // Remove 1s from out_shape - AxisSet adjusted_axes(broadcast_axes); - for (uint64_t axis = 0; axis < out_shape.size(); ++axis) - { - auto length = out_shape.at(axis); - if (length == 1) - { - adjusted_axes.insert(axis); - } - } - CoordinateTransform input_transform(adjusted_in_shape); - CoordinateTransform output_transform(out_shape); - - for (const Coordinate& output_coord : output_transform) - { - Coordinate input_coord = reduce(output_coord, adjusted_axes, false); - out[output_transform.index(output_coord)] = - arg[input_transform.index(input_coord)]; - } - } + const AxisSet& broadcast_axes, + size_t elem_size); } } } diff --git a/ngraph/core/reference/include/ngraph/runtime/reference/matmul.hpp b/ngraph/core/reference/include/ngraph/runtime/reference/matmul.hpp index 4ac53903299..8ec3b8e7287 100644 --- a/ngraph/core/reference/include/ngraph/runtime/reference/matmul.hpp +++ b/ngraph/core/reference/include/ngraph/runtime/reference/matmul.hpp @@ -197,11 +197,12 @@ namespace ngraph if (!broadcast_axes.empty()) { arg0_broadcast_vec.reserve(shape_size(arg0_br_target_shape)); - broadcast(arg0_update, - arg0_broadcast_vec.data(), + broadcast(reinterpret_cast(arg0_update), + reinterpret_cast(arg0_broadcast_vec.data()), wip_arg0_shape, arg0_br_target_shape, - broadcast_axes); + broadcast_axes, + sizeof(T)); arg0_update = arg0_broadcast_vec.data(); wip_arg0_shape = arg0_br_target_shape; @@ -216,11 +217,12 @@ namespace ngraph if (!broadcast_axes.empty()) { arg1_broadcast_vec.reserve(shape_size(arg1_br_target_shape)); - broadcast(arg1_update, - arg1_broadcast_vec.data(), + broadcast(reinterpret_cast(arg1_update), + reinterpret_cast(arg1_broadcast_vec.data()), wip_arg1_shape, arg1_br_target_shape, - broadcast_axes); + broadcast_axes, + sizeof(T)); arg1_update = arg1_broadcast_vec.data(); wip_arg1_shape = arg1_br_target_shape; diff --git a/ngraph/core/reference/src/runtime/reference/broadcast.cpp b/ngraph/core/reference/src/runtime/reference/broadcast.cpp new file mode 100644 index 00000000000..9625e04c32f --- /dev/null +++ b/ngraph/core/reference/src/runtime/reference/broadcast.cpp @@ -0,0 +1,55 @@ +//***************************************************************************** +// 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 "ngraph/runtime/reference/broadcast.hpp" +#include "ngraph/runtime/reference/tile.hpp" + +namespace ngraph +{ + namespace runtime + { + namespace reference + { + void broadcast(const char* arg, + char* out, + const Shape& in_shape, + const Shape& out_shape, + const AxisSet& broadcast_axes, + size_t elem_size) + { + const auto output_rank = std::max(in_shape.size(), out_shape.size()); + Shape adjusted_in_shape = in_shape; + for (const auto& axis : broadcast_axes) + { + if (adjusted_in_shape.size() < output_rank) + { + adjusted_in_shape.insert(adjusted_in_shape.begin() + axis, 1); + } + } + Shape adjusted_out_shape = out_shape; + adjusted_out_shape.insert( + adjusted_out_shape.begin(), output_rank - adjusted_out_shape.size(), 1); + std::vector repeats(output_rank); + for (size_t i = 0; i < repeats.size(); ++i) + { + repeats[i] = adjusted_out_shape[i] / adjusted_in_shape[i]; + } + + return tile(arg, out, adjusted_in_shape, adjusted_out_shape, elem_size, repeats); + } + } + } +} \ No newline at end of file diff --git a/ngraph/core/src/op/util/broadcast_base.cpp b/ngraph/core/src/op/util/broadcast_base.cpp index 0baad397bf8..c42f5b14501 100644 --- a/ngraph/core/src/op/util/broadcast_base.cpp +++ b/ngraph/core/src/op/util/broadcast_base.cpp @@ -92,7 +92,7 @@ void op::util::BroadcastBase::validate_target_shape_numpy(const PartialShape& ar return; } const auto arg_rank_length = arg_shape.rank().get_length(); - auto start_axis = target_shape.size() - arg_rank_length; + const int64_t start_axis = target_shape.size() - arg_rank_length; NODE_VALIDATION_CHECK(this, start_axis >= 0, "Broadcast target_shape has smaller rank ", @@ -357,18 +357,17 @@ std::pair op::util::BroadcastBase::get_broadcast_axes() const return std::make_pair(axes_known, broadcast_axes); } -template bool op::util::BroadcastBase::evaluate(const HostTensorPtr& arg0, const HostTensorPtr& out, const AxisSet& broadcast_axes) const { OV_ITT_SCOPED_TASK(itt::domains::nGraphOp, "op::util::BroadcastBase::evaluate"); - using T = typename element_type_traits::value_type; - runtime::reference::broadcast((arg0->get_data_ptr()), - (out->get_data_ptr()), - arg0->get_shape(), - out->get_shape(), - broadcast_axes); + runtime::reference::broadcast(arg0->get_data_ptr(), + out->get_data_ptr(), + arg0->get_shape(), + out->get_shape(), + broadcast_axes, + arg0->get_element_type().size()); return true; } @@ -475,37 +474,11 @@ bool op::util::BroadcastBase::evaluate_broadcast(const HostTensorPtr& arg0, // broadcast_axes not known deterministically return false; } - bool rc = true; Shape in_shape = arg0->get_shape(); out->set_shape(output_shape); out->set_element_type(arg0->get_element_type()); - switch (arg0->get_element_type()) - { - TYPE_CASE(boolean)(arg0, out, pair_broadcast_axes.second); - break; - TYPE_CASE(i8)(arg0, out, pair_broadcast_axes.second); - break; - TYPE_CASE(i16)(arg0, out, pair_broadcast_axes.second); - break; - TYPE_CASE(i32)(arg0, out, pair_broadcast_axes.second); - break; - TYPE_CASE(i64)(arg0, out, pair_broadcast_axes.second); - break; - TYPE_CASE(u8)(arg0, out, pair_broadcast_axes.second); - break; - TYPE_CASE(u16)(arg0, out, pair_broadcast_axes.second); - break; - TYPE_CASE(u32)(arg0, out, pair_broadcast_axes.second); - break; - TYPE_CASE(u64)(arg0, out, pair_broadcast_axes.second); - break; - TYPE_CASE(f16)(arg0, out, pair_broadcast_axes.second); - break; - TYPE_CASE(f32)(arg0, out, pair_broadcast_axes.second); - break; - default: rc = false; break; - } - return rc; + + return evaluate(arg0, out, pair_broadcast_axes.second); } Shape op::util::BroadcastBase::get_target_shape(const HostTensorPtr& input1) const diff --git a/ngraph/test/eval.cpp b/ngraph/test/eval.cpp index 926d6e0e355..b0d4b670b8d 100644 --- a/ngraph/test/eval.cpp +++ b/ngraph/test/eval.cpp @@ -247,6 +247,43 @@ TEST(eval, evaluate_broadcast_v3_bidirectional) ASSERT_EQ(result_val, expec); } +TEST(eval, evaluate_broadcast_v3_bidirectional_target_rank_smaller_than_input) +{ + Shape shape_a{1, 1, 1, 1, 1, 1, 1, 1}; + auto A = make_shared(element::f32, shape_a); + auto target_shape = op::Constant::create(element::i64, Shape{4}, {1, 3, 1, 1}); + auto bcast_v3 = + make_shared(A, target_shape, op::BroadcastType::BIDIRECTIONAL); + auto fun = make_shared(OutputVector{bcast_v3}, ParameterVector{A}); + + auto result = make_shared(); + ASSERT_TRUE(fun->evaluate({result}, {make_host_tensor(shape_a, {1.0f})})); + EXPECT_EQ(result->get_element_type(), element::f32); + EXPECT_EQ(result->get_partial_shape(), (PartialShape{1, 1, 1, 1, 1, 3, 1, 1})); + auto result_val = read_vector(result); + vector expec{1.0f, 1.0f, 1.0f}; + ASSERT_EQ(result_val, expec); +} + +TEST(eval, evaluate_broadcast_v3_bidirectional_target_rank_smaller_than_input_2) +{ + Shape shape_a{1, 3, 1}; + auto A = make_shared(element::f32, shape_a); + auto target_shape = op::Constant::create(element::i32, Shape{2}, {3, 1}); + auto bcast_v3 = + make_shared(A, target_shape, op::BroadcastType::BIDIRECTIONAL); + auto fun = make_shared(OutputVector{bcast_v3}, ParameterVector{A}); + + auto result = make_shared(); + ASSERT_TRUE(fun->evaluate( + {result}, {make_host_tensor(Shape{1, 3, 1}, {1.0f, 2.0f, 3.0f})})); + EXPECT_EQ(result->get_element_type(), element::f32); + EXPECT_EQ(result->get_partial_shape(), (PartialShape{1, 3, 1})); + auto result_val = read_vector(result); + vector expec{1.0f, 2.0f, 3.0f}; + ASSERT_EQ(result_val, expec); +} + TEST(eval, evaluate_broadcast_v3_bidirectional_dyn) { Shape shape_a{4, 1}; diff --git a/ngraph/test/runtime/pass/opset1_downgrade.cpp b/ngraph/test/runtime/pass/opset1_downgrade.cpp index d9d4bdfcedb..b4fd099c8e2 100644 --- a/ngraph/test/runtime/pass/opset1_downgrade.cpp +++ b/ngraph/test/runtime/pass/opset1_downgrade.cpp @@ -39,7 +39,14 @@ namespace opset1_downgrade { const auto const_filled_with_ones = make_shared( op::Constant::create(data->get_element_type(), {}, {1}), target_shape); - replacement_node = make_shared(data, const_filled_with_ones); + if (const_filled_with_ones->get_element_type() == element::boolean) + { + replacement_node = make_shared(data, const_filled_with_ones); + } + else + { + replacement_node = make_shared(data, const_filled_with_ones); + } break; } case op::BroadcastType::EXPLICIT: