未验证 提交 e5a62493 编写于 作者: C chajchaj 提交者: GitHub

Enhance error message of cross_entropy_op, sigmoid_cross_entropy_with_logits_op (#24485)

* error message of cross_entropy_op, test=develop
* fix bug : can't use platform::errors::InvalidArgument in HOSTDEVICE, test=develop
* fix bug: recovery the check_variable_and_dtype for rank_loss and bpr_loss, test=develop
上级 aa02e347
...@@ -25,12 +25,9 @@ class CrossEntropyOpBase : public framework::OperatorWithKernel { ...@@ -25,12 +25,9 @@ class CrossEntropyOpBase : public framework::OperatorWithKernel {
using framework::OperatorWithKernel::OperatorWithKernel; using framework::OperatorWithKernel::OperatorWithKernel;
void InferShape(framework::InferShapeContext* ctx) const override { void InferShape(framework::InferShapeContext* ctx) const override {
PADDLE_ENFORCE_EQ(ctx->HasInput("X"), true, "Input(X) should be not null."); OP_INOUT_CHECK(ctx->HasInput("X"), "Input", "X", "CrossEntropy");
PADDLE_ENFORCE_EQ(ctx->HasInput("Label"), true, OP_INOUT_CHECK(ctx->HasInput("Label"), "Input", "Label", "CrossEntropy");
"Input(Label) should be not null."); OP_INOUT_CHECK(ctx->HasOutput("Y"), "Output", "Y", "CrossEntropy");
PADDLE_ENFORCE_EQ(ctx->HasOutput("Y"), true,
"Output(Y) should be not null.");
auto x_dims = ctx->GetInputDim("X"); auto x_dims = ctx->GetInputDim("X");
auto label_dims = ctx->GetInputDim("Label"); auto label_dims = ctx->GetInputDim("Label");
...@@ -44,53 +41,61 @@ class CrossEntropyOpBase : public framework::OperatorWithKernel { ...@@ -44,53 +41,61 @@ class CrossEntropyOpBase : public framework::OperatorWithKernel {
PADDLE_ENFORCE_EQ( PADDLE_ENFORCE_EQ(
framework::slice_ddim(x_dims, 0, rank - 1), framework::slice_ddim(x_dims, 0, rank - 1),
framework::slice_ddim(label_dims, 0, rank - 1), framework::slice_ddim(label_dims, 0, rank - 1),
"ShapeError: Input(X) and Input(Label) shall have the same shape " platform::errors::InvalidArgument(
"except the last dimension. But received: the shape of Input(X) is " "Input(X) and Input(Label) shall have the same shape "
"[%s]," "except the last dimension. But received: the shape of Input(X) "
"the shape of Input(Label) is [%s].", "is "
x_dims, label_dims); "[%s], the shape of Input(Label) is [%s].",
x_dims, label_dims));
} }
if (IsSoftLabel(ctx)) { if (IsSoftLabel(ctx)) {
PADDLE_ENFORCE_EQ( PADDLE_ENFORCE_EQ(
rank, label_dims.size(), rank, label_dims.size(),
"ShapeError: If Attr(soft_label) == true, Input(X) and Input(Label) " platform::errors::InvalidArgument(
"shall have the same dimensions. But received: the dimensions of " "If Attr(soft_label) == true, Input(X) and Input(Label) "
"Input(X) is [%d]," "shall have the same dimensions. But received: the dimensions of "
"the shape of Input(X) is [%s], the dimensions of Input(Label) is " "Input(X) is [%d],"
"[%d], the shape of" "the shape of Input(X) is [%s], the dimensions of Input(Label) "
"Input(Label) is [%s]", "is "
rank, x_dims, label_dims.size(), label_dims); "[%d], the shape of"
"Input(Label) is [%s]",
rank, x_dims, label_dims.size(), label_dims));
if (check) { if (check) {
PADDLE_ENFORCE_EQ( PADDLE_ENFORCE_EQ(
x_dims[rank - 1], label_dims[rank - 1], x_dims[rank - 1], label_dims[rank - 1],
"ShapeError: If Attr(soft_label) == true, the last dimension of " platform::errors::InvalidArgument(
"Input(X) and Input(Label) should be equal. But received: the" "If Attr(soft_label) == true, the last dimension of "
"last dimension of Input(X) is [%d], the shape of Input(X) is [%s]," "Input(X) and Input(Label) should be equal. But received: the"
"the last dimension of Input(Label) is [%d], the shape of " "last dimension of Input(X) is [%d], the shape of Input(X) is "
"Input(Label)" "[%s],"
"is [%s], the last dimension is [%d].", "the last dimension of Input(Label) is [%d], the shape of "
x_dims[rank - 1], x_dims, label_dims[rank - 1], label_dims, "Input(Label)"
rank - 1); "is [%s], the last dimension is [%d].",
x_dims[rank - 1], x_dims, label_dims[rank - 1], label_dims,
rank - 1));
} }
} else { } else {
if (rank == label_dims.size()) { if (rank == label_dims.size()) {
PADDLE_ENFORCE_EQ( PADDLE_ENFORCE_EQ(
label_dims[rank - 1], 1UL, label_dims[rank - 1], 1UL,
"ShapeError: the last dimension of Input(Label) should be 1." platform::errors::InvalidArgument(
"But received: the last dimension of Input(Label) is [%d]," "the last dimension of Input(Label) should be 1."
"the last dimension is [%d]", "But received: the last dimension of Input(Label) is [%d],"
label_dims[rank - 1], rank - 1); "the last dimension is [%d]",
label_dims[rank - 1], rank - 1));
} else { } else {
PADDLE_ENFORCE_EQ(rank, label_dims.size() + 1, PADDLE_ENFORCE_EQ(
"ShapeError: The rank of Input(X) should be equal to " rank, label_dims.size() + 1,
"Input(Label) plus 1." platform::errors::InvalidArgument(
"But received: The dimension of Input(X) is [%d], " "ShapeError: The rank of Input(X) should be equal to "
"the shape of Input(X) is [%s]," "Input(Label) plus 1."
"the dimension of Input(Label) is [%d], the shape of " "But received: The dimension of Input(X) is [%d], "
"Input(Label) is [%s]", "the shape of Input(X) is [%s],"
rank, x_dims, label_dims.size(), label_dims); "the dimension of Input(Label) is [%d], the shape of "
"Input(Label) is [%s]",
rank, x_dims, label_dims.size(), label_dims));
} }
} }
...@@ -122,19 +127,23 @@ class CrossEntropyGradientOpBase : public framework::OperatorWithKernel { ...@@ -122,19 +127,23 @@ class CrossEntropyGradientOpBase : public framework::OperatorWithKernel {
using framework::OperatorWithKernel::OperatorWithKernel; using framework::OperatorWithKernel::OperatorWithKernel;
void InferShape(framework::InferShapeContext* ctx) const { void InferShape(framework::InferShapeContext* ctx) const {
PADDLE_ENFORCE_EQ(ctx->HasInput("Label"), true, OP_INOUT_CHECK(ctx->HasInput("Label"), "Input", "Label",
"Input(Label) should be not null."); "CrossEntropyGradientOpBase");
PADDLE_ENFORCE_EQ(ctx->HasInput(framework::GradVarName("Y")), true, OP_INOUT_CHECK(ctx->HasInput(framework::GradVarName("Y")), "Input",
"Input(Y@GRAD) shoudl be not null."); framework::GradVarName("Y"), "CrossEntropyGradientOpBase");
PADDLE_ENFORCE_EQ(ctx->HasOutput(framework::GradVarName("X")), true, OP_INOUT_CHECK(ctx->HasOutput(framework::GradVarName("X")), "Output",
"Output(X@GRAD) should be not null."); framework::GradVarName("X"), "CrossEntropyGradientOpBase");
auto x_dims = GetXDim(ctx); auto x_dims = GetXDim(ctx);
auto label_dims = ctx->GetInputDim("Label"); auto label_dims = ctx->GetInputDim("Label");
auto dy_dims = ctx->GetInputDim(framework::GradVarName("Y")); auto dy_dims = ctx->GetInputDim(framework::GradVarName("Y"));
int rank = x_dims.size(); int rank = x_dims.size();
PADDLE_ENFORCE_EQ(dy_dims.size(), label_dims.size(), PADDLE_ENFORCE_EQ(
"Input(Y@Grad) and Input(Y) should have the same rank."); dy_dims.size(), label_dims.size(),
platform::errors::InvalidArgument(
"Input(Y@Grad) and Input(Y) should have the same rank."
"But received: Y@Grad's rank is [%d], Y's rank is [%d]",
dy_dims.size(), label_dims.size()));
bool check = true; bool check = true;
if ((!ctx->IsRuntime()) && if ((!ctx->IsRuntime()) &&
...@@ -143,10 +152,15 @@ class CrossEntropyGradientOpBase : public framework::OperatorWithKernel { ...@@ -143,10 +152,15 @@ class CrossEntropyGradientOpBase : public framework::OperatorWithKernel {
} }
if (check) { if (check) {
PADDLE_ENFORCE_EQ(framework::slice_ddim(x_dims, 0, rank - 1), PADDLE_ENFORCE_EQ(
framework::slice_ddim(dy_dims, 0, rank - 1), framework::slice_ddim(x_dims, 0, rank - 1),
"The Input(X) and Input(Y@Grad) should have the same " framework::slice_ddim(dy_dims, 0, rank - 1),
"shape except the last dimension."); platform::errors::InvalidArgument(
"The Input(X) and Input(Y@Grad) should have the same "
"shape except the last dimension. but received: "
"the shape of Input(X) is [%s], "
"the shape of Input(Y@Grad) is [%s].",
x_dims, dy_dims));
} }
ctx->SetOutputDim(framework::GradVarName("X"), x_dims); ctx->SetOutputDim(framework::GradVarName("X"), x_dims);
...@@ -253,7 +267,7 @@ class CrossEntropyGradientOp : public CrossEntropyGradientOpBase { ...@@ -253,7 +267,7 @@ class CrossEntropyGradientOp : public CrossEntropyGradientOpBase {
using CrossEntropyGradientOpBase::CrossEntropyGradientOpBase; using CrossEntropyGradientOpBase::CrossEntropyGradientOpBase;
void InferShape(framework::InferShapeContext* ctx) const override { void InferShape(framework::InferShapeContext* ctx) const override {
PADDLE_ENFORCE_EQ(ctx->HasInput("X"), true, "Input(X) should be not null."); OP_INOUT_CHECK(ctx->HasInput("X"), "Input", "X", "CrossEntropyGradientOp");
CrossEntropyGradientOpBase::InferShape(ctx); CrossEntropyGradientOpBase::InferShape(ctx);
} }
}; };
...@@ -281,11 +295,10 @@ class CrossEntropyOp2 : public CrossEntropyOpBase { ...@@ -281,11 +295,10 @@ class CrossEntropyOp2 : public CrossEntropyOpBase {
void InferShape(framework::InferShapeContext* ctx) const override { void InferShape(framework::InferShapeContext* ctx) const override {
CrossEntropyOpBase::InferShape(ctx); CrossEntropyOpBase::InferShape(ctx);
PADDLE_ENFORCE_EQ(ctx->HasOutput("XShape"), true, OP_INOUT_CHECK(ctx->HasOutput("XShape"), "Output", "XShape",
"Output(XShape) should be not null."); "CrossEntropyOp2");
OP_INOUT_CHECK(ctx->HasOutput("MatchX"), "Output", "MatchX",
PADDLE_ENFORCE_EQ(ctx->HasOutput("MatchX"), true, "CrossEntropyOp2");
"Output(MatchX) should be not null.");
auto x_dims = ctx->GetInputDim("X"); auto x_dims = ctx->GetInputDim("X");
auto x_dims_vec = framework::vectorize(x_dims); auto x_dims_vec = framework::vectorize(x_dims);
x_dims_vec.push_back(0); x_dims_vec.push_back(0);
...@@ -305,8 +318,8 @@ class CrossEntropyGradientOp2 : public CrossEntropyGradientOpBase { ...@@ -305,8 +318,8 @@ class CrossEntropyGradientOp2 : public CrossEntropyGradientOpBase {
public: public:
using CrossEntropyGradientOpBase::CrossEntropyGradientOpBase; using CrossEntropyGradientOpBase::CrossEntropyGradientOpBase;
void InferShape(framework::InferShapeContext* ctx) const override { void InferShape(framework::InferShapeContext* ctx) const override {
PADDLE_ENFORCE_EQ(ctx->HasInput("MatchX"), true, OP_INOUT_CHECK(ctx->HasInput("MatchX"), "Input", "MatchX",
"Input(MatchX) must exist"); "CrossEntropyGradientOp2");
CrossEntropyGradientOpBase::InferShape(ctx); CrossEntropyGradientOpBase::InferShape(ctx);
} }
......
...@@ -166,11 +166,14 @@ struct HardLabelCrossEntropyForwardFunctor { ...@@ -166,11 +166,14 @@ struct HardLabelCrossEntropyForwardFunctor {
HOSTDEVICE void operator()(int64_t idx) const { HOSTDEVICE void operator()(int64_t idx) const {
auto label = label_[idx]; auto label = label_[idx];
if (label != ignore_index_) { if (label != ignore_index_) {
// don't update to PADDLE_ENFORCE_GE and PADDLE_ENFORCE_LT cause
// can't use platform::errors::InvalidArgument in HOSTDEVICE
PADDLE_ENFORCE(label >= 0 && label < feature_size_, PADDLE_ENFORCE(label >= 0 && label < feature_size_,
"Variable value (label) of " "Variable value (label) of "
"OP(fluid.layers.cross_entropy) expected >= 0 " "OP(fluid.layers.cross_entropy) expected >= 0 "
"and < %ld, but got %ld. Please check label value.", "and < %ld, but got %ld. Please check label value.",
feature_size_, label); feature_size_, label);
auto match_x = x_[idx * feature_size_ + label]; auto match_x = x_[idx * feature_size_ + label];
y_[idx] = -math::TolerableValue<T>()(real_log(match_x)); y_[idx] = -math::TolerableValue<T>()(real_log(match_x));
match_x_[idx] = match_x; match_x_[idx] = match_x;
......
...@@ -28,16 +28,24 @@ class SigmoidCrossEntropyWithLogitsOp : public framework::OperatorWithKernel { ...@@ -28,16 +28,24 @@ class SigmoidCrossEntropyWithLogitsOp : public framework::OperatorWithKernel {
using framework::OperatorWithKernel::OperatorWithKernel; using framework::OperatorWithKernel::OperatorWithKernel;
void InferShape(framework::InferShapeContext* ctx) const override { void InferShape(framework::InferShapeContext* ctx) const override {
PADDLE_ENFORCE(ctx->HasInput("X"), "Input(X) should be not null."); OP_INOUT_CHECK(ctx->HasInput("X"), "Input", "X",
PADDLE_ENFORCE(ctx->HasInput("Label"), "Input(Label) should be not null."); "SigmoidCrossEntropyWithLogitsOp");
PADDLE_ENFORCE(ctx->HasOutput("Out"), "Output(Out) should be not null."); OP_INOUT_CHECK(ctx->HasInput("Label"), "Input", "Label",
"SigmoidCrossEntropyWithLogitsOp");
OP_INOUT_CHECK(ctx->HasOutput("Out"), "Output", "Out",
"SigmoidCrossEntropyWithLogitsOp");
auto x_dims = ctx->GetInputDim("X"); auto x_dims = ctx->GetInputDim("X");
auto labels_dims = ctx->GetInputDim("Label"); auto labels_dims = ctx->GetInputDim("Label");
int rank = x_dims.size(); int rank = x_dims.size();
PADDLE_ENFORCE_EQ(rank, labels_dims.size(), PADDLE_ENFORCE_EQ(rank, labels_dims.size(),
"Input(X) and Input(Label) shall have the same rank."); platform::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, labels_dims.size()));
bool check = true; bool check = true;
if ((!ctx->IsRuntime()) && (framework::product(x_dims) <= 0 || if ((!ctx->IsRuntime()) && (framework::product(x_dims) <= 0 ||
framework::product(labels_dims) <= 0)) { framework::product(labels_dims) <= 0)) {
...@@ -45,10 +53,14 @@ class SigmoidCrossEntropyWithLogitsOp : public framework::OperatorWithKernel { ...@@ -45,10 +53,14 @@ class SigmoidCrossEntropyWithLogitsOp : public framework::OperatorWithKernel {
} }
if (check) { if (check) {
PADDLE_ENFORCE_EQ(framework::slice_ddim(x_dims, 0, rank), PADDLE_ENFORCE_EQ(
framework::slice_ddim(labels_dims, 0, rank), framework::slice_ddim(x_dims, 0, rank),
"Input(X) and Input(Label) shall have the same shape " framework::slice_ddim(labels_dims, 0, rank),
"except the last dimension."); platform::errors::InvalidArgument(
"Input(X) and Input(Label) shall have the same shape "
"except the last dimension. But received: the shape of "
"Input(X) is [%s], the shape of Input(Label) is [%s].",
x_dims, labels_dims));
} }
ctx->ShareDim("X", /*->*/ "Out"); ctx->ShareDim("X", /*->*/ "Out");
...@@ -62,12 +74,16 @@ class SigmoidCrossEntropyWithLogitsGradOp ...@@ -62,12 +74,16 @@ class SigmoidCrossEntropyWithLogitsGradOp
using framework::OperatorWithKernel::OperatorWithKernel; using framework::OperatorWithKernel::OperatorWithKernel;
void InferShape(framework::InferShapeContext* ctx) const override { void InferShape(framework::InferShapeContext* ctx) const override {
PADDLE_ENFORCE(ctx->HasInput("X"), "Input(X) should be not null."); OP_INOUT_CHECK(ctx->HasInput("X"), "Input", "X",
PADDLE_ENFORCE(ctx->HasInput("Label"), "Input(Label) should be not null."); "SigmoidCrossEntropyWithLogitsGradOp");
PADDLE_ENFORCE(ctx->HasInput(framework::GradVarName("Out")), OP_INOUT_CHECK(ctx->HasInput("Label"), "Input", "Label",
"Input(Out@GRAD) shoudl be not null."); "SigmoidCrossEntropyWithLogitsGradOp");
PADDLE_ENFORCE(ctx->HasOutput(framework::GradVarName("X")), OP_INOUT_CHECK(ctx->HasInput(framework::GradVarName("Out")), "Input",
"Output(X@GRAD) should be not null."); framework::GradVarName("Out"),
"SigmoidCrossEntropyWithLogitsGradOp");
OP_INOUT_CHECK(ctx->HasOutput(framework::GradVarName("X")), "Output",
framework::GradVarName("X"),
"SigmoidCrossEntropyWithLogitsGradOp");
auto x_dims = ctx->GetInputDim("X"); auto x_dims = ctx->GetInputDim("X");
auto labels_dims = ctx->GetInputDim("Label"); auto labels_dims = ctx->GetInputDim("Label");
...@@ -81,14 +97,23 @@ class SigmoidCrossEntropyWithLogitsGradOp ...@@ -81,14 +97,23 @@ class SigmoidCrossEntropyWithLogitsGradOp
} }
if (check) { if (check) {
PADDLE_ENFORCE_EQ(framework::slice_ddim(x_dims, 0, rank), PADDLE_ENFORCE_EQ(
framework::slice_ddim(labels_dims, 0, rank), framework::slice_ddim(x_dims, 0, rank),
"Input(X) and Input(Label) shall have the same shape."); framework::slice_ddim(labels_dims, 0, rank),
platform::errors::InvalidArgument(
"Input(X) and Input(Label) shall have the same shape "
"except the last dimension. But received: the shape of "
"Input(X) is [%s], the shape of Input(Label) is [%s].",
x_dims, labels_dims));
PADDLE_ENFORCE_EQ( PADDLE_ENFORCE_EQ(
framework::slice_ddim(x_dims, 0, rank), framework::slice_ddim(x_dims, 0, rank),
framework::slice_ddim(dout_dims, 0, rank), framework::slice_ddim(dout_dims, 0, rank),
"Input(X) and Input(Out@Grad) shall have the same shape."); platform::errors::InvalidArgument(
"Input(X) and Input(Out@Grad) shall have the same shape "
"except the last dimension. 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->SetOutputDim(framework::GradVarName("X"), x_dims);
......
...@@ -1410,9 +1410,14 @@ def sigmoid_cross_entropy_with_logits(x, ...@@ -1410,9 +1410,14 @@ def sigmoid_cross_entropy_with_logits(x,
${comment} ${comment}
Args: Args:
x(${x_type}): ${x_comment} x(Variable): a 2-D tensor with shape N x D, where N is the batch size and
label(${label_type}): ${label_comment} D is the number of classes. This input is a tensor of logits computed
ignore_index(int): ${ignore_index_comment} by the previous operator. Logits are unscaled log probabilities given
as log(p/(1-p)) The data type should be float32 or float64.
label (Variable): a 2-D tensor of the same type and shape as X.
This input is a tensor of probabalistic labels for each logit.
ignore_index(int): Specifies a target value that is ignored and
does not contribute to the input gradient.
name(str|None): The default value is None. Normally there is name(str|None): The default value is None. Normally there is
no need for user to set this property. For more information, no need for user to set this property. For more information,
please refer to :ref:`api_guide_Name` please refer to :ref:`api_guide_Name`
...@@ -1437,6 +1442,8 @@ def sigmoid_cross_entropy_with_logits(x, ...@@ -1437,6 +1442,8 @@ def sigmoid_cross_entropy_with_logits(x,
normalize=True) # or False normalize=True) # or False
# loss = fluid.layers.reduce_sum(loss) # summation of loss # loss = fluid.layers.reduce_sum(loss) # summation of loss
""" """
check_variable_and_dtype(x, 'input', ['float16', 'float32', 'float64'],
'sigmoid_cross_entropy_with_logits')
helper = LayerHelper("sigmoid_cross_entropy_with_logits", **locals()) helper = LayerHelper("sigmoid_cross_entropy_with_logits", **locals())
......
...@@ -20,6 +20,8 @@ from scipy.special import logit ...@@ -20,6 +20,8 @@ from scipy.special import logit
from scipy.special import expit from scipy.special import expit
import paddle.fluid.core as core import paddle.fluid.core as core
import unittest import unittest
from paddle.fluid import compiler, Program, program_guard
import paddle.fluid as fluid
class TestSigmoidCrossEntropyWithLogitsOp1(OpTest): class TestSigmoidCrossEntropyWithLogitsOp1(OpTest):
...@@ -242,5 +244,31 @@ class TestSigmoidCrossEntropyWithLogitsOp6(OpTest): ...@@ -242,5 +244,31 @@ class TestSigmoidCrossEntropyWithLogitsOp6(OpTest):
self.check_grad(['X'], 'Out') self.check_grad(['X'], 'Out')
class TestSigmoidCrossEntropyWithLogitsOpError(unittest.TestCase):
def test_errors(self):
with program_guard(Program(), Program()):
def test_Variable():
# the input of sigmoid_cross_entropy_with_logits must be Variable.
x1 = fluid.create_lod_tensor(
np.array([-1, 3, 5, 5]), [[1, 1, 1, 1]], fluid.CPUPlace())
lab1 = fluid.create_lod_tensor(
np.array([-1, 3, 5, 5]), [[1, 1, 1, 1]], fluid.CPUPlace())
fluid.layers.sigmoid_cross_entropy_with_logits(x1, lab1)
self.assertRaises(TypeError, test_Variable)
def test_dtype():
# the input dtype of sigmoid_cross_entropy_with_logits must be float16 or float32 or float64
# float16 only can be set on GPU place
x2 = fluid.layers.data(
name='x2', shape=[3, 4, 5, 6], dtype="int32")
lab2 = fluid.layers.data(
name='lab2', shape=[3, 4, 5, 6], dtype="int32")
fluid.layers.sigmoid_cross_entropy_with_logits(x2, lab2)
self.assertRaises(TypeError, test_dtype)
if __name__ == '__main__': if __name__ == '__main__':
unittest.main() unittest.main()
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册