首页 > 解决方案 > 为什么输出层在网络末端简单为零?

问题描述

我正在尝试训练一个采用 15x15 图像并将每个像素分为两类 (1/0) 的模型。

这是我的损失函数:

smooth = 1
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.5
    return (true_pos + smooth)/(true_pos + alpha*false_neg + (1-alpha)*false_pos + smooth)

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

这是模型:

input_image = layers.Input(shape=(size, size, 1))

b2 = layers.Conv2D(128, (3,3), padding='same',  activation='relu')(input_image)
b2 = layers.Conv2D(128, (3,3), padding='same',  activation='relu')(b2)
b2 = layers.Conv2D(128, (3,3), padding='same',  activation='relu')(b2)

output = layers.Conv2D(1, (1,1), activation='sigmoid', padding='same')(b2)

model = models.Model(input_image, output)
model.compile(optimizer='adam', loss=tversky_loss2, metrics=['accuracy'])

左边的模型是输入,标签是中间一列,右边一列的预测总是为零:

在此处输入图像描述

训练效果很差:

Epoch 1/10
100/100 [==============================] - 4s 38ms/step - loss: 0.9269 - acc: 0.1825
Epoch 2/10
100/100 [==============================] - 3s 29ms/step - loss: 0.9277 - acc: 0.0238
Epoch 3/10
100/100 [==============================] - 3s 29ms/step - loss: 0.9276 - acc: 0.0239
Epoch 4/10
100/100 [==============================] - 3s 29ms/step - loss: 0.9270 - acc: 0.0241
Epoch 5/10
100/100 [==============================] - 3s 30ms/step - loss: 0.9274 - acc: 0.0240
Epoch 6/10
100/100 [==============================] - 3s 29ms/step - loss: 0.9269 - acc: 0.0242
Epoch 7/10
100/100 [==============================] - 3s 29ms/step - loss: 0.9270 - acc: 0.0241
Epoch 8/10
100/100 [==============================] - 3s 29ms/step - loss: 0.9271 - acc: 0.0241
Epoch 9/10
100/100 [==============================] - 3s 29ms/step - loss: 0.9276 - acc: 0.0239
Epoch 10/10
100/100 [==============================] - 3s 29ms/step - loss: 0.9266 - acc: 0.0242

标签: tensorflowkerasconv-neural-networkloss-function

解决方案


这听起来像是一个非常不平衡的数据集,真实区域非常小。这可能确实很难训练。

您可能希望增加alpha以惩罚比误报更多的误报。无论如何,除非 alpha 足够大,否则一开始你的模型首先变为全负是很正常的,因为这绝对是减少损失的好方法。

现在,关于 Keras 在这种损失中的工作方式存在概念上的错误。您需要将“样本”分开。否则,您正在计算损失,就好像所有图像都是一张图像一样。(因此,正数多的图像可能有合理的结果,而正数少的图像则没有,这将是一个很好的解决方案)

将损失修正为:


def tversky(y_true, y_pred):
    y_true_pos = K.batch_flatten(y_true) #keep the batch dimension
    y_pred_pos = K.batch_flatten(y_pred)

    true_pos = K.sum(y_true_pos * y_pred_pos, axis=-1) #don't sum over the batch dimension   
    false_neg = K.sum(y_true_pos * (1-y_pred_pos), axis=-1)
    false_pos = K.sum((1-y_true_pos)*y_pred_pos, axis=-1)
    alpha = 0.5
    return (true_pos + smooth)/(true_pos + alpha*false_neg + (1-alpha)*false_pos + smooth)

这样,每个图像都有一个单独的损失值,因此具有许多正值的图像的存在不会影响具有很少正值的图像的结果。


推荐阅读