Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

【PaddlePaddle Hackathon 2】29、为 Paddle 新增 PixelUnshuffle 组网 API #40728

Merged
merged 40 commits into from Apr 26, 2022
Merged
Show file tree
Hide file tree
Changes from 29 commits
Commits
Show all changes
40 commits
Select commit Hold shift + click to select a range
995bdad
增加PixelUnshuffle的形状推断
BrilliantYuKaimin Mar 19, 2022
8c401fb
增加PixelUnshuffle的算子注册
BrilliantYuKaimin Mar 19, 2022
7a62b6e
增加PixelUnshuffle及其梯度的核函数
BrilliantYuKaimin Mar 19, 2022
9591a48
增加PixelUnshuffle算子的描述
BrilliantYuKaimin Mar 19, 2022
f6ad365
增加PixelUnshuffle算子的签名
BrilliantYuKaimin Mar 19, 2022
73aed02
在Python层面增加PixelUnshuffle
BrilliantYuKaimin Mar 19, 2022
8a259c0
增加PixelUnshuffle的单测
BrilliantYuKaimin Mar 19, 2022
b28157e
Update test_pixel_unshuffle.py
BrilliantYuKaimin Mar 19, 2022
d16b545
test=document_fix
BrilliantYuKaimin Mar 20, 2022
89e36a0
Update test_pixel_unshuffle.py
BrilliantYuKaimin Mar 20, 2022
3792573
修正代码格式
BrilliantYuKaimin Mar 20, 2022
3388c97
Update test_pixel_unshuffle.py
BrilliantYuKaimin Mar 20, 2022
9e28fef
修改pixel_unshuffle核函数的实现位置
BrilliantYuKaimin Mar 22, 2022
ef6f8ea
修正代码格式
BrilliantYuKaimin Mar 23, 2022
51bb6f8
完善对输入的检查
BrilliantYuKaimin Mar 29, 2022
cf80ace
Update test_pixel_unshuffle.py
BrilliantYuKaimin Mar 29, 2022
4ca1ab4
完善pixel_unshuffle的输入检查
BrilliantYuKaimin Mar 29, 2022
ea07a17
Update pixel_unshuffle_op.cc
BrilliantYuKaimin Mar 29, 2022
41c0705
Merge branch 'develop' into pixel_unshuffle
BrilliantYuKaimin Mar 29, 2022
b0cc19a
Update unary.cc
BrilliantYuKaimin Mar 30, 2022
e96d98a
add pixel_unshuffle
BrilliantYuKaimin Apr 1, 2022
fc1ff53
Update test_pixel_unshuffle.py
BrilliantYuKaimin Apr 1, 2022
b3c084b
Update vision.py
BrilliantYuKaimin Apr 1, 2022
bcb06dd
调整代码格式
BrilliantYuKaimin Apr 1, 2022
b3126ed
Update vision.py
BrilliantYuKaimin Apr 7, 2022
be2f4ad
Merge branch 'PaddlePaddle:develop' into pixel_unshuffle
BrilliantYuKaimin Apr 7, 2022
034c17f
Merge branch 'develop' into pixel_unshuffle
BrilliantYuKaimin Apr 8, 2022
8653519
Delete extra spaces
BrilliantYuKaimin Apr 14, 2022
b13f476
Merge branch 'PaddlePaddle:develop' into pixel_unshuffle
BrilliantYuKaimin Apr 14, 2022
9aeb8b8
Merge branch 'PaddlePaddle:develop' into pixel_unshuffle
BrilliantYuKaimin Apr 18, 2022
c3fbce6
Update pixel_unshuffle_sig.cc
BrilliantYuKaimin Apr 18, 2022
d0e0351
Merge branch 'PaddlePaddle:develop' into pixel_unshuffle
BrilliantYuKaimin Apr 21, 2022
2310fc8
Update vision.py
BrilliantYuKaimin Apr 21, 2022
777c9f8
Update vision.py
BrilliantYuKaimin Apr 21, 2022
b937d0e
add PixelUnshuffleGradInferMeta
BrilliantYuKaimin Apr 21, 2022
73fabcb
remove PixelUnshuffleOpArgumentMapping
BrilliantYuKaimin Apr 21, 2022
d5f6874
Update pixel_unshuffle_op.cc
BrilliantYuKaimin Apr 21, 2022
e871227
调整pixel_unshuffle及其梯度的核函数的实现位置
BrilliantYuKaimin Apr 21, 2022
948f32b
Update pixel_unshuffle_op.cc
BrilliantYuKaimin Apr 21, 2022
e270ab7
Merge branch 'develop' into pixel_unshuffle
BrilliantYuKaimin Apr 25, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
130 changes: 130 additions & 0 deletions paddle/fluid/operators/pixel_unshuffle_op.cc
@@ -0,0 +1,130 @@
/*Copyright (c) 2022 PaddlePaddle Authors. All Rights Reserved.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

license格式有点问题,参考下其他头文件,增加下缩进和换行

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

image

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

完成

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. */

