首页 Paddle框架 帖子详情
ISSUE:F.binary_cross_entropy_with_logits 错误 已解决
收藏
快速回复
Paddle框架 其他深度学习 1275 4
ISSUE:F.binary_cross_entropy_with_logits 错误 已解决
收藏
快速回复
Paddle框架 其他深度学习 1275 4

我在复现教程 https://www.paddlepaddle.org.cn/tutorials/projectdetail/2200757 在使用LeNet做2分类任务时发现了一个关于 F.binary_cross_entropy_with_logits 函数的错误。具体地,在执行loss =loss_func(predicts, labels)这一步时报错,其中:

loss_func = F.binary_cross_entropy_with_logits

>>> predicts

Tensor(shape=[16, 2], dtype=float32, place=CUDAPlace(0), stop_gradient=False,
[[-0.98617983, -0.32807556],
[-0.98647952, -0.32846922],
[-0.98505223, -0.32609159],
[-0.98462701, -0.32401377],
[-0.98319340, -0.32233417],
[-0.98485214, -0.33011013],
[-0.98596299, -0.32521594],
[-0.98411733, -0.32351846],
[-0.98307610, -0.32719469],
[-0.98402691, -0.32211584],
[-0.98657179, -0.32506210],
[-0.98671150, -0.32411507],
[-0.98507845, -0.32603347],
[-0.98604727, -0.32774526],
[-0.98620296, -0.32551673],
[-0.98661911, -0.32729667]])

>>> labels

Tensor(shape=[16, 1], dtype=int64, place=CUDAPlace(0), stop_gradient=True,
[[1],
[1],
[1],
[0],
[1],
[1],
[0],
[1],
[0],
[0],
[0],
[0],
[1],
[1],
[1],
[1]])

报的错为:

Traceback (most recent call last):
File "/opt/pycharm-community-2021.2.2/plugins/python-ce/helpers/pydev/_pydevd_bundle/pydevd_exec2.py", line 3, in Exec
exec(exp, global_vars, local_vars)
File "", line 1, in
File "/home/yu/anaconda3/envs/BostonHouse/lib/python3.8/site-packages/paddle/nn/functional/loss.py", line 256, in binary_cross_entropy_with_logits
out = core.ops.sigmoid_cross_entropy_with_logits(logit, label)
ValueError: (InvalidArgument) The DataType of sigmoid_cross_entropy_with_logits Op's duplicable Variable X must be consistent. The current variable type is (float), but the previous variable type is (int64_t). (at /paddle/paddle/fluid/framework/operator.cc:1579)
[operator < sigmoid_cross_entropy_with_logits > error]

然后我又尝试了:

>>> loss = loss_func(predicts, labels.astype('float32'))

Traceback (most recent call last):
File "/opt/pycharm-community-2021.2.2/plugins/python-ce/helpers/pydev/_pydevd_bundle/pydevd_exec2.py", line 3, in Exec
exec(exp, global_vars, local_vars)
File "", line 1, in
File "/home/yu/anaconda3/envs/BostonHouse/lib/python3.8/site-packages/paddle/nn/functional/loss.py", line 256, in binary_cross_entropy_with_logits
out = core.ops.sigmoid_cross_entropy_with_logits(logit, label)
ValueError: (InvalidArgument) Input(X) and Input(Label) shall have the same shape except the last dimension. But received: the shape of Input(X) is [16, 2], the shape of Input(Label) is [16, 1].
[Hint: Expected framework::slice_ddim(x_dims, 0, rank) == framework::slice_ddim(labels_dims, 0, rank), but received framework::slice_ddim(x_dims, 0, rank):16, 2 != framework::slice_ddim(labels_dims, 0, rank):16, 1.] (at /paddle/paddle/fluid/operators/sigmoid_cross_entropy_with_logits_op.cc:63)
[operator < sigmoid_cross_entropy_with_logits > error]

能看到这次报的错为输入X和Label的shape不一致,但是其中又说“Input(X) and Input(Label) shall have the same shape except the last dimension.”而我的X.shape为[16,2],Label.shape为[16,1],这个按说是符合要求的。这就是我要issue的问题,请解决!

