Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[cpu] Remove custom shape inference factories #27924

Open
wants to merge 8 commits into
base: master
Choose a base branch
from
37 changes: 32 additions & 5 deletions src/plugins/intel_cpu/src/nodes/deconv.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -125,16 +125,43 @@ bool DeconvKey::operator==(const DeconvKey& rhs) const {
* input. Since in case it exists, plugin should pass the input data to the shape inference function.
*
*/
class DeconfolutionShapeInferFactory : public ShapeInferFactory {
class DeconvolutionShapeInferFactory : public ShapeInferFactory {
public:
DeconfolutionShapeInferFactory(std::shared_ptr<ov::Node> op) : m_op(std::move(op)) {}
DeconvolutionShapeInferFactory(std::shared_ptr<ov::Node> op) : m_op(std::move(op)) {}

ShapeInferPtr makeShapeInfer() const override {
const auto port_mask = (m_op->get_input_size() > 2) ? PortMask(2) : EMPTY_PORT_MASK;
return make_shape_inference(m_op, port_mask);
return std::make_shared<DeconvolutionShapeInfer>(m_op);
}

private:
class DeconvolutionShapeInfer : public IShapeInfer {
public:
DeconvolutionShapeInfer(const std::shared_ptr<ov::Node>& op)
: m_shape_infer(make_shape_inference(op)),
m_port_mask((op->get_input_size() > 2) ? PortMask(2) : EMPTY_PORT_MASK) {}

Result infer(const std::vector<std::reference_wrapper<const VectorDims>>& input_shapes,
const std::unordered_map<size_t, MemoryPtr>& data_dependency) override {
return m_shape_infer->infer(input_shapes, data_dependency);
}

const ov::CoordinateDiff& get_pads_begin() override {
return m_shape_infer->get_pads_begin();
}

const ov::CoordinateDiff& get_pads_end() override {
return m_shape_infer->get_pads_end();
}

port_mask_t get_port_mask() const override {
return m_port_mask;
};

private:
ShapeInferPtr m_shape_infer;
const port_mask_t m_port_mask;
};

std::shared_ptr<ov::Node> m_op;
};
} // namespace
Expand Down Expand Up @@ -165,7 +192,7 @@ bool Deconvolution::isSupportedOperation(const std::shared_ptr<const ov::Node>&
}

Deconvolution::Deconvolution(const std::shared_ptr<ov::Node>& op, const GraphContext::CPtr context)
: Node(op, context, DeconfolutionShapeInferFactory(op)) {
: Node(op, context, DeconvolutionShapeInferFactory(op)) {
std::string errorMessage;
errorPrefix = "Deconvolution node with name '" + getName() + "' ";
if (!isSupportedOperation(op, errorMessage))
Expand Down
16 changes: 1 addition & 15 deletions src/plugins/intel_cpu/src/nodes/eye.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -30,22 +30,8 @@ bool Eye::isSupportedOperation(const std::shared_ptr<const ov::Node>& op, std::s
return true;
}

namespace {
class EyeShapeInferFactory : public ShapeInferFactory {
public:
EyeShapeInferFactory(std::shared_ptr<ov::Node> op) : m_op(op) {}
ShapeInferPtr makeShapeInfer() const override {
return (m_op->get_input_size() == 4) ? make_shape_inference(m_op)
: make_shape_inference(m_op, PortMask(Eye::ROWS_NUM, Eye::COLS_NUM));
}

private:
std::shared_ptr<ov::Node> m_op;
};
} // namespace

Eye::Eye(const std::shared_ptr<ov::Node>& op, const GraphContext::CPtr context)
: Node(op, context, EyeShapeInferFactory(op)) {
: Node(op, context, NgraphShapeInferFactory(op)) {
std::string errorMessage;
if (!isSupportedOperation(op, errorMessage)) {
OPENVINO_THROW_NOT_IMPLEMENTED(errorMessage);
Expand Down
14 changes: 1 addition & 13 deletions src/plugins/intel_cpu/src/nodes/reference.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,24 +10,12 @@
namespace ov {
namespace intel_cpu {

class ReferenceShapeInferFactory : public ShapeInferFactory {
public:
ReferenceShapeInferFactory(std::shared_ptr<ov::Node> op) : m_op{std::move(op)} {}

ShapeInferPtr makeShapeInfer() const override {
return make_shape_inference(m_op, FULL_PORT_MASK);
}

private:
std::shared_ptr<ov::Node> m_op;
};

namespace node {

Reference::Reference(const std::shared_ptr<ov::Node>& op,
const GraphContext::CPtr& context,
const std::string& errorMessage)
: Node(op, context, ReferenceShapeInferFactory(op)),
: Node(op, context, NgraphShapeInferFactory(op)),
ovCoreNode(op),
additionalErrorMessage(errorMessage) {
if (!op->has_evaluate()) {
Expand Down
104 changes: 70 additions & 34 deletions src/plugins/intel_cpu/src/shape_inference/shape_inference.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -234,8 +234,7 @@ class ShapeInferFallback : public ShapeInferBase {

ov::optional<std::vector<StaticShape>> infer(const std::vector<StaticShapeRef>& input_shapes,
const ov::ITensorAccessor& tensor_accessor) override {
auto op = m_node.get();
std::vector<StaticShape> output_shapes;
const auto op = m_node.get();

std::shared_ptr<ov::Node> local_op;
ov::OutputVector new_inputs;
Expand All @@ -252,7 +251,7 @@ class ShapeInferFallback : public ShapeInferBase {
local_op = op->clone_with_new_inputs(new_inputs);
local_op->validate_and_infer_types();

output_shapes.resize(local_op->get_output_size());
std::vector<StaticShape> output_shapes(local_op->get_output_size());
for (size_t i = 0; i < output_shapes.size(); ++i) {
const auto& partial_shape = local_op->get_output_partial_shape(i);

Expand All @@ -265,6 +264,11 @@ class ShapeInferFallback : public ShapeInferBase {

return {std::move(output_shapes)};
}

port_mask_t get_port_mask() const override {
// For fallback return full port mask to try get data for all node's inputs
return FULL_PORT_MASK;
}
};

template <class TOp, IShapeInfer::port_mask_t MASK>
Expand Down Expand Up @@ -300,6 +304,27 @@ class ShapeInferTA<TOp, EMPTY_PORT_MASK> : public ShapeInferBase {
}
};

/**
* @brief Shape inference for v0 FakeQuantize.
*
* It requires dedicated port mask for CPU output shape data dependency but is not used by inference function.
* Review shape_infer function to include this dependency.
*/
template <>
class ShapeInferTA<ov::op::v0::FakeQuantize, EMPTY_PORT_MASK> : public ShapeInferBase {
public:
using ShapeInferBase::ShapeInferBase;

ov::optional<std::vector<StaticShape>> infer(const std::vector<StaticShapeRef>& input_shapes,
const ov::ITensorAccessor&) override {
return {shape_infer(static_cast<ov::op::v0::FakeQuantize*>(m_node.get()), input_shapes)};
}

port_mask_t get_port_mask() const override {
return util::bit::mask(0);
}
};

praasz marked this conversation as resolved.
Show resolved Hide resolved
/** @brief Base shape inference object implementing the IStaticShapeInfer with padding support. */
class ShapeInferPaddingBase : public ShapeInferBase {
public:
Expand Down Expand Up @@ -355,6 +380,48 @@ class ShapeInferPaddingTA<TOp, EMPTY_PORT_MASK> : public ShapeInferPaddingBase {
}
};

/**
* @brief Shape inference for v14 MaxPool.
*
* It requires dedicated port mask for CPU output shape data dependency but is not used by inference function.
* Review shape_infer function to include this dependency.
*/
template <>
class ShapeInferPaddingTA<ov::op::v14::MaxPool, EMPTY_PORT_MASK> : public ShapeInferPaddingBase {
public:
using ShapeInferPaddingBase::ShapeInferPaddingBase;

ov::optional<std::vector<StaticShape>> infer(const std::vector<StaticShapeRef>& input_shapes,
const ov::ITensorAccessor&) override {
return {shape_infer(static_cast<ov::op::v14::MaxPool*>(m_node.get()), input_shapes, m_pads_begin, m_pads_end)};
}

port_mask_t get_port_mask() const override {
return util::bit::mask(0);
}
};

/**
* @brief Shape inference for v8 MaxPool.
*
* It requires dedicated port mask for CPU output shape data dependency but is not used by inference function.
* Review shape_infer function to include this dependency.
*/
template <>
class ShapeInferPaddingTA<ov::op::v8::MaxPool, EMPTY_PORT_MASK> : public ShapeInferPaddingBase {
public:
using ShapeInferPaddingBase::ShapeInferPaddingBase;

ov::optional<std::vector<StaticShape>> infer(const std::vector<StaticShapeRef>& input_shapes,
const ov::ITensorAccessor&) override {
return {shape_infer(static_cast<ov::op::v8::MaxPool*>(m_node.get()), input_shapes, m_pads_begin, m_pads_end)};
}

port_mask_t get_port_mask() const override {
return util::bit::mask(0);
}
};

Comment on lines +383 to +424
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pooling::Pooling CPU node has been using NgraphShapeInferFactory without any additional mask modifications. And it seems that the Pooling node doesn't require input data dependency for shape inference. Such change may negatively impact performance, as the artificial data dependency introduce additional synchronizations to inference.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is no issue when pooling is created as Pooling node.
The issue is visible if is not possible to make as Pooling and the Reference node, its case for some dynamic cases
in tests/layer_tests/pytorch_tests/test_pooling.py::TestPooling tests.

The previous Reference node always used FULL_MASK regardless if shape inference is defined or not (fallback path). I think this approach has masked issues. Now reference use mask defined in shape inference (if defined) or FULL_MASK for fallback path.

Then issue appears in when the input(0) has dynamic shape but data at port(0) has static shape (exception thrown when get static shape). When dada dependency is set then static shape from data is taken and pooling output shape can be calculated.

These specialization (can be removed if problem solved) shows that issue could be fixed in:

  • shape inference add additional data dependency (it looks like is not required now)
  • for dynamic cases the data dependency should be always set for port 0 to get input static shape.

For FakeQuantize is similar issue and there are test failing if data dependency not set to port 0

/**
* \brief Shape infer factory
*
Expand Down Expand Up @@ -610,34 +677,6 @@ const IStaticShapeInferFactory::TRegistry IStaticShapeInferFactory::registry{
#undef _OV_OP_SHAPE_INFER_MASK_REG
#undef _OV_OP_SHAPE_INFER_VA_REG

class ShapeInferCustomMask : public IShapeInfer {
public:
ShapeInferCustomMask(ShapeInferPtr shape_infer, port_mask_t port_mask)
: m_shape_infer{std::move(shape_infer)},
m_port_mask{port_mask} {}

Result infer(const std::vector<std::reference_wrapper<const VectorDims>>& input_shapes,
const std::unordered_map<size_t, MemoryPtr>& data_dependency) override {
return m_shape_infer->infer(input_shapes, data_dependency);
}

const ov::CoordinateDiff& get_pads_begin() override {
return m_shape_infer->get_pads_begin();
}

const ov::CoordinateDiff& get_pads_end() override {
return m_shape_infer->get_pads_end();
}

port_mask_t get_port_mask() const override {
return m_port_mask;
}

private:
const ShapeInferPtr m_shape_infer;
const port_mask_t m_port_mask;
};

std::shared_ptr<IStaticShapeInfer> make_shape_inference(std::shared_ptr<ov::Node> op) {
if (auto shape_infer = IStaticShapeInferFactory::make(op->get_type_info(), op)) {
return shape_infer;
Expand All @@ -652,8 +691,5 @@ std::shared_ptr<IStaticShapeInfer> make_shape_inference(std::shared_ptr<ov::Node
}
}

ShapeInferPtr make_shape_inference(std::shared_ptr<ov::Node> op, IShapeInfer::port_mask_t port_mask) {
return std::make_shared<ShapeInferCustomMask>(make_shape_inference(std::move(op)), port_mask);
}
} // namespace intel_cpu
} // namespace ov
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,5 @@ class IStaticShapeInfer : public IShapeInfer {
};

std::shared_ptr<IStaticShapeInfer> make_shape_inference(std::shared_ptr<ov::Node> op);
ShapeInferPtr make_shape_inference(std::shared_ptr<ov::Node> op, IShapeInfer::port_mask_t port_mask);
} // namespace intel_cpu
} // namespace ov
Loading