-
Notifications
You must be signed in to change notification settings - Fork 5.6k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add correlation api to contrib (#27015)
* add correlation api to contrib
- Loading branch information
1 parent
cbcd5e4
commit 8df5b4d
Showing
4 changed files
with
908 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,181 @@ | ||
/* 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. */ | ||
|
||
#include <memory> | ||
#include <string> | ||
#include <unordered_map> | ||
#include <vector> | ||
#include "paddle/fluid/framework/op_registry.h" | ||
|
||
namespace paddle { | ||
namespace operators { | ||
|
||
using Tensor = framework::Tensor; | ||
|
||
inline std::vector<int64_t> CorrelationOutputSize(int batch, int input_height, | ||
int input_width, int stride1, | ||
int stride2, int kernel_size, | ||
int pad_size, | ||
int max_displacement) { | ||
std::vector<int64_t> output_shape({batch}); | ||
int kernel_radius = (kernel_size - 1) / 2; | ||
int border_radius = kernel_radius + max_displacement; | ||
int padded_input_height = input_height + 2 * pad_size; | ||
int padded_input_width = input_width + 2 * pad_size; | ||
int output_channel = ((max_displacement / stride2) * 2 + 1) * | ||
((max_displacement / stride2) * 2 + 1); | ||
output_shape.push_back(output_channel); | ||
int output_height = | ||
std::ceil(static_cast<float>(padded_input_height - 2 * border_radius) / | ||
static_cast<float>(stride1)); | ||
int output_width = | ||
std::ceil(static_cast<float>(padded_input_width - 2 * border_radius) / | ||
static_cast<float>(stride1)); | ||
output_shape.push_back(output_height); | ||
output_shape.push_back(output_width); | ||
return output_shape; | ||
} | ||
|
||
class CorrelationOpMaker : public framework::OpProtoAndCheckerMaker { | ||
public: | ||
void Make() override { | ||
AddInput("Input1", "Input is a 4-D Tensor with shape [N, C, H, W]"); | ||
AddInput("Input2", "Input is a 4-D Tensor with shape [N, C, H, W]"); | ||
AddOutput("Output", | ||
"(Tensor) The output tensor of correlation operator. " | ||
"It has same data fromat and data type as the Input."); | ||
AddAttr<int>("pad_size", "pad size for input1 and input2"); | ||
AddAttr<int>("kernel_size", "kernel size of input1 and input2"); | ||
AddAttr<int>("max_displacement", "max displacement of input1 and input2"); | ||
AddAttr<int>("stride1", "Input1 stride"); | ||
AddAttr<int>("stride2", "Input2 stride"); | ||
AddAttr<int>("corr_type_multiply", "correlation coefficient").SetDefault(1); | ||
AddComment( | ||
R"DOC(Correlation of two feature map. Only support NCHW data format.)DOC"); | ||
} | ||
}; | ||
|
||
class CorrelationOp : public framework::OperatorWithKernel { | ||
public: | ||
using framework::OperatorWithKernel::OperatorWithKernel; | ||
|
||
void InferShape(framework::InferShapeContext* ctx) const override { | ||
OP_INOUT_CHECK(ctx->HasInput("Input1"), "Input", "X", "CorrelationOp"); | ||
OP_INOUT_CHECK(ctx->HasInput("Input2"), "Input", "Y", "CorrelationOp"); | ||
int stride1 = ctx->Attrs().Get<int>("stride1"); | ||
int stride2 = ctx->Attrs().Get<int>("stride2"); | ||
int max_displacement = ctx->Attrs().Get<int>("max_displacement"); | ||
int pad_size = ctx->Attrs().Get<int>("pad_size"); | ||
int kernel_size = ctx->Attrs().Get<int>("kernel_size"); | ||
|
||
auto in_dims = ctx->GetInputDim("Input1"); | ||
auto in2_dims = ctx->GetInputDim("Input2"); | ||
|
||
PADDLE_ENFORCE_EQ(in_dims.size() == 4, true, | ||
platform::errors::InvalidArgument( | ||
"Input(X) of CorrelationOp must be 4 dims." | ||
"But received dims is %d.", | ||
in_dims.size())); | ||
|
||
PADDLE_ENFORCE_EQ(in2_dims.size() == 4, true, | ||
platform::errors::InvalidArgument( | ||
"Input(Y) of CorrelationOp must be 4 dims." | ||
"But received dims is %d.", | ||
in2_dims.size())); | ||
std::vector<int64_t> output_shape = | ||
CorrelationOutputSize(in_dims[0], in_dims[2], in_dims[3], stride1, | ||
stride2, kernel_size, pad_size, max_displacement); | ||
ctx->SetOutputDim("Output", framework::make_ddim(output_shape)); | ||
} | ||
|
||
protected: | ||
framework::OpKernelType GetExpectedKernelType( | ||
const framework::ExecutionContext& ctx) const override { | ||
auto input_data_type = | ||
OperatorWithKernel::IndicateVarDataType(ctx, "Input1"); | ||
PADDLE_ENFORCE_EQ(input_data_type, ctx.Input<Tensor>("Input2")->type(), | ||
platform::errors::InvalidArgument( | ||
"X and Y shoule have the same datatype")); | ||
return framework::OpKernelType(input_data_type, ctx.GetPlace()); | ||
} | ||
|
||
framework::OpKernelType GetKernelTypeForVar( | ||
const std::string& var_name, const Tensor& tensor, | ||
const framework::OpKernelType& expected_kernel_type) const override { | ||
return framework::OpKernelType(expected_kernel_type.data_type_, | ||
tensor.place(), tensor.layout()); | ||
} | ||
}; | ||
|
||
template <typename T> | ||
class CorrelationOpGradMaker : public framework::SingleGradOpMaker<T> { | ||
public: | ||
using framework::SingleGradOpMaker<T>::SingleGradOpMaker; | ||
|
||
protected: | ||
void Apply(GradOpPtr<T> op) const override { | ||
op->SetType("correlation_grad"); | ||
op->SetInput("Input1", this->Input("Input1")); | ||
op->SetInput("Input2", this->Input("Input2")); | ||
op->SetInput(framework::GradVarName("Output"), this->OutputGrad("Output")); | ||
op->SetOutput(framework::GradVarName("Input1"), this->InputGrad("Input1")); | ||
op->SetOutput(framework::GradVarName("Input2"), this->InputGrad("Input2")); | ||
op->SetAttrMap(this->Attrs()); | ||
} | ||
}; | ||
|
||
class CorrelationOpGrad : public framework::OperatorWithKernel { | ||
public: | ||
using framework::OperatorWithKernel::OperatorWithKernel; | ||
|
||
void InferShape(framework::InferShapeContext* ctx) const override { | ||
OP_INOUT_CHECK(ctx->HasInput("Input1"), "Input", "X", "CorrelationOp"); | ||
OP_INOUT_CHECK(ctx->HasInput("Input2"), "Input", "Y", "CorrelationOp"); | ||
OP_INOUT_CHECK(ctx->HasInput(framework::GradVarName("Output")), "Input", | ||
"Output@GRAD", "CorrelationGradOp"); | ||
|
||
auto in1_dims = ctx->GetInputDim("Input1"); | ||
auto in2_dims = ctx->GetInputDim("Input2"); | ||
ctx->SetOutputDim(framework::GradVarName("Input1"), in1_dims); | ||
ctx->SetOutputDim(framework::GradVarName("Input2"), in2_dims); | ||
} | ||
|
||
protected: | ||
framework::OpKernelType GetExpectedKernelType( | ||
const framework::ExecutionContext& ctx) const override { | ||
return framework::OpKernelType( | ||
OperatorWithKernel::IndicateVarDataType(ctx, "Input1"), ctx.GetPlace()); | ||
} | ||
}; | ||
|
||
template <typename T> | ||
class CorrelationKernel : public framework::OpKernel<T> { | ||
public: | ||
void Compute(const framework::ExecutionContext& ctx) const override { | ||
PADDLE_ENFORCE_EQ( | ||
platform::is_gpu_place(ctx.GetPlace()), true, | ||
platform::errors::Unimplemented("Correlation only supports GPU now.")); | ||
} | ||
}; | ||
|
||
} // namespace operators | ||
} // namespace paddle | ||
|
||
namespace ops = paddle::operators; | ||
REGISTER_OPERATOR(correlation, ops::CorrelationOp, ops::CorrelationOpMaker, | ||
ops::CorrelationOpGradMaker<paddle::framework::OpDesc>, | ||
ops::CorrelationOpGradMaker<paddle::imperative::OpBase>); | ||
REGISTER_OPERATOR(correlation_grad, ops::CorrelationOpGrad); | ||
REGISTER_OP_CPU_KERNEL(correlation, ops::CorrelationKernel<float>, | ||
ops::CorrelationKernel<double>); |
Oops, something went wrong.