我正在开发一个只有两个类别的分段神经网络,即0和1(0是背景,而1是我想在图像上找到的对象)。在每个图像上,大约1的80%和0的20%。如您所见,数据集是不平衡的,并且会导致结果错误。我的准确度是85%,损失也很低,但这仅仅是因为我的模型擅长寻找背景!
我希望优化器基于其他指标,例如精度或召回率,在这种情况下更有用。
有人知道如何实现吗?
答案 0 :(得分:5)
由于我们的评论不够清楚,让我给您代码以跟踪您的需求。您不会使用精度或召回率来进行优化。您只需将它们作为有效分数进行跟踪即可获得最佳权重。请勿将损失,优化程序,指标等混合使用。它们不是为了同一件事。
def precision(y_true, y_pred, threshold_shift=0.5-THRESHOLD):
beta = 1
# just in case of hipster activation at the final layer
y_pred = K.clip(y_pred, 0, 1)
# shifting the prediction threshold from .5 if needed
y_pred_bin = K.round(y_pred + threshold_shift)
tp = K.sum(K.round(y_true * y_pred_bin)) + K.epsilon()
fp = K.sum(K.round(K.clip(y_pred_bin - y_true, 0, 1)))
fn = K.sum(K.round(K.clip(y_true - y_pred, 0, 1)))
precision = tp / (tp + fp)
return precision
def recall(y_true, y_pred, threshold_shift=0.5-THRESHOLD):
beta = 1
# just in case of hipster activation at the final layer
y_pred = K.clip(y_pred, 0, 1)
# shifting the prediction threshold from .5 if needed
y_pred_bin = K.round(y_pred + threshold_shift)
tp = K.sum(K.round(y_true * y_pred_bin)) + K.epsilon()
fp = K.sum(K.round(K.clip(y_pred_bin - y_true, 0, 1)))
fn = K.sum(K.round(K.clip(y_true - y_pred_bin, 0, 1)))
recall = tp / (tp + fn)
return recall
def fbeta(y_true, y_pred, threshold_shift=0.5-THRESHOLD):
beta = 2
# just in case of hipster activation at the final layer
y_pred = K.clip(y_pred, 0, 1)
# shifting the prediction threshold from .5 if needed
y_pred_bin = K.round(y_pred + threshold_shift)
tp = K.sum(K.round(y_true * y_pred_bin)) + K.epsilon()
fp = K.sum(K.round(K.clip(y_pred_bin - y_true, 0, 1)))
fn = K.sum(K.round(K.clip(y_true - y_pred, 0, 1)))
precision = tp / (tp + fp)
recall = tp / (tp + fn)
beta_squared = beta ** 2
return (beta_squared + 1) * (precision * recall) / (beta_squared * precision + recall)
def model_fit(X,y,X_test,y_test):
class_weight={
1: 1/(np.sum(y) / len(y)),
0:1}
np.random.seed(47)
model = Sequential()
model.add(Dense(1000, input_shape=(X.shape[1],)))
model.add(Activation('relu'))
model.add(Dropout(0.35))
model.add(Dense(500))
model.add(Activation('relu'))
model.add(Dropout(0.35))
model.add(Dense(250))
model.add(Activation('relu'))
model.add(Dropout(0.35))
model.add(Dense(1))
model.add(Activation('sigmoid'))
model.compile(loss='binary_crossentropy', optimizer='adamax',metrics=[fbeta,precision,recall])
model.fit(X, y,validation_data=(X_test,y_test), epochs=200, batch_size=50, verbose=2,class_weight = class_weight)
return model
答案 1 :(得分:2)
正如其他人所述,精度/召回率不能直接用作损失函数。但是,人们发现更好的代理丢失功能可以帮助解决与精度/召回相关的整个功能系列(例如ROC AUC,固定召回的精度等)
研究论文Scalable Learning of Non-Decomposable Objectives通过使用某些计算出的边界来避免组合优化的方法涵盖了这一点,作者的一些Tensorflow代码可在tensorflow/models存储库中找到。此外,还有一个后续问题on StackOverflow,其答案将其调整为可用的Keras损失函数。
特别感谢弗朗索瓦·乔莱特(Francois Chollet)和其他Keras issue thread here参与者的支持,他提出了该研究论文。您可能还会发现该线程提供了有关当前问题的其他有用见解。
答案 2 :(得分:1)
不。要进行“梯度下降”,您需要计算一个梯度。为此,功能需要以某种方式平滑。精度/召回率或精度不是平滑函数,它仅具有斜率无限大的尖锐边缘和斜率为零的平坦位置。因此,您不能使用任何数值方法来找到此类函数的最小值-您将不得不使用某种组合优化,这对NP来说很困难。
答案 3 :(得分:0)
对于二进制分类的不平衡数据集,我也有同样的问题,我也想提高召回敏感性。我发现tf.keras中有一个内置的回调函数,可以在compile语句中使用它,如下所示:
from tensorflow.keras.metrics import Recall, Accuracy
model.compile(loss='binary_crossentropy' , optimizer=opt, metrics=[Accuracy(),Recall()])
答案 4 :(得分:0)
对于不平衡的数据集也有同样的问题,建议您使用 F1分数作为优化器的指标。 吴安德(Andrew Ng)教导说,对模型采用一个度量标准是训练模型的最简单(最佳方法)。如果您有2个指标,例如精确度和召回率,则不清楚哪个更重要。试图为一个指标设置限制显然会影响另一个指标...
F1分数是召回率和精确度的天才-这是它们的谐波平均值。
不幸的是,我正在使用的Keras并没有将F1分数作为指标来实现,就像有一个准确性指标或许多其他Keras指标https://keras.io/api/metrics/。
我发现将F1分数作为Keras量度的一种实现方式,用于每个时期: https://medium.com/@aakashgoel12/how-to-add-user-defined-function-get-f1-score-in-keras-metrics-3013f979ce0d
我已经实现了上一篇文章中的简单功能,并且该模型现在以F1分数作为其Keras优化器指标进行训练。测试结果:准确度下降了一点,F1分数上升了很多。
答案 5 :(得分:0)
处理不平衡数据集的推荐方法是使用class_weights或sample_weights。有关详细信息,请参见模型fit API。
报价:
class_weight:可选的字典,将类索引(整数)映射到权重(浮点)值,用于对损失函数加权(仅在训练过程中)。这可能有助于告诉模型“更多关注”来自代表性不足的类的样本。
权重与班级频率成反比,则损失将避免仅预测背景班级。
我知道这不是您提出问题的方式,而是恕我直言,这是解决您面临的问题的最实用方法。