幾種分割loss

來源:互聯網
上載者:User
1 2d交叉熵(mutil class 分割)

定義

def cross_entropy2d(input, target, weight=None, size_average=True):    # input: (n, c, h, w), target: (n, h, w)    n, c, h, w = input.size()    # log_p: (n, c, h, w)    if LooseVersion(torch.__version__) < LooseVersion('0.3'):        # ==0.2.X        log_p = F.log_softmax(input)    else:        # >=0.3        log_p = F.log_softmax(input, dim=1)    # log_p: (n*h*w, c)    log_p = log_p.transpose(1, 2).transpose(2, 3).contiguous()    log_p = log_p[target.view(n, h, w, 1).repeat(1, 1, 1, c) >= 0]    log_p = log_p.view(-1, c)    # target: (n*h*w,)    mask = target >= 0    target = target[mask]    loss = F.nll_loss(log_p, target, weight=weight, size_average=False)    if size_average:        loss /= mask.data.sum()    return loss

使用

            data, target = Variable(data, volatile=True), Variable(target)            score = self.model(data)            loss = cross_entropy2d(score, target,                                   size_average=self.size_average)            if np.isnan(float(loss.data[0])):                raise ValueError('loss is nan while validating')            val_loss += float(loss.data[0]) / len(data)            imgs = data.data.cpu()            lbl_pred = score.data.max(1)[1].cpu().numpy()[:, :, :]            lbl_true = target.data.cpu()

其他metrics

metrics = label_accuracy_score(label_trues, label_preds, n_class)import numpy as npdef _fast_hist(label_true, label_pred, n_class):    mask = (label_true >= 0) & (label_true < n_class)    hist = np.bincount(        n_class * label_true[mask].astype(int) +        label_pred[mask], minlength=n_class ** 2).reshape(n_class, n_class)    return histdef label_accuracy_score(label_trues, label_preds, n_class):    """Returns accuracy score evaluation result.      - overall accuracy      - mean accuracy      - mean IU      - fwavacc    """    hist = np.zeros((n_class, n_class))    for lt, lp in zip(label_trues, label_preds):        hist += _fast_hist(lt.flatten(), lp.flatten(), n_class)    acc = np.diag(hist).sum() / hist.sum()    acc_cls = np.diag(hist) / hist.sum(axis=1)    acc_cls = np.nanmean(acc_cls)    iu = np.diag(hist) / (hist.sum(axis=1) + hist.sum(axis=0) - np.diag(hist))    mean_iu = np.nanmean(iu)    freq = hist.sum(axis=1) / hist.sum()    fwavacc = (freq[freq > 0] * iu[freq > 0]).sum()    return acc, acc_cls, mean_iu, fwavacc

https://github.com/wkentaro/pytorch-fcn 2 bce loss

            criterion = nn.BCELoss()            y_pred = net(X)            probs = F.sigmoid(y_pred)            probs_flat = probs.view(-1)            y_flat = y.view(-1)            loss = criterion(probs_flat, y_flat.float())            epoch_loss += loss.data[0]            print('{0:.4f} --- loss: {1:.6f}'.format(i * batch_size / N_train,                                                     loss.data[0]))            optimizer.zero_grad()            loss.backward()            optimizer.step()

評估的時候又選擇dice loss 這是啥原因。

import torchfrom torch.autograd import Function, Variableclass DiceCoeff(Function):    """Dice coeff for individual examples"""    def forward(self, input, target):        self.save_for_backward(input, target)        self.inter = torch.dot(input, target) + 0.0001        self.union = torch.sum(input) + torch.sum(target) + 0.0001        t = 2 * self.inter.float() / self.union.float()        return t    # This function has only a single output, so it gets only one gradient    def backward(self, grad_output):        input, target = self.saved_variables        grad_input = grad_target = None        if self.needs_input_grad[0]:            grad_input = grad_output * 2 * (target * self.union + self.inter) \                         / self.union * self.union        if self.needs_input_grad[1]:            grad_target = None        return grad_input, grad_targetdef eval_net():        ...        y_pred = net(X)        y_pred = (F.sigmoid(y_pred) > 0.6).float()        # y_pred = F.sigmoid(y_pred).float()        dice = dice_coeff(y_pred, y.float()).data[0]        ...

