我正在尝试将 u-net 与 keras 实现一起使用,我正在使用以下存储库 https://github.com/zhixuhao/unet 它工作得很好,但我的问题是一个二分类分割问题,所以我想将精度指标设置为 jaccard,还有损失函数
我尝试定义函数:
def Jac(y_true, y_pred):
y_pred_f = K.flatten(K.round(y_pred))
y_true_f = K.flatten(y_true)
num = K.sum(y_true_f * y_pred_f)
den = K.sum(y_true_f) + K.sum(y_pred_f) - num
return num / den
并在编译中调用它:
model.compile(optimizer = Adam(lr = 1e-4), loss = ['binary_crossentropy'], metrics = [Jac])
当我这样做时,每次迭代中的 jaccard 精度都会降低,直到达到零!
有什么解释为什么会发生吗?
P.S:同样的事情也发生在骰子上。
P.S: 输出层是 conv 1 * 1,带有 sigmoid 激活函数
更新:
附上 keras 中二进制精度的原始实现:
def binary_accuracy(y_true, y_pred):
return K.mean(K.equal(y_true, K.round(y_pred)), axis=-1)
我可以看到它还使用舍入来获得输出预测。
最佳答案
您正在对函数进行舍入 (K.round
)。
这会导致两个问题:
- (真正的问题)该函数不可微分,不能作为损失函数(将显示“不支持任何值”错误)
- 每当您的网络不确定且任何值低于 0.5 时,这些值都将被视为零。
如果 y_true
中黑色(零)像素的数量大于白色(1)像素的数量,则会发生这种情况:
- 你的网络倾向于首先将所有内容预测为零,这确实会导致更好的二元交叉熵损失!
- 如果不是四舍五入的话,还有更好的 Jaccard
- 但是如果四舍五入则为零 Jaccard
- 只有稍后,当学习率得到更精细的调整时,它才会开始将白色像素带出它们应该在的位置。
出于上述两个原因,您确实应该使用非舍入函数。
有时绘制你的输出来看看发生了什么:)
请注意,如果您将其用作损失函数,请将其乘以 -1(因为您希望它减少,而不是增加)
关于python - 使用 keras 实现 u-net 时 Jaccard 精度为零,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49296099/