diff --git a/src/core/dev_api/dimension_tracker.hpp b/src/core/dev_api/dimension_tracker.hpp index 7b1f8735f06..2bedaf8bef2 100644 --- a/src/core/dev_api/dimension_tracker.hpp +++ b/src/core/dev_api/dimension_tracker.hpp @@ -9,6 +9,7 @@ #include #include "openvino/core/dimension.hpp" +#include "openvino/core/type/element_type.hpp" namespace ov { /// \brief Special label value indicate no label set. diff --git a/src/core/include/openvino/op/tile.hpp b/src/core/include/openvino/op/tile.hpp index 91d14d6ec58..bb631c5bce1 100644 --- a/src/core/include/openvino/op/tile.hpp +++ b/src/core/include/openvino/op/tile.hpp @@ -34,6 +34,7 @@ public: bool evaluate_upper(const HostTensorVector& outputs) const override; OPENVINO_SUPPRESS_DEPRECATED_END bool has_evaluate() const override; + bool evaluate(ov::TensorVector& output_values, const ov::TensorVector& input_values) const override; bool evaluate_label(TensorLabelVector& output_labels) const override; private: diff --git a/src/core/shape_inference/include/compare.hpp b/src/core/shape_inference/include/compare.hpp index 8f222570c0f..88844c0c5da 100644 --- a/src/core/shape_inference/include/compare.hpp +++ b/src/core/shape_inference/include/compare.hpp @@ -79,24 +79,21 @@ public: }; /** - * \brief Compare two integers (a < b) in safe way against lossy integer conversion. + * \brief Compare two values (a < b) in safe way against lossy integer conversion. * * \tparam T Type of a value. * \tparam U Type of b value. * - * \param a Integer value. - * \param b Integer value. + * \param a Value a. + * \param b Value b. * * \return true if a less b otherwise false. */ -template < - class T, - class U, - typename std::enable_if<(std::is_signed::value && std::is_signed::value) || - (std::is_unsigned::value && std::is_unsigned::value) || - // temporary to be able compare float element types - (std::is_floating_point::value || std::is_floating_point::value) || - (std::is_same::value || std::is_same::value)>::type* = nullptr> +template ::value || std::is_same::value) && + (std::is_signed::value || std::is_same::value)) || + (std::is_unsigned::value && std::is_unsigned::value)>::type* = nullptr> constexpr bool lt(T a, U b) noexcept { return a < b; } @@ -109,6 +106,14 @@ constexpr bool lt(T a, U b) noexcept { return a < 0 ? true : static_cast::type>(a) < b; } +template ::value || std::is_same::value) && + std::is_unsigned::value>::type* = nullptr> +constexpr bool lt(T a, U b) noexcept { + return a < 0 ? true : a < b; +} + template ::value && std::is_integral::value && @@ -117,51 +122,59 @@ constexpr bool lt(T a, U b) noexcept { return b < 0 ? false : a < static_cast::type>(b); } +template ::value && (std::is_floating_point::value || + std::is_same::value)>::type* = nullptr> +constexpr bool lt(T a, U b) noexcept { + return b < 0 ? false : a < b; +} + /** - * \brief Compare two integers (a > b) in safe way against lossy integer conversion. + * \brief Compare two values (a > b) in safe way against lossy integer conversion. * * \tparam T Type of a value. * \tparam U Type of b value. * - * \param a Integer value. - * \param b Integer value. + * \param a Value a. + * \param b Value b. * * \return true if a > b otherwise false. */ template -bool gt(T a, U b) noexcept { +constexpr bool gt(T a, U b) noexcept { return lt(b, a); } /** - * \brief Compare two integers (a <= b) in safe way against lossy integer conversion. + * \brief Compare two values (a <= b) in safe way against lossy integer conversion. * * \tparam T Type of a value. * \tparam U Type of b value. * - * \param a Integer value. - * \param b Integer value. + * \param a Value a. + * \param b Value b. * * \return true if a <= b otherwise false. */ template -bool le(T a, U b) noexcept { +constexpr bool le(T a, U b) noexcept { return !gt(a, b); } /** - * \brief Compare two integers (a >= b) in safe way against lossy integer conversion. + * \brief Compare two values (a >= b) in safe way against lossy integer conversion. * * \tparam T Type of a value. * \tparam U Type of b value. * - * \param a Integer value. - * \param b Integer value. + * \param a Value a. + * \param b Value b. * * \return true if a >= b otherwise false. */ template -bool ge(T a, U b) noexcept { +constexpr bool ge(T a, U b) noexcept { return !lt(a, b); } } // namespace cmp diff --git a/src/core/shape_inference/include/shape_infer_type_utils.hpp b/src/core/shape_inference/include/shape_infer_type_utils.hpp new file mode 100644 index 00000000000..c7b4eac8e21 --- /dev/null +++ b/src/core/shape_inference/include/shape_infer_type_utils.hpp @@ -0,0 +1,50 @@ +// Copyright (C) 2023 Intel Corporation +// SPDX-License-Identifier: Apache-2.0 +// + +#pragma once + +#include "compare.hpp" +#include "openvino/core/except.hpp" + +namespace ov { +namespace util { + +/** + * \brief Trnsform tensor data by cast them to type T + * + * \tparam T Type of returned value. + */ +template +struct Cast { + constexpr Cast() = default; + + template + constexpr T operator()(const U u) const { + return static_cast(u); + } +}; + +/** + * \brief Check if input data is in [T::min(), T::max()] and then cast it to T. + * + * \tparam T Type of returned value and used to specified min, max of valid value range. + * + * \throws ov::AssertFailure if input value not in type range. + */ +template +struct InTypeRange { + const T m_min{std::numeric_limits::lowest()}, m_max{std::numeric_limits::max()}; + + constexpr InTypeRange() = default; + constexpr InTypeRange(const T& min, const T& max) : m_min{min}, m_max{max} {}; + + template + T operator()(const U u) const { + OPENVINO_ASSERT(cmp::le(m_min, u) && cmp::le(u, m_max), "Value ", u, " not in range [", m_min, ":", m_max, "]"); + return static_cast(u); + } +}; + +} // namespace util +} // namespace ov diff --git a/src/core/shape_inference/include/slice_shape_inference.hpp b/src/core/shape_inference/include/slice_shape_inference.hpp index eb43f3eaba9..4007cf56040 100644 --- a/src/core/shape_inference/include/slice_shape_inference.hpp +++ b/src/core/shape_inference/include/slice_shape_inference.hpp @@ -94,12 +94,10 @@ void shape_infer(const Slice* op, return; } - constexpr auto cast_i64 = sh_infer::tr::Cast(); - // compute constant values of begin, end, and strides if possible const auto start = slice::get_input_bounds(op, 1, constant_data); const auto stop = slice::get_input_bounds(op, 2, constant_data); - const auto steps = get_input_const_data_as(op, 3, constant_data, cast_i64); + const auto steps = get_input_const_data_as(op, 3, constant_data); slice::AxesMap axes_map; if (input_shapes.size() > 4) { @@ -107,7 +105,7 @@ void shape_infer(const Slice* op, input_shapes[4].compatible(start_shape), "Slice `axes` input must have compatible shape with `start`, `stop`, `step` inputs."); - if (auto axes = get_input_const_data_as(op, 4, constant_data, cast_i64)) { + if (auto axes = get_input_const_data_as(op, 4, constant_data)) { ov::normalize_axes(op, input_shape.rank().get_length(), *axes); axes_map.add(*axes); NODE_VALIDATION_CHECK(op, axes_map.is_valid, "Slice values in `axes` input must be unique."); diff --git a/src/core/shape_inference/include/slice_shape_inference_utils.hpp b/src/core/shape_inference/include/slice_shape_inference_utils.hpp index 4332e530977..2c5ce26ea38 100644 --- a/src/core/shape_inference/include/slice_shape_inference_utils.hpp +++ b/src/core/shape_inference/include/slice_shape_inference_utils.hpp @@ -233,8 +233,7 @@ std::unique_ptr get_input_bounds(const ov::Node* op, }; std::unique_ptr out; - if (auto lowers = - op::get_input_const_data_as(op, idx, constant_data, sh_infer::tr::Cast())) { + if (auto lowers = op::get_input_const_data_as(op, idx, constant_data)) { const auto& et = get_input_const_element_type(op, idx, constant_data); out.reset(new TResult(make_bounds_vec(et, *lowers, *lowers))); } else { diff --git a/src/core/shape_inference/include/strided_slice_shape_inference.hpp b/src/core/shape_inference/include/strided_slice_shape_inference.hpp index c1fb01dda2d..8f4503f1a5e 100644 --- a/src/core/shape_inference/include/strided_slice_shape_inference.hpp +++ b/src/core/shape_inference/include/strided_slice_shape_inference.hpp @@ -64,7 +64,7 @@ void shape_infer(const StridedSlice* op, std::unique_ptr> strides; if (input_shapes.size() > 3) { - strides = get_input_const_data_as(op, 3, constant_data, sh_infer::tr::Cast()); + strides = get_input_const_data_as(op, 3, constant_data); } else if (begin) { // generate default strides strides.reset(new std::vector(begin->size(), 1)); diff --git a/src/core/shape_inference/include/tile_shape_inference.hpp b/src/core/shape_inference/include/tile_shape_inference.hpp index 7d28ea54142..465eca75903 100644 --- a/src/core/shape_inference/include/tile_shape_inference.hpp +++ b/src/core/shape_inference/include/tile_shape_inference.hpp @@ -12,24 +12,23 @@ namespace op { namespace v0 { template -void shape_infer(const Tile* op, - const std::vector& input_shapes, - std::vector& output_shapes, - const std::map>& constant_data = {}) { +std::vector shape_infer(const Tile* op, + const std::vector& input_shapes, + const std::map>& constant_data = {}) { using TDim = typename T::value_type; using TDimValue = typename TDim::value_type; - NODE_VALIDATION_CHECK(op, input_shapes.size() == 2 && output_shapes.size() == 1); + NODE_VALIDATION_CHECK(op, input_shapes.size() == 2); const auto& repeats_shape = input_shapes[1]; NODE_VALIDATION_CHECK(op, repeats_shape.rank().compatible(1), "Tile repeats must be of rank 1"); const auto& arg_shape = input_shapes[0]; - auto& output_shape = output_shapes[0]; + T output_shape; // Get repeats and pre process values auto negative_repeats_to_zero = [](const TDimValue v) -> TDimValue { - return std::max(0, sh_infer::tr::InTypeRange()(v)); + return std::max(0, ov::util::InTypeRange()(v)); }; auto repeats = get_input_const_data_as_shape(op, 1, constant_data, negative_repeats_to_zero); @@ -37,21 +36,21 @@ void shape_infer(const Tile* op, const auto& arg_rank = arg_shape.rank(); if (arg_rank.is_static() && repeats) { const auto output_rank = std::max(arg_shape.size(), repeats->size()); - - std::vector dims; - dims.reserve(output_rank); + output_shape.reserve(output_rank); // add missing repeats repeats->insert(repeats->begin(), output_rank - repeats->size(), TDim{1}); // insert missing input dimensions auto rep_it = std::next(repeats->begin(), output_rank - arg_shape.size()); - dims.insert(dims.begin(), repeats->begin(), rep_it); + output_shape.insert(output_shape.begin(), repeats->begin(), rep_it); // calc repeated output dimensions - std::transform(arg_shape.begin(), arg_shape.end(), rep_it, std::back_inserter(dims), std::multiplies()); - - output_shape = T(std::move(dims)); + std::transform(arg_shape.begin(), + arg_shape.end(), + rep_it, + std::back_inserter(output_shape), + std::multiplies()); } else if (arg_rank.is_static() && repeats_shape[0].is_static()) { // unknown repeats but shape is 1-D static, any dim can be repeated (add missing dimension) output_shape.resize(std::max(arg_rank.get_length(), repeats_shape[0].get_length())); @@ -59,6 +58,7 @@ void shape_infer(const Tile* op, // can't deduce shape, set default value output_shape = PartialShape::dynamic(); } + return {output_shape}; } } // namespace v0 } // namespace op diff --git a/src/core/shape_inference/include/utils.hpp b/src/core/shape_inference/include/utils.hpp index 839469d46de..c8fbce1ca35 100644 --- a/src/core/shape_inference/include/utils.hpp +++ b/src/core/shape_inference/include/utils.hpp @@ -8,7 +8,7 @@ #include #include -#include "shape_infer_transformations.hpp" +#include "shape_infer_type_utils.hpp" template void copy_shape_infer(const OpType* op, const std::vector& input_shapes, std::vector& output_shapes) { @@ -154,7 +154,7 @@ TResult get_raw_data_as(const element::Type_t et, const void* const ptr, const s std::forward(func)); } break; default: - OPENVINO_ASSERT(false, "Not supported element type ", et); + OPENVINO_ASSERT(false, "Get raw data from tensor is not supported for element type: ", et); }; return out; } @@ -177,6 +177,11 @@ TResult get_tensor_data_as(HostTensor& tv, UnaryOperation&& func) { return get_tensor_data_as(t, std::forward(func)); } +template , class UnaryOperation> +TResult get_tensor_data_as(HostTensor* tv, UnaryOperation&& func) { + return get_tensor_data_as(*tv, std::forward(func)); +} + /** * \brief Get data from ov:tensor as object TResult. * @@ -207,6 +212,7 @@ namespace op { * \tparam TShape Shape type which enabled this version (not ov::PartialShape) * \tparam TData Type use to cast input's data. * \tparam TRes Result type which has got default type as std::vector. + * \tparam TTensorPtr Type of tensor pointer or reference_wrapper. Default HostTensorPtr. * \tparam UnaryOperation Unary function object applied on data with signature (Ret f(const TData &a)). * * \param op Pointer to operator. @@ -219,15 +225,16 @@ namespace op { template , - class UnaryOperation, + class TTensorPtr = HostTensorPtr, + class UnaryOperation = ov::util::Cast, typename std::enable_if::value>::type* = nullptr> std::unique_ptr get_input_const_data_as(const ov::Node* op, size_t idx, - const std::map& constant_data = {}, - UnaryOperation&& func = sh_infer::tr::Cast()) { + const std::map& constant_data = {}, + UnaryOperation&& func = ov::util::Cast()) { if (constant_data.count(idx)) { return std::unique_ptr( - new TRes(get_tensor_data_as(*constant_data.at(idx), std::forward(func)))); + new TRes(get_tensor_data_as(constant_data.at(idx).get(), std::forward(func)))); } else { const auto& constant = ov::as_type_ptr(op->get_input_node_shared_ptr(idx)); NODE_VALIDATION_CHECK(op, constant != nullptr, "Static shape inference lacks constant data on port ", idx); @@ -249,6 +256,7 @@ std::unique_ptr get_input_const_data_as(const ov::Node* op, * \tparam TShape Shape type which enabled this version (ov::PartialShape) * \tparam TData Type use to cast input's data. * \tparam TRes Result type which has got default type as std::vector. + * \tparam TTensorPtr Type of tensor pointer or reference_wrapper. Default HostTensorPtr. * \tparam UnaryOperation Unary function object applied on data with signature (Ret f(const TData &a)). * * \param op Pointer to operator. @@ -261,15 +269,16 @@ std::unique_ptr get_input_const_data_as(const ov::Node* op, template , - class UnaryOperation, + class TTensorPtr = HostTensorPtr, + class UnaryOperation = ov::util::Cast, typename std::enable_if::value>::type* = nullptr> std::unique_ptr get_input_const_data_as(const ov::Node* op, size_t idx, - const std::map& constant_data = {}, - UnaryOperation&& func = sh_infer::tr::Cast()) { + const std::map& constant_data = {}, + UnaryOperation&& func = ov::util::Cast()) { if (constant_data.count(idx)) { return std::unique_ptr( - new TRes(get_tensor_data_as(*constant_data.at(idx), std::forward(func)))); + new TRes(get_tensor_data_as(constant_data.at(idx).get(), std::forward(func)))); } else if (const auto& constant = ov::get_constant_from_source(op->input_value(idx))) { const auto& et = constant->get_element_type(); const auto& shape = constant->get_shape(); @@ -288,36 +297,37 @@ std::unique_ptr get_input_const_data_as(const ov::Node* op, * The input data can be processed by unary operation. By default is validated and casted to shape's dimension type. * * \tparam TShape + * \tparam TTensorPtr Type of tensor pointer or reference_wrapper. Default HostTensorPtr. * \tparam UnaryOperation Unary function object applied on data with signature (Ret f(const TDimValue &a)). * * \param op Pointer to operator. * \param idx Operator input index. * \param constant_data Map with constant data. Default empty. * \param func Unary operation function object to apply in input data. - * Default sh_infer::tr::InTypeRange. + * Default ov::utils::InTypeRange. * * \return Unique pointer to shape created from input data. */ template > -std::unique_ptr get_input_const_data_as_shape( - const ov::Node* op, - size_t idx, - const std::map>& constant_data = {}, - UnaryOperation&& func = sh_infer::tr::InTypeRange()) { + class TTensorPtr = HostTensorPtr, + class UnaryOperation = ov::util::InTypeRange> +std::unique_ptr get_input_const_data_as_shape(const ov::Node* op, + size_t idx, + const std::map& constant_data = {}, + UnaryOperation&& func = ov::util::InTypeRange()) { std::unique_ptr shape_ptr; if (auto d = get_input_const_data_as(op, idx, constant_data, std::forward(func))) { - shape_ptr.reset(new TShape(std::move(*d))); + return std::unique_ptr(new TShape(std::move(*d))); } else { PartialShape shape; if (ov::evaluate_as_partial_shape(op->input_value(idx), shape)) { - shape_ptr.reset(new TShape(std::move(shape))); + return std::unique_ptr(new TShape(std::move(shape))); } } - return shape_ptr; + return {}; } } // namespace op } // namespace ov @@ -328,8 +338,7 @@ inline bool get_data_as(const ov::Node* op, size_t idx, std::vector& data_out, const std::map& constant_data = {}) { - if (auto out = - ov::op::get_input_const_data_as(op, idx, constant_data, ov::sh_infer::tr::Cast())) { + if (auto out = ov::op::get_input_const_data_as(op, idx, constant_data, ov::util::Cast())) { data_out = std::move(*out); return true; } else { @@ -374,8 +383,8 @@ inline bool get_data_as_shape(size_t idx, TShape& shape, const std::map& constant_data = {}) { using TDimValue = typename TShape::value_type::value_type; - shape = std::move( - *ov::op::get_input_const_data_as_shape(op, idx, constant_data, ov::sh_infer::tr::Cast())); + shape = + std::move(*ov::op::get_input_const_data_as_shape(op, idx, constant_data, ov::util::Cast())); return true; } diff --git a/src/core/src/op/tile.cpp b/src/core/src/op/tile.cpp index f89bb50158a..7b4a6caaaf1 100644 --- a/src/core/src/op/tile.cpp +++ b/src/core/src/op/tile.cpp @@ -35,9 +35,7 @@ void op::v0::Tile::validate_and_infer_types() { "Tile repeats must have any integer element type, but has ", repeats_et); - const auto input_shapes = get_node_input_partial_shapes(*this); - auto output_shapes = std::vector(1, ov::PartialShape{}); - shape_infer(this, input_shapes, output_shapes); + auto output_shapes = shape_infer(this, get_node_input_partial_shapes(*this)); set_output_type(0, get_input_element_type(0), output_shapes[0]); set_input_is_relevant_to_shape(0); @@ -57,10 +55,11 @@ bool op::v0::Tile::evaluate_tile(const HostTensorVector& outputs, const HostTens auto repeats_val = read_index_vector(axis); const auto repeats_rank = repeats_val.size(); - std::vector output_shapes = {ov::PartialShape{}}; - std::vector input_shapes = {data->get_shape(), axis->get_shape()}; - shape_infer(this, input_shapes, output_shapes, {{1, axis}}); - const auto& output_shape = output_shapes[0].to_shape(); + auto axis_tensor = Tensor(axis->get_element_type(), axis->get_shape(), axis->get_data_ptr()); + auto const_map = std::map>{{1, axis_tensor}}; + + const auto input_shapes = std::vector{data->get_shape(), axis->get_shape()}; + const auto& output_shape = shape_infer(this, input_shapes, const_map).front().to_shape(); if (!output->get_is_allocated()) { output->set_shape(output_shape); } @@ -75,9 +74,28 @@ bool op::v0::Tile::evaluate_tile(const HostTensorVector& outputs, const HostTens return true; } -bool op::v0::Tile::evaluate(const HostTensorVector& outputs, const HostTensorVector& inputs) const { +bool op::v0::Tile::evaluate(ov::TensorVector& output_values, const ov::TensorVector& input_values) const { OV_OP_SCOPE(v0_Tile_evaluate); - return evaluate_tile(outputs, inputs); + const auto& data = input_values[0]; + const auto& axis = input_values[1]; + auto& output = output_values[0]; + auto repeats_val = get_tensor_data_as(axis, ov::util::Cast()); + const auto repeats_rank = repeats_val.size(); + + std::vector input_shapes = {data.get_shape(), axis.get_shape()}; + + auto const_map = std::map>{{1, axis}}; + const auto& output_shape = shape_infer(this, input_shapes, const_map).front().to_shape(); + output.set_shape(output_shape); + repeats_val.insert(repeats_val.begin(), output_shape.size() - repeats_rank, 1); + ngraph::runtime::reference::tile(static_cast(data.data()), + static_cast(output.data()), + data.get_shape(), + output_shape, + data.get_element_type().size(), + repeats_val); + + return true; } bool op::v0::Tile::has_evaluate() const { @@ -85,6 +103,13 @@ bool op::v0::Tile::has_evaluate() const { return true; } +bool op::v0::Tile::evaluate(const HostTensorVector& outputs, const HostTensorVector& inputs) const { + // This duplicate version for ov::Tensor because template plugin and shape inference utils + // are not ready for usage with ov::Tensor when it happens this function can be removed. + OV_OP_SCOPE(v0_Tile_evaluate); + return evaluate_tile(outputs, inputs); +} + bool op::v0::Tile::evaluate_lower(const HostTensorVector& output_values) const { OV_OP_SCOPE(v0_Tile_evaluate_lower); diff --git a/src/core/src/validation_util.cpp b/src/core/src/validation_util.cpp index 205e2b64557..caefe3696e1 100644 --- a/src/core/src/validation_util.cpp +++ b/src/core/src/validation_util.cpp @@ -1348,43 +1348,46 @@ bool ov::evaluate_as_partial_shape(const Output& output, PartialShape& psh } bool ov::default_label_evaluator(const Node* node, TensorLabelVector& output_labels) { - const auto& input_values = node->input_values(); + const auto& inputs_count = node->get_input_size(); + if (inputs_count > 0) { + const auto& labels = node->get_input_tensor(0).get_value_label(); + if (!has_no_labels(labels)) { + TensorVector inputs; + inputs.reserve(inputs_count); - HostTensorVector input_tensors(input_values.size()); - for (size_t i = 0; i < input_values.size(); ++i) { - const auto& input = input_values[i]; - if (i != 0) { - if (input.get_tensor().has_and_set_bound()) - input_tensors[i] = input.get_tensor().get_lower_value(); - else - return false; - } else { - const auto& input_labels = input.get_tensor().get_value_label(); - if (has_no_labels(input_labels)) { - return false; + inputs.emplace_back(element::from(), node->get_input_shape(0)); + std::copy(labels.begin(), labels.end(), inputs.back().data()); + + for (size_t i = 1; i < inputs_count; ++i) { + if (node->get_input_tensor(i).has_and_set_bound()) { + const auto& et = node->get_input_element_type(i); + const auto& shape = node->get_input_shape(i); + inputs.emplace_back(et, shape, node->get_input_tensor(i).get_lower_value()->get_data_ptr()); + } else { + return false; + } } - auto labels_constant = op::v0::Constant::create(ov::element::u64, input.get_shape(), input_labels); - auto idxs_htp = std::make_shared(labels_constant); - input_tensors[i] = idxs_htp; + const auto& outputs_count = node->get_output_size(); + TensorVector outputs; + outputs.reserve(outputs_count); + + for (size_t i = 0; i < outputs_count; ++i) { + const auto& partial_shape = node->get_output_partial_shape(i); + // Set shape for static or Shape{0} for dynamic to postpone memory allocation + auto shape = partial_shape.is_static() ? partial_shape.to_shape() : Shape{0}; + outputs.emplace_back(element::from(), shape); + } + + if (node->evaluate(outputs, inputs)) { + std::transform(outputs.cbegin(), outputs.cend(), output_labels.begin(), [](const Tensor& t) { + // Return empty label tensor if input tensor not valid (can have Shape{0}) + return t ? TensorLabel(t.data(), t.data() + t.get_size()) : TensorLabel(); + }); + return true; + } } } - - HostTensorVector output_tensors; - output_tensors.reserve(node->get_output_size()); - for (size_t i = 0; i < node->get_output_size(); ++i) { - output_tensors.push_back(std::make_shared(element::u64, node->get_output_partial_shape(i))); - } - - if (node->evaluate(output_tensors, input_tensors)) { - std::transform(output_tensors.cbegin(), - output_tensors.cend(), - output_labels.begin(), - [](const HostTensorPtr& tensor) { - return std::make_shared(tensor)->cast_vector(); - }); - return true; - } return false; } diff --git a/src/plugins/intel_cpu/src/utils/shape_inference/shape_inference.cpp b/src/plugins/intel_cpu/src/utils/shape_inference/shape_inference.cpp index c4af39c640e..f802aab6530 100644 --- a/src/plugins/intel_cpu/src/utils/shape_inference/shape_inference.cpp +++ b/src/plugins/intel_cpu/src/utils/shape_inference/shape_inference.cpp @@ -4,12 +4,8 @@ #include #include #include -#include -#include -#include -#include +#include #include -#include #include "assign_shape_inference.hpp" #include "augru_cell_shape_inference.hpp" @@ -82,14 +78,16 @@ namespace intel_cpu { void shape_inference(ov::Node* op, const std::vector& input_shapes, std::vector& output_shapes, - const std::map>& constant_data) { + const std::map& constant_data) { auto shapeInfer = make_shape_inference(op->shared_from_this()); output_shapes = shapeInfer->infer(input_shapes, constant_data); } class entryBase : public IShapeInferCommon { public: - entryBase(std::shared_ptr node) : node(node) { + using iface_type = IShapeInferCommon; + + entryBase(std::shared_ptr node) : node{node} { for (size_t i = 0; i < node->get_input_size(); i++) { const auto& shape = node->get_input_partial_shape(i); if (shape.rank().is_static()) { @@ -122,9 +120,8 @@ class entryIO : public entryBase { public: using entryBase::entryBase; - std::vector infer( - const std::vector& input_shapes, - const std::map>& constant_data) override { + std::vector infer(const std::vector& input_shapes, + const std::map& constant_data) override { auto op = static_cast(node.get()); std::vector output_shapes(op->get_output_size()); shape_infer(op, input_shapes, output_shapes); @@ -137,9 +134,8 @@ class entryIOC : public entryBase { public: using entryBase::entryBase; - std::vector infer( - const std::vector& input_shapes, - const std::map>& constant_data) override { + std::vector infer(const std::vector& input_shapes, + const std::map& constant_data) override { auto op = static_cast(node.get()); std::vector output_shapes(op->get_output_size()); shape_infer(op, input_shapes, output_shapes, constant_data); @@ -151,9 +147,8 @@ class entryCopy : public entryBase { public: using entryBase::entryBase; - std::vector infer( - const std::vector& input_shapes, - const std::map>& constant_data) override { + std::vector infer(const std::vector& input_shapes, + const std::map& constant_data) override { auto op = node.get(); std::vector output_shapes(op->get_output_size()); copy_shape_infer(op, input_shapes, output_shapes); @@ -165,9 +160,8 @@ class entryFirstPassthrough : public entryBase { public: using entryBase::entryBase; - std::vector infer( - const std::vector& input_shapes, - const std::map>& constant_data) override { + std::vector infer(const std::vector& input_shapes, + const std::map& constant_data) override { auto op = node.get(); std::vector output_shapes(op->get_output_size()); first_input_passthrough_infer(op, input_shapes, output_shapes); @@ -179,9 +173,8 @@ class entryEltwise : public entryBase { public: using entryBase::entryBase; - std::vector infer( - const std::vector& input_shapes, - const std::map>& constant_data) override { + std::vector infer(const std::vector& input_shapes, + const std::map& constant_data) override { auto op = node.get(); std::vector output_shapes(op->get_output_size()); eltwise_shape_infer(op, input_shapes, output_shapes); @@ -210,9 +203,8 @@ public: virtual void post_validate_and_infer_types(const std::shared_ptr& local_op) {} - std::vector infer( - const std::vector& input_shapes, - const std::map>& constant_data) override { + std::vector infer(const std::vector& input_shapes, + const std::map& constant_data) override { auto op = node.get(); std::vector output_shapes; @@ -249,8 +241,8 @@ public: if (partial_shape.is_dynamic()) { std::ostringstream errorMessage; - errorMessage << "Can't compute static output shape on " << i - << " port for " << op->get_type_name() << " node with name: " << op->get_name(); + errorMessage << "Can't compute static output shape on " << i << " port for " << op->get_type_name() + << " node with name: " << op->get_name(); errorMessage << ". Input shapes = ( "; for (size_t in = 0; in < op->get_input_size(); in++) { errorMessage << in << " port = " << op->get_input_partial_shape(in) << ", "; @@ -323,10 +315,10 @@ public: } }; -template +template class entryConv : public entryBase { public: - entryConv(std::shared_ptr node, bool is_grouped) : entryBase(node), is_grouped(is_grouped) {} + entryConv(std::shared_ptr node) : entryBase(std::move(node)) {} const ov::CoordinateDiff& get_pads_begin() override { return pads_begin; } @@ -347,13 +339,13 @@ public: protected: ov::CoordinateDiff pads_begin, pads_end; - bool is_grouped; }; -template +template class entryConvBackprop : public entryBase { public: - entryConvBackprop(std::shared_ptr node, bool is_grouped) : entryBase(node), is_grouped(is_grouped) {} + entryConvBackprop(std::shared_ptr node) : entryBase{std::move(node)} {} + const ov::CoordinateDiff& get_pads_begin() override { return pads_begin; } @@ -384,203 +376,301 @@ public: protected: ov::CoordinateDiff pads_begin, pads_end; - bool is_grouped; }; -template -std::shared_ptr> make_shared_entryIOC(std::shared_ptr node) { - return std::make_shared>(node); +template +class ShapeInferBase : public IStaticShapeInfer { +public: + using iface_type = IStaticShapeInfer; + virtual ~ShapeInferBase() = default; + + ShapeInferBase(std::shared_ptr node) : m_node{node} { + static_assert(std::is_same::value, "Rank type not match to input_ranks type."); + for (size_t i = 0; i < node->get_input_size(); ++i) { + const auto& shape = node->get_input_partial_shape(i); + const auto& rank_length = shape.rank().is_static() ? shape.rank().get_length() : -1; + m_input_ranks.push_back(rank_length); + } + } + + std::vector infer(const std::vector& input_shapes, + const std::map& constant_data) override { + // For backward compatibility, create ov tensors and run shape inference. + TensorVector tensors; + tensors.reserve(constant_data.size()); + + std::map> const_tensor_map; + for (const auto& c : constant_data) { + tensors.emplace_back(c.second->get_element_type(), c.second->get_shape(), c.second->get_data_ptr()); + const_tensor_map.emplace(c.first, tensors.back()); + } + return infer(input_shapes, const_tensor_map); + } + + std::vector infer( + const std::vector& input_shapes, + const std::map>& constant_data) override { + return shape_infer(static_cast(m_node.get()), input_shapes, constant_data); + } + + const ov::CoordinateDiff& get_pads_begin() override { + OPENVINO_ASSERT(false, "ShapeInferBase do not support get_pads_begin() by default."); + } + + const ov::CoordinateDiff& get_pads_end() override { + OPENVINO_ASSERT(false, "ShapeInferBase do not support get_pads_end() by default."); + } + + const std::vector& get_input_ranks() override { + return m_input_ranks; + } + +protected: + std::vector m_input_ranks; + std::shared_ptr m_node; +}; + +/** + * \brief Shape infer factory + * + * \tparam R Result type of created interface object. + * \tparam TKey Type of Maker map key. + * \tparam Args TypesInference object ctor args. + */ +template +class ShapeInferFactory { +public: + // Helper type to define specific Makers map values. + using TValue = std::function; + + // Helper type to define specific Makers map type. + using TRegistry = std::unordered_map; + + /** + * \brief Creates the shape inference object. + * + * \param key Key value to get specified shape inference object maker. + * \param args Inference object args. + * + * \return The shape inference object or R{} if not found in the map. + */ + static R make(const TKey& key, Args... args) { + const auto& maker_iter = registry.find(key); + if (maker_iter != registry.end()) { + return maker_iter->second(std::forward(args)...); + } else { + return {}; + } + } + +private: + /** \brief Factory makers registry which can be specialized for key and value. */ + static const TRegistry registry; +}; + +// Helpers to make shape inference objects (primary template). +template