我遇到了一个有趣且令人沮丧的问题,即使用 Unet 进行图像分割时使用的 Dice 损失。
我必须将图像分为两类:背景和感兴趣区域。感兴趣区域通常是整个图像像素的 4%。图片大约为 1600x1600 像素。 我发现 Dice 损失比交叉熵更有效。 但是,如果我使用标准的 Dice 损失公式,我的 Unet 不会提供正确的输出,即所有像素都被预测为背景。
标准骰子损失我的意思是:
其中 x_{c,i} 是 Unet 为像素 i 和通道 c 预测的概率,y_{c,i} 是相应的真实标签。 我使用的修改版本是:
注意分母处的平方 x。
出于某种原因,后一个使网络产生正确的输出,尽管损失收敛到~0.5。
我不明白为什么后者有效而前者无效。即使我在分母处使用三的幂,后者也有效。
下面是我的实现:
def make_one_hot(labels, classes):
one_hot = torch.FloatTensor(labels.size()[0], classes, labels.size()[2], labels.size()[3]).zero_().to(labels.device)
target = one_hot.scatter_(1, labels.data, 1)
return target
class DiceLoss(nn.Module):
def __init__(self,):
super(DiceLoss, self).__init__()
def forward(self, output, target):
target = make_one_hot(target.unsqueeze(dim=1), classes=output.size()[1])
output = F.softmax(output, dim=1)
numerator = (output * target).sum(dim=(2, 3))
denominator = output.pow(2).sum(dim=(2, 3)) + target.sum(dim=(2, 3))
iou = numerator / denominator
return 1 - iou.mean()
Milletari 等人。当他们在V-Net的论文中提出这个时,已经解释了这一点。他们认为 ROI 可能只占据整个扫描的非常小的区域,这很可能会偏向背景。既然你说你的投资回报率大约是整个图像的 4%,也许你正面临类似的问题。