Des*_*wal 11 machine-learning computer-vision deep-learning keras tensorflow
我一直在尝试尝试基于区域的:骰子损失,但互联网上有很多不同程度的变化,我找不到两个相同的实现。问题是所有这些都会产生不同的结果。以下是我找到的实现。有些使用作者在本文中称为smoothing的因子,有些在分子和分母中使用它,使用一种实现等等。epsilonGamma
有人可以帮助我正确实施吗?
import tensorflow as tf
import tensorflow.keras.backend as K
import numpy as np
def dice_loss1(y_true, y_pred, smooth=1e-6):
'''
https://www.kaggle.com/code/bigironsphere/loss-function-library-keras-pytorch/notebook
'''
y_pred = tf.convert_to_tensor(y_pred)
y_true = tf.cast(y_true, y_pred.dtype)
smooth = tf.cast(smooth, y_pred.dtype)
y_pred = K.flatten(y_pred)
y_true = K.flatten(y_true)
intersection = K.sum(K.dot(y_true, y_pred))
dice_coef = (2*intersection + smooth) / (K.sum(y_true) + K.sum(y_pred) + smooth)
dice_loss = 1-dice_coef
return dice_loss
def dice_loss2(y_true, y_pred, smooth=1e-6): # Only Smooth
"""
https://gist.github.com/wassname/7793e2058c5c9dacb5212c0ac0b18a8a
"""
y_pred = tf.convert_to_tensor(y_pred)
y_true = tf.cast(y_true, y_pred.dtype)
smooth = tf.cast(smooth, y_pred.dtype)
intersection = K.sum(K.abs(y_true * y_pred), axis=-1)
dice_coef = (2. * intersection + smooth) / (K.sum(K.square(y_true),-1) + K.sum(K.square(y_pred),-1) + smooth)
return 1- dice_coef
def dice_loss3(y_true, y_pred): # No gamma, no smooth
'''
https://lars76.github.io/2018/09/27/loss-functions-for-segmentation.html
'''
y_pred = tf.convert_to_tensor(y_pred)
y_true = tf.cast(y_true, y_pred.dtype)
y_pred = tf.math.sigmoid(y_pred)
numerator = 2 * tf.reduce_sum(y_true * y_pred)
denominator = tf.reduce_sum(y_true + y_pred)
return 1 - numerator / denominator
def dice_loss4(y_true, y_pred, smooth=1e-6, gama=1): # Gama + Smooth is used
'''
https://dev.to/_aadidev/3-common-loss-functions-for-image-segmentation-545o
'''
y_pred = tf.convert_to_tensor(y_pred)
y_true = tf.cast(y_true, y_pred.dtype)
smooth = tf.cast(smooth, y_pred.dtype)
gama = tf.cast(gama, y_pred.dtype)
nominator = 2 * tf.reduce_sum(tf.multiply(y_pred, y_true)) + smooth
denominator = tf.reduce_sum(y_pred ** gama) + tf.reduce_sum(y_true ** gama) + smooth
result = 1 - tf.divide(nominator, denominator)
return result
y_true = np.array([[0,0,1,0],
[0,0,1,0],
[0,0,1.,0.]])
y_pred = np.array([[0,0,0.9,0],
[0,0,0.1,0],
[1,1,0.1,1.]])
# print(dice_loss1(y_true, y_pred)) # Gives you error in K.dot()
print(dice_loss2(y_true, y_pred))
print(dice_loss3(y_true, y_pred)) # provides array of values
print(dice_loss4(y_true, y_pred))
Run Code Online (Sandbox Code Playgroud)
dan*_*all 21
我利用骰子损失的变体进行脑肿瘤分割。我用于此类结果的骰子系数的实现是:
def dice_coef(y_true, y_pred, smooth=100):
y_true_f = K.flatten(y_true)
y_pred_f = K.flatten(y_pred)
intersection = K.sum(y_true_f * y_pred_f)
dice = (2. * intersection + smooth) / (K.sum(y_true_f) + K.sum(y_pred_f) + smooth)
return dice
Run Code Online (Sandbox Code Playgroud)
为了使其成为损失,需要将其做成我们想要最小化的函数。这可以通过将其设为负数来实现:
def dice_coef_loss(y_true, y_pred):
return -dice_coef(y_true, y_pred)
Run Code Online (Sandbox Code Playgroud)
或从 1 中减去它:
def dice_coef_loss(y_true, y_pred):
return 1 - dice_coef(y_true, y_pred)
Run Code Online (Sandbox Code Playgroud)
或应用一些其他函数然后取负 - 例如,取负对数(这可以平滑梯度):
def dice_coef_loss(y_true, y_pred):
return -K.log(dice_coef(y_true, y_pred))
Run Code Online (Sandbox Code Playgroud)
该变量smooth代表您在其他实现中使用各种名称(smoothing、epsilon等)观察到的结果。为了清楚起见,这个平滑变量的存在是为了处理地面事实具有很少白色(或没有)白色像素的情况(假设白色像素属于对象的类或边界,具体取决于您的实现)。
如果smooth设置得太低,当真实图像具有很少到 0 的白色像素并且预测图像具有一些非零数量的白色像素时,模型将受到更严重的惩罚。设置smooth较高意味着如果预测图像具有少量白色像素,而地面实况没有白色像素,则损失值会较低。不过,根据模型需要达到的积极程度,较低的值可能会更好。
这是一个说明性示例:
import numpy as np
import tensorflow as tf
from tensorflow.keras import backend as K
def dice_coef(y_true, y_pred, smooth):
y_true_f = K.flatten(y_true)
y_pred_f = K.flatten(y_pred)
intersection = K.sum(y_true_f * y_pred_f)
dice = (2. * intersection + smooth) / (K.sum(y_true_f) + K.sum(y_pred_f) + smooth)
return dice
def dice_coef_loss(y_true, y_pred, smooth):
return 1 - dice_coef(y_true, y_pred, smooth)
if __name__ == '__main__':
smooth = 10e-6
y_pred = np.zeros((1, 128, 128))
# one pixel is set to 1
y_pred[0, 0, 0] = 1
y_pred = tf.convert_to_tensor(y_pred, dtype=tf.float32)
y_true = tf.zeros((1, 128, 128), dtype=tf.float32)
print(dice_coef(y_true, y_pred, smooth=smooth))
print(dice_coef_loss(y_true, y_pred, smooth=smooth))
Run Code Online (Sandbox Code Playgroud)
将打印出:
tf.Tensor(9.9999e-06, shape=(), dtype=float32)
tf.Tensor(0.99999, shape=(), dtype=float32)
Run Code Online (Sandbox Code Playgroud)
但如果smooth设置为 100:
tf.Tensor(0.990099, shape=(), dtype=float32)
tf.Tensor(0.009900987, shape=(), dtype=float32)
Run Code Online (Sandbox Code Playgroud)
显示损失减少到 0.009,而不是 0.99。
为了完整起见,如果您有多个分割通道(B X W X H X K,其中B是批量大小,W是H图像的尺寸, 是K不同的分割通道),则适用相同的概念,但可以按如下方式实现:
def dice_coef_multilabel(y_true, y_pred, M, smooth):
dice = 0
for index in range(M):
dice += dice_coef(y_true[:,:,:,index], y_pred[:,:,:,index], smooth)
return dice
Run Code Online (Sandbox Code Playgroud)
并且可以通过求反或减法将其转换为损失函数,方法与原样相同dice_coef。smooth如果您提供列表或其他序列(例如;smooth_list),也可以按频道进行调整:
def dice_coef_multilabel(y_true, y_pred, M, smooth_list):
dice = 0
for index in range(M):
dice += dice_coef(y_true[:,:,:,index], y_pred[:,:,:,index], smooth_list[index])
return dice
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
12549 次 |
| 最近记录: |