add keepdims option to SigmoidCrossEntropy
@@ -13,9 +13,10 @@ class SigmoidCrossEntropy(function.Function):
ignore_label = -1
- def __init__(self, use_cudnn=True, normalize=True):
+ def __init__(self, use_cudnn=True, normalize=True, keepdims=False):
self.use_cudnn = use_cudnn
self.normalize = normalize
+ self.keepdims = keepdims
def check_type_forward(self, in_types):
type_check.expect(in_types.size() == 2)
@@ -31,29 +32,40 @@ class SigmoidCrossEntropy(function.Function):
xp = cuda.get_array_module(*inputs)
x, t = inputs
self.ignore_mask = (t != self.ignore_label)
+
+ # stable computation of the cross entropy.
+ loss = -(
+ self.ignore_mask *
+ (x * (t - (x >= 0)) - xp.log1p(xp.exp(-xp.abs(x)))))
+
+ if self.keepdims:
+ return utils.force_array(loss.astype(x.dtype)),
+
if self.normalize:
count = xp.maximum(1, self.ignore_mask.sum())
else:
count = max(1, len(x))
self.count = count
- # stable computation of the cross entropy.
- loss = -xp.sum(
- self.ignore_mask * (x * (t - (x >= 0)) -
- xp.log1p(xp.exp(-xp.abs(x)))))
- return utils.force_array(xp.divide(loss, self.count, dtype=x.dtype)),
+
+ return utils.force_array(
+ xp.divide(xp.sum(loss), self.count, dtype=x.dtype)),
def backward(self, inputs, grad_outputs):
xp = cuda.get_array_module(*inputs)
x, t = inputs
gloss = grad_outputs[0]
y, = sigmoid.Sigmoid(self.use_cudnn).forward((x,))
+ if self.keepdims:
+ gx = (gloss * self.ignore_mask * (y - t)).astype(y.dtype)
+ else:
gx = xp.divide(
gloss * self.ignore_mask * (y - t), self.count,
dtype=y.dtype)
return gx, None
-def sigmoid_cross_entropy(x, t, use_cudnn=True, normalize=True):
+def sigmoid_cross_entropy(
+ x, t, use_cudnn=True, normalize=True, keepdims=False):
"""Computes cross entropy loss for pre-sigmoid activations.
Args:
@@ -77,4 +89,4 @@ def sigmoid_cross_entropy(x, t, use_cudnn=True, normalize=True):
This function is differentiable only by ``x``.
"""
- return SigmoidCrossEntropy(use_cudnn, normalize)(x, t)
+ return SigmoidCrossEntropy(use_cudnn, normalize, keepdims)(x, t)
