圖像分割中的loss--處理數據極度不均衡的狀況


序言:

對於小目標圖像分割任務,一副圖畫中往往只有一兩個目標,這樣會加大網絡訓練難度,一般有三種方法解決:

1、選擇合適的loss,對網絡進行合理優化,關注較小的目標。

2、改變網絡結構,使用attention機制。

3、類屬attention機制,即先檢測目標區域,裁剪后再分割訓練。

 

場景:

現在以U-net網絡為基礎,使用keras進行實現小目標的分割。

 

Loss函數:

1、Log loss

對於二分類任務,log loss如下:

其中,yi為輸入實例xixi​的真實類別, pi為預測輸入實例 xi屬於類別 1 的概率。對所有樣本的對數損失表示對每個樣本的對數損失的平均值。

這個loss函數每一次梯度的回傳對每一個類別具有相同的關注度,所以容易受到類別不平衡的影響。

這種情況參照airbus-ship-detection。這個任務是檢測海面上的船只,整個圖片中大海占幅較大,所以采用一些技巧:使用montage拼接圖片,對只有大海的圖片進行采樣來減少圖片大小。

 

2、WCE loss(weighted cross-entropy)

帶權重的交叉熵

二分類WCE:

這個loss的缺點時需要人為的調整困難樣本的權重,增加調整難度。

 

3、Focal loss

能否使網絡主動學習困難樣本呢?

focal loss的提出是在目標檢測領域,為了解決正負樣本比例嚴重失調的問題。

focal函數公式:

對比上面其實就是多了 (1-pi)r

loss值隨樣本概率變大而變小。

 

基本思想是,對於類別極度不平衡的情況下,網絡如果在log loss下會傾向只預測負樣本,並且負樣本的預測概率會非常高,回傳的梯度也很大。

但是如果添加了上述項,則focal 函數會使預測概率大的樣本的loss變小,而預測概率小的樣本的loss變大,從而加強了對正樣本的關注度。

from keras import backend as K
'''
Compatible with tensorflow backend
'''
def focal_loss(gamma=2., alpha=.25):
    def focal_loss_fixed(y_true, y_pred):
        pt_1 = tf.where(tf.equal(y_true, 1), y_pred, tf.ones_like(y_pred))
            pt_0 = tf.where(tf.equal(y_true, 0), y_pred, tf.zeros_like(y_pred))
            return -K.sum(alpha * K.pow(1. - pt_1, gamma) * K.log(pt_1))-K.sum((1-alpha) * K.pow( pt_0, gamma) * K.log(1. - pt_0))
return focal_loss_fixed

model_prn.compile(optimizer=optimizer, loss=[focal_loss(alpha=.25, gamma=2)])

使用U-net輸入輸出都是一張圖,直接使用會導致loss值很大。而且調參alpha和gamma也麻煩。

 

4、Dice loss

直觀理解為兩個輪廓的相似程度。

或則表示為:

二分類的dice loss:

def dice_coef(y_true, y_pred, smooth=1): 
    intersection = K.sum(y_true * y_pred, axis=[1,2,3]) 
    union = K.sum(y_true, axis=[1,2,3]) + K.sum(y_pred, axis=[1,2,3]) 
    return K.mean( (2. * intersection + smooth) / (union + smooth), axis=0) 

def dice_coef_loss(y_true, y_pred): 
    1 - dice_coef(y_true, y_pred, smooth=1)

使用dice loss有時會不可信,原因是對於sofemax或log loss其梯度簡言之是p-t ,t為目標值,p為預測值。而dice loss 為 2t2  /  (p+t)2

如果p,t過小會導致梯度變化劇烈,導致訓練困難。

 

5、IOU loss

類比dice loss,IOU函數公式:

def IoU(y_true, y_pred, eps=1e-6):
    if np.max(y_true) == 0.0:
        return IoU(1-y_true, 1-y_pred) ## empty image; calc IoU of zeros
    intersection = K.sum(y_true * y_pred, axis=[1,2,3])
    union = K.sum(y_true, axis=[1,2,3]) + K.sum(y_pred, axis=[1,2,3]) - intersection
    return -K.mean( (intersection + eps) / (union + eps), axis=0)

