223 lines
8.8 KiB
C++
223 lines
8.8 KiB
C++
// Copyright (C) 2018-2021 Intel Corporation
|
|
// SPDX-License-Identifier: Apache-2.0
|
|
//
|
|
|
|
#include "opset1_upgrade.hpp"
|
|
|
|
#include <functional>
|
|
#include <iterator>
|
|
#include <limits>
|
|
#include <numeric>
|
|
|
|
#include "ngraph/builder/autobroadcast.hpp"
|
|
#include "ngraph/builder/reshape.hpp"
|
|
#include "ngraph/graph_util.hpp"
|
|
#include "ngraph/op/util/op_types.hpp"
|
|
#include "ngraph/ops.hpp"
|
|
#include "ngraph/provenance.hpp"
|
|
#include "op/avg_pool.hpp"
|
|
#include "op/convolution.hpp"
|
|
#include "op/group_conv.hpp"
|
|
|
|
NGRAPH_SUPPRESS_DEPRECATED_START
|
|
|
|
using namespace std;
|
|
using namespace ngraph;
|
|
|
|
namespace opset1_upgrade
|
|
{
|
|
template <typename OpV0, typename OpV1>
|
|
shared_ptr<Node> op_cast_binary_elementwise_node(const shared_ptr<OpV0>& node)
|
|
{
|
|
const auto autob = node->get_autob();
|
|
auto replacement_node =
|
|
make_shared<OpV1>(node->input_value(0), node->input_value(1), autob);
|
|
replace_node(node, replacement_node);
|
|
return replacement_node;
|
|
}
|
|
|
|
// Default is that we didn nothing
|
|
shared_ptr<Node> op_cast(shared_ptr<Node> node) { return nullptr; }
|
|
shared_ptr<Node> op_cast(shared_ptr<op::v0::ConvolutionBackpropData> node)
|
|
{
|
|
auto data_batch_shape = node->get_data_batch_shape();
|
|
auto strides = node->get_window_movement_strides_forward();
|
|
auto dilations = node->get_window_dilation_strides_forward();
|
|
auto pads_begin = node->get_padding_below_forward();
|
|
auto pads_end = node->get_padding_above_forward();
|
|
auto data_dilation_strides = node->get_data_dilation_strides_forward();
|
|
|
|
bool is_dds_valid = all_of(data_dilation_strides.begin(),
|
|
data_dilation_strides.end(),
|
|
[](size_t value) { return value == 1; });
|
|
|
|
NGRAPH_CHECK(is_dds_valid,
|
|
"Unable to convert ConvolutionBackpropData:0 to ConvolutionBackpropData:1 "
|
|
"with data dilation strides "
|
|
"other than `1`. Node: ",
|
|
*node);
|
|
|
|
auto replacement_node = make_shared<op::v1::ConvolutionBackpropData>(
|
|
node->input_value(1), // data
|
|
node->input_value(0), // filters
|
|
op::Constant::create(
|
|
element::i64,
|
|
Shape{data_batch_shape.size() - 2},
|
|
vector<size_t>(data_batch_shape.begin() + 2, data_batch_shape.end())),
|
|
strides,
|
|
pads_begin,
|
|
pads_end,
|
|
dilations);
|
|
replace_node(node, replacement_node);
|
|
return replacement_node;
|
|
}
|
|
|
|
shared_ptr<Node> op_cast(shared_ptr<op::v0::GroupConvolution> node)
|
|
{
|
|
auto strides = node->get_window_movement_strides();
|
|
auto dilations = node->get_window_dilation_strides();
|
|
auto pads_begin = node->get_padding_below();
|
|
auto pads_end = node->get_padding_above();
|
|
auto data_dilation_strides = node->get_data_dilation_strides();
|
|
auto auto_pad = node->get_pad_type();
|
|
|
|
bool is_dds_valid = all_of(data_dilation_strides.begin(),
|
|
data_dilation_strides.end(),
|
|
[](size_t value) { return value == 1; });
|
|
|
|
NGRAPH_CHECK(is_dds_valid,
|
|
"Unable to convert GroupConvolution:0 to GroupConvolution:1"
|
|
"with data dilation strides other than `1`. Node: ",
|
|
*node);
|
|
|
|
shared_ptr<Node> replacement_node;
|
|
if (node->has_groups_in_filters())
|
|
{
|
|
replacement_node = make_shared<op::v1::GroupConvolution>(node->input_value(0),
|
|
node->input_value(1),
|
|
strides,
|
|
pads_begin,
|
|
pads_end,
|
|
dilations,
|
|
auto_pad);
|
|
}
|
|
else
|
|
{
|
|
NGRAPH_CHECK(node->get_input_partial_shape(1).is_static(),
|
|
"Unable to convert GroupConvolution:0 to GroupConvolution:1"
|
|
"with dynamic filters shape. Node: ",
|
|
*node);
|
|
|
|
auto filters_shape = node->get_input_shape(1);
|
|
auto groups = node->get_groups();
|
|
filters_shape[0] /= groups;
|
|
filters_shape.insert(filters_shape.begin(), groups);
|
|
|
|
auto reshaped_filters = builder::opset1::reshape(node->input_value(1), filters_shape);
|
|
|
|
replacement_node = make_shared<op::v1::GroupConvolution>(node->input_value(0),
|
|
reshaped_filters,
|
|
strides,
|
|
pads_begin,
|
|
pads_end,
|
|
dilations,
|
|
auto_pad);
|
|
}
|
|
replace_node(node, replacement_node);
|
|
return replacement_node;
|
|
}
|
|
|
|
shared_ptr<Node> op_cast(shared_ptr<op::v0::GroupConvolutionBackpropData> node)
|
|
{
|
|
const auto strides = node->get_window_movement_strides();
|
|
const auto dilations = node->get_window_dilation_strides();
|
|
const auto pads_begin = node->get_padding_below();
|
|
const auto pads_end = node->get_padding_above();
|
|
|
|
const auto data_batch_pshape = node->get_input_partial_shape(0);
|
|
const auto filters_pshape = node->get_input_partial_shape(1);
|
|
|
|
NGRAPH_CHECK(data_batch_pshape.is_static(),
|
|
"Unable to convert GroupConvolutionBackpropData:0 to "
|
|
"GroupConvolutionBackpropData:1 with dynamic data_batch shape. Node: ",
|
|
*node);
|
|
NGRAPH_CHECK(filters_pshape.is_static(),
|
|
"Unable to convert GroupConvolutionBackpropData:0 to "
|
|
"GroupConvolutionBackpropData:1 with dynamic filters shape. Node: ",
|
|
*node);
|
|
|
|
auto data_batch_shape = data_batch_pshape.to_shape();
|
|
// Remove N, C from output shape to preserve only spatial dimentions.
|
|
data_batch_shape.erase(std::begin(data_batch_shape),
|
|
std::next(std::begin(data_batch_shape), 2));
|
|
auto filters_shape = filters_pshape.to_shape();
|
|
auto groups = node->get_groups();
|
|
|
|
filters_shape[0] /= groups;
|
|
filters_shape.insert(filters_shape.begin(), groups);
|
|
auto reshaped_filters = builder::opset1::reshape(node->input_value(1), filters_shape);
|
|
|
|
auto replacement_node = make_shared<op::v1::GroupConvolutionBackpropData>(
|
|
node->input_value(2),
|
|
reshaped_filters,
|
|
op::Constant::create(element::i64, Shape{data_batch_shape.size()}, data_batch_shape),
|
|
strides,
|
|
pads_begin,
|
|
pads_end,
|
|
dilations);
|
|
replace_node(node, replacement_node);
|
|
return replacement_node;
|
|
}
|
|
|
|
shared_ptr<Node> op_cast(shared_ptr<op::Xor> node)
|
|
{
|
|
auto replacement_node = make_shared<op::v1::LogicalXor>(
|
|
node->input_value(0), node->input_value(1), node->get_autob());
|
|
replace_node(node, replacement_node);
|
|
return replacement_node;
|
|
}
|
|
|
|
using DispatchMap = map<NodeTypeInfo, std::function<bool(shared_ptr<Node> node)>>;
|
|
|
|
template <typename T>
|
|
bool op_cast_thunk(shared_ptr<Node> node)
|
|
{
|
|
auto upgraded_node = op_cast(as_type_ptr<T>(node));
|
|
if (upgraded_node)
|
|
{
|
|
if (ngraph::get_provenance_enabled())
|
|
{
|
|
const std::string provenance_tag =
|
|
"<Opset1_Upgrade (v0 " + std::string(node->get_type_name()) + ")>";
|
|
upgraded_node->add_provenance_tags_above(node->input_values(), {provenance_tag});
|
|
}
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
DispatchMap& get_dispatch_map()
|
|
{
|
|
NGRAPH_SUPPRESS_DEPRECATED_START
|
|
static DispatchMap dispatch_map{
|
|
#define NGRAPH_OP(NAME, NAMESPACE) {NAMESPACE::NAME::type_info, op_cast_thunk<NAMESPACE::NAME>},
|
|
#include "opset0_tbl.hpp"
|
|
#undef NGRAPH_OP
|
|
};
|
|
return dispatch_map;
|
|
NGRAPH_SUPPRESS_DEPRECATED_END
|
|
}
|
|
} // namespace opset1_upgrade
|
|
|
|
bool pass::Opset1Upgrade::run_on_node(shared_ptr<Node> node)
|
|
{
|
|
bool modified = false;
|
|
auto& dispatch_map = opset1_upgrade::get_dispatch_map();
|
|
auto it = dispatch_map.find(node->get_type_info());
|
|
if (it != dispatch_map.end())
|
|
{
|
|
modified = it->second(node);
|
|
}
|
|
return modified;
|
|
}
|