def __init__(self, sparse_label=True, batch_axis=0, ignore_label=-1,
size_average=True, **kwargs):
ignore_label=-1
这里的ignore_label
是-1
,这里是可以设置的,但是在SegmentationMetric
中是强制ignore_label
是-1
的,因此,如果要在SoftmaxCrossEntropyLoss
中不要忽略背景,而要在SegmentationMetric
中忽略背景,可以把读入数据的背景类别设置成 -1,然后在调用SoftmaxCrossEntropyLoss
中设置ignore_label
是0
softmaxout = F.SoftmaxOutput(pred, label, ignore_label)
pred
是 N x C x H x W,label 是 N x H x W- 这里的
label
即使对于计算softmaxout
本身是用不到的,但是 Backward 会用到;同理,ignore_label
也是对于计算softmaxout
本身是用不到,但是会让对应 label 的梯度为 0 - 得到的
softmaxout
也是 N x C x H x W
loss = -F.pick(F.log(softmaxout), label, axis=1, keepdims=True)
pick
函数,axis=1
指定了是对 C 挑选出 index(也就是 label)对应的 softmaxout 输出,由于keepdims=True
得到的loss
是 N x 1 x H x W
loss = F.where(label.expand_dims(axis=1) == self._ignore_label, F.zeros_like(loss), loss)
label.expand_dims(axis=1)
后的形状是 N x 1 x H x W,这么做是为了和形状同为 N x 1 x H x W 的 loss 可以一起用于 where 函数where(cond, A, B)
如果 cond 中的为 True,则选 A 中对应位置上的返回,否则选 B 对应位置上的- 这句代码也就是如果预测的是 ignored label,则令其 loss 为 0,否则就返回对应的 loss
- 从这里可以看出,如果是背景-前景二分类,那么令背景为 ignored 是不对的,那样网络只会往全部预测成前景的方向去优化,因为背景的 loss 被 ignore 了,所以在计算 loss 时,不可以将背景的 label 设置为 ignore label
F.mean(loss, axis=self._batch_axis, exclude=True)
self._batch_axis
默认是0
,对于 N x 1 x H x W 的 loss,求完均值后返回的大小为 N 的 Array,也就是只有 axis = 0 被保留下来了。
像 SSD 的 cls_pred
的大小是 B x N x (C + 1),cls_target
的大小是 B x N,box_targets
的大小是 B x N x 4,因此除非交换 axis,SSD 的分类损失是不可以直接调用 SoftmaxCrossEntropyLoss
的,因为 SoftmaxCrossEntropyLoss
是设置了 axis=1 是分类类别的 Channel,而 SSD 则是 axis = 2 才是分类的 Channel。
只要数据格式是 B x C [ x H x W ] 就可以直接用 SoftmaxCrossEntropyLoss
,SSD 的输出和标签不符合这个,所以不可以直接调用。