預測

        X = torch.FloatTensor(X).unsqueeze(0)        y = torch.ByteTensor(y).unsqueeze(0)        if gpu:            X = Variable(X, volatile=True).cuda()            y = Variable(y, volatile=True).cuda()        else:            X = Variable(X, volatile=True)            y = Variable(y, volatile=True)        y_pred = net(X)        y_pred = (F.sigmoid(y_pred) > 0.6).float()        # y_pred = F.sigmoid(y_pred).float()        dice = dice_coeff(y_pred, y.float()).data[0]        tot += dice        if 0:            X = X.data.squeeze(0).cpu().numpy()            X = np.transpose(X, axes=[1, 2, 0])            y = y.data.squeeze(0).cpu().numpy()            y_pred = y_pred.data.squeeze(0).squeeze(0).cpu().numpy()            print(y_pred.shape)            fig = plt.figure()            ax1 = fig.add_subplot(1, 4, 1)            ax1.imshow(X)            ax2 = fig.add_subplot(1, 4, 2)            ax2.imshow(y)            ax3 = fig.add_subplot(1, 4, 3)            ax3.imshow((y_pred > 0.5))

https://github.com/milesial/Pytorch-UNet/blob/master/eval.py 3 loss與bce疊加

        outputs = model(images)        loss, bce_loss, soft_dice_loss = criterion(outputs, labels)        loss_val = loss.data[0]        sum_epoch_loss += loss_val        if i == 0:            optimizer.zero_grad()        loss.backward()

loss.py

import torchimport torch.utils.dataimport torch.nn as nnimport torch.nn.functional as Ffrom torch.autograd import Variableimport numpy as npclass BCELoss2d(nn.Module):    """    Binary Cross Entropy loss function    """    def __init__(self):        super(BCELoss2d, self).__init__()        self.bce_loss = nn.BCEWithLogitsLoss()    def forward(self, logits, labels):        logits_flat = logits.view(-1)        labels_flat = labels.view(-1)        return self.bce_loss(logits_flat, labels_flat)class WeightedBCELoss2d(nn.Module):    def __init__(self):        super(WeightedBCELoss2d, self).__init__()    def forward(self, logits, labels, weights):        w = weights.view(-1)        logits = logits.view(-1)        gt = labels.view(-1)        # http://geek.csdn.net/news/detail/126833        loss = logits.clamp(min=0) - logits * gt + torch.log(1 + torch.exp(-logits.abs()))        loss = loss * w        loss = loss.sum() / w.sum()        return lossclass WeightedSoftDiceLoss(nn.Module):    def __init__(self):        super(WeightedSoftDiceLoss, self).__init__()    def forward(self, logits, labels, weights):        probs = F.sigmoid(logits)        num = labels.size(0)        w = weights.view(num, -1)        w2 = w * w        m1 = probs.view(num, -1)        m2 = labels.view(num, -1)        intersection = (m1 * m2)        score = 2. * ((w2 * intersection).sum(1) + 1) / (            (w2 * m1).sum(1) + (w2 * m2).sum(1) + 1)        score = 1 - score.sum() / num        return scoreclass SoftDiceLoss(nn.Module):    def __init__(self):        super(SoftDiceLoss, self).__init__()    def forward(self, logits, labels):        probs = F.sigmoid(logits)        num = labels.size(0)        m1 = probs.view(num, -1)        m2 = labels.view(num, -1)        intersection = (m1 * m2)        score = 2. * (intersection.sum(1) + 1) / (m1.sum(1) + m2.sum(1) + 1)        score = 1 - score.sum() / num        return scoreclass DiceScore(nn.Module):    def __init__(self, threshold=0.5):        super(DiceScore, self).__init__()        self.threshold = threshold    def forward(self, logits, labels):        probs = F.sigmoid(logits)        num = labels.size(0)        predicts = (probs.view(num, -1) > self.threshold).float()        labels = labels.view(num, -1)        intersection = (predicts * labels)        score = 2. * (intersection.sum(1)) / (predicts.sum(1) + labels.sum(1))        return score.mean()def dice_score_np(predicted_masks, labels):    assert len(predicted_masks.shape) >= 3    num = predicted_masks.shape[0]    predicted_masks = predicted_masks.reshape(num, -1).astype(float)    assert predicted_masks.min() == 0 and predicted_masks.max() == 1.0    labels = labels.reshape(num, -1)    assert labels.min() == 0 and labels.max() == 1.0    intersection = (predicted_masks * labels)    assert not np.any((predicted_masks.sum(1) + labels.sum(1)) == 0)    score = 2. * (intersection.sum(1)) / (predicted_masks.sum(1) + labels.sum(1))    assert len(score.shape) == 1    return score.mean()class CombinedLoss(nn.Module):    def __init__(self, is_weight=True, is_log_dice=False):        super(CombinedLoss, self).__init__()        self.is_weight = is_weight        self.is_log_dice = is_log_dice        if self.is_weight:            self.weighted_bce = WeightedBCELoss2d()            self.soft_weighted_dice = WeightedSoftDiceLoss()        else:            self.bce = BCELoss2d()            self.soft_dice = SoftDiceLoss()    def forward(self, logits, labels):        size = logits.size()        assert size[1] == 1, size        logits = logits.view(size[0], size[2], size[3])        labels = labels.view(size[0], size[2], size[3])        if self.is_weight:            batch_size, H, W = labels.size()            if H == 128:                kernel_size = 11            elif H == 256:                kernel_size = 21            elif H == 512:                kernel_size = 21            elif H == 1024:                kernel_size = 41            elif H == 1280:                kernel_size = 51            else:                raise ValueError('Unknown height')            a = F.avg_pool2d(labels, kernel_size=kernel_size, padding=kernel_size // 2,                             stride=1)            ind = a.ge(0.01) * a.le(0.99)            ind = ind.float()            weights = Variable(torch.tensor.torch.ones(a.size())).cuda()            w0 = weights.sum()            weights += ind * 2            w1 = weights.sum()            weights = weights / w1 * w0            bce_loss = self.weighted_bce(logits, labels, weights)            dice_loss = self.soft_weighted_dice(logits, labels, weights)        else:            bce_loss = self.bce(logits, labels)            dice_loss = self.soft_dice(logits, labels)        if self.is_log_dice:            l = bce_loss - (1 - dice_loss).log()        else:            l = bce_loss + dice_loss        return l, bce_loss, dice_lossdef combined_loss(logits, labels, is_weight=True, is_log_dice=False):    size = logits.size()    assert size[1] == 1, size    logits = logits.view(size[0], size[2], size[3])    labels = labels.view(size[0], size[2], size[3])    if is_weight:        batch_size, H, W = labels.size()        if H == 128:            kernel_size = 11        elif H == 256:            kernel_size = 21        elif H == 512:            kernel_size = 21        elif H == 1024:            kernel_size = 41        elif H == 1280:            kernel_size = 51        else:            raise ValueError('Unknown height')        a = F.avg_pool2d(labels, kernel_size=kernel_size, padding=kernel_size // 2, stride=1)        ind = a.ge(0.01) * a.le(0.99)        ind = ind.float()        weights = Variable(torch.tensor.torch.ones(a.size())).cuda()        w0 = weights.sum()        weights += ind * 2        w1 = weights.sum()        weights = weights / w1 * w0        bce_loss = WeightedBCELoss2d().cuda()(logits, labels, weights)        dice_loss = WeightedSoftDiceLoss().cuda()(logits, labels, weights)    else:        bce_loss = BCELoss2d().cuda()(logits, labels)        dice_loss = SoftDiceLoss().cuda()(logits, labels)    if is_log_dice:        l = bce_loss - (1 - dice_loss).log()    else:        l = bce_loss + dice_loss    return l, bce_loss, dice_loss

