From 8533194626938dbd2982469496ef1ea39146eded Mon Sep 17 00:00:00 2001 From: shippingwang Date: Sun, 9 Aug 2020 19:28:55 +0000 Subject: [PATCH 01/13] add pixel shuffle class --- .../tests/unittests/test_pixel_shuffle.py | 36 +++- python/paddle/nn/__init__.py | 3 + python/paddle/nn/functional/vision.py | 166 ++++++++++-------- python/paddle/nn/layer/__init__.py | 5 + python/paddle/nn/layer/vision.py | 70 ++++++++ 5 files changed, 201 insertions(+), 79 deletions(-) create mode 100644 python/paddle/nn/layer/vision.py diff --git a/python/paddle/fluid/tests/unittests/test_pixel_shuffle.py b/python/paddle/fluid/tests/unittests/test_pixel_shuffle.py index 0bcb4be3b7fb9..fbdd22a9cac3c 100644 --- a/python/paddle/fluid/tests/unittests/test_pixel_shuffle.py +++ b/python/paddle/fluid/tests/unittests/test_pixel_shuffle.py @@ -19,6 +19,18 @@ from op_test import OpTest +def pixel_shuffle_np(x, up_factor): + n, c, h, w = x.shape + new_shape = (n, c // (up_factor * up_factor), up_factor, up_factor, h, w) + # reshape to (num,output_channel,upscale_factor,upscale_factor,h,w) + npresult = np.reshape(x, new_shape) + # transpose to (num,output_channel,h,upscale_factor,w,upscale_factor) + npresult = npresult.transpose(0, 1, 4, 2, 5, 3) + oshape = [n, c // (up_factor * up_factor), h * up_factor, w * up_factor] + npresult = np.reshape(npresult, oshape) + return npresult + + class TestPixelShuffle(OpTest): def setUp(self): self.op_type = "pixel_shuffle" @@ -26,14 +38,7 @@ def setUp(self): up_factor = 3 shape = [n, c, h, w] x = np.random.random(shape).astype("float64") - new_shape = (n, c // (up_factor * up_factor), up_factor, up_factor, h, - w) - # reshape to (num,output_channel,upscale_factor,upscale_factor,h,w) - npresult = np.reshape(x, new_shape) - # transpose to (num,output_channel,h,upscale_factor,w,upscale_factor) - npresult = npresult.transpose(0, 1, 4, 2, 5, 3) - oshape = [n, c // (up_factor * up_factor), h * up_factor, w * up_factor] - npresult = np.reshape(npresult, oshape) + npresult = pixel_shuffle_np(x, up_factor) self.inputs = {'X': x} self.outputs = {'Out': npresult} @@ -46,5 +51,20 @@ def test_check_grad(self): self.check_grad(['X'], 'Out') +class TestPixelShuffleDygraph(unittest.TestCase): + def run_pixel_shuffle(self, up_factor): + x = np.random.rand(2, 9, 4, 4).astype(np.float32) + + npresult = pixel_shuffle_np(x, np_factor) + with paddle.imperative.guard(): + pixel_shuffle = paddle.nn.PixelShuffle(up_factor) + result = pixel_shuffle(paddle.imperative.to_variable(x)) + + self.assertTrue(np.allclose(result.numpy(), npresult)) + + def test_pixel_shuffle(self): + self.run_pixel_shuffle(3) + + if __name__ == '__main__': unittest.main() diff --git a/python/paddle/nn/__init__.py b/python/paddle/nn/__init__.py index 98948fa91e2e8..ce521f7ca6739 100644 --- a/python/paddle/nn/__init__.py +++ b/python/paddle/nn/__init__.py @@ -94,7 +94,10 @@ # from .layer.rnn import GRUCell #DEFINE_ALIAS # from .layer.rnn import LSTMCell #DEFINE_ALIAS +from .layer.vision import PixelShuffle + from .layer import loss #DEFINE_ALIAS from .layer import conv #DEFINE_ALIAS +from .layer import vision #DEFINE_ALIAS from ..fluid.dygraph.layers import Layer #DEFINE_ALIAS from ..fluid.dygraph.container import LayerList, ParameterList, Sequential #DEFINE_ALIAS diff --git a/python/paddle/nn/functional/vision.py b/python/paddle/nn/functional/vision.py index a2cc8fde5ad71..a59de5775f8e0 100644 --- a/python/paddle/nn/functional/vision.py +++ b/python/paddle/nn/functional/vision.py @@ -12,80 +12,104 @@ # See the License for the specific language governing permissions and # limitations under the License. -# TODO: define specitial functions used in computer vision task -from ...fluid.layers import affine_channel #DEFINE_ALIAS -from ...fluid.layers import affine_grid #DEFINE_ALIAS -from ...fluid.layers import anchor_generator #DEFINE_ALIAS -from ...fluid.layers import bipartite_match #DEFINE_ALIAS -from ...fluid.layers import box_clip #DEFINE_ALIAS -from ...fluid.layers import box_coder #DEFINE_ALIAS -from ...fluid.layers import box_decoder_and_assign #DEFINE_ALIAS -from ...fluid.layers import collect_fpn_proposals #DEFINE_ALIAS -from ...fluid.layers import deformable_roi_pooling #DEFINE_ALIAS -from ...fluid.layers import density_prior_box #DEFINE_ALIAS -from ...fluid.layers import detection_output #DEFINE_ALIAS -from ...fluid.layers import distribute_fpn_proposals #DEFINE_ALIAS -from ...fluid.layers import generate_mask_labels #DEFINE_ALIAS -from ...fluid.layers import generate_proposal_labels #DEFINE_ALIAS -from ...fluid.layers import generate_proposals #DEFINE_ALIAS -from ...fluid.layers import grid_sampler #DEFINE_ALIAS -from ...fluid.layers import image_resize #DEFINE_ALIAS -from ...fluid.layers import prior_box #DEFINE_ALIAS -from ...fluid.layers import prroi_pool #DEFINE_ALIAS -from ...fluid.layers import psroi_pool #DEFINE_ALIAS -from ...fluid.layers import resize_bilinear #DEFINE_ALIAS -from ...fluid.layers import resize_nearest #DEFINE_ALIAS -from ...fluid.layers import resize_trilinear #DEFINE_ALIAS -from ...fluid.layers import roi_align #DEFINE_ALIAS -from ...fluid.layers import roi_pool #DEFINE_ALIAS -from ...fluid.layers import space_to_depth #DEFINE_ALIAS -from ...fluid.layers import yolo_box #DEFINE_ALIAS -from ...fluid.layers import yolov3_loss #DEFINE_ALIAS - -from ...fluid.layers import fsp_matrix #DEFINE_ALIAS -from ...fluid.layers import image_resize_short #DEFINE_ALIAS -from ...fluid.layers import pixel_shuffle #DEFINE_ALIAS -from ...fluid.layers import retinanet_detection_output #DEFINE_ALIAS -from ...fluid.layers import retinanet_target_assign #DEFINE_ALIAS -from ...fluid.layers import roi_perspective_transform #DEFINE_ALIAS -from ...fluid.layers import shuffle_channel #DEFINE_ALIAS +from ...fluid.data_feeder import check_variable_and_dtype +from ...fluid.layer_helper import LayerHelper __all__ = [ - 'affine_channel', - 'affine_grid', - 'anchor_generator', - 'bipartite_match', - 'box_clip', - 'box_coder', - 'box_decoder_and_assign', - 'collect_fpn_proposals', + #'affine_channel', + #'affine_grid', + #'anchor_generator', + #'bipartite_match', + #'box_clip', + #'box_coder', + #'box_decoder_and_assign', + #'collect_fpn_proposals', # 'deformable_conv', - 'deformable_roi_pooling', - 'density_prior_box', - 'detection_output', - 'distribute_fpn_proposals', - 'fsp_matrix', - 'generate_mask_labels', - 'generate_proposal_labels', - 'generate_proposals', - 'grid_sampler', - 'image_resize', - 'image_resize_short', + #'deformable_roi_pooling', + #'density_prior_box', + #'detection_output', + #'distribute_fpn_proposals', + #'fsp_matrix', + #'generate_mask_labels', + #'generate_proposal_labels', + #'generate_proposals', + #'grid_sampler', + #'image_resize', + #'image_resize_short', # 'multi_box_head', 'pixel_shuffle', - 'prior_box', - 'prroi_pool', - 'psroi_pool', - 'resize_bilinear', - 'resize_nearest', - 'resize_trilinear', - 'retinanet_detection_output', - 'retinanet_target_assign', - 'roi_align', - 'roi_perspective_transform', - 'roi_pool', - 'shuffle_channel', - 'space_to_depth', - 'yolo_box', - 'yolov3_loss' + #'prior_box', + #'prroi_pool', + #'psroi_pool', + #'resize_bilinear', + #'resize_nearest', + #'resize_trilinear', + #'retinanet_detection_output', + #'retinanet_target_assign', + #'roi_align', + #'roi_perspective_transform', + #'roi_pool', + #'shuffle_channel', + #'space_to_depth', + #'yolo_box', + #'yolov3_loss' ] + + +def pixel_shuffle(x, upscale_factor, name=None): + """ + :alias_main: paddle.nn.functional.pixel_shuffle + :alias: paddle.nn.functional.pixel_shuffle,paddle.nn.functional.vision.pixel_shuffle + + This operator rearranges elements in a tensor of shape [N, C, H, W] + to a tensor of shape [N, C/upscale_factor**2, H*upscale_factor, W*upscale_factor]. + This is useful for implementing efficient sub-pixel convolution + with a stride of 1/upscale_factor. + Please refer to the paper: `Real-Time Single Image and Video Super-Resolution + Using an Efficient Sub-Pixel Convolutional Neural Network `_ . + by Shi et. al (2016) for more details. + + Parameters: + + x(Variable): 4-D tensor, the data type should be float32 or float64. + upscale_factor(int): factor to increase spatial resolution. + name (str, optional): The default value is None. Normally there is no need for user to set this property. + + Returns: + Out(Variable): Reshaped tensor according to the new dimension. + + Raises: + ValueError: If the square of upscale_factor cannot divide the channels of input. + + Examples: + .. code-block:: python + + import paddle + import paddle.nn.functional as F + import numpy as np + + x = np.random.randn(2, 9, 4, 4).astype(np.float32) + place = fluid.CPUPlace() + paddle.enable_imperative() + + x_var = paddle.imperative.to_variable(x) + y_var = F.pixel_shuffle(x_var, 3) + y_np = y_var.numpy() + print(y_np.shape) # (2, 1, 12, 12) + + """ + + check_variable_and_dtype(x, 'x', ['float32', 'float64'], 'pixel_shuffle') + helper = LayerHelper("pixel_shuffle", **locals()) + + out = helper.create_variable_for_type_inference(dtype=x.dtype) + + if not isinstance(upscale_factor, int): + raise TypeError("upscale factor must be int type") + + helper.append_op( + type="pixel_shuffle", + inputs={"X": x}, + outputs={"Out": out}, + attrs={"upscale_factor": upscale_factor}) + return out diff --git a/python/paddle/nn/layer/__init__.py b/python/paddle/nn/layer/__init__.py index 7173c5b587759..1ebf5bc1dbe06 100644 --- a/python/paddle/nn/layer/__init__.py +++ b/python/paddle/nn/layer/__init__.py @@ -20,6 +20,7 @@ from . import extension from . import activation from . import norm +from . import vision from .activation import * from .loss import * @@ -27,6 +28,8 @@ from .extension import * from .activation import * from .norm import * +from .vision import * + # from .activation import PReLU #DEFINE_ALIAS from .activation import ReLU #DEFINE_ALIAS from .activation import LeakyReLU #DEFINE_ALIAS @@ -69,3 +72,5 @@ # from .rnn import RNNCell #DEFINE_ALIAS # from .rnn import GRUCell #DEFINE_ALIAS # from .rnn import LSTMCell #DEFINE_ALIAS + +from .vision import PixelShuffle #DEFINE_ALIAS diff --git a/python/paddle/nn/layer/vision.py b/python/paddle/nn/layer/vision.py new file mode 100644 index 0000000000000..cbad50bc0d809 --- /dev/null +++ b/python/paddle/nn/layer/vision.py @@ -0,0 +1,70 @@ +# Copyright (c) 2020 PaddlePaddle Authors. All Rights Reserved. +# +# 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. + +# TODO: define specitial functions used in computer vision task + +from ...fluid.dygraph import layers +from .. import functional + +__all__ = ['PixelShuffle'] + + +class PixelShuffle(layers.Layer): + """ + :alias_main: paddle.nn.PixelShuffle + :alias: paddle.nn.PixelShuffle,paddle.nn.layer.PixelShuffle,paddle.nn.layer.vision.PixelShuffle + + PixelShuffle Layer + + This operator rearranges elements in a tensor of shape [N, C, H, W] + to a tensor of shape [N, C/upscale_factor**2, H*upscale_factor, W*upscale_factor]. + This is useful for implementing efficient sub-pixel convolution + with a stride of 1/upscale_factor. + Please refer to the paper: `Real-Time Single Image and Video Super-Resolution + Using an Efficient Sub-Pixel Convolutional Neural Network `_ . + by Shi et. al (2016) for more details. + + Parameters: + + upscale_factor(int): factor to increase spatial resolution. + + Shape: + - x: 4-D tensor with shape: (N, C, H, W). + - out: 4-D tensor with shape: (N, C/upscale_factor**2, H*upscale_factor, W*upscale_factor). + + + Examples: + .. code-block:: python + + import paddle + import paddle.nn as nn + import numpy as np + + paddle.enable_imperative() + x = np.random.randn(2, 9, 4, 4).astype(np.float32) + place = fluid.CPUPlace() + x_var = paddle.imperative.to_variable(x) + pixel_shuffle = nn.PixelShuffle(3) + y_var = pixel_shuffle(x_var) + y_np = y_var.numpy() + print(y_np.shape) # (2, 1, 12, 12) + + """ + + def __init__(self, upscale_factor): + super(PixelShuffle, self).__init__() + self._upscale_factor = upscale_factor + + def forward(self, x): + return functional.pixel_shuffle(x, self._upscale_factor) From ca751a0c2e42e1e10ee5ce5d4e12be37b5de2bf6 Mon Sep 17 00:00:00 2001 From: shippingwang Date: Sun, 16 Aug 2020 11:23:53 +0000 Subject: [PATCH 02/13] add data format --- paddle/fluid/operators/pixel_shuffle_op.cc | 98 +++++++++++++------ paddle/fluid/operators/pixel_shuffle_op.h | 40 ++++++-- .../tests/unittests/test_pixel_shuffle.py | 62 +++++++++--- python/paddle/nn/functional/vision.py | 28 ++++-- python/paddle/nn/layer/vision.py | 34 ++++--- 5 files changed, 186 insertions(+), 76 deletions(-) diff --git a/paddle/fluid/operators/pixel_shuffle_op.cc b/paddle/fluid/operators/pixel_shuffle_op.cc index 1ed7988dcfcc0..df38f1a7b9a7e 100644 --- a/paddle/fluid/operators/pixel_shuffle_op.cc +++ b/paddle/fluid/operators/pixel_shuffle_op.cc @@ -28,25 +28,44 @@ class PixelShuffleOp : public framework::OperatorWithKernel { "Output(Out) of PixelShuffleOp should not be null.")); auto input_dims = ctx->GetInputDim("X"); - PADDLE_ENFORCE_EQ( - input_dims.size(), 4, - platform::errors::InvalidArgument( - "Input should be a 4-D tensor of format [N, C, H, W], but got %u.", - input_dims.size())); + PADDLE_ENFORCE_EQ(input_dims.size(), 4, + platform::errors::InvalidArgument( + "Input should be a 4-D tensor of format [N, C, H, W] " + "or [N, H, W, C], but got %u.", + input_dims.size())); auto upscale_factor = ctx->Attrs().Get("upscale_factor"); - PADDLE_ENFORCE_EQ(input_dims[1] % (upscale_factor * upscale_factor), 0, - platform::errors::InvalidArgument( - "The square of upscale_factor[%u] should divide the " - "number of channel[%u]", - input_dims[1], upscale_factor * upscale_factor)); - + const std::string data_format = + ctx->Attrs().Get < std : string > ("data_format"); + const bool channel_last = (data_format == "NHWC"); + + if (!channel_last) { + PADDLE_ENFORCE_EQ( + input_dims[1] % (upscale_factor * upscale_factor), 0, + platform::errors::InvalidArgument( + "The square of upscale_factor[%u] should divide the " + "number of channel[%u]", + input_dims[1], upscale_factor * upscale_factor)); + } else { + PADDLE_ENFORCE_EQ( + input_dims[3] % (upscale_factor * upscale_factor), 0, + platform::errors::InvalidArgument( + "The square of upscale_factor[%u] should divide the " + "number of channel[%u]", + input_dims[3], upscale_factor * upscale_factor)); + } auto output_dims = input_dims; output_dims[0] = input_dims[0]; - output_dims[1] = input_dims[1] / (upscale_factor * upscale_factor); - output_dims[2] = input_dims[2] * upscale_factor; - output_dims[3] = input_dims[3] * upscale_factor; + if (!channel_last) { + output_dims[1] = input_dims[1] / (upscale_factor * upscale_factor); + output_dims[2] = input_dims[2] * upscale_factor; + output_dims[3] = input_dims[3] * upscale_factor; + } else { + output_dims[1] = input_dims[1] * upscale_factor; + output_dims[2] = input_dims[2] * upscale_factor; + output_dims[3] = input_dims[3] / (upscale_factor * upscale_factor); + } ctx->SetOutputDim("Out", output_dims); } }; @@ -54,14 +73,14 @@ class PixelShuffleOp : public framework::OperatorWithKernel { class PixelShuffleOpMaker : public framework::OpProtoAndCheckerMaker { public: void Make() override { - AddInput( - "X", - "(Tensor, default Tensor), " - "the input feature data of PixelShuffleOp, the layout is [N C H W]."); - AddOutput( - "Out", - "(Tensor, default Tensor), the output of " - "PixelShuffleOp. The layout is [N,C/factor^2,H*factor,W*factor]."); + AddInput("X", + "(Tensor, default Tensor), " + "the input feature data of PixelShuffleOp, the layout is [N, C, " + "H, W] or [N, H, W, C]."); + AddOutput("Out", + "(Tensor, default Tensor), the output of " + "PixelShuffleOp. The layout is [N, C/factor^2, H*factor, " + "W*factor] or [N, H*factor, W*factor, C/factor^2]."); AddAttr("upscale_factor", "the factor to increase spatial resolution by.") .SetDefault(1) @@ -70,6 +89,12 @@ class PixelShuffleOpMaker : public framework::OpProtoAndCheckerMaker { platform::errors::InvalidArgument( "upscale_factor should be larger than 0.")); }); + AddAttr( + "data_format", + "(string, default NCHW) Only used in " + "An optional string from: \"NHWC\", \"NCHW\". " + "Defaults to \"NHWC\", Specify the data format of the input data.") + .SetDefault("NCHW"); AddComment(R"DOC( Pixel Shuffle operator @@ -114,19 +139,30 @@ class PixelShuffleGradOp : public framework::OperatorWithKernel { platform::errors::NotFound("Output(X@Grad) should not be null")); auto do_dims = ctx->GetInputDim(framework::GradVarName("Out")); - PADDLE_ENFORCE_EQ( - do_dims.size(), 4, - platform::errors::InvalidArgument( - "Input should be a 4-D tensor of format [N, C, H, W], but got %u.", - do_dims.size())); + PADDLE_ENFORCE_EQ(do_dims.size(), 4, + platform::errors::InvalidArgument( + "Input should be a 4-D tensor of format [N, C, H, W] " + "or [N, H, W, C], but got %u.", + do_dims.size())); auto upscale_factor = ctx->Attrs().Get("upscale_factor"); - auto dx_dims = do_dims; + const std::string data_format = + ctx->Attrs().Get < std : string > ("data_format"); + const bool channel_last = (data_format == "NHWC") + + auto dx_dims = do_dims; dx_dims[0] = do_dims[0]; - dx_dims[1] = do_dims[1] * (upscale_factor * upscale_factor); - dx_dims[2] = do_dims[2] / upscale_factor; - dx_dims[3] = do_dims[3] / upscale_factor; + + if (!channel_last) { + dx_dims[1] = do_dims[1] * (upscale_factor * upscale_factor); + dx_dims[2] = do_dims[2] / upscale_factor; + dx_dims[3] = do_dims[3] / upscale_factor; + } else { + dx_dims[1] = do_dims[1] / upscale_factor; + dx_dims[2] = do_dims[2] / upscale_factor; + dx_dims[3] = do_dims[3] * (upscale_factor * upscale_factor); + } ctx->SetOutputDim(framework::GradVarName("X"), dx_dims); } }; diff --git a/paddle/fluid/operators/pixel_shuffle_op.h b/paddle/fluid/operators/pixel_shuffle_op.h index 1ae1c7e9d50cb..d819029324ba4 100644 --- a/paddle/fluid/operators/pixel_shuffle_op.h +++ b/paddle/fluid/operators/pixel_shuffle_op.h @@ -11,6 +11,7 @@ limitations under the License. */ #pragma once #include +#include #include #include "paddle/fluid/framework/op_registry.h" #include "paddle/fluid/operators/math/math_function.h" @@ -24,23 +25,33 @@ class PixelShuffleOpKernel : public framework::OpKernel { void Compute(const framework::ExecutionContext& ctx) const override { auto* in = ctx.Input("X"); auto* out = ctx.Output("Out"); + out->mutable_data(ctx.GetPlace()); int factor = ctx.Attr("upscale_factor"); + std::string data_format = ctx.Attr("data_format"); + bool channel_last = (data_format == "NHWC"); + auto in_dims = in->dims(); auto o_dims = out->dims(); framework::Tensor t; t.ShareDataWith(*in); - t.Resize({in_dims[0], o_dims[1], factor, factor, in_dims[2], in_dims[3]}); - + if (!channel_last) { + t.Resize({in_dims[0], o_dims[1], factor, factor, in_dims[2], in_dims[3]}); + } else { + t.Resize({in_dims[0], in_dims[1], in_dims[2], o_dims[3], factor, factor}); + } std::vector axis = {0, 1, 4, 2, 5, 3}; framework::Tensor o; o.ShareDataWith(*out); - o.Resize({in_dims[0], o_dims[1], in_dims[2], factor, in_dims[3], factor}); - + if (!channel_last) { + o.Resize({in_dims[0], o_dims[1], in_dims[2], factor, in_dims[3], factor}); + } else { + o.Resize({in_dims[0], in_dims[1], factor, in_dims[2], factor, o_dim[3]}); + } math::Transpose trans; auto& dev_ctx = ctx.template device_context(); trans(dev_ctx, t, &o, axis); @@ -58,19 +69,32 @@ class PixelShuffleGradOpKernel : public framework::OpKernel { int factor = ctx.Attr("upscale_factor"); + std::string data_format = ctx.Attr("data_format"); + bool channel_fast = (data_format == "NHWC"); + auto do_dims = dout->dims(); auto dx_dims = dx->dims(); framework::Tensor t; t.ShareDataWith(*dout); - t.Resize({do_dims[0], do_dims[1], dx_dims[2], factor, dx_dims[3], factor}); - + if (!channel_last) { + t.Resize( + {do_dims[0], do_dims[1], dx_dims[2], factor, dx_dims[3], factor}); + } else { + t.Resize( + {do_dims[0], dx_dims[1], factor, dx_dims[2], factor, do_dims[3]}); + } std::vector axis = {0, 1, 3, 5, 2, 4}; framework::Tensor o; o.ShareDataWith(*dx); - o.Resize({do_dims[0], do_dims[1], factor, factor, dx_dims[2], dx_dims[3]}); - + if (!channel_last) { + o.Resize( + {do_dims[0], do_dims[1], factor, factor, dx_dims[2], dx_dims[3]}); + } else { + o.Resize( + {do_dims[0], dx_dims[1], dx_dims[2], do_dims[3], factor, factor}); + } math::Transpose trans; auto& dev_ctx = ctx.template device_context(); trans(dev_ctx, t, &o, axis); diff --git a/python/paddle/fluid/tests/unittests/test_pixel_shuffle.py b/python/paddle/fluid/tests/unittests/test_pixel_shuffle.py index fbdd22a9cac3c..778f9d6b5eed4 100644 --- a/python/paddle/fluid/tests/unittests/test_pixel_shuffle.py +++ b/python/paddle/fluid/tests/unittests/test_pixel_shuffle.py @@ -19,30 +19,54 @@ from op_test import OpTest -def pixel_shuffle_np(x, up_factor): - n, c, h, w = x.shape - new_shape = (n, c // (up_factor * up_factor), up_factor, up_factor, h, w) - # reshape to (num,output_channel,upscale_factor,upscale_factor,h,w) - npresult = np.reshape(x, new_shape) - # transpose to (num,output_channel,h,upscale_factor,w,upscale_factor) - npresult = npresult.transpose(0, 1, 4, 2, 5, 3) - oshape = [n, c // (up_factor * up_factor), h * up_factor, w * up_factor] - npresult = np.reshape(npresult, oshape) - return npresult +def pixel_shuffle_np(x, up_factor, data_format="NCHW"): + if data_format == "NCHW": + n, c, h, w = x.shape + new_shape = (n, c // (up_factor * up_factor), up_factor, up_factor, h, + w) + # reshape to (num,output_channel,upscale_factor,upscale_factor,h,w) + npresult = np.reshape(x, new_shape) + # transpose to (num,output_channel,h,upscale_factor,w,upscale_factor) + npresult = npresult.transpose(0, 1, 4, 2, 5, 3) + oshape = [n, c // (up_factor * up_factor), h * up_factor, w * up_factor] + npresult = np.reshape(npresult, oshape) + return npresult + else: + n, h, w, c = x.shape + + new_shape = (n, h, w, c // (up_factor * up_factor), up_factor, + up_factor) + # reshape to (num,h,w,output_channel,upscale_factor,upscale_factor) + npresult = np.reshape(x, new_shape) + # transpose to (num,h,upscale_factor,w,upscale_factor,output_channel) + npresult = npresult.transpose(0, 1, 4, 2, 5, 3) + oshape = [n, h * up_factor, w * up_factor, c // (up_factor * up_factor)] + npresult = np.reshape(npresult, oshape) + return npresult class TestPixelShuffle(OpTest): def setUp(self): self.op_type = "pixel_shuffle" + self.init_data_format() n, c, h, w = 2, 9, 4, 4 + + if self.format == "NCHW": + shape = [n, c, h, w] + if self.format == "NHWC": + shape = [n, h, w, c] + up_factor = 3 - shape = [n, c, h, w] + x = np.random.random(shape).astype("float64") - npresult = pixel_shuffle_np(x, up_factor) + npresult = pixel_shuffle_np(x, up_factor, self.format) self.inputs = {'X': x} self.outputs = {'Out': npresult} - self.attrs = {'upscale_factor': up_factor} + self.attrs = {'upscale_factor': up_factor, "data_format": self.format} + + def init_data_format(self): + self.format = "NCHW" def test_check_output(self): self.check_output() @@ -51,14 +75,20 @@ def test_check_grad(self): self.check_grad(['X'], 'Out') +class TestChannelLast(TestPixelShuffle): + def init_data_format(self): + self.format = "NHWC" + + class TestPixelShuffleDygraph(unittest.TestCase): def run_pixel_shuffle(self, up_factor): x = np.random.rand(2, 9, 4, 4).astype(np.float32) npresult = pixel_shuffle_np(x, np_factor) - with paddle.imperative.guard(): - pixel_shuffle = paddle.nn.PixelShuffle(up_factor) - result = pixel_shuffle(paddle.imperative.to_variable(x)) + + paddle.disable_static() + pixel_shuffle = paddle.nn.PixelShuffle(up_factor) + result = pixel_shuffle(paddle.to_variable(x)) self.assertTrue(np.allclose(result.numpy(), npresult)) diff --git a/python/paddle/nn/functional/vision.py b/python/paddle/nn/functional/vision.py index a59de5775f8e0..602727fc7d568 100644 --- a/python/paddle/nn/functional/vision.py +++ b/python/paddle/nn/functional/vision.py @@ -56,13 +56,14 @@ ] -def pixel_shuffle(x, upscale_factor, name=None): +def pixel_shuffle(x, upscale_factor, data_format="NCHW", name=None): """ :alias_main: paddle.nn.functional.pixel_shuffle :alias: paddle.nn.functional.pixel_shuffle,paddle.nn.functional.vision.pixel_shuffle This operator rearranges elements in a tensor of shape [N, C, H, W] - to a tensor of shape [N, C/upscale_factor**2, H*upscale_factor, W*upscale_factor]. + to a tensor of shape [N, C/upscale_factor**2, H*upscale_factor, W*upscale_factor], + or from shape [N, H, W, C] to [N, H*upscale_factor, W*upscale_factor, C/upscale_factor^2]. This is useful for implementing efficient sub-pixel convolution with a stride of 1/upscale_factor. Please refer to the paper: `Real-Time Single Image and Video Super-Resolution @@ -89,17 +90,19 @@ def pixel_shuffle(x, upscale_factor, name=None): import numpy as np x = np.random.randn(2, 9, 4, 4).astype(np.float32) - place = fluid.CPUPlace() - paddle.enable_imperative() + paddle.disable_static() - x_var = paddle.imperative.to_variable(x) - y_var = F.pixel_shuffle(x_var, 3) - y_np = y_var.numpy() - print(y_np.shape) # (2, 1, 12, 12) + x_var = paddle.to_variable(x) + out_var = F.pixel_shuffle(x_var, 3) + out = out_var.numpy() + print(out.shape) + # (2, 1, 12, 12) """ + if not fluid.framework.in_dygraph_mode(): + check_variable_and_dtype(x, 'x', ['float32', 'float64'], + 'pixel_shuffle') - check_variable_and_dtype(x, 'x', ['float32', 'float64'], 'pixel_shuffle') helper = LayerHelper("pixel_shuffle", **locals()) out = helper.create_variable_for_type_inference(dtype=x.dtype) @@ -107,9 +110,14 @@ def pixel_shuffle(x, upscale_factor, name=None): if not isinstance(upscale_factor, int): raise TypeError("upscale factor must be int type") + if data_format not in ["NCHW", "NHWC"]: + raise ValueError("Attr(data_format) should be 'NCHW' or 'NHWC'." + "But recevie Attr(data_format): {} ".format( + data_format)) helper.append_op( type="pixel_shuffle", inputs={"X": x}, outputs={"Out": out}, - attrs={"upscale_factor": upscale_factor}) + attrs={"upscale_factor": upscale_factor, + "data_format": data_format}) return out diff --git a/python/paddle/nn/layer/vision.py b/python/paddle/nn/layer/vision.py index cbad50bc0d809..fe7f9fa859672 100644 --- a/python/paddle/nn/layer/vision.py +++ b/python/paddle/nn/layer/vision.py @@ -28,7 +28,8 @@ class PixelShuffle(layers.Layer): PixelShuffle Layer This operator rearranges elements in a tensor of shape [N, C, H, W] - to a tensor of shape [N, C/upscale_factor**2, H*upscale_factor, W*upscale_factor]. + to a tensor of shape [N, C/upscale_factor**2, H*upscale_factor, W*upscale_factor], + or from shape [N, H, W, C] to [N, H*upscale_factor, W*upscale_factor, C/upscale_factor^2]. This is useful for implementing efficient sub-pixel convolution with a stride of 1/upscale_factor. Please refer to the paper: `Real-Time Single Image and Video Super-Resolution @@ -40,8 +41,8 @@ class PixelShuffle(layers.Layer): upscale_factor(int): factor to increase spatial resolution. Shape: - - x: 4-D tensor with shape: (N, C, H, W). - - out: 4-D tensor with shape: (N, C/upscale_factor**2, H*upscale_factor, W*upscale_factor). + - x: 4-D tensor with shape: (N, C, H, W) or (N, H, W, C). + - out: 4-D tensor with shape: (N, C/upscale_factor**2, H*upscale_factor, W*upscale_factor) or (N, H*upscale_factor, W*upscale_factor, C/upscale_factor^2). Examples: @@ -51,20 +52,31 @@ class PixelShuffle(layers.Layer): import paddle.nn as nn import numpy as np - paddle.enable_imperative() + paddle.disable_static() x = np.random.randn(2, 9, 4, 4).astype(np.float32) - place = fluid.CPUPlace() - x_var = paddle.imperative.to_variable(x) + x_var = paddle.to_variable(x) pixel_shuffle = nn.PixelShuffle(3) - y_var = pixel_shuffle(x_var) - y_np = y_var.numpy() - print(y_np.shape) # (2, 1, 12, 12) + out_var = pixel_shuffle(x_var) + out = out_var.numpy() + print(out.shape) + # (2, 1, 12, 12) """ - def __init__(self, upscale_factor): + def __init__(self, upscale_factor, data_format="NCHW", name=None): super(PixelShuffle, self).__init__() + + if not isinstance(upscale_factor, int): + raise TypeError("upscale factor must be int type") + + if data_format not in ["NCHW", "NHWC"]: + raise ValueError("Data format should be 'NCHW' or 'NHWC'." + "But recevie data format: {}".format(data_format)) + self._upscale_factor = upscale_factor + self._data_format = data_dormat + self._name = name def forward(self, x): - return functional.pixel_shuffle(x, self._upscale_factor) + return functional.pixel_shuffle(x, self._upscale_factor, + self._data_format, self._name) From 2269ab971c307b2c187a86c8b19bd561e7da7365 Mon Sep 17 00:00:00 2001 From: shippingwang Date: Mon, 17 Aug 2020 14:13:59 +0000 Subject: [PATCH 03/13] fix bug --- paddle/fluid/operators/pixel_shuffle_op.cc | 8 +-- paddle/fluid/operators/pixel_shuffle_op.h | 4 +- .../tests/unittests/test_pixel_shuffle.py | 3 +- python/paddle/nn/functional/__init__.py | 68 +++++++++---------- python/paddle/nn/functional/vision.py | 3 +- python/paddle/nn/layer/vision.py | 2 +- 6 files changed, 45 insertions(+), 43 deletions(-) diff --git a/paddle/fluid/operators/pixel_shuffle_op.cc b/paddle/fluid/operators/pixel_shuffle_op.cc index df38f1a7b9a7e..ee25fe6c57990 100644 --- a/paddle/fluid/operators/pixel_shuffle_op.cc +++ b/paddle/fluid/operators/pixel_shuffle_op.cc @@ -37,7 +37,7 @@ class PixelShuffleOp : public framework::OperatorWithKernel { auto upscale_factor = ctx->Attrs().Get("upscale_factor"); const std::string data_format = - ctx->Attrs().Get < std : string > ("data_format"); + ctx->Attrs().Get("data_format"); const bool channel_last = (data_format == "NHWC"); if (!channel_last) { @@ -148,10 +148,10 @@ class PixelShuffleGradOp : public framework::OperatorWithKernel { auto upscale_factor = ctx->Attrs().Get("upscale_factor"); const std::string data_format = - ctx->Attrs().Get < std : string > ("data_format"); - const bool channel_last = (data_format == "NHWC") + ctx->Attrs().Get("data_format"); + const bool channel_last = (data_format == "NHWC"); - auto dx_dims = do_dims; + auto dx_dims = do_dims; dx_dims[0] = do_dims[0]; if (!channel_last) { diff --git a/paddle/fluid/operators/pixel_shuffle_op.h b/paddle/fluid/operators/pixel_shuffle_op.h index d819029324ba4..b2a0db0f838d5 100644 --- a/paddle/fluid/operators/pixel_shuffle_op.h +++ b/paddle/fluid/operators/pixel_shuffle_op.h @@ -50,7 +50,7 @@ class PixelShuffleOpKernel : public framework::OpKernel { if (!channel_last) { o.Resize({in_dims[0], o_dims[1], in_dims[2], factor, in_dims[3], factor}); } else { - o.Resize({in_dims[0], in_dims[1], factor, in_dims[2], factor, o_dim[3]}); + o.Resize({in_dims[0], in_dims[1], factor, in_dims[2], factor, o_dims[3]}); } math::Transpose trans; auto& dev_ctx = ctx.template device_context(); @@ -70,7 +70,7 @@ class PixelShuffleGradOpKernel : public framework::OpKernel { int factor = ctx.Attr("upscale_factor"); std::string data_format = ctx.Attr("data_format"); - bool channel_fast = (data_format == "NHWC"); + bool channel_last = (data_format == "NHWC"); auto do_dims = dout->dims(); auto dx_dims = dx->dims(); diff --git a/python/paddle/fluid/tests/unittests/test_pixel_shuffle.py b/python/paddle/fluid/tests/unittests/test_pixel_shuffle.py index 778f9d6b5eed4..2def3a09dbf57 100644 --- a/python/paddle/fluid/tests/unittests/test_pixel_shuffle.py +++ b/python/paddle/fluid/tests/unittests/test_pixel_shuffle.py @@ -17,6 +17,7 @@ import unittest import numpy as np from op_test import OpTest +import paddle def pixel_shuffle_np(x, up_factor, data_format="NCHW"): @@ -84,7 +85,7 @@ class TestPixelShuffleDygraph(unittest.TestCase): def run_pixel_shuffle(self, up_factor): x = np.random.rand(2, 9, 4, 4).astype(np.float32) - npresult = pixel_shuffle_np(x, np_factor) + npresult = pixel_shuffle_np(x, up_factor) paddle.disable_static() pixel_shuffle = paddle.nn.PixelShuffle(up_factor) diff --git a/python/paddle/nn/functional/__init__.py b/python/paddle/nn/functional/__init__.py index fa85b19426cd2..921d94a6f7c80 100644 --- a/python/paddle/nn/functional/__init__.py +++ b/python/paddle/nn/functional/__init__.py @@ -158,40 +158,40 @@ # from .rnn import gru_unit #DEFINE_ALIAS # from .rnn import lstm #DEFINE_ALIAS # from .rnn import lstm_unit #DEFINE_ALIAS -from .vision import affine_channel #DEFINE_ALIAS -from .vision import affine_grid #DEFINE_ALIAS -from .vision import anchor_generator #DEFINE_ALIAS -from .vision import bipartite_match #DEFINE_ALIAS -from .vision import box_clip #DEFINE_ALIAS -from .vision import box_coder #DEFINE_ALIAS -from .vision import box_decoder_and_assign #DEFINE_ALIAS -from .vision import collect_fpn_proposals #DEFINE_ALIAS +#from .vision import affine_channel #DEFINE_ALIAS +#from .vision import affine_grid #DEFINE_ALIAS +#from .vision import anchor_generator #DEFINE_ALIAS +#from .vision import bipartite_match #DEFINE_ALIAS +#from .vision import box_clip #DEFINE_ALIAS +#from .vision import box_coder #DEFINE_ALIAS +#from .vision import box_decoder_and_assign #DEFINE_ALIAS +#from .vision import collect_fpn_proposals #DEFINE_ALIAS # from .vision import deformable_conv #DEFINE_ALIAS -from .vision import deformable_roi_pooling #DEFINE_ALIAS -from .vision import density_prior_box #DEFINE_ALIAS -from .vision import detection_output #DEFINE_ALIAS -from .vision import distribute_fpn_proposals #DEFINE_ALIAS -from .vision import fsp_matrix #DEFINE_ALIAS -from .vision import generate_mask_labels #DEFINE_ALIAS -from .vision import generate_proposal_labels #DEFINE_ALIAS -from .vision import generate_proposals #DEFINE_ALIAS -from .vision import grid_sampler #DEFINE_ALIAS -from .vision import image_resize #DEFINE_ALIAS -from .vision import image_resize_short #DEFINE_ALIAS +#from .vision import deformable_roi_pooling #DEFINE_ALIAS +#from .vision import density_prior_box #DEFINE_ALIAS +#from .vision import detection_output #DEFINE_ALIAS +#from .vision import distribute_fpn_proposals #DEFINE_ALIAS +#from .vision import fsp_matrix #DEFINE_ALIAS +#from .vision import generate_mask_labels #DEFINE_ALIAS +#from .vision import generate_proposal_labels #DEFINE_ALIAS +#from .vision import generate_proposals #DEFINE_ALIAS +#from .vision import grid_sampler #DEFINE_ALIAS +#from .vision import image_resize #DEFINE_ALIAS +#from .vision import image_resize_short #DEFINE_ALIAS # from .vision import multi_box_head #DEFINE_ALIAS from .vision import pixel_shuffle #DEFINE_ALIAS -from .vision import prior_box #DEFINE_ALIAS -from .vision import prroi_pool #DEFINE_ALIAS -from .vision import psroi_pool #DEFINE_ALIAS -from .vision import resize_bilinear #DEFINE_ALIAS -from .vision import resize_nearest #DEFINE_ALIAS -from .vision import resize_trilinear #DEFINE_ALIAS -from .vision import retinanet_detection_output #DEFINE_ALIAS -from .vision import retinanet_target_assign #DEFINE_ALIAS -from .vision import roi_align #DEFINE_ALIAS -from .vision import roi_perspective_transform #DEFINE_ALIAS -from .vision import roi_pool #DEFINE_ALIAS -from .vision import shuffle_channel #DEFINE_ALIAS -from .vision import space_to_depth #DEFINE_ALIAS -from .vision import yolo_box #DEFINE_ALIAS -from .vision import yolov3_loss #DEFINE_ALIAS +#from .vision import prior_box #DEFINE_ALIAS +#from .vision import prroi_pool #DEFINE_ALIAS +#from .vision import psroi_pool #DEFINE_ALIAS +#from .vision import resize_bilinear #DEFINE_ALIAS +#from .vision import resize_nearest #DEFINE_ALIAS +#from .vision import resize_trilinear #DEFINE_ALIAS +#from .vision import retinanet_detection_output #DEFINE_ALIAS +#from .vision import retinanet_target_assign #DEFINE_ALIAS +#from .vision import roi_align #DEFINE_ALIAS +#from .vision import roi_perspective_transform #DEFINE_ALIAS +#from .vision import roi_pool #DEFINE_ALIAS +#from .vision import shuffle_channel #DEFINE_ALIAS +#from .vision import space_to_depth #DEFINE_ALIAS +#from .vision import yolo_box #DEFINE_ALIAS +#from .vision import yolov3_loss #DEFINE_ALIAS diff --git a/python/paddle/nn/functional/vision.py b/python/paddle/nn/functional/vision.py index 602727fc7d568..d53610ea97411 100644 --- a/python/paddle/nn/functional/vision.py +++ b/python/paddle/nn/functional/vision.py @@ -14,6 +14,7 @@ from ...fluid.data_feeder import check_variable_and_dtype from ...fluid.layer_helper import LayerHelper +from ...fluid.framework import in_dygraph_mode __all__ = [ #'affine_channel', @@ -99,7 +100,7 @@ def pixel_shuffle(x, upscale_factor, data_format="NCHW", name=None): # (2, 1, 12, 12) """ - if not fluid.framework.in_dygraph_mode(): + if not in_dygraph_mode(): check_variable_and_dtype(x, 'x', ['float32', 'float64'], 'pixel_shuffle') diff --git a/python/paddle/nn/layer/vision.py b/python/paddle/nn/layer/vision.py index fe7f9fa859672..e638b2f19e685 100644 --- a/python/paddle/nn/layer/vision.py +++ b/python/paddle/nn/layer/vision.py @@ -74,7 +74,7 @@ def __init__(self, upscale_factor, data_format="NCHW", name=None): "But recevie data format: {}".format(data_format)) self._upscale_factor = upscale_factor - self._data_format = data_dormat + self._data_format = data_format self._name = name def forward(self, x): From d9533b2a3df76b8639961cae3e4a97d3aa14c94a Mon Sep 17 00:00:00 2001 From: shippingwang Date: Tue, 18 Aug 2020 04:22:45 +0000 Subject: [PATCH 04/13] refine --- paddle/fluid/operators/pixel_shuffle_op.cc | 1 - python/paddle/nn/functional/__init__.py | 72 ++++++------- python/paddle/nn/functional/vision.py | 119 +++++++++++++-------- python/paddle/nn/layer/vision.py | 7 +- 4 files changed, 116 insertions(+), 83 deletions(-) diff --git a/paddle/fluid/operators/pixel_shuffle_op.cc b/paddle/fluid/operators/pixel_shuffle_op.cc index ee25fe6c57990..70d232ad6a51e 100644 --- a/paddle/fluid/operators/pixel_shuffle_op.cc +++ b/paddle/fluid/operators/pixel_shuffle_op.cc @@ -91,7 +91,6 @@ class PixelShuffleOpMaker : public framework::OpProtoAndCheckerMaker { }); AddAttr( "data_format", - "(string, default NCHW) Only used in " "An optional string from: \"NHWC\", \"NCHW\". " "Defaults to \"NHWC\", Specify the data format of the input data.") .SetDefault("NCHW"); diff --git a/python/paddle/nn/functional/__init__.py b/python/paddle/nn/functional/__init__.py index 921d94a6f7c80..3fd6bf4bbf25e 100644 --- a/python/paddle/nn/functional/__init__.py +++ b/python/paddle/nn/functional/__init__.py @@ -158,40 +158,40 @@ # from .rnn import gru_unit #DEFINE_ALIAS # from .rnn import lstm #DEFINE_ALIAS # from .rnn import lstm_unit #DEFINE_ALIAS -#from .vision import affine_channel #DEFINE_ALIAS -#from .vision import affine_grid #DEFINE_ALIAS -#from .vision import anchor_generator #DEFINE_ALIAS -#from .vision import bipartite_match #DEFINE_ALIAS -#from .vision import box_clip #DEFINE_ALIAS -#from .vision import box_coder #DEFINE_ALIAS -#from .vision import box_decoder_and_assign #DEFINE_ALIAS -#from .vision import collect_fpn_proposals #DEFINE_ALIAS -# from .vision import deformable_conv #DEFINE_ALIAS -#from .vision import deformable_roi_pooling #DEFINE_ALIAS -#from .vision import density_prior_box #DEFINE_ALIAS -#from .vision import detection_output #DEFINE_ALIAS -#from .vision import distribute_fpn_proposals #DEFINE_ALIAS -#from .vision import fsp_matrix #DEFINE_ALIAS -#from .vision import generate_mask_labels #DEFINE_ALIAS -#from .vision import generate_proposal_labels #DEFINE_ALIAS -#from .vision import generate_proposals #DEFINE_ALIAS -#from .vision import grid_sampler #DEFINE_ALIAS -#from .vision import image_resize #DEFINE_ALIAS -#from .vision import image_resize_short #DEFINE_ALIAS -# from .vision import multi_box_head #DEFINE_ALIAS +from .vision import affine_channel #DEFINE_ALIAS +from .vision import affine_grid #DEFINE_ALIAS +from .vision import anchor_generator #DEFINE_ALIAS +from .vision import bipartite_match #DEFINE_ALIAS +from .vision import box_clip #DEFINE_ALIAS +from .vision import box_coder #DEFINE_ALIAS +from .vision import box_decoder_and_assign #DEFINE_ALIAS +from .vision import collect_fpn_proposals #DEFINE_ALIAS +from .vision import deformable_conv #DEFINE_ALIAS +from .vision import deformable_roi_pooling #DEFINE_ALIAS +from .vision import density_prior_box #DEFINE_ALIAS +from .vision import detection_output #DEFINE_ALIAS +from .vision import distribute_fpn_proposals #DEFINE_ALIAS +from .vision import fsp_matrix #DEFINE_ALIAS +from .vision import generate_mask_labels #DEFINE_ALIAS +from .vision import generate_proposal_labels #DEFINE_ALIAS +from .vision import generate_proposals #DEFINE_ALIAS +from .vision import grid_sampler #DEFINE_ALIAS +from .vision import image_resize #DEFINE_ALIAS +from .vision import image_resize_short #DEFINE_ALIAS +from .vision import multi_box_head #DEFINE_ALIAS from .vision import pixel_shuffle #DEFINE_ALIAS -#from .vision import prior_box #DEFINE_ALIAS -#from .vision import prroi_pool #DEFINE_ALIAS -#from .vision import psroi_pool #DEFINE_ALIAS -#from .vision import resize_bilinear #DEFINE_ALIAS -#from .vision import resize_nearest #DEFINE_ALIAS -#from .vision import resize_trilinear #DEFINE_ALIAS -#from .vision import retinanet_detection_output #DEFINE_ALIAS -#from .vision import retinanet_target_assign #DEFINE_ALIAS -#from .vision import roi_align #DEFINE_ALIAS -#from .vision import roi_perspective_transform #DEFINE_ALIAS -#from .vision import roi_pool #DEFINE_ALIAS -#from .vision import shuffle_channel #DEFINE_ALIAS -#from .vision import space_to_depth #DEFINE_ALIAS -#from .vision import yolo_box #DEFINE_ALIAS -#from .vision import yolov3_loss #DEFINE_ALIAS +from .vision import prior_box #DEFINE_ALIAS +from .vision import prroi_pool #DEFINE_ALIAS +from .vision import psroi_pool #DEFINE_ALIAS +from .vision import resize_bilinear #DEFINE_ALIAS +from .vision import resize_nearest #DEFINE_ALIAS +from .vision import resize_trilinear #DEFINE_ALIAS +from .vision import retinanet_detection_output #DEFINE_ALIAS +from .vision import retinanet_target_assign #DEFINE_ALIAS +from .vision import roi_align #DEFINE_ALIAS +from .vision import roi_perspective_transform #DEFINE_ALIAS +from .vision import roi_pool #DEFINE_ALIAS +from .vision import shuffle_channel #DEFINE_ALIAS +from .vision import space_to_depth #DEFINE_ALIAS +from .vision import yolo_box #DEFINE_ALIAS +from .vision import yolov3_loss #DEFINE_ALIAS diff --git a/python/paddle/nn/functional/vision.py b/python/paddle/nn/functional/vision.py index d53610ea97411..04f0628edcfe4 100644 --- a/python/paddle/nn/functional/vision.py +++ b/python/paddle/nn/functional/vision.py @@ -16,55 +16,90 @@ from ...fluid.layer_helper import LayerHelper from ...fluid.framework import in_dygraph_mode +from ...fluid.layers import affine_channel #DEFINE_ALIAS +from ...fluid.layers import affine_grid #DEFINE_ALIAS +from ...fluid.layers import anchor_generator #DEFINE_ALIAS +from ...fluid.layers import bipartite_match #DEFINE_ALIAS +from ...fluid.layers import box_clip #DEFINE_ALIAS +from ...fluid.layers import box_coder #DEFINE_ALIAS +from ...fluid.layers import box_decoder_and_assign #DEFINE_ALIAS +from ...fluid.layers import collect_fpn_proposals #DEFINE_ALIAS +from ...fluid.layers import deformable_roi_pooling #DEFINE_ALIAS +from ...fluid.layers import density_prior_box #DEFINE_ALIAS +from ...fluid.layers import detection_output #DEFINE_ALIAS +from ...fluid.layers import distribute_fpn_proposals #DEFINE_ALIAS +from ...fluid.layers import generate_mask_labels #DEFINE_ALIAS +from ...fluid.layers import generate_proposal_labels #DEFINE_ALIAS +from ...fluid.layers import generate_proposals #DEFINE_ALIAS +from ...fluid.layers import grid_sampler #DEFINE_ALIAS +from ...fluid.layers import image_resize #DEFINE_ALIAS +from ...fluid.layers import prior_box #DEFINE_ALIAS +from ...fluid.layers import prroi_pool #DEFINE_ALIAS +from ...fluid.layers import psroi_pool #DEFINE_ALIAS +from ...fluid.layers import resize_bilinear #DEFINE_ALIAS +from ...fluid.layers import resize_nearest #DEFINE_ALIAS +from ...fluid.layers import resize_trilinear #DEFINE_ALIAS +from ...fluid.layers import roi_align #DEFINE_ALIAS +from ...fluid.layers import roi_pool #DEFINE_ALIAS +from ...fluid.layers import space_to_depth #DEFINE_ALIAS +from ...fluid.layers import yolo_box #DEFINE_ALIAS +from ...fluid.layers import yolov3_loss #DEFINE_ALIAS + +from ...fluid.layers import fsp_matrix #DEFINE_ALIAS +from ...fluid.layers import image_resize_short #DEFINE_ALIAS +# from ...fluid.layers import pixel_shuffle #DEFINE_ALIAS +from ...fluid.layers import retinanet_detection_output #DEFINE_ALIAS +from ...fluid.layers import retinanet_target_assign #DEFINE_ALIAS +from ...fluid.layers import roi_perspective_transform #DEFINE_ALIAS +from ...fluid.layers import shuffle_channel #DEFINE_ALIAS + __all__ = [ - #'affine_channel', - #'affine_grid', - #'anchor_generator', - #'bipartite_match', - #'box_clip', - #'box_coder', - #'box_decoder_and_assign', - #'collect_fpn_proposals', + 'affine_channel', + 'affine_grid', + 'anchor_generator', + 'bipartite_match', + 'box_clip', + 'box_coder', + 'box_decoder_and_assign', + 'collect_fpn_proposals', # 'deformable_conv', - #'deformable_roi_pooling', - #'density_prior_box', - #'detection_output', - #'distribute_fpn_proposals', - #'fsp_matrix', - #'generate_mask_labels', - #'generate_proposal_labels', - #'generate_proposals', - #'grid_sampler', - #'image_resize', - #'image_resize_short', + 'deformable_roi_pooling', + 'density_prior_box', + 'detection_output', + 'distribute_fpn_proposals', + 'fsp_matrix', + 'generate_mask_labels', + 'generate_proposal_labels', + 'generate_proposals', + 'grid_sampler', + 'image_resize', + 'image_resize_short', # 'multi_box_head', 'pixel_shuffle', - #'prior_box', - #'prroi_pool', - #'psroi_pool', - #'resize_bilinear', - #'resize_nearest', - #'resize_trilinear', - #'retinanet_detection_output', - #'retinanet_target_assign', - #'roi_align', - #'roi_perspective_transform', - #'roi_pool', - #'shuffle_channel', - #'space_to_depth', - #'yolo_box', - #'yolov3_loss' + 'prior_box', + 'prroi_pool', + 'psroi_pool', + 'resize_bilinear', + 'resize_nearest', + 'resize_trilinear', + 'retinanet_detection_output', + 'retinanet_target_assign', + 'roi_align', + 'roi_perspective_transform', + 'roi_pool', + 'shuffle_channel', + 'space_to_depth', + 'yolo_box', + 'yolov3_loss' ] def pixel_shuffle(x, upscale_factor, data_format="NCHW", name=None): """ - :alias_main: paddle.nn.functional.pixel_shuffle - :alias: paddle.nn.functional.pixel_shuffle,paddle.nn.functional.vision.pixel_shuffle This operator rearranges elements in a tensor of shape [N, C, H, W] to a tensor of shape [N, C/upscale_factor**2, H*upscale_factor, W*upscale_factor], - or from shape [N, H, W, C] to [N, H*upscale_factor, W*upscale_factor, C/upscale_factor^2]. + or from shape [N, H, W, C] to [N, H*upscale_factor, W*upscale_factor, C/upscale_factor**2]. This is useful for implementing efficient sub-pixel convolution with a stride of 1/upscale_factor. Please refer to the paper: `Real-Time Single Image and Video Super-Resolution @@ -73,7 +108,7 @@ def pixel_shuffle(x, upscale_factor, data_format="NCHW", name=None): Parameters: - x(Variable): 4-D tensor, the data type should be float32 or float64. + x(tensor): 4-D tensor, the data type should be float32 or float64. upscale_factor(int): factor to increase spatial resolution. name (str, optional): The default value is None. Normally there is no need for user to set this property. @@ -93,18 +128,18 @@ def pixel_shuffle(x, upscale_factor, data_format="NCHW", name=None): x = np.random.randn(2, 9, 4, 4).astype(np.float32) paddle.disable_static() - x_var = paddle.to_variable(x) + x_var = paddle.to_tensor(x) out_var = F.pixel_shuffle(x_var, 3) out = out_var.numpy() print(out.shape) # (2, 1, 12, 12) """ - if not in_dygraph_mode(): - check_variable_and_dtype(x, 'x', ['float32', 'float64'], - 'pixel_shuffle') + if in_dygraph_mode(): + return core.ops.pixel_shuffle(x, upscale_factor, data_format) helper = LayerHelper("pixel_shuffle", **locals()) + check_variable_and_dtype(x, 'x', ['float32', 'float64'], 'pixel_shuffle') out = helper.create_variable_for_type_inference(dtype=x.dtype) diff --git a/python/paddle/nn/layer/vision.py b/python/paddle/nn/layer/vision.py index e638b2f19e685..78e08d9e0eedf 100644 --- a/python/paddle/nn/layer/vision.py +++ b/python/paddle/nn/layer/vision.py @@ -22,14 +22,12 @@ class PixelShuffle(layers.Layer): """ - :alias_main: paddle.nn.PixelShuffle - :alias: paddle.nn.PixelShuffle,paddle.nn.layer.PixelShuffle,paddle.nn.layer.vision.PixelShuffle PixelShuffle Layer This operator rearranges elements in a tensor of shape [N, C, H, W] to a tensor of shape [N, C/upscale_factor**2, H*upscale_factor, W*upscale_factor], - or from shape [N, H, W, C] to [N, H*upscale_factor, W*upscale_factor, C/upscale_factor^2]. + or from shape [N, H, W, C] to [N, H*upscale_factor, W*upscale_factor, C/upscale_factor**2]. This is useful for implementing efficient sub-pixel convolution with a stride of 1/upscale_factor. Please refer to the paper: `Real-Time Single Image and Video Super-Resolution @@ -39,6 +37,7 @@ class PixelShuffle(layers.Layer): Parameters: upscale_factor(int): factor to increase spatial resolution. + name (str, optional): Name for the operation (optional, default is None). For more information, please refer to :ref:`api_guide_Name`. Shape: - x: 4-D tensor with shape: (N, C, H, W) or (N, H, W, C). @@ -54,7 +53,7 @@ class PixelShuffle(layers.Layer): paddle.disable_static() x = np.random.randn(2, 9, 4, 4).astype(np.float32) - x_var = paddle.to_variable(x) + x_var = paddle.to_tensor(x) pixel_shuffle = nn.PixelShuffle(3) out_var = pixel_shuffle(x_var) out = out_var.numpy() From 23cb839fd873290d915b915363896daafab92b79 Mon Sep 17 00:00:00 2001 From: shippingwang Date: Tue, 18 Aug 2020 06:26:57 +0000 Subject: [PATCH 05/13] fix --- python/paddle/nn/functional/__init__.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/python/paddle/nn/functional/__init__.py b/python/paddle/nn/functional/__init__.py index 1ef24bb79ee53..201fdd51e83d9 100644 --- a/python/paddle/nn/functional/__init__.py +++ b/python/paddle/nn/functional/__init__.py @@ -167,7 +167,7 @@ from .vision import box_coder #DEFINE_ALIAS from .vision import box_decoder_and_assign #DEFINE_ALIAS from .vision import collect_fpn_proposals #DEFINE_ALIAS -from .vision import deformable_conv #DEFINE_ALIAS +# from .vision import deformable_conv #DEFINE_ALIAS from .vision import deformable_roi_pooling #DEFINE_ALIAS from .vision import density_prior_box #DEFINE_ALIAS from .vision import detection_output #DEFINE_ALIAS @@ -179,7 +179,7 @@ from .vision import grid_sampler #DEFINE_ALIAS from .vision import image_resize #DEFINE_ALIAS from .vision import image_resize_short #DEFINE_ALIAS -from .vision import multi_box_head #DEFINE_ALIAS +# from .vision import multi_box_head #DEFINE_ALIAS from .vision import pixel_shuffle #DEFINE_ALIAS from .vision import prior_box #DEFINE_ALIAS from .vision import prroi_pool #DEFINE_ALIAS From eb2fdc0900a95b03e01750bb5a4317564f4e1e57 Mon Sep 17 00:00:00 2001 From: shippingwang Date: Tue, 18 Aug 2020 12:25:30 +0000 Subject: [PATCH 06/13] fix bug --- python/paddle/nn/functional/vision.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python/paddle/nn/functional/vision.py b/python/paddle/nn/functional/vision.py index 04f0628edcfe4..6a64cb775ebb6 100644 --- a/python/paddle/nn/functional/vision.py +++ b/python/paddle/nn/functional/vision.py @@ -14,7 +14,7 @@ from ...fluid.data_feeder import check_variable_and_dtype from ...fluid.layer_helper import LayerHelper -from ...fluid.framework import in_dygraph_mode +from ...fluid.framework import core, in_dygraph_mode from ...fluid.layers import affine_channel #DEFINE_ALIAS from ...fluid.layers import affine_grid #DEFINE_ALIAS From 5d23a77edd8714307994e0899569cae5fcbf7e75 Mon Sep 17 00:00:00 2001 From: shippingwang Date: Wed, 19 Aug 2020 14:09:50 +0000 Subject: [PATCH 07/13] fix --- .../tests/unittests/test_pixel_shuffle.py | 25 +++++++++++++------ python/paddle/nn/functional/vision.py | 3 ++- 2 files changed, 20 insertions(+), 8 deletions(-) diff --git a/python/paddle/fluid/tests/unittests/test_pixel_shuffle.py b/python/paddle/fluid/tests/unittests/test_pixel_shuffle.py index 2def3a09dbf57..f87b150deb1c1 100644 --- a/python/paddle/fluid/tests/unittests/test_pixel_shuffle.py +++ b/python/paddle/fluid/tests/unittests/test_pixel_shuffle.py @@ -34,7 +34,6 @@ def pixel_shuffle_np(x, up_factor, data_format="NCHW"): return npresult else: n, h, w, c = x.shape - new_shape = (n, h, w, c // (up_factor * up_factor), up_factor, up_factor) # reshape to (num,h,w,output_channel,upscale_factor,upscale_factor) @@ -82,19 +81,31 @@ def init_data_format(self): class TestPixelShuffleDygraph(unittest.TestCase): - def run_pixel_shuffle(self, up_factor): - x = np.random.rand(2, 9, 4, 4).astype(np.float32) + def run_pixel_shuffle(self, up_factor, data_format): + + n, c, h, w = 2, 9, 4, 4 - npresult = pixel_shuffle_np(x, up_factor) + if data_format == "NCHW": + shape = [n, c, h, w] + if data_format == "NHWC": + shape = [n, h, w, c] + + x = np.random.random(shape).astype("float64") + + npresult = pixel_shuffle_np(x, up_factor, data_format) paddle.disable_static() - pixel_shuffle = paddle.nn.PixelShuffle(up_factor) - result = pixel_shuffle(paddle.to_variable(x)) + pixel_shuffle = paddle.nn.PixelShuffle( + up_factor, data_format=data_format) + result = pixel_shuffle(paddle.to_tensor(x)) self.assertTrue(np.allclose(result.numpy(), npresult)) def test_pixel_shuffle(self): - self.run_pixel_shuffle(3) + self.run_pixel_shuffle(3, "NCHW") + + def test_channel_last(self): + self.run_pixel_shuffle(3, "NHWC") if __name__ == '__main__': diff --git a/python/paddle/nn/functional/vision.py b/python/paddle/nn/functional/vision.py index 6a64cb775ebb6..8f6aab8411cbf 100644 --- a/python/paddle/nn/functional/vision.py +++ b/python/paddle/nn/functional/vision.py @@ -136,7 +136,8 @@ def pixel_shuffle(x, upscale_factor, data_format="NCHW", name=None): """ if in_dygraph_mode(): - return core.ops.pixel_shuffle(x, upscale_factor, data_format) + return core.ops.pixel_shuffle(x, "upscale_factor", upscale_factor, + "data_format", data_format) helper = LayerHelper("pixel_shuffle", **locals()) check_variable_and_dtype(x, 'x', ['float32', 'float64'], 'pixel_shuffle') From 59450d09c32f83f15bab8c35a6548fae18b27525 Mon Sep 17 00:00:00 2001 From: shippingwang Date: Wed, 19 Aug 2020 14:13:43 +0000 Subject: [PATCH 08/13] fix typo --- python/paddle/nn/functional/vision.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/python/paddle/nn/functional/vision.py b/python/paddle/nn/functional/vision.py index 8f6aab8411cbf..10d49a3833ad2 100644 --- a/python/paddle/nn/functional/vision.py +++ b/python/paddle/nn/functional/vision.py @@ -108,12 +108,12 @@ def pixel_shuffle(x, upscale_factor, data_format="NCHW", name=None): Parameters: - x(tensor): 4-D tensor, the data type should be float32 or float64. + x(Tensor): 4-D tensor, the data type should be float32 or float64. upscale_factor(int): factor to increase spatial resolution. name (str, optional): The default value is None. Normally there is no need for user to set this property. Returns: - Out(Variable): Reshaped tensor according to the new dimension. + Out(tensor): Reshaped tensor according to the new dimension. Raises: ValueError: If the square of upscale_factor cannot divide the channels of input. From 6ceae74a0d03e52803cb0195c59dbfcfa8de0373 Mon Sep 17 00:00:00 2001 From: shippingwang Date: Thu, 20 Aug 2020 05:48:38 +0000 Subject: [PATCH 09/13] vision.py --- python/paddle/nn/functional/vision.py | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/python/paddle/nn/functional/vision.py b/python/paddle/nn/functional/vision.py index 10d49a3833ad2..a022efb4b32b2 100644 --- a/python/paddle/nn/functional/vision.py +++ b/python/paddle/nn/functional/vision.py @@ -96,15 +96,8 @@ def pixel_shuffle(x, upscale_factor, data_format="NCHW", name=None): """ - - This operator rearranges elements in a tensor of shape [N, C, H, W] - to a tensor of shape [N, C/upscale_factor**2, H*upscale_factor, W*upscale_factor], - or from shape [N, H, W, C] to [N, H*upscale_factor, W*upscale_factor, C/upscale_factor**2]. - This is useful for implementing efficient sub-pixel convolution - with a stride of 1/upscale_factor. - Please refer to the paper: `Real-Time Single Image and Video Super-Resolution - Using an Efficient Sub-Pixel Convolutional Neural Network `_ . - by Shi et. al (2016) for more details. + This API implements pixel shuffle operation. + See more details in :ref:`api_nn_vision_PixelShuffle` . Parameters: From 985112d74435656afadeeb7940e94025d37b9e6d Mon Sep 17 00:00:00 2001 From: shippingwang Date: Thu, 20 Aug 2020 07:05:57 +0000 Subject: [PATCH 10/13] refine doc --- python/paddle/nn/functional/vision.py | 1 + python/paddle/nn/layer/vision.py | 1 + 2 files changed, 2 insertions(+) diff --git a/python/paddle/nn/functional/vision.py b/python/paddle/nn/functional/vision.py index a022efb4b32b2..78d79dba82b81 100644 --- a/python/paddle/nn/functional/vision.py +++ b/python/paddle/nn/functional/vision.py @@ -103,6 +103,7 @@ def pixel_shuffle(x, upscale_factor, data_format="NCHW", name=None): x(Tensor): 4-D tensor, the data type should be float32 or float64. upscale_factor(int): factor to increase spatial resolution. + data_format (str): The data format of the input and output data. An optional string from: "NCHW", "NHWC". The default is "NCHW". When it is "NCHW", the data is stored in the order of: [batch_size, input_channels, input_height, input_width]. name (str, optional): The default value is None. Normally there is no need for user to set this property. Returns: diff --git a/python/paddle/nn/layer/vision.py b/python/paddle/nn/layer/vision.py index 78e08d9e0eedf..a5f360ec02e6d 100644 --- a/python/paddle/nn/layer/vision.py +++ b/python/paddle/nn/layer/vision.py @@ -37,6 +37,7 @@ class PixelShuffle(layers.Layer): Parameters: upscale_factor(int): factor to increase spatial resolution. + data_format (str): The data format of the input and output data. An optional string from: "NCHW", "NHWC". The default is "NCHW". When it is "NCHW", the data is stored in the order of: [batch_size, input_channels, input_height, input_width]. name (str, optional): Name for the operation (optional, default is None). For more information, please refer to :ref:`api_guide_Name`. Shape: From e7d68bbd050906984dd549b3b2963a7f154f092b Mon Sep 17 00:00:00 2001 From: shippingwang Date: Fri, 21 Aug 2020 12:18:46 +0000 Subject: [PATCH 11/13] fix unittestgit status! --- .../tests/unittests/test_pixel_shuffle.py | 97 ++++++++++++++++--- 1 file changed, 84 insertions(+), 13 deletions(-) diff --git a/python/paddle/fluid/tests/unittests/test_pixel_shuffle.py b/python/paddle/fluid/tests/unittests/test_pixel_shuffle.py index f87b150deb1c1..b0eb504b6515a 100644 --- a/python/paddle/fluid/tests/unittests/test_pixel_shuffle.py +++ b/python/paddle/fluid/tests/unittests/test_pixel_shuffle.py @@ -16,8 +16,12 @@ import unittest import numpy as np + from op_test import OpTest import paddle +import paddle.nn.functional as F +import paddle.fluid.core as core +import paddle.fluid as fluid def pixel_shuffle_np(x, up_factor, data_format="NCHW"): @@ -45,7 +49,7 @@ def pixel_shuffle_np(x, up_factor, data_format="NCHW"): return npresult -class TestPixelShuffle(OpTest): +class TestPixelShuffleOp(OpTest): def setUp(self): self.op_type = "pixel_shuffle" self.init_data_format() @@ -75,13 +79,71 @@ def test_check_grad(self): self.check_grad(['X'], 'Out') -class TestChannelLast(TestPixelShuffle): +class TestChannelLast(TestPixelShuffleOp): def init_data_format(self): self.format = "NHWC" -class TestPixelShuffleDygraph(unittest.TestCase): - def run_pixel_shuffle(self, up_factor, data_format): +class TestPixelShuffleAPI(unittest.TestCase): + def setUp(self): + self.x_1_np = np.random.random([2, 9, 4, 4]).astype("float64") + self.x_2_np = np.random.random([2, 4, 4, 9]).astype("float64") + self.out_1_np = pixel_shuffle_np(self.x_1_np, 3) + self.out_2_np = pixel_shuffle_np(self.x_2_np, 3, "NHWC") + + def test_static_graph_functional(self): + for use_cuda in ([False, True] + if core.is_compiled_with_cuda() else [False]): + place = paddle.CUDAPlace(0) if use_cuda else paddle.CPUPlace() + + paddle.enable_static() + x_1 = paddle.data(name="x", shape=[2, 9, 4, 4], dtype="float64") + x_2 = paddle.data(name="x2", shape=[2, 4, 4, 9], dtype="float64") + out_1 = F.pixel_shuffle(x_1, 3) + out_2 = F.pixel_shuffle(x_2, 3, "NHWC") + + exe = paddle.static.Executor(place=place) + res_1 = exe.run(fluid.default_main_program(), + feed={"x": self.x_1_np}, + fetch_list=out_1) + + res_2 = exe.run(fluid.default_main_program(), + feed={"x2": self.x_2_np}, + fetch_list=out_2) + + assert np.allclose(res_1, self.out_1_np) + assert np.allclose(res_2, self.out_2_np) + + # same test between layer and functional in this op. + def test_static_graph_layer(self): + for use_cuda in ([False, True] + if core.is_compiled_with_cuda() else [False]): + place = paddle.CUDAPlace(0) if use_cuda else paddle.CPUPlace() + + paddle.enable_static() + x_1 = paddle.data(name="x", shape=[2, 9, 4, 4], dtype="float64") + x_2 = paddle.data(name="x2", shape=[2, 4, 4, 9], dtype="float64") + # init instance + ps_1 = paddle.nn.PixelShuffle(3) + ps_2 = paddle.nn.PixelShuffle(3, "NHWC") + out_1 = ps_1(x_1) + out_2 = ps_2(x_2) + out_1_np = pixel_shuffle_np(self.x_1_np, 3) + out_2_np = pixel_shuffle_np(self.x_2_np, 3, "NHWC") + + exe = paddle.static.Executor(place=place) + res_1 = exe.run(fluid.default_main_program(), + feed={"x": self.x_1_np}, + fetch_list=out_1) + + res_2 = exe.run(fluid.default_main_program(), + feed={"x2": self.x_2_np}, + fetch_list=out_2) + + assert np.allclose(res_1, out_1_np) + assert np.allclose(res_2, out_2_np) + + def run_dygraph(self, up_factor, data_format): n, c, h, w = 2, 9, 4, 4 @@ -94,18 +156,27 @@ def run_pixel_shuffle(self, up_factor, data_format): npresult = pixel_shuffle_np(x, up_factor, data_format) - paddle.disable_static() - pixel_shuffle = paddle.nn.PixelShuffle( - up_factor, data_format=data_format) - result = pixel_shuffle(paddle.to_tensor(x)) + for use_cuda in ([False, True] + if core.is_compiled_with_cuda() else [False]): + place = paddle.CUDAPlace(0) if use_cuda else paddle.CPUPlace() + + paddle.disable_static(place=place) + + pixel_shuffle = paddle.nn.PixelShuffle( + up_factor, data_format=data_format) + result = pixel_shuffle(paddle.to_tensor(x)) + + self.assertTrue(np.allclose(result.numpy(), npresult)) - self.assertTrue(np.allclose(result.numpy(), npresult)) + result_functional = F.pixel_shuffle( + paddle.to_tensor(x), 3, data_format) + self.assertTrue(np.allclose(result_functional.numpy(), npresult)) - def test_pixel_shuffle(self): - self.run_pixel_shuffle(3, "NCHW") + def test_dygraph1(self): + self.run_dygraph(3, "NCHW") - def test_channel_last(self): - self.run_pixel_shuffle(3, "NHWC") + def test_dygraph2(self): + self.run_dygraph(3, "NHWC") if __name__ == '__main__': From b54e8df8dffe39a603ad941d4f28ea9f9db84c1a Mon Sep 17 00:00:00 2001 From: shippingwang Date: Sun, 23 Aug 2020 04:15:05 +0000 Subject: [PATCH 12/13] fix graph --- .../fluid/tests/unittests/test_pixel_shuffle.py | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/python/paddle/fluid/tests/unittests/test_pixel_shuffle.py b/python/paddle/fluid/tests/unittests/test_pixel_shuffle.py index b0eb504b6515a..26d006f6b45dc 100644 --- a/python/paddle/fluid/tests/unittests/test_pixel_shuffle.py +++ b/python/paddle/fluid/tests/unittests/test_pixel_shuffle.py @@ -105,11 +105,13 @@ def test_static_graph_functional(self): exe = paddle.static.Executor(place=place) res_1 = exe.run(fluid.default_main_program(), feed={"x": self.x_1_np}, - fetch_list=out_1) + fetch_list=out_1, + use_prune=True) res_2 = exe.run(fluid.default_main_program(), feed={"x2": self.x_2_np}, - fetch_list=out_2) + fetch_list=out_2, + use_prune=True) assert np.allclose(res_1, self.out_1_np) assert np.allclose(res_2, self.out_2_np) @@ -134,11 +136,13 @@ def test_static_graph_layer(self): exe = paddle.static.Executor(place=place) res_1 = exe.run(fluid.default_main_program(), feed={"x": self.x_1_np}, - fetch_list=out_1) + fetch_list=out_1, + use_prune=True) res_2 = exe.run(fluid.default_main_program(), feed={"x2": self.x_2_np}, - fetch_list=out_2) + fetch_list=out_2, + use_prune=True) assert np.allclose(res_1, out_1_np) assert np.allclose(res_2, out_2_np) From 9e63bb0b733a7b3bbfef63d0b779bc1e6eeec85b Mon Sep 17 00:00:00 2001 From: shippingwang Date: Mon, 24 Aug 2020 09:14:47 +0000 Subject: [PATCH 13/13] fix coverage --- .../tests/unittests/test_pixel_shuffle.py | 32 +++++++++++++++++++ python/paddle/nn/functional/vision.py | 19 ++++++----- 2 files changed, 43 insertions(+), 8 deletions(-) diff --git a/python/paddle/fluid/tests/unittests/test_pixel_shuffle.py b/python/paddle/fluid/tests/unittests/test_pixel_shuffle.py index 26d006f6b45dc..cf93f39ab8c5c 100644 --- a/python/paddle/fluid/tests/unittests/test_pixel_shuffle.py +++ b/python/paddle/fluid/tests/unittests/test_pixel_shuffle.py @@ -183,5 +183,37 @@ def test_dygraph2(self): self.run_dygraph(3, "NHWC") +class TestPixelShuffleError(unittest.TestCase): + def test_error_functional(self): + def error_upscale_factor(): + with paddle.fluid.dygraph.guard(): + x = np.random.random([2, 9, 4, 4]).astype("float64") + pixel_shuffle = F.pixel_shuffle(paddle.to_tensor(x), 3.33) + + self.assertRaises(TypeError, error_upscale_factor) + + def error_data_format(): + with paddle.fluid.dygraph.guard(): + x = np.random.random([2, 9, 4, 4]).astype("float64") + pixel_shuffle = F.pixel_shuffle(paddle.to_tensor(x), 3, "WOW") + + self.assertRaises(ValueError, error_data_format) + + def test_error_layer(self): + def error_upscale_factor_layer(): + with paddle.fluid.dygraph.guard(): + x = np.random.random([2, 9, 4, 4]).astype("float64") + ps = paddle.nn.PixelShuffle(3.33) + + self.assertRaises(TypeError, error_upscale_factor_layer) + + def error_data_format_layer(): + with paddle.fluid.dygraph.guard(): + x = np.random.random([2, 9, 4, 4]).astype("float64") + ps = paddle.nn.PixelShuffle(3, "MEOW") + + self.assertRaises(ValueError, error_data_format_layer) + + if __name__ == '__main__': unittest.main() diff --git a/python/paddle/nn/functional/vision.py b/python/paddle/nn/functional/vision.py index 78d79dba82b81..ef2ec4d9dba87 100644 --- a/python/paddle/nn/functional/vision.py +++ b/python/paddle/nn/functional/vision.py @@ -129,14 +129,9 @@ def pixel_shuffle(x, upscale_factor, data_format="NCHW", name=None): # (2, 1, 12, 12) """ - if in_dygraph_mode(): - return core.ops.pixel_shuffle(x, "upscale_factor", upscale_factor, - "data_format", data_format) - - helper = LayerHelper("pixel_shuffle", **locals()) - check_variable_and_dtype(x, 'x', ['float32', 'float64'], 'pixel_shuffle') - - out = helper.create_variable_for_type_inference(dtype=x.dtype) + if not in_dygraph_mode(): + check_variable_and_dtype(x, 'x', ['float32', 'float64'], + 'pixel_shuffle') if not isinstance(upscale_factor, int): raise TypeError("upscale factor must be int type") @@ -145,6 +140,14 @@ def pixel_shuffle(x, upscale_factor, data_format="NCHW", name=None): raise ValueError("Attr(data_format) should be 'NCHW' or 'NHWC'." "But recevie Attr(data_format): {} ".format( data_format)) + + if in_dygraph_mode(): + return core.ops.pixel_shuffle(x, "upscale_factor", upscale_factor, + "data_format", data_format) + + helper = LayerHelper("pixel_shuffle", **locals()) + + out = helper.create_variable_for_type_inference(dtype=x.dtype) helper.append_op( type="pixel_shuffle", inputs={"X": x},