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
Changes from 31 commits
995bdad
8c401fb
7a62b6e
9591a48
f6ad365
73aed02
8a259c0
b28157e
d16b545
89e36a0
3792573
3388c97
9e28fef
ef6f8ea
51bb6f8
cf80ace
4ca1ab4
ea07a17
41c0705
b0cc19a
e96d98a
fc1ff53
b3c084b
bcb06dd
b3126ed
be2f4ad
034c17f
8653519
b13f476
9aeb8b8
c3fbce6
d0e0351
2310fc8
777c9f8
b937d0e
73fabcb
d5f6874
e871227
948f32b
e270ab7
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,130 @@ | ||
/*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. */ | ||
|
||
#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 { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Apply 函数增加 protected 关键字限制访问。 There was a problem hiding this comment. Choose a reason for hiding this commentThe 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 { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 这个建议放到infermeta/backward.h中哈,其他的还有是因为正在迁移中,历史算子量比较大,我们还在推进中,比如可以参考softmax_op.cc There was a problem hiding this comment. Choose a reason for hiding this commentThe 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); | ||
} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 输出形状推断放在infermata中 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 这部分和infermata内存在重复 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 我看其他算子也都是只把前向的形状推断放在infermeta中,而反向的形状推断放在xxx_op.cc中。 There was a problem hiding this comment. Choose a reason for hiding this commentThe 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); |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -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(); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 增加对downscale_factor的检查、对输入format的检查 There was a problem hiding this comment. Choose a reason for hiding this commentThe 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, | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,74 @@ | ||
// Copyright (c) 2022 PaddlePaddle Authors. All Rights Reserved. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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以及将来可能有其他设备 There was a problem hiding this comment. Choose a reason for hiding this commentThe 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 |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 参数名建议统一为dev_ctx There was a problem hiding this comment. Choose a reason for hiding this commentThe 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 |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,73 @@ | ||
// Copyright (c) 2022 PaddlePaddle Authors. All Rights Reserved. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 同上,该Kernel属于仅支持CPU和GPU的实现,并非设备无关的实现,麻烦移到impl中 There was a problem hiding this comment. Choose a reason for hiding this commentThe 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 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
license格式有点问题,参考下其他头文件,增加下缩进和换行
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
完成