web-dev-qa-db-ja.com

損失ではなく精度または再現率に基づくケラのオプティマイザはありますか?

私は、0と1の2つのクラスのみを使用してセグメンテーションニューラルネットワークを開発しています(0は背景、1は画像上で見つけたいオブジェクトです)。各画像には、1の約80%と0の約20%があります。ご覧のとおり、データセットは不均衡であり、結果が間違っています。私の精度は85%で、損失は少ないですが、それは私のモデルがバックグラウンドを見つけるのが得意だからです!

オプティマイザを精度や再現率など、この場合により有効な別のメトリックに基づいて使用したいと思います。

誰もがこれを実装する方法を知っていますか?

11
freshmanData

コメントが十分に明確ではなかったので、必要なものを追跡するためのコードを紹介しましょう。最適化のために精度や再現率を使用しません。最高の重みを得るために、それらを有効なスコアとして追跡するだけです。損失、オプティマイザ、メトリックなどを混在させないでください。それらは同じもののためのものではありません。

THRESHOLD = 0.5
def precision(y_true, y_pred, threshold_shift=0.5-THRESHOLD):

    # just in case 
    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)))

    precision = tp / (tp + fp)
    return precision


def recall(y_true, y_pred, threshold_shift=0.5-THRESHOLD):

    # just in case 
    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()
    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 
    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
8
Frayal

いいえ。「勾配降下」を行うには、勾配を計算する必要があります。このため、関数はなんとかスムーズである必要があります。精度/再現率または精度は滑らかな関数ではなく、勾配が無限である鋭いエッジと勾配がゼロである平らな場所しかありません。したがって、そのような関数の最小値を見つけるために、どのような数値的方法も使用できません。ある種の組み合わせ最適化を使用する必要があり、それはNP困難です。

3
jlanik

他の人が述べたように、精度/再現率は損失関数として直接使用できません。ただし、精度/再現に関連する関数全体(ROC AUC、固定再現時の精度など)に役立つ、より優れたプロキシ損失関数が見つかりました。

研究論文 分解不可能な目的のスケーラブルな学習 は、特定の計算された境界を使用して組み合わせ最適化を回避する方法でこれをカバーし、著者によるいくつかのTensorflowコードは tensorflow/models リポジトリ。さらに、フォローアップの質問 StackOverflowで があり、これを使用可能なKeras損失関数に適応させる回答があります。

Francois Chollet氏と他の参加者に特に感謝します Kerasの問題のスレッドはこちら その研究論文を発表してくれました。また、スレッドは、目前の問題に対する他の有用な洞察を提供することもあります。

0
J Trana