#include "paddle/fluid/framework/infershape_utils.h"
#include "paddle/fluid/framework/op_registry.h"
#include "paddle/fluid/framework/op_version_registry.h"
#include "paddle/phi/core/infermeta_utils.h"
#include "paddle/phi/infermeta/unary.h"

namespace paddle {
namespace operators {

class PixelUnshuffleOp : public framework::OperatorWithKernel {
public:
using framework::OperatorWithKernel::OperatorWithKernel;
};

class PixelUnshuffleOpMaker : public framework::OpProtoAndCheckerMaker {
public:
void Make() override {
AddInput("X",
"(Tensor, default Tensor<float>), "
"the input feature data of PixelUnshuffleOp, the layout is "
"[N, C, H, W] or [N, H, W, C].");
AddOutput("Out",
"(Tensor, default Tensor<float>), the output of "
"PixelUnshuffleOp. The layout is [N, C*factor^2, H/factor, "
"W/factor] or [N, H/factor, W/factor, C*factor^2].");
AddAttr<int>("downscale_factor",
"the factor to decrease spatial resolution by.")
.SetDefault(1);
AddAttr<std::string>(
"data_format",
"An optional string from: \"NHWC\", \"NCHW\". "
"Defaults to \"NHWC\", Specify the data format of the input data.")
.SetDefault("NCHW");

AddComment(R"DOC(
Pixel Unshuffle operator
This operator rearranges elements in a tensor of shape :math:`(*, C, H, W)`
to a tensor of shape :math:`(*, C\times r^2, H / r, W / r)`.

This operation is the reversion of PixelShuffle operation.

Please refer to the paper:
`Real-Time Single Image and Video Super-Resolution Using an Efficient
Sub-Pixel Convolutional Neural Network <https://arxiv.org/abs/1609.05158v2>`_
by Shi et. al (2016) for more details.

)DOC");
}
};

template <typename T>
class PixelUnshuffleGradOpMaker : public framework::SingleGradOpMaker<T> {
public:
using framework::SingleGradOpMaker<T>::SingleGradOpMaker;

protected:
void Apply(GradOpPtr<T> op) const override {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Apply 函数增加 protected 关键字限制访问。

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

完成

op->SetType("pixel_unshuffle_grad");
op->SetInput(framework::GradVarName("Out"), this->OutputGrad("Out"));
op->SetAttrMap(this->Attrs());
op->SetOutput(framework::GradVarName("X"), this->InputGrad("X"));
}
};

class PixelUnshuffleGradOp : public framework::OperatorWithKernel {
public:
using framework::OperatorWithKernel::OperatorWithKernel;

void InferShape(framework::InferShapeContext* ctx) const override {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

这个建议放到infermeta/backward.h中哈,其他的还有是因为正在迁移中,历史算子量比较大,我们还在推进中,比如可以参考softmax_op.cc

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

完成

PADDLE_ENFORCE_EQ(
ctx->HasInput(framework::GradVarName("Out")), true,
platform::errors::NotFound("Input(Out@Grad) should not be null"));
PADDLE_ENFORCE_EQ(
ctx->HasOutput(framework::GradVarName("X")), true,
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] "
"or [N, H, W, C], but got %u.",
do_dims.size()));

auto downscale_factor = ctx->Attrs().Get<int>("downscale_factor");

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];

if (!channel_last) {
dx_dims[1] = do_dims[1] / (downscale_factor * downscale_factor);
dx_dims[2] = do_dims[2] * downscale_factor;
dx_dims[3] = do_dims[3] * downscale_factor;
} else {
dx_dims[1] = do_dims[1] * downscale_factor;
dx_dims[2] = do_dims[2] * downscale_factor;
dx_dims[3] = do_dims[3] / (downscale_factor * downscale_factor);
}
ctx->SetOutputDim(framework::GradVarName("X"), dx_dims);
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

输出形状推断放在infermata中

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

这部分和infermata内存在重复

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

我看其他算子也都是只把前向的形状推断放在infermeta中,而反向的形状推断放在xxx_op.cc中。

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

好的

};

} // namespace operators
} // namespace paddle

namespace ops = paddle::operators;
DECLARE_INFER_SHAPE_FUNCTOR(pixel_unshuffle, PixelUnshuffleInferShapeFunctor,
PD_INFER_META(phi::PixelUnshuffleInferMeta));