IOU loss的缺點呢同DICE loss是相類似的,訓練曲線可能並不可信,訓練的過程也可能並不穩定,有時不如使用softmax loss等的曲線有直觀性,通常而言softmax loss得到的loss下降曲線較為平滑。

 

6、Tversky loss

Tversky loss使dice系數和jaccard系數的一種廣義系數。

觀察可得當設置α=β=0.5,此時Tversky系數就是Dice系數。

而當設置α=β=1時,此時Tversky系數就是Jaccard系數。

∣A−B∣則意味着是FP(假陽性),而∣B−A∣則意味着是FN(假陰性);α和β分別控制假陰性和假陽性。通過調整α和β我們可以控制假陽性和假陰性之間的權衡。

def tversky(y_true, y_pred):
    y_true_pos = K.flatten(y_true)
    y_pred_pos = K.flatten(y_pred)
    true_pos = K.sum(y_true_pos * y_pred_pos)
    false_neg = K.sum(y_true_pos * (1-y_pred_pos))
    false_pos = K.sum((1-y_true_pos)*y_pred_pos)
    alpha = 0.7
    return (true_pos + smooth)/(true_pos + alpha*false_neg + (1-alpha)*false_pos + smooth)

def tversky_loss(y_true, y_pred):
    return 1 - tversky(y_true,y_pred)

def focal_tversky(y_true,y_pred):
    pt_1 = tversky(y_true, y_pred)
    gamma = 0.75
    return K.pow((1-pt_1), gamma)

 

7、敏感性-特異性loss

首先敏感性就是召回率,檢測出確實有病的能力

特異性,檢測出確實沒病的能力

綜合

其中左邊為病灶像素的錯誤率即,1−Sensitivity,而不是正確率,所以設置λ 為0.05。其中(rn−pn)2是為了得到平滑的梯度。

 

8、Generalized dice loss

在使用DICE loss時,對小目標是十分不利的,因為在只有前景和背景的情況下,小目標一旦有部分像素預測錯誤,那么就會導致Dice大幅度的變動,從而導致梯度變化劇烈,訓練不穩定。

當病灶分割有多個區域時,一般針對每一類都會有一個DICE,而Generalized Dice index將多個類別的dice進行整合,使用一個指標對分割結果進行量化。

GDL公式:

其中rln為類別l在第n個像素的標准值(GT),而pln​為相應的預測概率值。此處最關鍵的是wl,為每個類別的權重。其中

這樣,GDL就能平衡病灶區域和Dice系數之間的平衡。

def generalized_dice_coeff(y_true, y_pred):
    Ncl = y_pred.shape[-1]
    w = K.zeros(shape=(Ncl,))
    w = K.sum(y_true, axis=(0,1,2))
    w = 1/(w**2+0.000001)
    # Compute gen dice coef:
    numerator = y_true*y_pred
    numerator = w*K.sum(numerator,(0,1,2,3))
    numerator = K.sum(numerator)
    denominator = y_true+y_pred
    denominator = w*K.sum(denominator,(0,1,2,3))
    denominator = K.sum(denominator)
    gen_dice_coef = 2*numerator/denominator
    return gen_dice_coef

def generalized_dice_loss(y_true, y_pred):
    return 1 - generalized_dice_coeff(y_true, y_pred)

以上本質上都是根據評測標准設計的loss function,有時候普遍會受到目標太小的影響,導致訓練的不穩定;對比可知,直接使用log loss等的loss曲線一般都是相比較光滑的。

 

9、BCE + dice loss(BCE : Binary Cross Entropy)

說白了,添加二分類交叉熵損失函數。在數據較為平衡的情況下有改善作用,但是在數據極度不均衡的情況下,交叉熵損失會在幾個訓練之后遠小於Dice 損失,效果會損失。

import keras.backend as K
from keras.losses import binary_crossentropy
def dice_coef(y_true, y_pred, smooth=1):
    intersection = K.sum(y_true * y_pred, axis=[1,2,3])  
    union = K.sum(y_true, axis=[1,2,3]) + K.sum(y_pred, axis=[1,2,3])
    return K.mean( (2. * intersection + smooth) / (union + smooth), axis=0)

def dice_p_bce(in_gt, in_pred):
    return 1e-3*binary_crossentropy(in_gt, in_pred) - dice_coef(in_gt, in_pred)

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM