Commit e21db881 authored by Adam Rogowiec's avatar Adam Rogowiec Committed by Robert Kimball

[FUSED] Group Transpose Convolution (#3040)

* Adding GroupConvTranspose fused operator.

* Add missing header and remove commented code.

* Remove unused variable.

* Add a few more convieniece constructors.

* Add more type prop UTs.

* Remove unused post validation functions.

* Style apply.

* Fix conversion of vector to CoordinateDiff

* Add GroupConvolutionTranspose to intel gpu backend.

* Add documentation.

* Use default (python-like) divide.
parent c0b4f2d3
......@@ -308,6 +308,8 @@ set (SRC
op/fused/grn.hpp
op/fused/group_conv.hpp
op/fused/group_conv.cpp
op/fused/group_conv_transpose.hpp
op/fused/group_conv_transpose.cpp
op/fused/leaky_relu.cpp
op/fused/leaky_relu.hpp
op/fused/mvn.cpp
......
......@@ -103,6 +103,7 @@
#include "ngraph/op/fused/gemm.hpp"
#include "ngraph/op/fused/grn.hpp"
#include "ngraph/op/fused/group_conv.hpp"
#include "ngraph/op/fused/group_conv_transpose.hpp"
#include "ngraph/op/fused/hard_sigmoid.hpp"
#include "ngraph/op/fused/leaky_relu.hpp"
#include "ngraph/op/fused/mvn.hpp"
......
This diff is collapsed.
//*****************************************************************************
// Copyright 2017-2019 Intel Corporation
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//*****************************************************************************
#pragma once
#include <cstdlib>
#include <memory>
#include "ngraph/autodiff/adjoints.hpp"
#include "ngraph/coordinate_diff.hpp"
#include "ngraph/node.hpp"
#include "ngraph/op/util/attr_types.hpp"
#include "ngraph/op/util/fused_op.hpp"
#include "ngraph/shape.hpp"
#include "ngraph/strides.hpp"
namespace ngraph
{
namespace op
{
/// \brief Group Transpose Convolution (Deconvolution)
class GroupConvolutionTranspose : public util::FusedOp
{
public:
///
/// \brief Constructs GroupConvolutionTranspose operation.
///
/// \param[in] data The node producing input data.
/// \param[in] filters The node producing filters data.
/// \param[in] strides The strides along each feature axis.
/// \param[in] dilations The dilations along each feature axis.
/// \param[in] padding_begin The padding added at the beggining of each feature axis.
/// \param[in] padding_end The padding added at the end of each feature axis.
/// \param[in] output_padding The zero-padding (adjustment) added to one side of the output.
/// \param[in] groups The number of groups the input channels and output channels
/// are divided into.
/// \param[in] pad_type The provided padding type.
/// \param[in] output_shape The output shape. When provided padding values are
/// automatically inferred.
///
GroupConvolutionTranspose(const std::shared_ptr<Node>& data,
const std::shared_ptr<Node>& filters,
const Strides& strides,
const Strides& dilations,
const CoordinateDiff& padding_begin,
const CoordinateDiff& padding_end,
const CoordinateDiff& output_padding,
const std::size_t groups = 1UL,
const PadType& pad_type = PadType::EXPLICIT,
const Shape& output_shape = Shape{});
///
/// \brief Constructs GroupConvolutionTranspose operation.
///
/// \param[in] data The node producing input data.
/// \param[in] filters The node producing filters data.
/// \param[in] groups The number of groups the input channels and output channels
/// are divided into.
///
GroupConvolutionTranspose(const std::shared_ptr<Node>& data,
const std::shared_ptr<Node>& filters,
const std::size_t groups = 1UL);
///
/// \brief Constructs GroupConvolutionTranspose operation.
///
/// \param[in] data The node producing input data.
/// \param[in] filters The node producing filters data.
/// \param[in] strides The strides along each feature axis.
/// \param[in] dilations The dilations along each feature axis.
/// \param[in] output_padding The zero-padding (adjustment) added to one side of the output.
/// \param[in] output_shape The output shape. When provided padding values are
/// automatically inferred.
/// \param[in] groups The number of groups the input channels and output channels
/// are divided into.
///
GroupConvolutionTranspose(const std::shared_ptr<Node>& data,
const std::shared_ptr<Node>& filters,
const Strides& strides,
const Strides& dilations,
const CoordinateDiff& output_padding,
const Shape& output_shape,
const std::size_t groups = 1UL);
///
/// \brief Constructs GroupConvolutionTranspose operation.
///
/// \param[in] data The node producing input data.
/// \param[in] filters The node producing filters data.
/// \param[in] output_shape The output shape. When provided padding values are
/// automatically inferred.
/// \param[in] groups The number of groups the input channels and output channels
/// are divided into.
///
GroupConvolutionTranspose(const std::shared_ptr<Node>& data,
const std::shared_ptr<Node>& filters,
const Shape& output_shape,
const std::size_t groups = 1UL);
std::shared_ptr<Node> get_filters() { return get_argument(1); }
std::shared_ptr<Node> get_data() { return get_argument(0); }
const Strides& get_strides() const { return m_strides; }
const Strides& get_dilations() const { return m_dilations; }
const CoordinateDiff& get_padding_begin() const { return m_padding_begin; }
const CoordinateDiff& get_padding_end() const { return m_padding_end; }
const CoordinateDiff& get_output_padding() const { return m_output_padding; }
std::size_t get_groups() const { return m_groups; }
const PadType& get_pad_type() const { return m_pad_type; }
const Shape& get_output_shape() const { return m_output_shape; }
virtual void pre_validate_and_infer_types() override;
virtual NodeVector decompose_op() const override;
virtual std::shared_ptr<Node>
copy_with_new_args(const NodeVector& new_args) const override;
virtual void generate_adjoints(autodiff::Adjoints& adjoints,
const NodeVector& deltas) override;
private:
///
/// \brief Calculate the shape of the data batch from forward propagation.
///
/// \return The data batch shape.
///
Shape get_data_batch_shape() const;
Strides m_strides;
Strides m_dilations;
CoordinateDiff m_padding_begin;
CoordinateDiff m_padding_end;
CoordinateDiff m_output_padding;
std::size_t m_groups;
PadType m_pad_type;
Shape m_output_shape;
};
}
}
......@@ -27,6 +27,7 @@ NGRAPH_OP(FakeQuantize, ngraph::op)
NGRAPH_OP(GRN, ngraph::op)
NGRAPH_OP(Gemm, ngraph::op)
NGRAPH_OP(GroupConvolution, ngraph::op)
NGRAPH_OP(GroupConvolutionTranspose, ngraph::op)
NGRAPH_OP(HardSigmoid, ngraph::op)
NGRAPH_OP(LeakyRelu, ngraph::op)
NGRAPH_OP(MVN, ngraph::op)
......
......@@ -86,6 +86,7 @@
#include "ngraph/op/fused/gemm.hpp"
#include "ngraph/op/fused/grn.hpp"
#include "ngraph/op/fused/group_conv.hpp"
#include "ngraph/op/fused/group_conv_transpose.hpp"
#include "ngraph/op/fused/hard_sigmoid.hpp"
#include "ngraph/op/fused/leaky_relu.hpp"
#include "ngraph/op/fused/mvn.hpp"
......@@ -2063,6 +2064,7 @@ shared_ptr<runtime::Executable>
case OP_TYPEID::GatherND:
case OP_TYPEID::GenerateMask:
case OP_TYPEID::GRN:
case OP_TYPEID::GroupConvolutionTranspose:
case OP_TYPEID::HardSigmoid:
case OP_TYPEID::LeakyRelu:
case OP_TYPEID::MVN:
......@@ -2183,6 +2185,7 @@ bool runtime::intelgpu::IntelGPUBackend::is_supported_impl(const Node& node)
case OP_TYPEID::FakeQuantize:
case OP_TYPEID::Gemm:
case OP_TYPEID::GRN:
case OP_TYPEID::GroupConvolutionTranspose:
case OP_TYPEID::LeakyRelu:
case OP_TYPEID::MVN:
case OP_TYPEID::Normalize:
......
......@@ -74,6 +74,7 @@
#include "ngraph/op/fused/gemm.hpp"
#include "ngraph/op/fused/grn.hpp"
#include "ngraph/op/fused/group_conv.hpp"
#include "ngraph/op/fused/group_conv_transpose.hpp"
#include "ngraph/op/fused/hard_sigmoid.hpp"
#include "ngraph/op/fused/leaky_relu.hpp"
#include "ngraph/op/fused/mvn.hpp"
......@@ -1078,6 +1079,31 @@ static shared_ptr<ngraph::Function>
pad_type);
break;
}
case OP_TYPEID::GroupConvolutionTranspose:
{
auto strides = node_js.at("strides").get<vector<size_t>>();
auto dilations = node_js.at("dilations").get<vector<size_t>>();
auto padding_begin = node_js.at("padding_begin").get<vector<ptrdiff_t>>();
auto padding_end = node_js.at("padding_end").get<vector<ptrdiff_t>>();
auto output_padding = node_js.at("output_padding").get<vector<ptrdiff_t>>();
auto groups = node_js.at("groups").get<size_t>();
op::PadType pad_type = node_js["pad_type"].empty()
? op::PadType::EXPLICIT
: static_cast<op::PadType>(node_js.at("pad_type"));
auto output_shape = node_js.at("output_shape").get<vector<size_t>>();
node = make_shared<op::GroupConvolutionTranspose>(args[0],
args[1],
strides,
dilations,
padding_begin,
padding_end,
output_padding,
groups,
pad_type,
output_shape);
break;
}
case OP_TYPEID::LeakyRelu:
{
node = make_shared<op::LeakyRelu>(args[0], args[1]);
......@@ -2091,6 +2117,19 @@ static json write(const Node& n, bool binary_constant_data)
node["pad_type"] = tmp->get_pad_type();
break;
}
case OP_TYPEID::GroupConvolutionTranspose:
{
auto tmp = dynamic_cast<const op::GroupConvolutionTranspose*>(&n);
node["strides"] = tmp->get_strides();
node["dilations"] = tmp->get_dilations();
node["padding_begin"] = tmp->get_padding_begin();
node["padding_end"] = tmp->get_padding_end();
node["output_padding"] = tmp->get_output_padding();
node["groups"] = tmp->get_groups();
node["pad_type"] = tmp->get_pad_type();
node["output_shape"] = tmp->get_output_shape();
break;
}
case OP_TYPEID::LeakyRelu: { break;
}
case OP_TYPEID::Less:
......
......@@ -1156,3 +1156,94 @@ NGRAPH_TEST(${BACKEND_NAME}, fake_quantize_with_clip_across_channels)
test_case.run();
}
NGRAPH_TEST(${BACKEND_NAME}, group_conv_transpose)
{
const CoordinateDiff output_padding{1, 1};
const CoordinateDiff padding_begin{1, 1};
const CoordinateDiff padding_end{1, 1};
Strides strides{2, 2};
Strides dilations{1, 1};
size_t groups = 1;
auto data = make_shared<op::Parameter>(element::f32, Shape{1, 1, 3, 3});
auto filters = make_shared<op::Parameter>(element::f32, Shape{1, 1, 3, 3});
auto gct = make_shared<op::GroupConvolutionTranspose>(
data, filters, strides, dilations, padding_begin, padding_end, output_padding, groups);
auto function = make_shared<Function>(NodeVector{gct}, ParameterVector{data, filters});
auto test_case = ngraph::test::NgraphTestCase(function, "${BACKEND_NAME}");
// X
test_case.add_input<float>(vector<float>{0.16857791f,
-0.15161794f,
0.08540368f,
0.1820628f,
-0.21746576f,
0.08245695f,
0.1431433f,
-0.43156421f,
0.30591947f});
// W
test_case.add_input<float>({-0.06230065f,
0.37932432f,
-0.25388849f,
0.33878803f,
0.43709868f,
-0.22477469f,
0.04118127f,
-0.44696793f,
0.06373066f});
test_case.add_expected_output(
Shape{1, 1, 6, 6},
vector<float>{
0.07368518f, -0.08925839f, -0.06627201f, 0.06301362f, 0.03732984f, -0.01919658f,
-0.00628807f, -0.02817563f, -0.01472169f, 0.04392925f, -0.00689478f, -0.01549204f,
0.07957941f, -0.11459791f, -0.09505399f, 0.07681622f, 0.03604182f, -0.01853423f,
-0.0270785f, -0.00680824f, -0.06650258f, 0.08004665f, 0.07918708f, -0.0724144f,
0.06256775f, -0.17838378f, -0.18863615f, 0.20064656f, 0.133717f, -0.06876295f,
-0.06398046f, -0.00864975f, 0.19289537f, -0.01490572f, -0.13673618f, 0.01949645f});
test_case.set_tolerance(3);
test_case.run();
}
NGRAPH_TEST(${BACKEND_NAME}, group_conv_transpose_output_shape)
{
const CoordinateDiff output_padding{};
const Shape output_shape{1, 1, 1, 14};
Strides strides{1, 1};
Strides dilations{1, 1};
size_t groups = 1;
auto data = make_shared<op::Parameter>(element::f32, Shape{1, 1, 1, 10});
auto filters = make_shared<op::Parameter>(element::f32, Shape{1, 1, 1, 5});
auto gct = make_shared<op::GroupConvolutionTranspose>(
data, filters, strides, dilations, output_padding, output_shape, groups);
auto function = make_shared<Function>(NodeVector{gct}, ParameterVector{data, filters});
auto test_case = ngraph::test::NgraphTestCase(function, "${BACKEND_NAME}");
// X
test_case.add_input<float>(
vector<float>{0.0f, 1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f, 7.0f, 8.0f, 9.0f});
// W
test_case.add_input<float>({1.0f, 2.0f, 3.0f, 2.0f, 1.0f});
test_case.add_expected_output(Shape{1, 1, 1, 14},
vector<float>{0.0f,
1.0f,
4.0f,
10.0f,
18.0f,
27.0f,
36.0f,
45.0f,
54.0f,
63.0f,
62.0f,
50.0f,
26.0f,
9.0f});
test_case.run();
}
This diff is collapsed.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment