真实非零预测的损失损失更高

时间:2019-08-23 00:31:46

标签: tensorflow keras deep-learning loss-function loss

我正在建立一个深度回归网络(CNN),以根据图像(7,11)预测(1000,1)目标向量。目标通常包含大约 90%的零和仅 10%的非零值。目标中(非)零值的分布因样本而异(即不存在全局类别不平衡)。

使用平均误差损失,这导致网络仅预测零,这并不奇怪。

我最好的猜测是编写一个自定义损失函数,该函数对与非零值有关的错误的惩罚要比对零值的预测要惩罚的多。

我尝试了此损失功能,目的是实现我认为可以在上面工作的功能。这是一种均方误差损失,其中对非零目标的预测的惩罚较少(w = 0.1)。

def my_loss(y_true, y_pred):
    # weights true zero predictions less than true nonzero predictions
    w = 0.1
    y_pred_of_nonzeros = tf.where(tf.equal(y_true, 0), y_pred-y_pred, y_pred)
    return K.mean(K.square(y_true-y_pred_of_nonzeros)) + K.mean(K.square(y_true-y_pred))*w

网络能够学习而不会陷入零预测。但是,此解决方案似乎不干净。有没有更好的方法来处理此类问题?关于改善自定义损失功能的任何建议? 欢迎任何建议,谢谢您!

最好, 卢卡斯

1 个答案:

答案 0 :(得分:0)

不确定像您所做的那样,有什么比自定义损失更好的方法,但是有一种更简洁的方法:

def weightedLoss(w):

    def loss(true, pred):

        error = K.square(true - pred)
        error = K.switch(K.equal(true, 0), w * error , error)

        return error 

    return loss

您也可以return K.mean(error),但是如果没有mean,您仍然可以从其他Keras选项中受益,例如增加样本权重和其他操作。

选择编译时的权重:

model.compile(loss = weightedLoss(0.1), ...)

如果整个数据都在一个数组中,则可以执行以下操作:

w = K.mean(y_train)
w = w / (1 - w) #this line compesates the lack of the 90% weights for class 1

另一个可以避免使用自定义损失,但需要更改数据和模型的解决方案是:

  • 将每个输出的y转换为2类问题。形状= (batch, originalClasses, 2)

对于零值,使两个类中的第一个= 1
对于一个值,使两个类中的第二个为1

newY = np.stack([1-oldY, oldY], axis=-1)    

调整模型以输出此新形状。

...
model.add(Dense(2*classes))
model.add(Reshape((classes,2)))
model.add(Activation('softmax'))

确保您使用softmaxcategorical_crossentropy作为损失。

然后在class_weight={0: w, 1: 1}中使用参数fit