[Transformations] ConvertDivide disabled transformation for divide ops from precision sensitive subgraphs (#9561)
* [Transformations] Skip ConvertDivide if Divide is on fp16 shapeOf subgraph * lambda definition moved out of loop * review fixes
This commit is contained in:
parent
282f37cdae
commit
456347e1b6
@ -0,0 +1,28 @@
|
||||
// Copyright (C) 2022 Intel Corporation
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
//
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "openvino/pass/pass.hpp"
|
||||
#include "transformations_visibility.hpp"
|
||||
|
||||
namespace ov {
|
||||
namespace pass {
|
||||
|
||||
class TRANSFORMATIONS_API MarkPrecisionSensitiveDivides;
|
||||
|
||||
} // namespace pass
|
||||
} // namespace ov
|
||||
|
||||
/**
|
||||
* @ingroup ie_transformation_common_api
|
||||
* @brief MarkPrecisionSensitiveDivides transformation marks the Divide fp16 layers
|
||||
* inside the subgraph starting from precision-sensitive input and ending at
|
||||
* the ShapeOf node as disabled for ConvertDivide transformation.
|
||||
*/
|
||||
class ov::pass::MarkPrecisionSensitiveDivides : public ModelPass {
|
||||
public:
|
||||
OPENVINO_RTTI("MarkPrecisionSensitiveDivides", "0");
|
||||
bool run_on_model(const std::shared_ptr<ov::Model>& m) override;
|
||||
};
|
@ -0,0 +1,34 @@
|
||||
// Copyright (C) 2022 Intel Corporation
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
//
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "openvino/core/node.hpp"
|
||||
#include "openvino/core/runtime_attribute.hpp"
|
||||
#include "transformations_visibility.hpp"
|
||||
|
||||
|
||||
namespace ov {
|
||||
|
||||
TRANSFORMATIONS_API void disable_divide_conversion(const std::shared_ptr<Node>& node);
|
||||
|
||||
TRANSFORMATIONS_API void enable_divide_conversion(const std::shared_ptr<Node>& node);
|
||||
|
||||
TRANSFORMATIONS_API bool divide_is_nonconvertible(const std::shared_ptr<Node>& node);
|
||||
|
||||
/**
|
||||
* @ingroup ie_runtime_attr_api
|
||||
* @brief NonconvertibleDivide class represents runtime info attribute that marks
|
||||
* a Divide as prohibitted to transform it to power.
|
||||
*/
|
||||
class TRANSFORMATIONS_API NonconvertibleDivide : public RuntimeAttribute {
|
||||
public:
|
||||
OPENVINO_RTTI("nonconvertable_divide", "0");
|
||||
|
||||
NonconvertibleDivide() = default;
|
||||
|
||||
bool is_copyable() const override { return false; }
|
||||
};
|
||||
|
||||
} // namespace ov
|
@ -180,6 +180,10 @@ TRANSFORMATIONS_API std::shared_ptr<Node> clone_try_fold(const std::shared_ptr<N
|
||||
|
||||
TRANSFORMATIONS_API bool shapes_equal_except_dynamic_expected_batch(const ngraph::PartialShape& expected, const ngraph::PartialShape& actual);
|
||||
|
||||
TRANSFORMATIONS_API void visit_shape_path(const std::shared_ptr<ov::Node>& node,
|
||||
std::unordered_set<std::shared_ptr<ov::Node>>& visited,
|
||||
std::function<void(std::shared_ptr<ov::Node>)> func);
|
||||
|
||||
template <typename T, typename... Args>
|
||||
std::shared_ptr<Node> make_try_fold(Args&&... args) {
|
||||
auto unary_output_node = std::make_shared<T>(std::forward<Args>(args)...);
|
||||
|
@ -53,6 +53,7 @@
|
||||
#include "transformations/common_optimizations/convert_compression_only_to_legacy.hpp"
|
||||
#include <transformations/common_optimizations/transpose_reshape_elimination_for_matmul.hpp>
|
||||
#include "transformations/common_optimizations/matmul_multiply_fusion.hpp"
|
||||
#include "transformations/common_optimizations/mark_precision_sensitive_divides.hpp"
|
||||
#include "transformations/op_conversions/bidirectional_sequences_decomposition.hpp"
|
||||
#include "transformations/op_conversions/convert_pad_to_group_conv.hpp"
|
||||
#include "transformations/op_conversions/convert_divide.hpp"
|
||||
@ -117,6 +118,8 @@ bool ngraph::pass::CommonOptimizations::run_on_model(const std::shared_ptr<ngrap
|
||||
// after support for FP16 IR is implemented
|
||||
manager.register_pass<ov::pass::ConvertCompressedOnlyToLegacy>();
|
||||
|
||||
manager.register_pass<ov::pass::MarkPrecisionSensitiveDivides>();
|
||||
|
||||
// TODO: move to KMB
|
||||
manager.register_pass<ngraph::pass::WeightsDequantizeToFakeQuantize>();
|
||||
|
||||
|
@ -0,0 +1,47 @@
|
||||
// Copyright (C) 2022 Intel Corporation
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
//
|
||||
|
||||
#include "transformations/common_optimizations/mark_precision_sensitive_divides.hpp"
|
||||
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
#include "openvino/op/util/precision_sensitive_attribute.hpp"
|
||||
#include "openvino/opsets/opset8.hpp"
|
||||
#include "transformations/rt_info/nonconvertible_divide.hpp"
|
||||
#include "transformations/utils/utils.hpp"
|
||||
|
||||
bool ov::pass::MarkPrecisionSensitiveDivides::run_on_model(const std::shared_ptr<ov::Model>& m) {
|
||||
std::deque<std::shared_ptr<Node>> nodes;
|
||||
std::unordered_set<std::shared_ptr<Node>> visited;
|
||||
for (auto& r : m->get_results())
|
||||
nodes.push_back(r);
|
||||
for (auto& r : m->get_sinks())
|
||||
nodes.emplace_back(r);
|
||||
|
||||
auto markup_func = [](std::shared_ptr<Node> node) {
|
||||
if (ov::is_type<ov::opset8::Divide>(node) && node->get_output_element_type(0) == ngraph::element::f16) {
|
||||
ov::disable_divide_conversion(node);
|
||||
}
|
||||
};
|
||||
|
||||
while (!nodes.empty()) {
|
||||
auto curr_node = nodes.front();
|
||||
nodes.pop_front();
|
||||
if (visited.count(curr_node))
|
||||
continue;
|
||||
for (auto& input : curr_node->inputs()) {
|
||||
if (ov::is_precision_sensitive(input))
|
||||
ngraph::op::util::visit_shape_path(input.get_source_output().get_node_shared_ptr(), visited, markup_func);
|
||||
}
|
||||
visited.insert(curr_node);
|
||||
|
||||
for (auto& input_value : curr_node->input_values()) {
|
||||
// continue searching
|
||||
const auto& input_node = input_value.get_node_shared_ptr();
|
||||
nodes.push_front(input_node);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
@ -17,33 +17,6 @@
|
||||
|
||||
using namespace std;
|
||||
|
||||
namespace {
|
||||
void visit_shape_path(const shared_ptr<ov::Node>& node, unordered_set<shared_ptr<ov::Node>>& visited) {
|
||||
if (!node)
|
||||
return;
|
||||
visited.insert(node);
|
||||
deque<shared_ptr<ov::Node>> nodes{node};
|
||||
while (!nodes.empty()) {
|
||||
auto curr_node = nodes.front();
|
||||
nodes.pop_front();
|
||||
// Do not check if already visited
|
||||
if (ov::is_type<ov::opset1::ShapeOf>(curr_node) || ov::is_type<ov::opset3::ShapeOf>(curr_node)) {
|
||||
continue;
|
||||
}
|
||||
visited.insert(curr_node);
|
||||
if (ov::is_type<ov::opset8::Constant>(curr_node)) {
|
||||
ov::disable_fp16_compression(curr_node);
|
||||
} else {
|
||||
for (auto& input_value : curr_node->input_values()) {
|
||||
// continue searching
|
||||
const auto& input_node = input_value.get_node_shared_ptr();
|
||||
nodes.push_front(input_node);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} // namespace
|
||||
|
||||
bool ov::pass::MarkPrecisionSensitiveSubgraphs::run_on_model(const std::shared_ptr<ov::Model>& f) {
|
||||
deque<shared_ptr<Node>> nodes;
|
||||
unordered_set<shared_ptr<Node>> visited;
|
||||
@ -52,6 +25,12 @@ bool ov::pass::MarkPrecisionSensitiveSubgraphs::run_on_model(const std::shared_p
|
||||
for (auto& r : f->get_sinks())
|
||||
nodes.emplace_back(r);
|
||||
|
||||
auto markup_func = [](shared_ptr<Node> node) {
|
||||
if (ov::is_type<ov::opset8::Constant>(node)) {
|
||||
ov::disable_fp16_compression(node);
|
||||
}
|
||||
};
|
||||
|
||||
while (!nodes.empty()) {
|
||||
auto curr_node = nodes.front();
|
||||
nodes.pop_front();
|
||||
@ -59,7 +38,7 @@ bool ov::pass::MarkPrecisionSensitiveSubgraphs::run_on_model(const std::shared_p
|
||||
continue;
|
||||
for (auto& input : curr_node->inputs()) {
|
||||
if (ov::is_precision_sensitive(input))
|
||||
visit_shape_path(input.get_source_output().get_node_shared_ptr(), visited);
|
||||
ngraph::op::util::visit_shape_path(input.get_source_output().get_node_shared_ptr(), visited, markup_func);
|
||||
}
|
||||
visited.insert(curr_node);
|
||||
|
||||
|
@ -14,6 +14,8 @@
|
||||
#include <ngraph/validation_util.hpp>
|
||||
#include <ngraph/log.hpp>
|
||||
|
||||
#include "transformations/rt_info/nonconvertible_divide.hpp"
|
||||
|
||||
NGRAPH_RTTI_DEFINITION(ngraph::pass::ConvertDivide, "ConvertDivide", 0);
|
||||
NGRAPH_RTTI_DEFINITION(ngraph::pass::ConvertDivideWithConstant, "ConvertDivideWithConstant", 0);
|
||||
|
||||
@ -21,8 +23,8 @@ namespace {
|
||||
bool convert_divide(std::shared_ptr<ngraph::Node> node) {
|
||||
auto div = std::dynamic_pointer_cast<ngraph::opset1::Divide>(node);
|
||||
// We can not apply this transformation in case with integer input data type
|
||||
if (!div || div->get_input_element_type(0).is_integral()
|
||||
|| div->get_input_element_type(1).is_integral()) {
|
||||
if (!div || ov::divide_is_nonconvertible(div)
|
||||
|| div->get_input_element_type(0).is_integral()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,20 @@
|
||||
// Copyright (C) 2022 Intel Corporation
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
//
|
||||
|
||||
#include "transformations/rt_info/nonconvertible_divide.hpp"
|
||||
|
||||
void ov::disable_divide_conversion(const std::shared_ptr<Node>& node) {
|
||||
auto& rt_info = node->get_rt_info();
|
||||
rt_info[NonconvertibleDivide::get_type_info_static()] = NonconvertibleDivide{};
|
||||
}
|
||||
|
||||
void ov::enable_divide_conversion(const std::shared_ptr<Node>& node) {
|
||||
auto& rt_info = node->get_rt_info();
|
||||
rt_info.erase(NonconvertibleDivide::get_type_info_static());
|
||||
}
|
||||
|
||||
bool ov::divide_is_nonconvertible(const std::shared_ptr<Node>& node) {
|
||||
const auto& rt_info = node->get_rt_info();
|
||||
return rt_info.count(NonconvertibleDivide::get_type_info_static());
|
||||
}
|
@ -8,6 +8,7 @@
|
||||
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <ngraph/opsets/opset1.hpp>
|
||||
#include <ngraph/op/broadcast.hpp>
|
||||
#include <ngraph/op/constant.hpp>
|
||||
#include <ngraph/op/reshape.hpp>
|
||||
@ -177,6 +178,31 @@ bool shapes_equal_except_dynamic_expected_batch(const ngraph::PartialShape& expe
|
||||
}
|
||||
}
|
||||
|
||||
void visit_shape_path(const std::shared_ptr<ov::Node>& node,
|
||||
std::unordered_set<std::shared_ptr<ov::Node>>& visited,
|
||||
std::function<void(std::shared_ptr<ov::Node>)> func) {
|
||||
if (!node)
|
||||
return;
|
||||
visited.insert(node);
|
||||
std::deque<std::shared_ptr<ov::Node>> nodes{node};
|
||||
while (!nodes.empty()) {
|
||||
auto curr_node = nodes.front();
|
||||
nodes.pop_front();
|
||||
// Do not check if already visited
|
||||
if (ngraph::is_type<ngraph::opset1::ShapeOf>(curr_node) || ngraph::is_type<ngraph::opset3::ShapeOf>(curr_node)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
visited.insert(curr_node);
|
||||
func(curr_node);
|
||||
for (auto& input_value : curr_node->input_values()) {
|
||||
// continue searching
|
||||
const auto& input_node = input_value.get_node_shared_ptr();
|
||||
nodes.push_front(input_node);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace util
|
||||
} // namespace op
|
||||
} // namespace ngraph
|
||||
|
@ -11,6 +11,7 @@
|
||||
#include <ngraph/function.hpp>
|
||||
#include <ngraph/opsets/opset1.hpp>
|
||||
#include <transformations/op_conversions/convert_divide.hpp>
|
||||
#include <transformations/common_optimizations/mark_precision_sensitive_divides.hpp>
|
||||
#include <transformations/init_node_info.hpp>
|
||||
#include <transformations/utils/utils.hpp>
|
||||
#include <ngraph/pass/manager.hpp>
|
||||
@ -122,3 +123,28 @@ TEST_F(TransformationTestsF, ConvertDivideWithConstantNegative) {
|
||||
function_ref = std::make_shared<ngraph::Function>(ngraph::NodeVector{divide}, ngraph::ParameterVector{data1, data2});
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(TransformationTestsF, ConvertDivideFP16ShapeOfSubgraphNegative) {
|
||||
{
|
||||
auto data = std::make_shared<ngraph::opset1::Parameter>(ngraph::element::f16, ngraph::Shape{1, 3, 22, 22});
|
||||
auto gather = ngraph::op::util::node_to_get_shape_value_of_indices_from_shape_source(data, {2, 3});
|
||||
auto convert = std::make_shared<ngraph::opset1::Convert>(gather, ngraph::element::f16);
|
||||
auto divide_constant = ngraph::opset1::Constant::create(ngraph::element::f16, ngraph::Shape{1}, {0.5});
|
||||
auto divide = std::make_shared<ngraph::opset1::Divide>(convert, divide_constant);
|
||||
auto convert_after = std::make_shared<ngraph::opset1::Convert>(divide, ngraph::element::i32);
|
||||
|
||||
ngraph::opset1::Interpolate::Attributes interp_attr;
|
||||
interp_attr.antialias = false;
|
||||
interp_attr.axes = {2, 3};
|
||||
interp_attr.mode = "nearest";
|
||||
interp_attr.pads_begin = {0, 0, 0, 0};
|
||||
interp_attr.pads_end = {0, 0, 0, 0};
|
||||
|
||||
auto interpolate = std::make_shared<ngraph::opset1::Interpolate>(data, convert_after, interp_attr);
|
||||
|
||||
function = std::make_shared<ngraph::Function>(ngraph::NodeVector{interpolate}, ngraph::ParameterVector{data});
|
||||
|
||||
ov::pass::MarkPrecisionSensitiveDivides().run_on_model(function);
|
||||
manager.register_pass<ngraph::pass::ConvertDivide>();
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user