如何在Keras中实现损失函数的像素加权



我正在使用Keras 2.2.4,并试图实现此处所述的逐像素分类的损失函数,但我遇到了一些困难。我正在进行3D分割,因此我的目标向量是(b_size, width_x, width_y, width_z, nb_classes)。我实现了以下损失函数,其中权重图与目标和预测向量的形状相同:

def dice_xent_loss(y_true, y_pred, weight_map):
"""Adaptation of https://arxiv.org/pdf/1809.10486.pdf for multilabel 
classification with overlapping pixels between classes. Dec 2018.
"""
loss_dice = weighted_dice(y_true, y_pred, weight_map)
loss_xent = weighted_binary_crossentropy(y_true, y_pred, weight_map)
return loss_dice + loss_xent
def weighted_binary_crossentropy(y_true, y_pred, weight_map):
return tf.reduce_mean((K.binary_crossentropy(y_true, 
y_pred)*weight_map)) / (tf.reduce_sum(weight_map) + K.epsilon())
def weighted_dice(y_true, y_pred, weight_map):
if weight_map is None:
raise ValueError("Weight map cannot be None")
if y_true.shape != weight_map.shape:
raise ValueError("Weight map must be the same size as target vector")
dice_numerator = 2.0 * K.sum(y_pred * y_true * weight_map, axis=[1,2,3])
dice_denominator = K.sum(weight_map * y_true, axis=[1,2,3]) + 
K.sum(y_pred * weight_map, axis=[1,2,3])
loss_dice = (dice_numerator) / (dice_denominator + K.epsilon())
h1=tf.square(tf.minimum(0.1,loss_dice)*10-1)
h2=tf.square(tf.minimum(0.01,loss_dice)*100-1)
return 1.0 - tf.reduce_mean(loss_dice) + 
tf.reduce_mean(h1)*10 + 
tf.reduce_mean(h2)*10

我按照建议使用sample_weights=temporal编译模型,并将权重作为sample_weight=weights传递给model.fit。我仍然得到以下错误:

File "overfit_one_case.py", line 153, in <module>
main()
File "overfit_one_case.py", line 81, in main
sample_weight_mode="temporal")
File "/home/igt/anaconda2/envs/niftynet/lib/python2.7/site-packages/keras/engine/training.py", line 342, in compile
sample_weight, mask)
File "/home/igt/anaconda2/envs/niftynet/lib/python2.7/site-packages/keras/engine/training_utils.py", line 404, in weighted
score_array = fn(y_true, y_pred)
TypeError: dice_xent_loss() takes exactly 3 arguments (2 given)

training_utils.py中,Keras称我的自定义失重没有任何重量。你知道怎么解决这个问题吗?我的另一个限制是,我试图在这个特定的模型上进行迁移学习。因此,我不能像这里建议的那样将weight_map添加到Input层。

样本权重是样本的权重,而不是像素的权重。

除了y_truey_pred之外,Keras损失从未接受过任何其他论点。所有keras加权都是自动的。

对于自定义权重,您需要自己实现它们。您可以创建这些损失函数,将其封装在一个接受权重的函数中,如下所示:

def weighted_dice_xent_loss(weight_map):
def dice_xent_loss(y_true, y_pred):
#code...    
return loss_dice + loss_xent
return dice_xent_loss
def weighted_binary_crossentropy(weight_map):
def inner_binary_crossentropy(y_true, y_pred):
return tf.reduce_mean(
(K.binary_crossentropy(y_true, y_pred)*weight_map)) / (
tf.reduce_sum(weight_map) + K.epsilon())
return inner_binnary_crossentropy
def weighted_dice(weight_map):
def dice(y_true, y_pred):
#code....
return 1.0 - tf.reduce_mean(loss_dice) + 
tf.reduce_mean(h1)*10 + 
tf.reduce_mean(h2)*10
return dice

例如,将它们用作loss=weighted_dice_xent_loss(weight_map)


使用样本权重的错误解决方法。

如果每个样本的权重都是唯一的,那么你必须将每个像素都变成一个样本(这是非常不寻常的)。

使用您的数据:

  • (b_size * width_x * width_y * width_z, nb_channels)一样展平数据的第一个维度
  • 用同样的方法压平你的权重矩阵
  • 以同样的方式扁平化您的真实输出

使用您的型号:

  • 创建兼容的`inputs=Input((nb_channels,))
  • 使用K.reshapeLambda层中重塑以恢复原始尺寸:K.reshape(x, (-1, width_x, width_y, width_z, nb_classes))
  • 照常制作模型的其余部分
  • 使用K.reshape(x, (-1, nb_classes))Lambda层中的输出进行整形

您的损失:

  • 计算每个像素的损失,不要求和像素
  • Keras权重将在您计算损失后相加(因此它与骰子不兼容)

最新更新