Skip to content

Commit

Permalink
Add 'pad' operator support for ov::preprocess::PrePostProcessor (open…
Browse files Browse the repository at this point in the history
…vinotoolkit#23093)

### Details:
 - Add 'pad' preprocessor operator
- openvinotoolkit#23068 

### Tickets:
 - [CVS-121548](https://jira.devtools.intel.com/browse/CVS-121548)
  • Loading branch information
ccinv authored and alvoron committed Apr 29, 2024
1 parent e805906 commit 81ec713
Show file tree
Hide file tree
Showing 8 changed files with 156 additions and 1 deletion.
1 change: 1 addition & 0 deletions src/core/include/openvino/core/core.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@
#include "openvino/core/preprocess/output_info.hpp"
#include "openvino/core/preprocess/output_model_info.hpp"
#include "openvino/core/preprocess/output_tensor_info.hpp"
#include "openvino/core/preprocess/padding_mode.hpp"
#include "openvino/core/preprocess/postprocess_steps.hpp"
#include "openvino/core/preprocess/pre_post_process.hpp"
#include "openvino/core/preprocess/preprocess_steps.hpp"
Expand Down
13 changes: 13 additions & 0 deletions src/core/include/openvino/core/preprocess/padding_mode.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
// Copyright (C) 2018-2023 Intel Corporation
// SPDX-License-Identifier: Apache-2.0
//

#pragma once

namespace ov {
namespace preprocess {

using PaddingMode = ov::op::PadMode;

} // namespace preprocess
} // namespace ov
27 changes: 27 additions & 0 deletions src/core/include/openvino/core/preprocess/preprocess_steps.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

#include "openvino/core/core_visibility.hpp"
#include "openvino/core/preprocess/color_format.hpp"
#include "openvino/core/preprocess/padding_mode.hpp"
#include "openvino/core/preprocess/resize_algorithm.hpp"
#include "openvino/core/type/element_type.hpp"

Expand Down Expand Up @@ -80,6 +81,32 @@ class OPENVINO_API PreProcessSteps final {
/// \return Reference to 'this' to allow chaining with other calls in a builder-like manner
PreProcessSteps& mean(const std::vector<float>& values);

/// \brief Add pad preprocess operation
/// Extends an input tensor on edges with constants
///
/// \param pads_begin Number of padding elements to add at the beginning of each axis.
/// \param pads_end Number of padding elements to add at the end of each axis.
/// \param value Value to be populated in the padded area
///
/// \return Reference to 'this' to allow chaining with other calls in a builder-like manner
PreProcessSteps& pad(const std::vector<int>& pads_begin,
const std::vector<int>& pads_end,
float value,
PaddingMode mode);

/// \brief Add pad preprocess operation
/// Extends an input tensor on edges with constants
///
/// \param pads_begin Number of padding elements to add at the beginning of each axis.
/// \param pads_end Number of padding elements to add at the end of each axis.
/// \param values Values to be populated in the padded area
///
/// \return Reference to 'this' to allow chaining with other calls in a builder-like manner
PreProcessSteps& pad(const std::vector<int>& pads_begin,
const std::vector<int>& pads_end,
const std::vector<float>& values,
PaddingMode mode);

/// \brief Signature for custom preprocessing operation. Custom preprocessing operation takes one input node and
/// produces one output node. For more advanced cases, client's code can use transformation passes over ov::Model
/// directly
Expand Down
16 changes: 16 additions & 0 deletions src/core/src/preprocess/pre_post_process.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -279,6 +279,22 @@ PreProcessSteps& PreProcessSteps::mean(const std::vector<float>& values) {
return *this;
}

PreProcessSteps& PreProcessSteps::pad(const std::vector<int>& pads_begin,
const std::vector<int>& pads_end,
float value,
PaddingMode mode) {
m_impl->add_pad_impl(pads_begin, pads_end, std::vector<float>{value}, mode);
return *this;
}

PreProcessSteps& PreProcessSteps::pad(const std::vector<int>& pads_begin,
const std::vector<int>& pads_end,
const std::vector<float>& values,
PaddingMode mode) {
m_impl->add_pad_impl(pads_begin, pads_end, values, mode);
return *this;
}

PreProcessSteps& PreProcessSteps::convert_element_type(const element::Type& type) {
m_impl->add_convert_impl(type);
return *this;
Expand Down
48 changes: 48 additions & 0 deletions src/core/src/preprocess/preprocess_steps_impl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,54 @@ void PreStepsList::add_mean_impl(const std::vector<float>& values) {
"mean " + vector_to_string(values));
}

void PreStepsList::add_pad_impl(const std::vector<int>& pads_begin,
const std::vector<int>& pads_end,
const std::vector<float>& pad_values,
PaddingMode mode) {
std::string name;
name = "pad(begin " + vector_to_string(pads_begin) + ", end " + vector_to_string(pads_end);
switch (mode) {
case PaddingMode::CONSTANT:
name += ", with " + vector_to_string(pad_values) + ")";
break;
case PaddingMode::EDGE:
name += ", copied from edge)";
break;
case PaddingMode::REFLECT:
name += ", reflected from tensor)";
break;
case PaddingMode::SYMMETRIC:
name += ", symmetrically added from tensor)";
break;
}

m_actions.emplace_back(
[pads_begin, pads_end, pad_values, mode](const std::vector<Output<Node>>& nodes,
const std::shared_ptr<Model>& function,
PreprocessingContext& ctxt) {
OPENVINO_ASSERT(nodes.size() == 1,
"Can't pad multi-plane input. Suggesting to convert current image to "
"RGB/BGR color format using 'PreProcessSteps::convert_color'");

const auto& node = nodes[0];
auto element_type = nodes[0].get_element_type();
OPENVINO_ASSERT(element_type.is_real(),
"Pad preprocessing can be applied to 'float' inputs. Consider using of "
"'convert_element_type' before padding. Current type is: ",
element_type);

auto pad_value = opset8::Constant::create(node.get_element_type(), Shape{}, pad_values);

auto npads_begin = opset8::Constant::create(element::i64, Shape{pads_begin.size()}, pads_begin);
auto npads_end = opset8::Constant::create(element::i64, Shape{pads_end.size()}, pads_end);
auto npad_value = opset8::Constant::create(element_type, Shape{}, pad_values);

auto pad = std::make_shared<opset8::Pad>(node, npads_begin, npads_end, npad_value, mode);
return std::make_tuple(std::vector<Output<Node>>{pad}, true);
},
name);
}

void PreStepsList::add_convert_impl(const element::Type& type) {
m_actions.emplace_back(
[type](const std::vector<Output<Node>>& nodes,
Expand Down
4 changes: 4 additions & 0 deletions src/core/src/preprocess/preprocess_steps_impl.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,10 @@ class PreStepsList {
public:
void add_scale_impl(const std::vector<float>& values);
void add_mean_impl(const std::vector<float>& values);
void add_pad_impl(const std::vector<int>& pads_begin,
const std::vector<int>& pads_end,
const std::vector<float>& values,
PaddingMode mode);
void add_convert_impl(const element::Type& type);
void add_crop_impl(const std::vector<int>& begin, const std::vector<int>& end);
void add_resize_impl(ResizeAlgorithm alg, int dst_height, int dst_width);
Expand Down
25 changes: 25 additions & 0 deletions src/core/tests/preprocess.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -914,6 +914,31 @@ TEST(pre_post_process, mean_vector_dynamic_channels_shape) {
EXPECT_EQ(f->get_output_element_type(0), element::f32);
}

TEST(pre_post_process, pad_vector_constant_layout) {
auto f = create_simple_function(element::f32, Shape{1, 3, 200, 200});
auto p = PrePostProcessor(f);

p.input().tensor().set_shape({1, 3, 199, 199});
p.input().preprocess().pad({0, 0, 0, 0}, {0, 0, 1, 1}, 0, PaddingMode::CONSTANT);
EXPECT_NO_THROW(p.build());
}

TEST(pre_post_process, pad_vector_out_of_range) {
auto f = create_simple_function(element::f32, Shape{1, 3, 5, 5});
auto p = PrePostProcessor(f);

ASSERT_THROW(p.input().preprocess().pad({0, 0, -2, 0}, {0, 0, -4, 1}, 0, PaddingMode::CONSTANT);
p.build(), ov::AssertFailure);
}

TEST(pre_post_process, pad_vector_dim_mismatch) {
auto f = create_simple_function(element::f32, Shape{1, 3, 5, 5});
auto p = PrePostProcessor(f);

ASSERT_THROW(p.input().preprocess().pad({0, 0, 2, 0, 1}, {0, 0, 4, 1, 1}, 0, PaddingMode::CONSTANT);
p.build(), ov::AssertFailure);
}

TEST(pre_post_process, resize_no_model_layout) {
auto f = create_simple_function(element::f32, Shape{1, 3, 224, 224});
auto p = PrePostProcessor(f);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -443,6 +443,26 @@ inline std::shared_ptr<Model> crop_dynamic() {
return function;
}

inline std::shared_ptr<Model> pad_constant() {
using namespace ov::preprocess;
auto function = create_preprocess_1input(ov::element::f32, PartialShape{1, 3, 10, 10});
auto p = PrePostProcessor(function);
p.input().tensor().set_shape({1, 3, 9, 5});
p.input().preprocess().pad({0, 0, 2, 2}, {0, 0, -1, 3}, 0, PaddingMode::CONSTANT);
function = p.build();
return function;
}

inline std::shared_ptr<Model> pad_edge() {
using namespace ov::preprocess;
auto function = create_preprocess_1input(ov::element::f32, PartialShape{1, 3, 10, 10});
auto p = PrePostProcessor(function);
p.input().tensor().set_shape({1, 3, 9, 5});
p.input().preprocess().pad({0, 0, 2, 2}, {0, 0, -1, 3}, 0, PaddingMode::EDGE);
function = p.build();
return function;
}

inline std::vector<preprocess_func> generic_preprocess_functions() {
return std::vector<preprocess_func>{
preprocess_func(mean_only, "mean_only", 0.01f),
Expand Down Expand Up @@ -477,7 +497,8 @@ inline std::vector<preprocess_func> generic_preprocess_functions() {
preprocess_func(cvt_color_i420_to_rgb_single_plane, "cvt_color_i420_to_rgb_single_plane", 1.f),
preprocess_func(cvt_color_i420_to_bgr_three_planes, "cvt_color_i420_to_bgr_three_planes", 1.f),
preprocess_func(cvt_color_bgrx_to_bgr, "cvt_color_bgrx_to_bgr", 0.01f),
};
preprocess_func(pad_constant, "pad_constant", 0.01f),
preprocess_func(pad_edge, "pad_edge", 0.01f)};
}

inline std::shared_ptr<Model> cvt_color_rgb_to_bgr() {
Expand Down

0 comments on commit 81ec713

Please sign in to comment.