我只是在kera中实现了广义骰子损失(骰子损失的多类版本),如ref中所述:
(我的目标定义为:(batch_size,image_dim1,image_dim2,image_dim3,nb_of_classes))
def generalized_dice_loss_w(y_true, y_pred):
# Compute weights: "the contribution of each label is corrected by the inverse of its volume"
Ncl = y_pred.shape[-1]
w = np.zeros((Ncl,))
for l in range(0,Ncl): w[l] = np.sum( np.asarray(y_true[:,:,:,:,l]==1,np.int8) )
w = 1/(w**2+0.00001)
# 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 = numerator/denominator
return 1-2*gen_dice_coef
但是一定有问题。我正在处理3D图像,必须将其分割为4类(1个背景类和3个对象类,我有一个不平衡的数据集)。首先奇怪的是:虽然我的训练损失和准确性在训练过程中有所改善(并且很快收敛),但我的验证损失/准确性却是持续不断的低谷时期(请参阅image)。其次,在对测试数据进行预测时,仅预测了背景类:我得到了恒定的音量。
我使用了完全相同的数据和脚本,但存在分类交叉熵损失,并得到了合理的结果(对象类别已分割)。这意味着我的实现存在问题。知道会是什么吗?
另外,我认为具有通用的骰子丢失实现对keras社区将是有用的,因为它似乎已用于大多数最近的语义分割任务中(至少在医学图像社区中)。
PS:对我来说,如何定义权重似乎很奇怪;我得到大约10 ^ -10的值。还有其他人试图实现这一目标吗?我也没有重量测试了我的功能,但遇到同样的问题。
最佳答案
我认为这是您的体重问题。想象一下,您正在尝试解决多类分割问题,但是在每个图像中,只有少数几个类存在。这方面的一个玩具示例(以及导致我遇到此问题的示例)是通过以下方式从mnist创建分割数据集。
x = 28x28图像和y = 28x28x11,如果每个像素均低于归一化灰度值0.4,则将其分类为背景,否则将其分类为x的原始类别的数字。因此,如果您看到一张数字为1的图片,则将得到一堆归类为1的像素和背景。
现在,在此数据集中,图像中将只存在两个类。这意味着,在您损失骰子之后,将有9个砝码1./(0. + eps) = large
因此,对于每张图片,我们都会严惩所有9个不存在的类。网络在这种情况下想要找到的一个明显强的局部最小值是将所有事物作为背景知识进行预测。
我们确实希望对不在图像中但没有那么强烈的任何错误预测的类进行惩罚。因此,我们只需要修改权重即可。这是我的方法:
def gen_dice(y_true, y_pred, eps=1e-6):
"""both tensors are [b, h, w, classes] and y_pred is in logit form"""
# [b, h, w, classes]
pred_tensor = tf.nn.softmax(y_pred)
y_true_shape = tf.shape(y_true)
# [b, h*w, classes]
y_true = tf.reshape(y_true, [-1, y_true_shape[1]*y_true_shape[2], y_true_shape[3]])
y_pred = tf.reshape(pred_tensor, [-1, y_true_shape[1]*y_true_shape[2], y_true_shape[3]])
# [b, classes]
# count how many of each class are present in
# each image, if there are zero, then assign
# them a fixed weight of eps
counts = tf.reduce_sum(y_true, axis=1)
weights = 1. / (counts ** 2)
weights = tf.where(tf.math.is_finite(weights), weights, eps)
multed = tf.reduce_sum(y_true * y_pred, axis=1)
summed = tf.reduce_sum(y_true + y_pred, axis=1)
# [b]
numerators = tf.reduce_sum(weights*multed, axis=-1)
denom = tf.reduce_sum(weights*summed, axis=-1)
dices = 1. - 2. * numerators / denom
dices = tf.where(tf.math.is_finite(dices), dices, tf.zeros_like(dices))
return tf.reduce_mean(dices)
关于machine-learning - 多类分割的广义骰子损失: keras implementation,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/49012025/