我又尝试了loss = F.cross_entropy(predicts, labels),这句话是可以正常执行的。

我又尝试了loss = F.binary_cross_entropy_with_logits(predicts[0:1], paddle.to_tensor([0,1]).reshape([1,2]).astype('float32')),这句话可以正常执行。

因此我觉得,F.cross_entropy函数内在地把int64多类标签转换为float32类型的one-hot向量, F.binary_cross_entropy_with_logits函数在设计上也考虑了这一点,但是却没有去实现这个功能,导致起报错的原因和实际的执行结果不一致。希望paddle开发团队解决这个bug。

三岁
已解决
2# 回复于2021-11
建议去paddle的GitHub进行回复
0
收藏
回复
全部评论(4)
时间顺序
三岁
#2 回复于2021-11

建议去paddle的GitHub进行回复

0
回复
李长安
#3 回复于2021-11

我也遇到过相似的,你可以看一下binary_cross_entropy_with_logits的API

0
回复
小白羊heaven
#4 回复于2021-11

所以大佬是杂解决的?看api, 要求label是float 类型

0
回复
走向梦想偶偶
#5 回复于2021-11

问题已解决:我认为这确实是paddlepaddle的F.binary_cross_entropy_with_logits函数实现的一个潜在bug——函数本身可以使用,只不过它本应该支持的一个功能,实际上却不支持。

解决这个问题的方法很简单:对于两类分类问题,网络最后全连接层的输出如果是2个数,则可以用F.cross_entropy函数来计算损失。但是其实这时候可以让全连接层只输出一个数值(这个值经过sigmoid后就变成了正样本的概率,相应的,负样本概率就是1减去它),没必要让网络输出两个数值。

这是我的一部分代码(经测试正常使用):

def train(model, optimizer=None, epoch_num=2, batch_size=16, log_dir='./log', loss_func=F.cross_entropy, acc_func=paddle.metric.accuracy):

训练函数中,默认为2分类问题输出2个值,则用F.cross_entropy来计算损失,用paddle.metric.accuracy来计算分类精度。

def loss_logistic_regression_1d(input, label):
# Calc cross-entropy-loss, when the classifier is binary (output of classifier is a single float32 for each sample)
assert (input.shape[0] == label.shape[0] and input.shape[1] == 1 and label.shape[1] == 1 and
input.dtype == paddle.float32 and label.dtype == paddle.int64)
loss = F.binary_cross_entropy_with_logits(input, label.astype('float32'))
return loss

当网络输出只有一个值时,我自己定义了一个损失函数loss_logistic_regression_1d。

def accuracy_logistic_regression_1d(input, label):
# Calc classification accuracy, when the classifier is binary (output of classifier is a single float32 for each sample)
assert(input.shape[0] == label.shape[0] and input.shape[1] == 1 and label.shape[1] == 1 and
input.dtype == paddle.float32 and label.dtype == paddle.int64)
input = F.sigmoid(input) # transform the output of fully-connected-layer to a probability in [0,1]
# Method 1.
# pred = paddle.concat([1.0-input, input],axis=1) # [N,2], the first col is probability of class 0, the second is prob of class 1
# acc = paddle.metric.accuracy(pred, label) # percentage of correct predictions (obtained by argmax of the predictions)
# Method 2. 两种方法产生一致的结果
pred_labels = input > 0.5 # >0.5 corresponds to prob of class 1, <=0.5 corresponds to prob of class 0
is_correct = pred_labels == (label == 1)
num_corrects = paddle.sum(is_correct.astype('int32'))
acc = num_corrects.astype('float32') / len(label)
return acc

当网络输出只有一个值时,我自己定义了一个分类精度计算函数accuracy_logistic_regression_1d。其中用两种等价的方法来计算精度,可能Method 2更直观一些。

 

0
回复
需求/bug反馈?一键提issue告诉我们
发现bug?如果您知道修复办法,欢迎提pr直接参与建设飞桨~
在@后输入用户全名并按空格结束,可艾特全站任一用户