Skip to content

Commit

Permalink
[Core] Add MaxPool-14 and AvgPool-14 (openvinotoolkit#22796)
Browse files Browse the repository at this point in the history
### Details:
 - Core implementation of MaxPool-14 and AvgPool-14
- They both introduce a new ceil mode:
`ov::op::RoundingType::CEIL_TORCH`
- The new ceiling mode does not allow the last pooling in a Dimension to
start in the padding area
 - No changes to reference implementation were necessary

### Related PRs
-
[Specification](openvinotoolkit#22930)
 - [Python API](openvinotoolkit#22966)
 - [PT FE](openvinotoolkit#23027)
- [Downgrade
transformations](openvinotoolkit#23381)

### Tickets:
 - 131961

### Context
openvinotoolkit#18731

---------

Co-authored-by: Pawel Raasz <pawel.raasz@intel.com>
  • Loading branch information
2 people authored and alvoron committed Apr 29, 2024
1 parent d59e1f6 commit ad01946
Show file tree
Hide file tree
Showing 21 changed files with 2,166 additions and 568 deletions.
72 changes: 72 additions & 0 deletions src/core/include/openvino/op/avg_pool.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -80,5 +80,77 @@ class OPENVINO_API AvgPool : public Op {
op::RoundingType m_rounding_type{op::RoundingType::FLOOR};
};
} // namespace v1

namespace v14 {
/// \brief Batched average pooling operation.
///
class OPENVINO_API AvgPool : public Op {
public:
OPENVINO_OP("AvgPool", "opset14", op::Op);

/// \brief Constructs a batched average pooling operation.
AvgPool() = default;

///
/// \brief Constructs a batched average pooling operation.
///
/// \param arg The output producing the input data batch tensor.<br>
/// `[d1, dn]`
/// \param strides The strides.<br> `[n]`
/// \param pads_begin The beginning of padding shape.<br> `[n]`
/// \param pads_end The end of padding shape.<br> `[n]`
/// \param kernel The kernel shape.<br> `[n]`
/// \param exclude_pad If false then averages include padding elements, each
/// treated as the number zero. If true, padding
/// elements
/// are entirely ignored when computing averages.
/// \param rounding_type Whether to use ceiling or floor rounding type while
/// computing output shape.
/// \param auto_pad Padding type to use for additional padded dimensions
///
AvgPool(const Output<Node>& arg,
const Strides& strides,
const Shape& pads_begin,
const Shape& pads_end,
const Shape& kernel,
bool exclude_pad,
op::RoundingType rounding_type = op::RoundingType::FLOOR,
const PadType& auto_pad = op::PadType::EXPLICIT);

void validate_and_infer_types() override;
bool visit_attributes(AttributeVisitor& visitor) override;

std::shared_ptr<Node> clone_with_new_inputs(const OutputVector& new_args) const override;

/// \return The kernel shape.
const Shape& get_kernel() const;
void set_kernel(const Shape& kernel);
/// \return The strides.
const Strides& get_strides() const;
void set_strides(const Strides& strides);
/// \return The beginning of padding shape.
const Shape& get_pads_begin() const;
void set_pads_begin(const Shape& pads_begin);
/// \return The end of padding shape.
const Shape& get_pads_end() const;
void set_pads_end(const Shape& pads_end);
bool get_exclude_pad() const;
void set_exclude_pad(bool exclude_pad);
/// \return The pad type for pooling.
const PadType& get_auto_pad() const;
void set_auto_pad(const PadType& auto_pad);
op::RoundingType get_rounding_type() const;
void set_rounding_type(op::RoundingType rounding_type);

protected:
Shape m_kernel;
Strides m_strides;
Shape m_pads_begin;
Shape m_pads_end;
bool m_exclude_pad{true};
PadType m_auto_pad{PadType::EXPLICIT};
op::RoundingType m_rounding_type{op::RoundingType::FLOOR};
};
} // namespace v14
} // namespace op
} // namespace ov
88 changes: 70 additions & 18 deletions src/core/include/openvino/op/max_pool.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -91,28 +91,16 @@ class OPENVINO_API MaxPool : public op::util::MaxPoolBase {
std::shared_ptr<Node> clone_with_new_inputs(const OutputVector& new_args) const override;

/// \return The pooling filter's dilations.
const Strides& get_dilations() const noexcept {
return m_dilations;
}
void set_dilations(const Strides& dilations) {
m_dilations = dilations;
}
const Strides& get_dilations() const noexcept;
void set_dilations(const Strides& dilations);

/// \return The data type of the second output tensor (indices).
element::Type get_index_element_type() const noexcept {
return m_index_element_type;
}
void set_index_element_type(const element::Type index_element_type) {
m_index_element_type = index_element_type;
}
element::Type get_index_element_type() const noexcept;
void set_index_element_type(const element::Type index_element_type);

// \return The 'axis' attribute value.
int64_t get_axis() const {
return m_axis;
}
void set_axis(const int64_t axis) {
m_axis = axis;
}
int64_t get_axis() const;
void set_axis(const int64_t axis);

bool evaluate(TensorVector& outputs, const TensorVector& inputs) const override;
bool has_evaluate() const override;
Expand All @@ -123,5 +111,69 @@ class OPENVINO_API MaxPool : public op::util::MaxPoolBase {
int64_t m_axis{0};
};
} // namespace v8

namespace v14 {
/// \brief MaxPooling operation with values and indices calculated as individual outputs
/// \ingroup ov_ops_cpp_api
class OPENVINO_API MaxPool : public op::util::MaxPoolBase {
public:
OPENVINO_OP("MaxPool", "opset14", op::util::MaxPoolBase);

/// \brief Constructs an empty MaxPool operation.
MaxPool() = default;

/// \brief Constructs a parametrized MaxPool operation.
///
/// \param arg Output of a node producing the feature tensor to be pooled.
/// \param strides The strides of the pooling filter.
/// \param dilations The dilations of the pooling filter.
/// \param pads_begin Paddings at the beginning of each spatial axis.
/// \param pads_end Paddings at the end of each spatial axis.
/// \param kernel The kernel shape.
/// \param rounding_type Whether to use ceiling or floor rounding type while
/// computing the output shape.
/// \param auto_pad The pad type for automatic calculation of the padding sizes.
/// \param index_element_type The data type used by the second output tensor
/// containing the selected indices.
/// \param axis Indicates a dimension in the input data shape which should be used
/// as a starting point for calculation of the upper bound of allowed
/// values of the indices output.
MaxPool(const Output<Node>& arg,
const Strides& strides,
const Strides& dilations,
const Shape& pads_begin,
const Shape& pads_end,
const Shape& kernel,
const op::RoundingType rounding_type = op::RoundingType::FLOOR,
const PadType auto_pad = op::PadType::EXPLICIT,
const element::Type index_element_type = element::i64,
const int64_t axis = 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;

/// \return The pooling filter's dilations.
const Strides& get_dilations() const noexcept;
void set_dilations(const Strides& dilations);

/// \return The data type of the second output tensor (indices).
element::Type get_index_element_type() const noexcept;
void set_index_element_type(const element::Type index_element_type);

// \return The 'axis' attribute value.
int64_t get_axis() const;
void set_axis(const int64_t axis);

bool evaluate(TensorVector& outputs, const TensorVector& inputs) const override;
bool has_evaluate() const override;

private:
Strides m_dilations;
element::Type m_index_element_type{element::i64};
int64_t m_axis{0};
};
} // namespace v14
} // namespace op
} // namespace ov
1 change: 1 addition & 0 deletions src/core/include/openvino/op/util/attr_types.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ std::ostream& operator<<(std::ostream& s, const PadType& type);
enum class RoundingType {
FLOOR = 0,
CEIL = 1,
CEIL_TORCH = 2,
};

OPENVINO_API
Expand Down
4 changes: 2 additions & 2 deletions src/core/include/openvino/opsets/opset14_tbl.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ _OPENVINO_OP_REG(Acos, ov::op::v0)
_OPENVINO_OP_REG(Add, ov::op::v1)
_OPENVINO_OP_REG(Asin, ov::op::v0)
_OPENVINO_OP_REG(Atan, ov::op::v0)
_OPENVINO_OP_REG(AvgPool, ov::op::v1)
_OPENVINO_OP_REG(AvgPool, ov::op::v14)
_OPENVINO_OP_REG(BatchNormInference, ov::op::v5)
_OPENVINO_OP_REG(BinaryConvolution, ov::op::v1)
_OPENVINO_OP_REG(Broadcast, ov::op::v3)
Expand Down Expand Up @@ -174,7 +174,7 @@ _OPENVINO_OP_REG(DetectionOutput, ov::op::v8)
_OPENVINO_OP_REG(I420toBGR, ov::op::v8)
_OPENVINO_OP_REG(I420toRGB, ov::op::v8)
_OPENVINO_OP_REG(MatrixNms, ov::op::v8)
_OPENVINO_OP_REG(MaxPool, ov::op::v8)
_OPENVINO_OP_REG(MaxPool, ov::op::v14)
_OPENVINO_OP_REG(NV12toBGR, ov::op::v8)
_OPENVINO_OP_REG(NV12toRGB, ov::op::v8)
_OPENVINO_OP_REG(RandomUniform, ov::op::v8)
Expand Down
51 changes: 44 additions & 7 deletions src/core/shape_inference/include/avg_pool_shape_inference.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -33,14 +33,31 @@ inline void valid_dilated_kernel_with_padding(const v1::AvgPool* op,
") and this is not ",
"allowed.");
}
} // namespace pooling