REGISTER_OPERATOR(pixel_unshuffle, ops::PixelUnshuffleOp,
ops::PixelUnshuffleOpMaker,
ops::PixelUnshuffleGradOpMaker<paddle::framework::OpDesc>,
ops::PixelUnshuffleGradOpMaker<paddle::imperative::OpBase>,
PixelUnshuffleInferShapeFunctor);

REGISTER_OPERATOR(pixel_unshuffle_grad, ops::PixelUnshuffleGradOp);
60 changes: 60 additions & 0 deletions paddle/phi/infermeta/unary.cc
Expand Up @@ -1417,6 +1417,66 @@ void PixelShuffleGradInferMeta(const MetaTensor& out_grad,
x_grad->set_dtype(out_grad.dtype());
}

void PixelUnshuffleInferMeta(const MetaTensor& x,
int downscale_factor,
const std::string& data_format,
MetaTensor* out) {
auto input_dims = x.dims();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

增加对downscale_factor的检查、对输入format的检查

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

完成

PADDLE_ENFORCE_EQ(input_dims.size(),
4,
phi::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()));
PADDLE_ENFORCE_GE(downscale_factor,
1,
phi::errors::InvalidArgument(
"downscale_factor should be larger than 0."));
PADDLE_ENFORCE_EQ(data_format == "NCHW" || data_format == "NHWC",
true,
phi::errors::InvalidArgument(
"data_format must be one of "
"NCHW and NHWC. But recevied data_format: %s",
data_format));

const bool channel_last = (data_format == "NHWC");

if (!channel_last) {
PADDLE_ENFORCE_EQ(
(input_dims[2] % downscale_factor) == 0 &&
(input_dims[3] % downscale_factor) == 0,
true,
phi::errors::InvalidArgument("Downscale factor[%u] should divide both "
"height[%u] and width[%u]",
downscale_factor,
input_dims[2],
input_dims[3]));
} else {
PADDLE_ENFORCE_EQ(
(input_dims[1] % downscale_factor) == 0 &&
(input_dims[2] % downscale_factor) == 0,
true,
phi::errors::InvalidArgument("Downscale factor[%u] should divide both "
"height[%u] and width[%u]",
downscale_factor,
input_dims[1],
input_dims[2]));
}
auto output_dims = input_dims;
output_dims[0] = input_dims[0];
if (!channel_last) {
output_dims[1] = input_dims[1] * (downscale_factor * downscale_factor);
output_dims[2] = input_dims[2] / downscale_factor;
output_dims[3] = input_dims[3] / downscale_factor;
} else {
output_dims[1] = input_dims[1] / downscale_factor;
output_dims[2] = input_dims[2] / downscale_factor;
output_dims[3] = input_dims[3] * (downscale_factor * downscale_factor);
}
out->set_dtype(x.dtype());
out->set_dims(output_dims);
}

