Add support for GroupConvolution in DilatedConvolutionConverter (#15168)

* Add support for GroupConvolution in DilatedConvolutionConverter

* Fix codestyle

* Update src/common/transformations/tests/common_optimizations/dilated_convolution_converter.cpp

* Update src/common/transformations/tests/common_optimizations/dilated_convolution_converter.cpp

* Add tf frontend test

* Apply codestyle

* Update src/frontends/tensorflow/tests/convert_tricky_models.cpp
This commit is contained in:
Maxim Vafin authored and GitHub committed 2023-01-22 14:01:16 +03:00
1 parent 2ec116f592
commit d4cb719213
5 files changed
+564 -18

No files matched your search

@@ -20,8 +20,8 @@ class TRANSFORMATIONS_API DilatedConvolutionConverter;
/**
* @ingroup ie_transformation_common_api
* @brief DilatedConvolutionConverter transformation replaces following graph:
* SpaceToBatch -> Convolution -> BatchToSpace
* to a single Convolution node with updated pads and dilations
* SpaceToBatch -> Convolution(GroupConvolution) -> BatchToSpace
* to a single Convolution(GroupConvolution) node with updated pads and dilations
* Restrictions:
* - pads in SpaceToBatch must have 0 on first and second position
*/
@@ -5,14 +5,17 @@
#include "transformations/common_optimizations/dilated_convolution_converter.hpp"
#include <memory>
#include <ngraph/pattern/op/wrap_type.hpp>
#include <ngraph/rt_info.hpp>
#include <openvino/opsets/opset6.hpp>
#include <vector>
#include "itt.hpp"
#include "openvino/core/rt_info.hpp"
#include "openvino/opsets/opset6.hpp"
#include "openvino/pass/pattern/op/or.hpp"
#include "openvino/pass/pattern/op/wrap_type.hpp"
#include "transformations/utils/utils.hpp"
// Replace the following graph SpaceToBatch -> Convolution(GroupConvolution) -> BatchToSpace with single
// Convolution(GroupConvolution) node
ov::pass::DilatedConvolutionConverter::DilatedConvolutionConverter() {
MATCHER_SCOPE(DilatedConvolutionConverter);
auto data_pattern = pattern::any_input();
@@ -21,7 +24,9 @@ ov::pass::DilatedConvolutionConverter::DilatedConvolutionConverter() {
auto pads_end_pattern = pattern::wrap_type<opset6::Constant>();
auto space_to_batch_pattern = pattern::wrap_type<opset6::SpaceToBatch>(
{data_pattern, block_shape_pattern, pads_begin_pattern, pads_end_pattern});
auto conv_pattern = pattern::wrap_type<opset6::Convolution>({space_to_batch_pattern, pattern::any_input()});
auto conv_p = pattern::wrap_type<opset6::Convolution>({space_to_batch_pattern, pattern::any_input()});
auto gconv_p = pattern::wrap_type<opset6::GroupConvolution>({space_to_batch_pattern, pattern::any_input()});
auto conv_pattern = std::make_shared<pattern::op::Or>(OutputVector{conv_p, gconv_p});
auto crops_begin_pattern = pattern::wrap_type<opset6::Constant>();
auto crops_end_pattern = pattern::wrap_type<opset6::Constant>();
auto batch_to_space_pattern = pattern::wrap_type<opset6::BatchToSpace>(
@@ -49,13 +54,30 @@ ov::pass::DilatedConvolutionConverter::DilatedConvolutionConverter() {
std::dynamic_pointer_cast<opset6::Constant>(pattern_map.at(crops_end_pattern).get_node_shared_ptr());
if (!crops_end)
return false;
auto conv = std::dynamic_pointer_cast<opset6::Convolution>(pattern_map.at(conv_pattern).get_node_shared_ptr());
if (!conv)
return false;
auto block_shape_val = block_shape->cast_vector<size_t>();
auto dilations = conv->get_dilations();
ov::Strides dilations;
ov::Strides strides;
std::shared_ptr<ov::Node> conv_node;
if (pattern_map.count(conv_p)) {
conv_node = pattern_map.at(conv_p).get_node_shared_ptr();
auto conv = std::dynamic_pointer_cast<opset6::Convolution>(conv_node);
if (!conv)
return false;
dilations = conv->get_dilations();
strides = conv->get_strides();
} else if (pattern_map.count(gconv_p)) {
conv_node = pattern_map.at(gconv_p).get_node_shared_ptr();
auto conv = std::dynamic_pointer_cast<opset6::GroupConvolution>(conv_node);
if (!conv)
return false;
dilations = conv->get_dilations();
strides = conv->get_strides();
} else {
return false;
}
for (size_t i = 0; i < dilations.size(); i++)
dilations[i] = block_shape_val[i + 2];
auto pads_begin_val = pads_begin->cast_vector<std::ptrdiff_t>();
@@ -76,13 +98,24 @@ ov::pass::DilatedConvolutionConverter::DilatedConvolutionConverter() {
return false;
new_pads_end.push_back(pads_end_val[i] - crops_end_val[i]);
}
auto new_conv = register_new_node<opset6::Convolution>(pattern_map.at(data_pattern),
conv->input_value(1),
conv->get_strides(),
new_pads_begin,
new_pads_end,
dilations,
op::PadType::EXPLICIT);
std::shared_ptr<ov::Node> new_conv;
if (pattern_map.count(gconv_p)) {
new_conv = register_new_node<opset6::GroupConvolution>(pattern_map.at(data_pattern),
conv_node->input_value(1),
strides,
new_pads_begin,
new_pads_end,
dilations,
op::PadType::EXPLICIT);
} else {
new_conv = register_new_node<opset6::Convolution>(pattern_map.at(data_pattern),
conv_node->input_value(1),
strides,
new_pads_begin,
new_pads_end,
dilations,
op::PadType::EXPLICIT);
}
auto batch_to_space = pattern_map.at(batch_to_space_pattern).get_node_shared_ptr();
new_conv->set_friendly_name(batch_to_space->get_friendly_name());
@@ -90,7 +123,7 @@ ov::pass::DilatedConvolutionConverter::DilatedConvolutionConverter() {
copy_runtime_info(
{
pattern_map.at(space_to_batch_pattern).get_node_shared_ptr(),
pattern_map.at(conv_pattern).get_node_shared_ptr(),
conv_node,
batch_to_space,
},
new_conv);
@@ -112,3 +112,44 @@ TEST_F(TransformationTestsF, NegativeDilatedConvolutionConverterNonZeroPadsForNC
manager.register_pass<pass::DilatedConvolutionConverter>();
}
}
TEST_F(TransformationTestsF, DilatedGroupConvolutionConverter) {
{
auto data = std::make_shared<opset6::Parameter>(element::f32, Shape{1, 4, 10, 10});
auto filters = std::make_shared<opset6::Parameter>(element::f32, Shape{4, 1, 1, 3, 3});
auto space_to_batch =
std::make_shared<opset6::SpaceToBatch>(data,
op::Constant::create(element::i64, Shape{4}, {1, 1, 2, 2}),
op::Constant::create(element::i64, Shape{4}, {0, 0, 2, 2}),
op::Constant::create(element::i64, Shape{4}, {0, 0, 2, 2}));
auto conv = std::make_shared<opset6::GroupConvolution>(space_to_batch,
filters,
Strides{1, 1},
CoordinateDiff{0, 0},
CoordinateDiff{0, 0},
Strides{1, 1});
auto batch_to_space =
std::make_shared<opset6::BatchToSpace>(conv,
op::Constant::create(element::i64, Shape{4}, {1, 1, 2, 2}),
op::Constant::create(element::i64, Shape{4}, {0, 0, 1, 1}),
op::Constant::create(element::i64, Shape{4}, {0, 0, 1, 1}));
function = std::make_shared<Function>(NodeVector{batch_to_space}, ParameterVector{data, filters});
manager.register_pass<pass::DilatedConvolutionConverter>();
}
{
auto data = std::make_shared<opset6::Parameter>(element::f32, Shape{1, 4, 10, 10});
auto filters = std::make_shared<opset6::Parameter>(element::f32, Shape{4, 1, 1, 3, 3});
auto conv = std::make_shared<opset6::GroupConvolution>(data,
filters,
Strides{1, 1},
CoordinateDiff{1, 1},
CoordinateDiff{1, 1},
Strides{2, 2},
op::PadType::EXPLICIT);
function_ref = std::make_shared<Function>(NodeVector{conv}, ParameterVector{data, filters});
}
comparator.enable(FunctionsComparator::CmpValues::CONST_VALUES);
comparator.enable(FunctionsComparator::CmpValues::ACCURACY);
comparator.enable(FunctionsComparator::CmpValues::ATTRIBUTES);
}
@@ -221,3 +221,28 @@ TEST_F(TransformationTestsF, InjectedBodyAndIf) {
model_ref = make_shared<Model>(OutputVector{if_op}, ParameterVector{x, y});
}
}
// Ticket 101756
TEST_F(TransformationTestsF, DISABLED_ModelWithDilatedGroupConvolution) {
{
model = convert_model("dilated_gconv_model/dilated_gconv_model.pb");
// need to call MOC to fuse BatchToSpace/SpaceToBatch with GroupConvolution
manager.register_pass<pass::MOCTransformations>(false);
}
{
auto x = make_shared<Parameter>(f32, Shape{1, 129, 257, 384});
auto transpose_before_const = make_shared<Constant>(i64, Shape{4}, std::vector<int64_t>{0, 3, 1, 2});
auto transpose_before = make_shared<Transpose>(x, transpose_before_const);
auto const_filter = make_shared<Constant>(f32, Shape{384, 1, 1, 3, 3}, std::vector<float>(384 * 3 * 3, 0));
Strides dilations{2, 2};
CoordinateDiff pads_begin{2, 2};
CoordinateDiff pads_end{2, 2};
Strides strides{1, 1};
auto gconv =
make_shared<GroupConvolution>(transpose_before, const_filter, strides, pads_begin, pads_end, dilations);
auto transpose_after_const = make_shared<Constant>(i64, Shape{4}, std::vector<int64_t>{0, 2, 3, 1});
auto transpose_after = make_shared<Transpose>(gconv, transpose_after_const);
model_ref = make_shared<Model>(OutputVector{transpose_after}, ParameterVector{x});
}
}
@@ -0,0 +1,447 @@
node {
name: "input"
op: "Placeholder"
attr {
key: "_output_shapes"
value {
list {
shape {
dim {
size: 1
}
dim {
size: 129
}
dim {
size: 257
}
dim {
size: 384
}
}
}
}
}
attr {
key: "dtype"
value {
type: DT_FLOAT
}
}
attr {
key: "shape"
value {
shape {
dim {
size: 1
}
dim {
size: 129
}
dim {
size: 257
}
dim {
size: 384
}
}
}
}
}
node {
name: "TestModel/depthwise_weights"
op: "Const"
attr {
key: "dtype"
value {
type: DT_FLOAT
}
}
attr {
key: "value"
value {
tensor {
dtype: DT_FLOAT
tensor_shape {
dim {
size: 3
}
dim {
size: 3
}
dim {
size: 384
}
dim {
size: 1
}
}
tensor_content: "pw\251=\222\030\323>\204\324\346\276\263\224j>@\217\221>\375\322h\277\211<^>ff\346\275c\322*>\346.\306=\014\324\005\274\310\355q\275u\222x\276\007\343s\274\r\267\232?d3\215>\202A_>\322%\025?\367gH\277\005}D\275S$\246?t V>\016\323\247=\3357\215>\001\253\365<\257\261O\276\326\264\200\276#\330\227\276\377}Q=o\222\372=<$\014\277\032b\205\276\333\362[>Z\227\034>f&\252=q\325\307\276$\230O?\035\237\255\276\030\377/>V\340W=\302\372\370<Jj\223\276\214\305\343\275\231\364\002\277]|\255\276\306\261^\275\024\025\327\276E$\030?\257<\026\276M\276\314=\036\006\300>H=D>4\020\277\276\364\375l\276\264\313\320>\366\327\315>`r\367=\241\224u\275PcT=\270\332\233\276\260\203\201\276\305\235\224\276\251\240\276=}\224\005>\216Q\370\275mj+\276\025\311H?\220\005P>\271.\361<\003r\007?\023a\304>!\'\236\2764\242+\277\032U\346\275+p\210>\024\023l\276\342E\271\276z\265\213\276\233\252K?&\0037=\225\243\204>+\3711>!w\236\276q\211{>q9\226>\025/\227\276\032|\350>\'n\237\276\351\235\343>\202\360\354\275\341k\230\276g\201\223\274O\314\301\276\315\007/=\332\031\221>\020\033d>@C\010?\314\236\034=\0053\363\273b\031\325\276\26204\276\265\326\201>\264\372\030\277\000\005\353\276\246\003\027?\374&\314\275\177\205N\277\361\267\223\275A\220\226\276X\257\347\275\346k\315?2\n\225=\326\300\342\276\034d\231>\t?\210?\300_\270\274\251\200\234\275@\262N>\354^\200>\307Q\r\277\247F\272>L\343};L\033M>nU\330>\3272&\277\354\232\376?=\\\334\276\367-\347>\315\r\265>\236,i\2763/\262=\353\330;\276\272$8\276\235\362\004>\333\240E=\245\221\301:\341\347|=}w\237\276\302w\243\2760\230\277\275\246*\206>\342\224D>\337\362\262\274\211\341\306\275\t\t\231\276u\324<\276\334p\217\276\246g\264<Z\270Y>\360Gs=e\272\033\277\270\243\007?^ \267<\217f\334\276\200\373\214>x\326\022\277\344s!\276\350U\251\274\021\233\217\276.\251\t?\273\'\274<3\002\300>.\013\260\276\026w`\277\nzM\275\221L\034>A\361,\276\352\343\254?-4i>Y%E\276\221h\264\276\243M\373>\231\247J?%}7>\373\2118>\233\332\\=\242%W\276aTS>\207\203\022\276 \326/?\363I\262>\326`o=\313\204\212\276mw\333\276,O\016\277\013\r\247>\265\0044\276o\036(=\270\353\336\275\252C\240\275r\257\267>\337\316\271\275\002\017N\276\332\001y?>\210I?\263\304\270\276\240:\234\275v\211\272\276\375\014\260\276\372l >\247:\020?\343\271\211>\010)\345;\003\240\213=u\n\234>\230\rW\276Y^J=\233\344\225\275\366\362\211=\352Xl>\262\013\024>&\310\376>\277\326S\276\036=^\276\340\360\372\275\326\213\226\276\n\250\017=\327\251s\276\353R\277>K\310\3779.s\351>\310\010\275\2766V =\327\350\233\276E\334\t\277h\216j>4>(>\177\366\200\276\023\3535=\222\213\222\275\205j;>\020\357\362=D\261\002\277]\353O>R8}=)if>\365\351\205<\344\355E>\'c\237\274\367nz=\243\213\344\275\214j\030\276}\347\022>aU\262>\320:\213\276\030\020H?\202 (>\266$\253\276N(}\276/\002\201?\371\200]=/\3063\276\366\334K\277\266/X?\331\031\250\276\033\267\217\276Vt[?\266p\342\275\271\331a>&\027\034\277\263\022\235\276\201\313e\276$\257Z>Z\334\212\276IIl\276\214\350\300\275\212P\253\276\023\274\313<\314$\000\277zz\207\276\370\020 \276\346\245\n\277\311\213\035>\371/\034\276\273\215\361\275\000`\302=\016\311\203>\237\r\322\276(\016\022=\223\343l\276ox6=\332\345\355>+6\256\2761&k\277\013s%\276p\013\027>o\366\010>\031j\327>!\2131>\026\340\032\277\202\271\212\275\206d]>\252\222\262<\211%\306\276\276n\222=\240,\347<\365h\242=\303\262\274\276\336\004\200=\244\035\224>:\035\023=a\274 >o&)\277\177TS\276\206X?=\031\345\227\276`\255\354>\334\002@>8\376\327\276\242\3728\277\321e\322\274\3201\201>[\327\305>\374^\257\276\370\0272\276_?\377\275*\263\216\276V P?\343\373\214\276\220t\232>z]\364\273xc\361=\335\0035\2765)\363=\374\231\334>X\004\234\275\033\n\034\276\002;X>K\355\246\275\243!\300\276|\221\025>\214\350\021\276\353\336w\275\231\233\211=zx\210\276\'\031)\276\256c<\275\r\355\246\276\366p;>\360;|\276^\211\303\274\353\263\026?\035\035\017>\346\342\232\276\357x\375\275\261l\323\276sq^\276\271\323\203>\377O#\276\033\333\200=)O\t\276m\024\244\276\2749\320>\250\2519?\236)8\275\375&>\275\270\017\221>w@\327\276C\032_\277\252#\201\276uJ\033>\342\017\265\2751Z\315=p\312i=\002k\342>VN\022>$\217\010?\366\266\366\276\363\216\201\276l,\251\276\256\232$=\321Z\006?\356l\253>\275Ee\275\322\r\334\276~\'\002@D<\250\276\366O\241\274\270\312\275=0\215\216\276C0\253?T2\314\276v\235\372\276\322\024\002\276\006\365\224\276\343&`\276rYI>X-B?P&\017?\346\235.\277!\'\246?\025\367\352>1\373\200>R\241R\277\224\252b?\264\301l\273\224\345\262\275\005\025\003?\324\266\331>X\237\001\277+V\224\276\332\260\253?\337d\344>\034\243\206\277V\232\t?Y\265)>\000\354\373\2766.(\277\265\256\300>\225\334\211\276\016L\227\277D\006\267\276\226\035\246\274Y\010\331\276>\024R\277\223\262\261\276\233H\255?>\rJ\277\325|(>phG\275\260q\215>\217\242;\277\026\352s\277\333\276\024\277E \301?&}\010\277\370\002\355=w\273\200\274c;\323\276\351\360\272>\213D\010\276\023\324\204;vR \277\221m ?\307Q\020@\320\332;\277I\035\262>\216S\276\276\0220\250?>\326\334?:mp>\235\335\003\277\353(^\276\326~\026\276\312\335\234?B\235a\276\361\366\235>\035C\276=o\317{?\26Line truncated
}
}
}
}
node {
name: "TestModel/depthwise_weights/read"
op: "Identity"
input: "TestModel/depthwise_weights"
attr {
key: "T"
value {
type: DT_FLOAT
}
}
attr {
key: "_class"
value {
list {
s: "loc:@TestModel/depthwise_weights"
}
}
}
attr {
key: "_output_shapes"
value {
list {
shape {
dim {
size: 3
}
dim {
size: 3
}
dim {
size: 384
}
dim {
size: 1
}
}
}
}
}
}
node {
name: "TestModel/depthwise/SpaceToBatchND/block_shape"
op: "Const"
attr {
key: "_output_shapes"
value {
list {
shape {
dim {
size: 2
}
}
}
}
}
attr {
key: "dtype"
value {
type: DT_INT32
}
}
attr {
key: "value"
value {
tensor {
dtype: DT_INT32
tensor_shape {
dim {
size: 2
}
}
tensor_content: "\002\000\000\000\002\000\000\000"
}
}
}
}
node {
name: "TestModel/depthwise/SpaceToBatchND/paddings"
op: "Const"
attr {
key: "_output_shapes"
value {
list {
shape {
dim {
size: 2
}
dim {
size: 2
}
}
}
}
}
attr {
key: "dtype"
value {
type: DT_INT32
}
}
attr {
key: "value"
value {
tensor {
dtype: DT_INT32
tensor_shape {
dim {
size: 2
}
dim {
size: 2
}
}
tensor_content: "\002\000\000\000\003\000\000\000\002\000\000\000\003\000\000\000"
}
}
}
}
node {
name: "TestModel/depthwise/SpaceToBatchND"
op: "SpaceToBatchND"
input: "input"
input: "TestModel/depthwise/SpaceToBatchND/block_shape"
input: "TestModel/depthwise/SpaceToBatchND/paddings"
attr {
key: "T"
value {
type: DT_FLOAT
}
}
attr {
key: "Tblock_shape"
value {
type: DT_INT32
}
}
attr {
key: "Tpaddings"
value {
type: DT_INT32
}
}
attr {
key: "_output_shapes"
value {
list {
shape {
dim {
size: 4
}
dim {
size: 67
}
dim {
size: 131
}
dim {
size: 384
}
}
}
}
}
}
node {
name: "TestModel/depthwise"
op: "DepthwiseConv2dNative"
input: "TestModel/depthwise/SpaceToBatchND"
input: "TestModel/depthwise_weights/read"
attr {
key: "T"
value {
type: DT_FLOAT
}
}
attr {
key: "_output_shapes"
value {
list {
shape {
dim {
size: 4
}
dim {
size: 65
}
dim {
size: 129
}
dim {
size: 384
}
}
}
}
}
attr {
key: "data_format"
value {
s: "NHWC"
}
}
attr {
key: "dilations"
value {
list {
i: 1
i: 1
i: 1
i: 1
}
}
}
attr {
key: "explicit_paddings"
value {
list {
}
}
}
attr {
key: "padding"
value {
s: "VALID"
}
}
attr {
key: "strides"
value {
list {
i: 1
i: 1
i: 1
i: 1
}
}
}
}
node {
name: "TestModel/depthwise/BatchToSpaceND/block_shape"
op: "Const"
attr {
key: "_output_shapes"
value {
list {
shape {
dim {
size: 2
}
}
}
}
}
attr {
key: "dtype"
value {
type: DT_INT32
}
}
attr {
key: "value"
value {
tensor {
dtype: DT_INT32
tensor_shape {
dim {
size: 2
}
}
tensor_content: "\002\000\000\000\002\000\000\000"
}
}
}
}
node {
name: "TestModel/depthwise/BatchToSpaceND/crops"
op: "Const"
attr {
key: "_output_shapes"
value {
list {
shape {
dim {
size: 2
}
dim {
size: 2
}
}
}
}
}
attr {
key: "dtype"
value {
type: DT_INT32
}
}
attr {
key: "value"
value {
tensor {
dtype: DT_INT32
tensor_shape {
dim {
size: 2
}
dim {
size: 2
}
}
tensor_content: "\000\000\000\000\001\000\000\000\000\000\000\000\001\000\000\000"
}
}
}
}
node {
name: "TestModel/depthwise/BatchToSpaceND"
op: "BatchToSpaceND"
input: "TestModel/depthwise"
input: "TestModel/depthwise/BatchToSpaceND/block_shape"
input: "TestModel/depthwise/BatchToSpaceND/crops"
attr {
key: "T"
value {
type: DT_FLOAT
}
}
attr {
key: "Tblock_shape"
value {
type: DT_INT32
}
}
attr {
key: "Tcrops"
value {
type: DT_INT32
}
}
attr {
key: "_output_shapes"
value {
list {
shape {
dim {
size: 1
}
dim {
size: 129
}
dim {
size: 257
}
dim {
size: 384
}
}
}
}
}
}
library {
}