diff --git a/paddle/operators/margin_rank_loss_op.cc b/paddle/operators/margin_rank_loss_op.cc index 3b9d551b83ba87e0ddcb2f51c9867a7404e88f9f..6869cedc82515b2799cc24ea9dd6ce8775cc511e 100644 --- a/paddle/operators/margin_rank_loss_op.cc +++ b/paddle/operators/margin_rank_loss_op.cc @@ -19,11 +19,7 @@ namespace operators { class MarginRankLossOp : public framework::OperatorWithKernel { public: - MarginRankLossOp(const std::string &type, - const framework::VariableNameMap &inputs, - const framework::VariableNameMap &outputs, - const framework::AttributeMap &attrs) - : OperatorWithKernel(type, inputs, outputs, attrs) {} + using framework::OperatorWithKernel::OperatorWithKernel; protected: void InferShape(const framework::InferShapeContext &ctx) const override { @@ -35,13 +31,11 @@ class MarginRankLossOp : public framework::OperatorWithKernel { auto label_dims = ctx.Input("Label")->dims(); auto x1_dims = ctx.Input("X1")->dims(); auto x2_dims = ctx.Input("X2")->dims(); - PADDLE_ENFORCE((label_dims.size() == 1) && (x1_dims.size() == 1) && - (x2_dims.size() == 1), - "The rank of all inputs must be 1."); - PADDLE_ENFORCE((label_dims == x1_dims) && (x1_dims == x2_dims), - "All inputs must have the same size"); - ctx.Output("Out")->Resize(label_dims); + PADDLE_ENFORCE((label_dims == x1_dims) && (x1_dims == x2_dims) && + (label_dims.size() == 2) && (label_dims[1] == 1), + "All inputs must be vector with the same size"); ctx.Output("Activated")->Resize(label_dims); + ctx.Output("Out")->Resize(label_dims); } }; @@ -51,18 +45,27 @@ class MarginRankLossOpMaker : public framework::OpProtoAndCheckerMaker { MarginRankLossOpMaker(framework::OpProto *proto, framework::OpAttrChecker *op_checker) : OpProtoAndCheckerMaker(proto, op_checker) { - AddInput("Label", "The label indicating X1 ranked higher than X2 or not."); - AddInput("X1", "The first input of MarginRankLossOp."); - AddInput("X2", "The second input of MarginRankLossOp"); - AddAttr("margin", "Margin for MarginRankLossOp").SetDefault(0); - AddOutput("Out", "The output loss of MarginRankLoss operator"); + AddInput("X1", "The first input of MarginRankLossOp, row vector."); + AddInput("X2", "The second input of MarginRankLossOp, row vector."); + AddInput("Label", + "The label indicating X1 ranked higher than X2 " + "or not, row vector."); + AddAttr("margin", "Margin for MarginRankLossOp, scalar.") + .SetDefault(0); AddOutput("Activated", - "Intermediate tensor to indicate " - "whether Output(Out) is activated") + "Intermediate tensor to indicate whether each element of " + "Output(Out) is activated") .AsIntermediate(); - AddComment(R"DOC(MarginRankLoss operator + AddOutput("Out", "The output loss of MarginRankLoss operator"); + AddComment(R"DOC( + +MarginRankLoss operator measures the loss given a pair of input {`X1`, `X2`} +and `Label` with attribuute `margin`, where `Label == 1` indicating X1 is +ranked higher than `X2`, otherwise `Label == -1`. The loss turns out + +loss(X1, X2, Label) = max(0, -Label * (X1-X2) + margin) -loss(x1, x2, y) = max(0, -label * (x1-x2) + margin) +For batch input, `X1`, `X2` and `Label` all have the same size batch_size x 1. )DOC"); } @@ -70,11 +73,7 @@ loss(x1, x2, y) = max(0, -label * (x1-x2) + margin) class MarginRankLossGradOp : public framework::OperatorWithKernel { public: - MarginRankLossGradOp(const std::string &type, - const framework::VariableNameMap &inputs, - const framework::VariableNameMap &outputs, - const framework::AttributeMap &attrs) - : OperatorWithKernel(type, inputs, outputs, attrs) {} + using framework::OperatorWithKernel::OperatorWithKernel; protected: void InferShape(const framework::InferShapeContext &ctx) const override { diff --git a/paddle/operators/margin_rank_loss_op.cu b/paddle/operators/margin_rank_loss_op.cu index 81cbf2fe8837f7e46ec13ade233e27178b5be5e4..3a639f25d478a712c1030d57c57d7e55de1488b5 100644 --- a/paddle/operators/margin_rank_loss_op.cu +++ b/paddle/operators/margin_rank_loss_op.cu @@ -14,9 +14,11 @@ #include "paddle/operators/margin_rank_loss_op.h" +namespace ops = paddle::operators; + REGISTER_OP_GPU_KERNEL( margin_rank_loss, - paddle::operators::MarginRankLossKernel); -REGISTER_OP_GPU_KERNEL(margin_rank_loss_grad, - paddle::operators::MarginRankLossGradKernel< - paddle::platform::GPUPlace, float>); + ops::MarginRankLossKernel); +REGISTER_OP_GPU_KERNEL( + margin_rank_loss_grad, + ops::MarginRankLossGradKernel); diff --git a/paddle/operators/margin_rank_loss_op.h b/paddle/operators/margin_rank_loss_op.h index cd6544f417b600fc4a588779e76164afa5783aa3..3d63343a613fe8dea3abe09fc2440743f4b9ac75 100644 --- a/paddle/operators/margin_rank_loss_op.h +++ b/paddle/operators/margin_rank_loss_op.h @@ -46,8 +46,8 @@ template class MarginRankLossKernel : public framework::OpKernel { public: void Compute(const framework::ExecutionContext& ctx) const { - auto* out_t = ctx.Output("Out"); - auto* act_t = ctx.Output("Activated"); + auto* out_t = ctx.Output("Out"); + auto* act_t = ctx.Output("Activated"); auto* label_t = ctx.Input("Label"); auto* x1_t = ctx.Input("X1"); @@ -65,8 +65,8 @@ class MarginRankLossKernel : public framework::OpKernel { auto x2 = framework::EigenVector::Flatten(*x2_t); auto& dev = ctx.GetEigenDevice(); - act.device(dev) = (-label * (x1 - x2) + margin).unaryExpr(Heaviside()); out.device(dev) = (-label * (x1 - x2) + margin).unaryExpr(ReLU()); + act.device(dev) = out.unaryExpr(Heaviside()); } }; @@ -78,15 +78,15 @@ class MarginRankLossGradKernel : public framework::OpKernel { ctx.Output(framework::GradVarName("X1")); auto* d_x2_t = ctx.Output(framework::GradVarName("X2")); - auto* act_t = ctx.Output("Activated"); + auto* act_t = ctx.Input("Activated"); auto* d_out_t = ctx.Input(framework::GradVarName("Out")); auto* label_t = ctx.Input("Label"); - auto& dev = ctx.GetEigenDevice(); auto d_out = framework::EigenVector::Flatten(*d_out_t); auto act = framework::EigenVector::Flatten(*act_t); auto label = framework::EigenVector::Flatten(*label_t); + auto& dev = ctx.GetEigenDevice(); // compute d_x1 if (d_x1_t) { diff --git a/python/paddle/v2/framework/tests/test_margin_rank_loss_op.py b/python/paddle/v2/framework/tests/test_margin_rank_loss_op.py index 7118be7cc6f62a596f048de96f88899d81bb7f35..2eb96053414134044235827fc37daf031e20232d 100644 --- a/python/paddle/v2/framework/tests/test_margin_rank_loss_op.py +++ b/python/paddle/v2/framework/tests/test_margin_rank_loss_op.py @@ -8,23 +8,23 @@ class TestMarginRankLossOp(OpTest): self.op_type = "margin_rank_loss" batch_size = 5 margin = 0.1 - # labels_{i} = {0, 1.0} or {0, 0.5, 1.0} - label = np.random.randint(0, 2, size=(batch_size, )).astype("float32") - x1 = np.random.random((batch_size, )).astype("float32") - x2 = np.random.random((batch_size, )).astype("float32") + # labels_{i} = {-1, 1} + label = 2 * np.random.randint( + 0, 2, size=(batch_size, 1)).astype("float32") - 1 + x1 = np.random.random((batch_size, 1)).astype("float32") + x2 = np.random.random((batch_size, 1)).astype("float32") # loss = max(0, -label * (x1 - x2) + margin) - loss = [ - max(0, -label[i] * (x1[i] - x2[i]) + margin) - for i in range(batch_size) - ] + loss = -label * (x1 - x2) + margin + loss = np.where(loss > 0, loss, 0) + act = np.where(loss > 0, 1., 0.) + self.attrs = {'margin': margin} self.inputs = {'Label': label, 'X1': x1, 'X2': x2} - self.outputs = {'Out': loss} + self.outputs = {'Activated': act, 'Out': loss} def test_check_output(self): self.check_output() - """ def test_check_grad(self): self.check_grad(["X1", "X2"], "Out") @@ -33,7 +33,6 @@ class TestMarginRankLossOp(OpTest): def test_check_grad_ignore_x2(self): self.check_grad(["X1"], "Out", no_grad_set=set('X2')) - """ if __name__ == '__main__':