void PNormInferMeta(const MetaTensor& x,
float porder,
int axis,
Expand Down
5 changes: 5 additions & 0 deletions paddle/phi/infermeta/unary.h
Expand Up @@ -209,6 +209,11 @@ void PixelShuffleGradInferMeta(const MetaTensor& out_grad,
const std::string& data_format,
MetaTensor* x_grad);

void PixelUnshuffleInferMeta(const MetaTensor& x,
int downscale_factor,
const std::string& data_format,
MetaTensor* out);

void PNormInferMeta(const MetaTensor& x,
float porder,
int axis,
Expand Down
74 changes: 74 additions & 0 deletions paddle/phi/kernels/pixel_unshuffle_grad_kernel.cc
@@ -0,0 +1,74 @@
// Copyright (c) 2022 PaddlePaddle Authors. All Rights Reserved.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

这个文件需要放到kernels/impl目录中哈,命名可以参考impl目录中的文件,然后kernel.cc和kernel.cu分别在cpu和gpu下,kernels根目录下的cc中是设备无关的kernel实现,即这个kernel的实现里,不能有设备相关的函数,而这个kernel里的Transpose是仅支持CPU和GPU的,我们还有XPU以及将来可能有其他设备

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

完成

//
// 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.

#include "paddle/phi/kernels/pixel_unshuffle_grad_kernel.h"
#include <string>
#include <vector>
#include "paddle/phi/backends/all_context.h"
#include "paddle/phi/core/dense_tensor.h"
#include "paddle/phi/core/kernel_registry.h"
#include "paddle/phi/kernels/funcs/math_function.h"

namespace phi {

template <typename T, typename Context>
void PixelUnshuffleGradKernel(const Context& ctx,
const DenseTensor& out_grad,
int downscale_factor,
const std::string& data_format,
DenseTensor* x_grad) {
auto* dout = &out_grad;
auto* dx = x_grad;
ctx.template Alloc<T>(dx);
int factor = downscale_factor;
bool channel_last = (data_format == "NHWC");
auto do_dims = dout->dims();
auto dx_dims = dx->dims();

DenseTensor t(*dout);
if (!channel_last) {
t.Resize({do_dims[0], dx_dims[1], factor, factor, do_dims[2], do_dims[3]});
} else {
t.Resize({do_dims[0], do_dims[1], do_dims[2], dx_dims[3], factor, factor});
}
std::vector<int> axis = {0, 1, 4, 2, 5, 3};

DenseTensor o(*dx);
if (!channel_last) {
o.Resize({do_dims[0], dx_dims[1], do_dims[2], factor, do_dims[3], factor});
} else {
o.Resize({do_dims[0], do_dims[1], factor, do_dims[2], factor, dx_dims[3]});
}
phi::funcs::Transpose<Context, T, 6> trans;
trans(ctx, t, &o, axis);
dx->Resize(dx_dims);
}

} // namespace phi

PD_REGISTER_KERNEL(pixel_unshuffle_grad,
CPU,
ALL_LAYOUT,
phi::PixelUnshuffleGradKernel,
float,
double) {}

#if defined(PADDLE_WITH_CUDA) || defined(PADDLE_WITH_HIP)
PD_REGISTER_KERNEL(pixel_unshuffle_grad,
GPU,
ALL_LAYOUT,
phi::PixelUnshuffleGradKernel,
float,
double) {}
#endif
29 changes: 29 additions & 0 deletions paddle/phi/kernels/pixel_unshuffle_grad_kernel.h
@@ -0,0 +1,29 @@
// Copyright (c) 2022 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.

#pragma once

#include <string>
#include "paddle/phi/core/dense_tensor.h"

namespace phi {

template <typename T, typename Context>
void PixelUnshuffleGradKernel(const Context& ctx,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

参数名建议统一为dev_ctx

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

完成

const DenseTensor& out_grad,
int downscale_factor,
const std::string& data_format,
DenseTensor* x_grad);

} // namespace phi
73 changes: 73 additions & 0 deletions paddle/phi/kernels/pixel_unshuffle_kernel.cc
@@ -0,0 +1,73 @@
// Copyright (c) 2022 PaddlePaddle Authors. All Rights Reserved.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

同上,该Kernel属于仅支持CPU和GPU的实现,并非设备无关的实现,麻烦移到impl中

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

完成

//
// 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.

#include "paddle/phi/kernels/pixel_unshuffle_kernel.h"
#include <string>
#include <vector>
#include "paddle/phi/backends/all_context.h"
#include "paddle/phi/core/dense_tensor.h"
#include "paddle/phi/core/kernel_registry.h"
#include "paddle/phi/kernels/funcs/math_function.h"

namespace phi {

template <typename T, typename Context>
void PixelUnshuffleKernel(const Context& ctx,
const DenseTensor& x,
int downscale_factor,
const std::string& data_format,
DenseTensor* out) {
auto* in = &x;
ctx.template Alloc<T>(out);
int factor = downscale_factor;
bool channel_last = (data_format == "NHWC");
auto in_dims = in->dims();
auto o_dims = out->dims();

DenseTensor t(*in);
if (!channel_last) {
t.Resize({in_dims[0], in_dims[1], o_dims[2], factor, o_dims[3], factor});
} else {
t.Resize({in_dims[0], o_dims[1], factor, o_dims[2], factor, in_dims[3]});
}
std::vector<int> axis = {0, 1, 3, 5, 2, 4};

DenseTensor o(*out);
if (!channel_last) {
o.Resize({in_dims[0], in_dims[1], factor, factor, o_dims[2], o_dims[3]});
} else {
o.Resize({in_dims[0], o_dims[1], o_dims[2], in_dims[3], factor, factor});
}
phi::funcs::Transpose<Context, T, 6> trans;
trans(ctx, t, &o, axis);
out->Resize(o_dims);
}

} // namespace phi

PD_REGISTER_KERNEL(pixel_unshuffle,
CPU,
ALL_LAYOUT,
phi::PixelUnshuffleKernel,
float,
double) {}

#if defined(PADDLE_WITH_CUDA) || defined(PADDLE_WITH_HIP)
PD_REGISTER_KERNEL(pixel_unshuffle,
GPU,
ALL_LAYOUT,
phi::PixelUnshuffleKernel,
float,
double) {}
#endif