namespace v1 {
template <class TShape, class TContainer, class TRShape = result_shape_t<TShape>>
std::vector<TRShape> shape_infer(const AvgPool* op,
const std::vector<TShape>& input_shapes,
TContainer& pads_begin,
TContainer& pads_end) {
template <>
inline void valid_dilated_kernel_with_padding(const v14::AvgPool* op,
const size_t kernel,
const size_t pad_begin,
const size_t pad_end,
const size_t axis) {
NODE_VALIDATION_CHECK(op,
!op->get_exclude_pad() || ((kernel > pad_begin) && (kernel > pad_end)),
"Kernel after dilation is sometimes entirely in the padding area for axis ",
axis,
" (dilated kernel dimension: ",
kernel,
", padding below dimension: ",
pad_begin,
", padding above dimension: ",
pad_end,
") and this is not allowed.");
}

template <class TOp, class TShape, class TContainer, class TRShape = result_shape_t<TShape>>
std::vector<TRShape> avg_pool_shape_infer_util(const TOp* op,
const std::vector<TShape>& input_shapes,
TContainer& pads_begin,
TContainer& pads_end) {
NODE_VALIDATION_CHECK(op, input_shapes.size() == 1);
const auto& data_shape = input_shapes[0];
const auto dilations = Strides(op->get_kernel().size(), 1);
Expand All @@ -53,6 +70,26 @@ std::vector<TRShape> shape_infer(const AvgPool* op,

return {pooling::out_shape_infer(op, data_shape, pads_begin, pads_end, dilations)};
}
} // namespace pooling

namespace v1 {
template <class TShape, class TContainer, class TRShape = result_shape_t<TShape>>
std::vector<TRShape> shape_infer(const AvgPool* op,
const std::vector<TShape>& input_shapes,
TContainer& pads_begin,
TContainer& pads_end) {
return pooling::avg_pool_shape_infer_util(op, input_shapes, pads_begin, pads_end);
}
} // namespace v1

namespace v14 {
template <class TShape, class TContainer, class TRShape = result_shape_t<TShape>>
std::vector<TRShape> shape_infer(const AvgPool* op,
const std::vector<TShape>& input_shapes,
TContainer& pads_begin,
TContainer& pads_end) {
return pooling::avg_pool_shape_infer_util(op, input_shapes, pads_begin, pads_end);
}
} // namespace v14
} // namespace op
} // namespace ov
53 changes: 38 additions & 15 deletions src/core/shape_inference/include/max_pool_shape_inference.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,33 @@

