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

【Hackathon No.21】为 Paddle 新增 SoftMarginLoss #42364

Merged
merged 45 commits into from Jul 25, 2022
Merged
Show file tree
Hide file tree
Changes from 39 commits
Commits
Show all changes
45 commits
Select commit Hold shift + click to select a range
2c0a131
2022-04-28
yangguohao Apr 28, 2022
5cb644c
2022-04-28_V2
yangguohao Apr 28, 2022
eec4f11
2022-04-30
yangguohao Apr 30, 2022
60e3fe8
Merge branch 'PaddlePaddle:develop' into SoftMarginLoss
yangguohao Apr 30, 2022
7099799
2022-04-30_V2
yangguohao Apr 30, 2022
bef3f8f
Merge branch 'PaddlePaddle:develop' into SoftMarginLoss
yangguohao May 1, 2022
04a8215
2022-05-01
yangguohao May 1, 2022
25e62db
2022-05-02
yangguohao May 1, 2022
bebb9c3
2022-05-02_V2
yangguohao May 2, 2022
eeee007
2022-05-05_V1
yangguohao May 5, 2022
2168c15
Merge branch 'PaddlePaddle:develop' into SoftMarginLoss
yangguohao May 5, 2022
298c238
2022-05-06_V1
yangguohao May 6, 2022
f970b37
Merge branch 'PaddlePaddle:develop' into SoftMarginLoss
yangguohao May 6, 2022
d133b4b
2022-05-07_V1
yangguohao May 7, 2022
60f353b
Merge branch 'PaddlePaddle:develop' into SoftMarginLoss
yangguohao May 7, 2022
90dd6ed
Update loss.py
yangguohao May 9, 2022
371b955
2022-05-07_V2
yangguohao May 7, 2022
4a85b06
2022-05-13_V1
yangguohao May 13, 2022
ec502c6
Update test_soft_margin_loss.py
yangguohao May 16, 2022
d593f0c
Update loss.py
yangguohao May 16, 2022
8e49f6e
Update loss.py
yangguohao May 16, 2022
0101201
2022-05-16_V1
yangguohao May 16, 2022
4c5bd16
2022-05-19_V1
yangguohao May 19, 2022
7bc9952
Merge branch 'PaddlePaddle:develop' into SoftMarginLoss
yangguohao May 19, 2022
84dae9a
2022-05-20_V1
yangguohao May 20, 2022
cb64918
Update test_soft_margin_loss.py
yangguohao May 20, 2022
ae92ab6
Merge branch 'PaddlePaddle:develop' into SoftMarginLoss
yangguohao May 30, 2022
e7d23ed
2022-06-01_V1
yangguohao Jun 1, 2022
60d636a
Merge branch 'develop' into SoftMarginLoss
yangguohao Jun 1, 2022
aab1136
2022-06-05
yangguohao Jun 5, 2022
fa51768
Merge branch 'develop' into SoftMarginLoss
yangguohao Jun 5, 2022
f5549be
2022-06-07
yangguohao Jun 6, 2022
ff7d7a0
2022-06-07
yangguohao Jun 7, 2022
3403bf5
2022-06-08
yangguohao Jun 7, 2022
7bdf5d3
2022-06-08_V2
yangguohao Jun 8, 2022
6c9f780
Merge branch 'develop' into SoftMarginLoss
yangguohao Jun 8, 2022
977f90e
Merge branch 'develop' into SoftMarginLoss
yangguohao Jun 15, 2022
91111ee
2022-06-17-code_style
yangguohao Jun 17, 2022
468847f
Merge branch 'develop' into SoftMarginLoss
yangguohao Jun 17, 2022
c558d14
Modify python
yangguohao Jun 17, 2022
cc269a9
2022-06-20
yangguohao Jun 20, 2022
bfde404
Merge branch 'PaddlePaddle:develop' into SoftMarginLoss
yangguohao Jun 20, 2022
038f50e
for
Ligoml Jul 20, 2022
0b0e00a
for CI;test=document_fix
Ligoml Jul 20, 2022
95f802e
Merge branch 'PaddlePaddle:develop' into SoftMarginLoss
yangguohao Jul 20, 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
140 changes: 140 additions & 0 deletions paddle/fluid/operators/soft_margin_loss_op.cc
@@ -0,0 +1,140 @@
/* Copyright (c) 2022 PaddlePaddle Authors. All Rights Reserved.
yangguohao marked this conversation as resolved.
Show resolved Hide resolved
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 <vector>

#include "paddle/fluid/framework/infershape_utils.h"
#include "paddle/fluid/framework/op_registry.h"
#include "paddle/phi/infermeta/binary.h"

namespace paddle {
namespace operators {

using framework::Tensor;

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

protected:
framework::OpKernelType GetExpectedKernelType(
const framework::ExecutionContext& ctx) const override {
return framework::OpKernelType(
OperatorWithKernel::IndicateVarDataType(ctx, "X"),
ctx.device_context());
}
};

class SoftMarginLossGradOp : 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.

这里的 InferShape 函数需要迁移到 phi/infermeta/backward.* 位置

Copy link
Contributor Author

Choose a reason for hiding this comment

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

这一部分我此前参考了其他的损失函数算子。没有在 phi/infermeta/backward.* 位置,不太清楚应如何修改。

Copy link
Contributor

Choose a reason for hiding this comment

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

这里和前向的一样写法即可,只是代码放到backward中,后面可以再改写下

OP_INOUT_CHECK(ctx->HasInput("X"), "Input", "X", "SoftMarginLossGrad");
OP_INOUT_CHECK(ctx->HasInput("Label"), "Input", "Label",
"SoftMarginLossGrad");
OP_INOUT_CHECK(ctx->HasInput(framework::GradVarName("Out")), "Input",
framework::GradVarName("Out"), "SoftMarginLossGrad");
OP_INOUT_CHECK(ctx->HasOutput(framework::GradVarName("X")), "Output",
framework::GradVarName("X"), "SoftMarginLossGrad");

auto x_dims = ctx->GetInputDim("X");
auto labels_dims = ctx->GetInputDim("Label");
auto dout_dims = ctx->GetInputDim(framework::GradVarName("Out"));

bool check = true;
if ((!ctx->IsRuntime()) &&
(phi::product(x_dims) <= 0 || phi::product(labels_dims) <= 0)) {
check = false;
}

if (check) {
PADDLE_ENFORCE_EQ(x_dims, labels_dims,
platform::errors::InvalidArgument(
"Input(X) and Input(Label) shall have the same "
"shape. But received: the shape of Input(X) is "
"[%s], the shape of Input(Label) is [%s].",
x_dims, labels_dims));

PADDLE_ENFORCE_EQ(x_dims, dout_dims,
platform::errors::InvalidArgument(
"Input(X) and Input(Out@Grad) shall have the same "
"shape. But received: the shape of Input(X) is "
"[%s], the shape of Input(Out@Grad) is [%s].",
x_dims, dout_dims));
}

ctx->SetOutputDim(framework::GradVarName("X"), x_dims);
ctx->ShareLoD("X", framework::GradVarName("X"));
}

protected:
framework::OpKernelType GetExpectedKernelType(
const framework::ExecutionContext& ctx) const override {
return framework::OpKernelType(
OperatorWithKernel::IndicateVarDataType(ctx, "X"),
ctx.device_context());
}
};

class SoftMarginLossOpMaker : public framework::OpProtoAndCheckerMaker {
public:
void Make() override {
AddInput("X",
"(Tensor, default Tensor<float>), the input is a tensor of logits"
"computed by the previous operator. ");
AddInput("Label",
"(Tensor, default Tensor<float>), have same shape with input"
"label should be -1 or 1.");
AddOutput("Out",
"(Tensor, default Tensor<float>), have same shape with"
"input");
AddComment(R"DOC(
SoftMarginLoss operator.
This measures the element-wise probability error in classification tasks
in which each class is independent.
The logitstic loss is given as follows:
$$loss = log(1+exp(-Label * X))$$
)DOC");
}
};

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

protected:
void Apply(GradOpPtr<T> op) const override {
op->SetType("soft_margin_loss_grad");
op->SetInput("X", this->Input("X"));
op->SetInput("Label", this->Input("Label"));
op->SetInput(framework::GradVarName("Out"), this->OutputGrad("Out"));
op->SetOutput(framework::GradVarName("X"), this->InputGrad("X"));
op->SetAttrMap(this->Attrs());
}
};

} // namespace operators
} // namespace paddle

namespace ops = paddle::operators;
DECLARE_INFER_SHAPE_FUNCTOR(soft_margin_loss, SoftMarginLossInferShapeFunctor,
PD_INFER_META(phi::SoftMarginLossInferMeta));

REGISTER_OPERATOR(soft_margin_loss, ops::SoftMarginLossOp,
ops::SoftMarginLossOpMaker,
ops::SoftMarginLossGradOpMaker<paddle::framework::OpDesc>,
ops::SoftMarginLossGradOpMaker<paddle::imperative::OpBase>,
SoftMarginLossInferShapeFunctor);
REGISTER_OPERATOR(soft_margin_loss_grad, ops::SoftMarginLossGradOp);
40 changes: 40 additions & 0 deletions paddle/phi/infermeta/binary.cc
Expand Up @@ -1838,6 +1838,46 @@ void SigmoidCrossEntropyWithLogitsInferMeta(const MetaTensor& x,
out->share_lod(x);
}

void SoftMarginLossInferMeta(const MetaTensor& input,
const MetaTensor& label,
MetaTensor* out,
MetaConfig config) {
auto input_dims = input.dims();
auto label_dims = label.dims();

int rank = input_dims.size();
PADDLE_ENFORCE_EQ(rank,
label_dims.size(),
phi::errors::InvalidArgument(
"Input(X) and Input(Label) shall have the same rank."
"But received: the rank of Input(X) is [%d], "
"the rank of Input(Label) is [%d].",
rank,
label_dims.size()));
yangguohao marked this conversation as resolved.
Show resolved Hide resolved

bool check = true;

if ((!config.is_runtime) &&
(phi::product(input_dims) <= 0 || phi::product(label_dims) <= 0)) {
check = false;
}

if (check) {
PADDLE_ENFORCE_EQ(input_dims,
label_dims,
phi::errors::InvalidArgument(
"Input(X) and Input(Label) shall have the same "
"shape. But received: the shape of Input(X) is "
"[%s], the shape of Input(Label) is [%s].",
input_dims,
label_dims));
}

out->set_dims(input_dims);
out->set_dtype(input.dtype());
out->share_lod(input);
}

void TakeAlongAxisInferMeta(const MetaTensor& x,
const MetaTensor& index,
int axis,
Expand Down
5 changes: 5 additions & 0 deletions paddle/phi/infermeta/binary.h
Expand Up @@ -270,6 +270,11 @@ void SigmoidCrossEntropyWithLogitsInferMeta(const MetaTensor& x,
MetaTensor* out,
MetaConfig config = MetaConfig());

void SoftMarginLossInferMeta(const MetaTensor& input,
const MetaTensor& label,
MetaTensor* out,
MetaConfig config = MetaConfig());

void TakeAlongAxisInferMeta(const MetaTensor& x,
const MetaTensor& index,
int axis,
Expand Down
51 changes: 51 additions & 0 deletions paddle/phi/kernels/cpu/soft_margin_loss_grad_kernel.cc
@@ -0,0 +1,51 @@
// 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/phi/kernels/soft_margin_loss_grad_kernel.h"

#include <algorithm>

#include "paddle/phi/backends/cpu/cpu_context.h"
#include "paddle/phi/core/kernel_registry.h"

namespace phi {

template <typename T, typename Context>
void SoftMarginLossGradKernel(const Context& dev_ctx,
const DenseTensor& input,
const DenseTensor& label,
const DenseTensor& out_grad,
DenseTensor* input_grad) {
auto dx_data = dev_ctx.template Alloc<T>(input_grad);
auto dout_data = out_grad.data<T>();
auto x_data = input.data<T>();
auto label_data = label.data<T>();

int x_numel = input.numel();

// dx = dout * (-label * exp(-label * x))/(1 + exp(-label * x ))
for (int i = 0; i < x_numel; ++i) {
dx_data[i] = dout_data[i] *
((-label_data[i] * std::exp(-label_data[i] * x_data[i])) /
(static_cast<T>(1) + std::exp(-label_data[i] * x_data[i])));
}
}
} // namespace phi

PD_REGISTER_KERNEL(soft_margin_loss_grad,
CPU,
ALL_LAYOUT,
phi::SoftMarginLossGradKernel,
float,
double) {}
46 changes: 46 additions & 0 deletions paddle/phi/kernels/cpu/soft_margin_loss_kernel.cc
@@ -0,0 +1,46 @@
// 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/phi/kernels/soft_margin_loss_kernel.h"

#include <algorithm>

#include "paddle/phi/backends/cpu/cpu_context.h"
#include "paddle/phi/core/kernel_registry.h"

namespace phi {

template <typename T, typename Context>
void SoftMarginLossKernel(const Context& dev_ctx,
const DenseTensor& input,
const DenseTensor& label,
DenseTensor* out) {
auto x_data = input.data<T>();
auto label_data = label.data<T>();
auto out_data = dev_ctx.template Alloc<T>(out);
auto x_numel = input.numel();

// out = ln(1+exp(-label * x)/(x_numel)
for (int64_t i = 0; i < x_numel; ++i) {
out_data[i] =
std::log(static_cast<T>(1) + std::exp(-label_data[i] * x_data[i]));
}
}
} // namespace phi
PD_REGISTER_KERNEL(soft_margin_loss,
CPU,
ALL_LAYOUT,
phi::SoftMarginLossKernel,
float,
double) {}
62 changes: 62 additions & 0 deletions paddle/phi/kernels/gpu/soft_margin_loss_grad_kernel.cu
@@ -0,0 +1,62 @@
// 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 <algorithm>
#include <vector>

#include "paddle/phi/backends/gpu/gpu_context.h"
#include "paddle/phi/core/hostdevice.h"
#include "paddle/phi/core/kernel_registry.h"
#include "paddle/phi/kernels/funcs/elementwise_base.h"
#include "paddle/phi/kernels/soft_margin_loss_grad_kernel.h"

namespace phi {

template <typename T>
struct SoftMarginLossGradFunctor {
T one;
T eps;

HOSTDEVICE inline SoftMarginLossGradFunctor() {
one = static_cast<T>(1.0f);
eps = static_cast<T>(1e-12);
}

HOSTDEVICE inline T operator()(const T x, const T label, const T dout) const {
T term1 = (one + std::exp(-label * x));
return (dout * (-label * std::exp(-label * x)) / term1);
}
};

template <typename T, typename Context>
void SoftMarginLossGradKernel(const Context& dev_ctx,
const DenseTensor& input,
const DenseTensor& label,
const DenseTensor& out_grad,
DenseTensor* input_grad) {
dev_ctx.template Alloc<T>(input_grad);
std::vector<const DenseTensor*> ins = {&input, &label, &out_grad};
std::vector<DenseTensor*> outs = {input_grad};
auto functor = SoftMarginLossGradFunctor<T>();
phi::funcs::ElementwiseKernel<T>(dev_ctx, ins, &outs, functor);
}

} // namespace phi

PD_REGISTER_KERNEL(soft_margin_loss_grad,
GPU,
ALL_LAYOUT,
phi::SoftMarginLossGradKernel,
float,
double) {}