預測mask

        images = Variable(images.cuda(), volatile=True)        outputs = model(images)        outputs = F.upsample(outputs, size=original_shape, mode='bilinear')        output_probs = F.sigmoid(outputs)        if save_probs:            probs_np = np.squeeze(output_probs.data.cpu().numpy())            if len(probs_np.shape) == 2:                probs_np = probs_np[np.newaxis, ...]            assert len(probs_np.shape) == 3, probs_np.shape            prob_images = np.asarray(np.round(probs_np * 255), dtype=np.uint8)            for probs_img, sample_name in izip(prob_images, names):                cv2.imwrite(str(output_dir.joinpath(sample_name + '.png')), probs_img)
4 bce和dice loss綜合

albu的方法也是綜合bce 和 diceloss

def dice_loss(preds, trues, weight=None, is_average=True):    num = preds.size(0)    preds = preds.view(num, -1)    trues = trues.view(num, -1)    if weight is not None:        w = torch.autograd.Variable(weight).view(num, -1)        preds = preds * w        trues = trues * w    intersection = (preds * trues).sum(1)    scores = 2. * (intersection + 1) / (preds.sum(1) + trues.sum(1) + 1)    if is_average:        score = scores.sum()/num        return torch.clamp(score, 0., 1.)    else:        return scoresdef dice_clamp(preds, trues, is_average=True):    preds = torch.round(preds)    return dice_loss(preds, trues, is_average=is_average)class DiceLoss(nn.Module):    def __init__(self, size_average=True):        super().__init__()        self.size_average = size_average    def forward(self, input, target, weight=None):        return 1-dice_loss(F.sigmoid(input), target, weight=weight, is_average=self.size_average)class BCEDiceLoss(nn.Module):    def __init__(self, size_average=True):        super().__init__()        self.size_average = size_average        self.dice = DiceLoss(size_average=size_average)    def forward(self, input, target, weight=None):        return nn.modules.loss.BCEWithLogitsLoss(size_average=self.size_average, weight=weight)(input, target) + self.dice(input, target, weight=weight)        ypreds = self.model(images)        loss = self.criterion(ypreds, ytrues)        ret['loss'

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.