-
Notifications
You must be signed in to change notification settings - Fork 2.4k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[Op] Add
Col2Im-15
implementation to Core (#24197)
### Details: - Add Core implementation of `Col2Im-15` ### Related PRs - #23947 ### Tickets: - CVS-138918 --------- Co-authored-by: Michal Lukaszewski <michal.lukaszewski@intel.com>
- Loading branch information
Showing
8 changed files
with
821 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,54 @@ | ||
// Copyright (C) 2018-2024 Intel Corporation | ||
// SPDX-License-Identifier: Apache-2.0 | ||
// | ||
|
||
#pragma once | ||
|
||
#include "openvino/op/op.hpp" | ||
|
||
namespace ov { | ||
namespace op { | ||
namespace v15 { | ||
/// \brief Operator combining sliding blocks into an image tensor | ||
/// \ingroup ov_ops_cpp_api | ||
class OPENVINO_API Col2Im : public ov::op::Op { | ||
public: | ||
OPENVINO_OP("Col2Im", "opset15", ov::op::Op); | ||
|
||
Col2Im() = default; | ||
/// \brief Constructs a Col2Im operation. | ||
/// | ||
/// \param data Input tensor with data | ||
/// \param output_size Shape of the spatial dimensions of the output image | ||
/// \param kernel_size Size of the sliding blocks | ||
/// \param strides Stride in the sliding blocks in the input spatial dimensions | ||
/// \param dilations Local stride of the elements | ||
/// \param pads_begin Paddings at the beginning of each spatial axis, if undefined no padding is applied | ||
/// \param pads_end Paddings at the end of each spatial axis, if undefined no padding is applied | ||
Col2Im(const Output<Node>& data, | ||
const Output<Node>& output_size, | ||
const Output<Node>& kernel_size, | ||
const Strides& strides = Strides{1, 1}, | ||
const Strides& dilations = Strides{1, 1}, | ||
const Shape& pads_begin = Shape{0, 0}, | ||
const Shape& pads_end = Shape{0, 0}); | ||
|
||
bool visit_attributes(AttributeVisitor& visitor) override; | ||
void validate_and_infer_types() override; | ||
std::shared_ptr<Node> clone_with_new_inputs(const OutputVector& new_args) const override; | ||
|
||
const Strides& get_strides() const; | ||
const Strides& get_dilations() const; | ||
const Shape& get_pads_begin() const; | ||
const Shape& get_pads_end() const; | ||
|
||
private: | ||
Strides m_strides; | ||
Strides m_dilations; | ||
Shape m_pads_begin; | ||
Shape m_pads_end; | ||
}; | ||
|
||
} // namespace v15 | ||
} // namespace op | ||
} // namespace ov |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
125 changes: 125 additions & 0 deletions
125
src/core/shape_inference/include/col2im_shape_inference.hpp
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,125 @@ | ||
// Copyright (C) 2018-2024 Intel Corporation | ||
// SPDX-License-Identifier: Apache-2.0 | ||
// | ||
|
||
#pragma once | ||
|
||
#include <cmath> | ||
|
||
#include "openvino/op/col2im.hpp" | ||
#include "utils.hpp" | ||
|
||
namespace ov { | ||
namespace op { | ||
namespace v15 { | ||
template <class TShape, class TRShape = result_shape_t<TShape>> | ||
std::vector<TRShape> shape_infer(const Col2Im* op, | ||
const std::vector<TShape>& input_shapes, | ||
const ITensorAccessor& tensor_accessor = make_tensor_accessor()) { | ||
NODE_VALIDATION_CHECK(op, input_shapes.size() == 3); | ||
|
||
const auto& data_shape = input_shapes[0]; | ||
const auto& output_size_shape = input_shapes[1]; | ||
const auto& kernel_shape = input_shapes[2]; | ||
|
||
NODE_SHAPE_INFER_CHECK(op, | ||
input_shapes, | ||
ov::util::is_rank_compatible_any_of(data_shape.rank(), {2, 3}), | ||
"input data must be an unbatched 2D or a batched 3D input. Got: ", | ||
data_shape); | ||
|
||
const auto is_two_elem_1d = [](const TShape& shape) -> bool { | ||
static const auto exp_shape = Shape{2}; | ||
return shape.rank().is_dynamic() || shape.to_shape() == exp_shape; | ||
}; | ||
|
||
if (output_size_shape.rank().is_static()) { | ||
NODE_SHAPE_INFER_CHECK(op, | ||
input_shapes, | ||
is_two_elem_1d(output_size_shape), | ||
"output_size must be a 1D input of shape [2]. Got: ", | ||
output_size_shape); | ||
} | ||
|
||
if (kernel_shape.rank().is_static()) { | ||
NODE_SHAPE_INFER_CHECK(op, | ||
input_shapes, | ||
is_two_elem_1d(kernel_shape), | ||
"kernel_size must be a 1D input of shape [2]."); | ||
} | ||
|
||
if (data_shape.rank().is_static()) { | ||
auto output_shapes = std::vector<TRShape>(1); | ||
auto& output_shape = output_shapes[0]; | ||
const bool is_batched = data_shape.rank() == 3; | ||
output_shape.resize(is_batched ? 4 : 3); | ||
size_t idx = 0; | ||
|
||
// output_shape: (N, C, H, W) | ||
// ^ | ||
if (is_batched) { | ||
output_shape[idx] = data_shape[0]; | ||
idx++; | ||
} | ||
|
||
// output_shape: (N, C, H, W) | ||
// ^ | ||
const size_t C_idx = is_batched ? 1 : 0; | ||
const auto kernel_val = ov::op::get_input_const_data_as<TRShape, int64_t>(op, 2, tensor_accessor); | ||
if (kernel_val && data_shape.rank().is_static() && data_shape[C_idx].is_static()) { | ||
const auto& dividend = data_shape[C_idx].get_length(); | ||
const auto divisor = ((*kernel_val)[0] * (*kernel_val)[1]); | ||
output_shape[idx] = dividend / divisor; | ||
|
||
NODE_SHAPE_INFER_CHECK(op, | ||
input_shapes, | ||
dividend % divisor == 0, | ||
"First non-batch dimension is not evenly divisible by Product(kernel_shape). Got: ", | ||
data_shape[C_idx].get_length()); | ||
} | ||
|
||
// output_shape: (N, C, H, W) | ||
// ^ ^ | ||
if (const auto output_size_val = | ||
ov::op::get_input_const_data_as_shape<TRShape, int64_t>(op, 1, tensor_accessor)) { | ||
idx++; | ||
output_shape[idx] = (*output_size_val)[0]; | ||
idx++; | ||
output_shape[idx] = (*output_size_val)[1]; | ||
const size_t L_idx = is_batched ? 2 : 1; | ||
if (data_shape.rank().is_static() && data_shape[L_idx].is_static()) { | ||
constexpr size_t spatial_dims = 2; | ||
|
||
const auto& pads_begin = op->get_pads_begin(); | ||
const auto& pads_end = op->get_pads_end(); | ||
const auto& strides = op->get_strides(); | ||
const auto& dilations = op->get_dilations(); | ||
|
||
if (kernel_val) { | ||
using TVal = typename TShape::value_type::value_type; | ||
TVal L_calculated = 1; | ||
for (size_t d = 0; d < spatial_dims; ++d) { | ||
L_calculated *= (((*output_size_val)[d].get_length() + pads_begin[d] + pads_end[d] - | ||
dilations[d] * ((*kernel_val)[d] - 1) - 1) / | ||
strides[d]) + | ||
1; | ||
} | ||
const auto L = data_shape[L_idx].get_length(); | ||
NODE_SHAPE_INFER_CHECK( | ||
op, | ||
input_shapes, | ||
L == L_calculated, | ||
"For given inputs and parameters the total number of data blocks must be equal to " + | ||
std::to_string(L_calculated) + ". Got: ", | ||
L); | ||
} | ||
} | ||
} | ||
return output_shapes; | ||
} else { | ||
return {PartialShape::dynamic()}; | ||
} | ||
} | ||
} // namespace v15 | ||
} // namespace op | ||
} // namespace ov |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,94 @@ | ||
// Copyright (C) 2018-2024 Intel Corporation | ||
// SPDX-License-Identifier: Apache-2.0 | ||
// | ||
|
||
#include "openvino/op/col2im.hpp" | ||
|
||
#include "col2im_shape_inference.hpp" | ||
#include "itt.hpp" | ||
#include "openvino/core/validation_util.hpp" | ||
#include "openvino/op/op.hpp" | ||
|
||
namespace ov { | ||
namespace op { | ||
namespace v15 { | ||
|
||
Col2Im::Col2Im(const Output<Node>& data, | ||
const Output<Node>& output_size, | ||
const Output<Node>& kernel_size, | ||
const Strides& strides, | ||
const Strides& dilations, | ||
const Shape& pads_begin, | ||
const Shape& pads_end) | ||
: Op({data, output_size, kernel_size}), | ||
m_strides(strides), | ||
m_dilations(dilations), | ||
m_pads_begin(pads_begin), | ||
m_pads_end(pads_end) { | ||
constructor_validate_and_infer_types(); | ||
} | ||
|
||
bool Col2Im::visit_attributes(ov::AttributeVisitor& visitor) { | ||
OV_OP_SCOPE(v15_Col2Im_visit_attributes); | ||
visitor.on_attribute("strides", m_strides); | ||
visitor.on_attribute("dilations", m_dilations); | ||
visitor.on_attribute("pads_begin", m_pads_begin); | ||
visitor.on_attribute("pads_end", m_pads_end); | ||
return true; | ||
} | ||
|
||
void Col2Im::validate_and_infer_types() { | ||
OV_OP_SCOPE(v15_Col2Im_validate_and_infer_types); | ||
|
||
const auto& data_element_type = get_input_element_type(0); | ||
const auto& output_size_element_type = get_input_element_type(1); | ||
const bool is_valid_output_size_type = | ||
output_size_element_type == element::i32 || output_size_element_type == element::i64; | ||
NODE_VALIDATION_CHECK(this, | ||
is_valid_output_size_type, | ||
"The element type of the output_size tensor must be i32 or i64 type. Got: ", | ||
output_size_element_type); | ||
|
||
const auto& kernel_size_element_type = get_input_element_type(2); | ||
const bool is_valid_kernel_size_type = | ||
kernel_size_element_type == element::i32 || kernel_size_element_type == element::i64; | ||
NODE_VALIDATION_CHECK(this, | ||
is_valid_kernel_size_type, | ||
"The element type of the kernel_size tensor must be i32 or i64 type. Got: ", | ||
kernel_size_element_type); | ||
|
||
const auto output_shapes = shape_infer(this, ov::util::get_node_input_partial_shapes(*this)); | ||
set_output_type(0, data_element_type, output_shapes[0]); | ||
} | ||
|
||
std::shared_ptr<Node> Col2Im::clone_with_new_inputs(const ov::OutputVector& new_args) const { | ||
OV_OP_SCOPE(v15_Col2Im_clone_with_new_inputs); | ||
check_new_args_count(this, new_args); | ||
return std::make_shared<Col2Im>(new_args.at(0), | ||
new_args.at(1), | ||
new_args.at(2), | ||
m_strides, | ||
m_dilations, | ||
m_pads_begin, | ||
m_pads_end); | ||
} | ||
|
||
const Strides& Col2Im::get_strides() const { | ||
return m_strides; | ||
} | ||
|
||
const Strides& Col2Im::get_dilations() const { | ||
return m_dilations; | ||
} | ||
|
||
const Shape& Col2Im::get_pads_begin() const { | ||
return m_pads_begin; | ||
} | ||
|
||
const Shape& Col2Im::get_pads_end() const { | ||
return m_pads_end; | ||
} | ||
|
||
} // namespace v15 | ||
} // namespace op | ||
} // namespace ov |
Oops, something went wrong.