真实非零预测的更高损失惩罚
Higher loss penalty for true non-zero predictions
我正在构建深度回归网络 (CNN) 以从图像 (7,11) 预测 (1000,1) 目标向量。目标通常由大约 90% 零值 和仅 10% 非零值组成。目标中(非)零值的分布因样本而异(即不存在全局 class 不平衡)。
使用均方误差损失,这导致网络仅预测零,我对此并不感到惊讶。
我最好的猜测是编写一个自定义损失函数,该函数对非零值的错误的惩罚比对零值的预测更多。
我已经尝试了这个损失函数,目的是实现我猜想可以在上面工作的东西。这是一个均方误差损失,其中非零目标的预测受到较少的惩罚(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
网络能够学习而不会陷入只有零的预测。然而,这个解决方案似乎很不干净。有没有更好的方法来处理这类问题?关于改进自定义损失函数的任何建议?
欢迎任何建议,提前谢谢!
最好的,
卢卡斯
不确定有什么比自定义损失更好的方法,但有更简洁的方法:
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 选项中获益,例如添加样本权重和其他内容。
Select编译时的权重:
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-class 问题。形状 = (batch, originalClasses, 2)
。
对于零值,使两个中的第一个 classes = 1
对于一个值,使两个值中的第二个 classes = 1
newY = np.stack([1-oldY, oldY], axis=-1)
调整模型以输出这个新形状。
...
model.add(Dense(2*classes))
model.add(Reshape((classes,2)))
model.add(Activation('softmax'))
确保您使用 softmax
和 categorical_crossentropy
作为损失。
然后在fit
中使用参数class_weight={0: w, 1: 1}
。
我正在构建深度回归网络 (CNN) 以从图像 (7,11) 预测 (1000,1) 目标向量。目标通常由大约 90% 零值 和仅 10% 非零值组成。目标中(非)零值的分布因样本而异(即不存在全局 class 不平衡)。
使用均方误差损失,这导致网络仅预测零,我对此并不感到惊讶。
我最好的猜测是编写一个自定义损失函数,该函数对非零值的错误的惩罚比对零值的预测更多。
我已经尝试了这个损失函数,目的是实现我猜想可以在上面工作的东西。这是一个均方误差损失,其中非零目标的预测受到较少的惩罚(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
网络能够学习而不会陷入只有零的预测。然而,这个解决方案似乎很不干净。有没有更好的方法来处理这类问题?关于改进自定义损失函数的任何建议? 欢迎任何建议,提前谢谢!
最好的, 卢卡斯
不确定有什么比自定义损失更好的方法,但有更简洁的方法:
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 选项中获益,例如添加样本权重和其他内容。
Select编译时的权重:
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-class 问题。形状 =(batch, originalClasses, 2)
。
对于零值,使两个中的第一个 classes = 1
对于一个值,使两个值中的第二个 classes = 1
newY = np.stack([1-oldY, oldY], axis=-1)
调整模型以输出这个新形状。
...
model.add(Dense(2*classes))
model.add(Reshape((classes,2)))
model.add(Activation('softmax'))
确保您使用 softmax
和 categorical_crossentropy
作为损失。
然后在fit
中使用参数class_weight={0: w, 1: 1}
。