namespace ov {
namespace op {
namespace pooling {

inline void resize_dilations(Strides& dilations, const size_t num_spatial) {
if (dilations.empty()) {
dilations.resize(num_spatial, 1);
}
}

template <class TOp, class TShape, class TContainer, class TRShape = result_shape_t<TShape>>
std::vector<TRShape> max_pool_shape_infer_util(const TOp* op,
const std::vector<TShape>& input_shapes,
TContainer& pads_begin,
TContainer& pads_end) {
NODE_VALIDATION_CHECK(op, input_shapes.size() == 1);
const auto& data_shape = input_shapes[0];

auto dilations = op->get_dilations();
auto num_spatial = op->get_kernel().size();
resize_dilations(dilations, num_spatial);
pooling::resize_empty_padding(num_spatial, pads_begin, pads_end);
pooling::validate::padding(op, pads_begin, pads_end);
pooling::validate::attributes(op, data_shape, dilations);
pooling::apply_padding(op, data_shape, dilations, pads_begin, pads_end);

return {2, pooling::out_shape_infer(op, data_shape, pads_begin, pads_end, dilations)};
}
} // namespace pooling

namespace v1 {
template <class TShape, class TContainer, class TRShape = result_shape_t<TShape>>
Expand All @@ -36,22 +63,18 @@ std::vector<TRShape> shape_infer(const MaxPool* op,
const std::vector<TShape>& input_shapes,
TContainer& pads_begin,
TContainer& pads_end) {
NODE_VALIDATION_CHECK(op, input_shapes.size() == 1);
const auto& data_shape = input_shapes[0];

auto num_spatial = op->get_kernel().size();
auto dilations = op->get_dilations();
if (dilations.empty()) {
dilations.resize(num_spatial, 1);
}

pooling::resize_empty_padding(num_spatial, pads_begin, pads_end);
pooling::validate::padding(op, pads_begin, pads_end);
pooling::validate::attributes(op, data_shape, dilations);
pooling::apply_padding(op, data_shape, dilations, pads_begin, pads_end);

return {2, pooling::out_shape_infer(op, data_shape, pads_begin, pads_end, dilations)};
return pooling::max_pool_shape_infer_util(op, input_shapes, pads_begin, pads_end);
}
} // namespace v8

namespace v14 {
template <class TShape, class TContainer, class TRShape = result_shape_t<TShape>>
std::vector<TRShape> shape_infer(const MaxPool* op,
const std::vector<TShape>& input_shapes,
TContainer& pads_begin,
TContainer& pads_end) {
return pooling::max_pool_shape_infer_util(op, input_shapes, pads_begin, pads_end);
}
} // namespace v14
} // namespace op
} // namespace ov
Loading

0 comments on commit ad01946

Please sign in to comment.