使用 keras 实现 u-net 的 Jaccard 准确度为零
Zero Jaccard accuracy in u-net implementation with keras
我正在尝试将 u-net 与 keras 实现一起使用,我正在使用以下 repo
https://github.com/zhixuhao/unet
它运作良好,但我的问题是两个 class 分割问题,所以我想将准确度指标设置为 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)
而且我可以看到它也使用舍入来获得输出预测。
尝试以下从 github 复制的函数。在keras指标中使用jacard_coef,如果你想要jacard_coef_loss keras loss
def jacard_coef(y_true, y_pred):
y_true_f = K.flatten(y_true)
y_pred_f = K.flatten(y_pred)
intersection = K.sum(y_true_f * y_pred_f)
return (intersection + 1.0) / (K.sum(y_true_f) + K.sum(y_pred_f) - intersection + 1.0)
def jacard_coef_loss(y_true, y_pred):
return -jacard_coef(y_true, y_pred)
model.compile(optimizer = Adam(lr = 1e-4), loss = [jacard_coef_loss], metrics = [jacard_coef])
您正在舍入函数 (K.round
)。
这会导致两个问题:
- (真正的问题)该函数不可微,不能成为损失函数(将显示 "None values not supported" 错误)
- 只要您的网络不确定并且有任何低于 0.5 的值,这些值将被视为零。
如果 y_true
中黑色(零)像素的数量大于白色(1)像素的数量,则会发生这种情况:
- 您的网络倾向于先将所有内容预测为零,这确实会导致更好的二元交叉熵损失!
- 如果不四舍五入,还有更好的 Jaccard
- 但如果四舍五入则为零 Jaccard
- 只有稍后,当学习率得到更精细的调整时,它才会开始在它们应该出现的地方显示白色像素。
出于上述两个原因,您确实应该使用 non-rounded 函数。
有时绘制输出以查看发生了什么:)
请注意,如果您将其用作损失函数,请将其乘以 -1(因为您希望它减少,而不是增加)
我正在尝试将 u-net 与 keras 实现一起使用,我正在使用以下 repo https://github.com/zhixuhao/unet 它运作良好,但我的问题是两个 class 分割问题,所以我想将准确度指标设置为 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)
而且我可以看到它也使用舍入来获得输出预测。
尝试以下从 github 复制的函数。在keras指标中使用jacard_coef,如果你想要jacard_coef_loss keras loss
def jacard_coef(y_true, y_pred):
y_true_f = K.flatten(y_true)
y_pred_f = K.flatten(y_pred)
intersection = K.sum(y_true_f * y_pred_f)
return (intersection + 1.0) / (K.sum(y_true_f) + K.sum(y_pred_f) - intersection + 1.0)
def jacard_coef_loss(y_true, y_pred):
return -jacard_coef(y_true, y_pred)
model.compile(optimizer = Adam(lr = 1e-4), loss = [jacard_coef_loss], metrics = [jacard_coef])
您正在舍入函数 (K.round
)。
这会导致两个问题:
- (真正的问题)该函数不可微,不能成为损失函数(将显示 "None values not supported" 错误)
- 只要您的网络不确定并且有任何低于 0.5 的值,这些值将被视为零。
如果 y_true
中黑色(零)像素的数量大于白色(1)像素的数量,则会发生这种情况:
- 您的网络倾向于先将所有内容预测为零,这确实会导致更好的二元交叉熵损失!
- 如果不四舍五入,还有更好的 Jaccard
- 但如果四舍五入则为零 Jaccard
- 只有稍后,当学习率得到更精细的调整时,它才会开始在它们应该出现的地方显示白色像素。
出于上述两个原因,您确实应该使用 non-rounded 函数。
有时绘制输出以查看发生了什么:)
请注意,如果您将其用作损失函数,请将其乘以 -1(因为您希望它减少,而不是增加)