web-dev-qa-db-ja.com

偽陰性にペナルティを課すKerasのカスタム損失関数

私は、偽陰性をできるだけ少なくしようとしている医療データセットに取り組んでいます。 「実際に病気がないときに病気になる」という予測は私には問題ありませんが、「実際に病気がないときに病気がない」という予測はそうではありません。つまり、FPは問題ありませんが、FNは問題ありません。

いくつかの調査を行った後、私は_Keeping higher learning rate for one class_、_using class weights_、_ensemble learning with specificity/sensitivity_などの方法を見つけました。

_class_weight = {0 : 0.3,1: 0.7}_のようなクラスの重みを使用し、次にmodel.fit(class_weights=class_weight)を呼び出すことで、ほぼ望ましい結果を達成しました。これにより、FNは非常に低くなりましたが、FPはかなり高くなりました。 FNを非常に低く保ちながら、FPを可能な限り削減しようとしています。

Kerasを使用してカスタム損失関数を作成するのに苦労しています。これは、偽陰性にペナルティを科すのに役立ちます。助けてくれてありがとう。

9
Swapnil B.

私たちが取り組んでいる概念を簡単に紹介します。

想起

allからpositive、どのように私たちのモデルは多くの人がポジティブであると予測しましたか?

ポジティブだったすべて= positive

私たちのモデルが言ったことは肯定的でした= said positive

recall

リコールはFNに反比例するため、リコールを改善するとFNが減少します。

特異性

allからnegative、どのように多くのモデルがネガティブと予測しましたか?

否定的だったすべて= negative

私たちのモデルが言ったことは否定的でした= said negative

specificity

リコールはFPに反比例するため、リコールを改善するとFPが減少します。

次の検索、または実行する分類関連のアクティビティでは、これらを知っていると、コミュニケーションと理解がさらに向上します。


解決策

そう。あなたがすでに理解しているように、これらの2つの概念は反対です。これは、一方を増やすともう一方が減少する可能性が高いことを意味します。

リコール時にpriorityが必要ですが、特異性をあまり緩めたくないので、これらと属性の重みの両方を組み合わせることができます。 この回答 で明確に説明されていることに従う:

import numpy as np
import keras.backend as K

def binary_recall_specificity(y_true, y_pred, recall_weight, spec_weight):

    TN = np.logical_and(K.eval(y_true) == 0, K.eval(y_pred) == 0)
    TP = np.logical_and(K.eval(y_true) == 1, K.eval(y_pred) == 1)

    FP = np.logical_and(K.eval(y_true) == 0, K.eval(y_pred) == 1)
    FN = np.logical_and(K.eval(y_true) == 1, K.eval(y_pred) == 0)

    # Converted as Keras Tensors
    TN = K.sum(K.variable(TN))
    FP = K.sum(K.variable(FP))

    specificity = TN / (TN + FP + K.epsilon())
    recall = TP / (TP + FN + K.epsilon())

    return 1.0 - (recall_weight*recall + spec_weight*specificity)

recall_weightspec_weightに注意してください?これらは、各指標に起因する重みです。配布規則の場合、常に1.0¹に追加する必要があります。例: recall_weight=0.9specificity_weight=0.1。ここでの目的は、ニーズに最適な比率を確認することです。

ただし、Kerasの損失関数は引数として(y_true, y_pred)のみを受け取る必要があるため、ラッパーを定義しましょう。

# Our custom loss' wrapper
def custom_loss(recall_weight, spec_weight):

    def recall_spec_loss(y_true, y_pred):
        return binary_recall_specificity(y_true, y_pred, recall_weight, spec_weight)

    # Returns the (y_true, y_pred) loss function
    return recall_spec_loss

そしてそれを使用すると、私たちは持っているでしょう

# Build model, add layers, etc
model = my_model
# Getting our loss function for specific weights
loss = custom_loss(recall_weight=0.9, spec_weight=0.1)
# Compiling the model with such loss
model.compile(loss=loss)

¹追加された重みは、合計1.0である必要があります。これは、recall=1.0specificity=1.0(満点)の両方の場合、式

loss1

たとえば、私たちに与えましょう

loss2

明らかに、完全なスコアを取得した場合、損失を0に等しくする必要があります。

3