Использование перекрестной проверки для выбора оптимального порога: двоичная классификация в Keras

#machine-learning #keras

#машинное обучение #keras

Вопрос:

У меня есть модель Keras, которая принимает преобразованный вектор x в качестве входных данных и выводит вероятности того, что каждое входное значение равно 1.

Я хотел бы взять прогнозы из этой модели и найти оптимальный порог. То есть, возможно, значение отсечения для «это значение равно 1» должно быть 0,23, или, может быть, оно должно быть 0,78, или что-то еще. Я знаю, что перекрестная проверка — хороший инструмент для этого.

Мой вопрос в том, как использовать это для обучения. Например, скажем, у меня есть следующая модель (взятая отсюда):

 def create_baseline():
    # create model
    model = Sequential()
    model.add(Dense(60, input_dim=60, kernel_initializer='normal', activation='relu'))
    model.add(Dense(1, kernel_initializer='normal', activation='sigmoid'))
    # Compile model
    model.compile(loss='binary_crossentropy', optimizer='adam', metrics=['accuracy'])
    return model
  

Я обучаю модель и получаю некоторые выходные вероятности:

 model.fit(train_x, train_y)
predictions = model.predict(train_y)
  

Теперь я хочу узнать пороговое значение для значения каждой записи predictions , например, для обеспечения наилучшей точности. Как я могу изучить этот параметр, вместо того, чтобы просто выбирать его после завершения обучения?

РЕДАКТИРОВАТЬ: например, скажем, у меня есть это:

 def fake_model(self):

    #Model that returns probability that each of 10 values is 1
    a_input = Input(shape=(2, 10), name='a_input')
    dense_1 = Dense(5)(a_input)
    outputs = Dense(10, activation='sigmoid')(dense_1)

    def hamming_loss(y_true, y_pred):
        return tf.to_float(tf.reduce_sum(abs(y_true - y_pred))) /tf.to_float(tf.size(y_pred))

    fakemodel = Model(a_input, outputs)

    #Use the outputs of the model; find the threshold value that minimizes the Hamming loss
    #Record the final confusion matrix.
  

Как я могу обучить такую модель от начала до конца?

Комментарии:

1. Конечно, похоже, что вы хотите реализовать некоторое повышение. Я имею в виду, вы могли бы просто поискать идеальное предельное значение, как вы сказали … или вы могли бы перейти actual - predicted к другой модели, пытаясь ее минимизировать. В любом случае вы достигаете аналогичного результата, и с помощью этого метода вы открываете возможность повышения точности. Просто мысль!

2. Спасибо @TheLoneDeranger. Есть ли способ обучить всю эту систему от начала до конца?

Ответ №1:

Если кривая ROC — это не то, что вы ищете, вы можете создать пользовательский слой Keras, который принимает выходные данные вашей исходной модели и пытается определить оптимальный порог с учетом истинных выходных данных и прогнозируемых вероятностей.

Этот уровень вычитает пороговое значение из прогнозируемой вероятности, умножает на относительно большую константу (в данном случае 100), а затем применяет сигмоидальную функцию. Вот график, который показывает функцию при трех разных порогах (.3, .5, .7).

введите описание изображения здесь

Ниже приведен код для определения этого уровня и создания модели, состоящей исключительно из него. После подгонки вашей исходной модели передайте ее выходные вероятности этой модели и начните обучение для достижения оптимального порога.

 class ThresholdLayer(keras.layers.Layer):
    def __init__(self, **kwargs):
        super(ThresholdLayer, self).__init__(**kwargs)

    def build(self, input_shape):
        self.kernel = self.add_weight(name="threshold", shape=(1,), initializer="uniform",
                                      trainable=True)
        super(ThresholdLayer, self).build(input_shape)

    def call(self, x):
        return keras.backend.sigmoid(100*(x-self.kernel))

    def compute_output_shape(self, input_shape):
        return input_shape

out = ThresholdLayer()(input_layer)
threshold_model = keras.Model(inputs=input_layer, outputs=out)
threshold_model.compile(optimizer="sgd", loss="mse")
  

Комментарии:

1. Привет, Ахмед, спасибо за ваш ответ. Почему необходимо вычитать пороговое значение и умножать на большое число?

2. Это приближение к функции определения порога, допустим, у нас есть вероятность .6 в качестве входных данных и порог .5, вычитая порог, вы получаете положительный результат (.1), умножение его на большую константу, а затем применение softmax просто приведет к 1. Если вероятность ввода была меньше порогового значения, результат будет отрицательным, и умножение его на большую константу с последующим применением softmax приведет к 0. Проверьте графики, которые я прикрепил к моему ответу, для лучшей визуализации функции.

Ответ №2:

Во-первых, вот прямой ответ на ваш вопрос. Вы думаете о кривой ROC. Например, предполагая, что некоторые данные X_test и y_test :

 from matplotlib import pyplot as plt
from sklearn.metrics import roc_curve
from sklearn.metrics import auc

y_pred = model.predict(X_test).ravel()

fpr, tpr, thresholds = roc_curve(y_test, y_pred)

my_auc = auc(fpr, tpr)

plt.figure(1)
plt.plot([0, 1], [0, 1], 'k--')
plt.plot(fpr, tpr, label='Model_name (area = {:.3f})'.format(my_auc))
plt.xlabel('False positive rate')
plt.ylabel('True positive rate')
plt.title('ROC curve')
plt.legend(loc='best')
plt.show()

plt.figure(2)
plt.xlim(0, 0.2)
plt.ylim(0.8, 1)
plt.plot([0, 1], [0, 1], 'k--')
plt.plot(fpr, tpr, label='Model_name (area = {:.3f})'.format(my_auc))
plt.xlabel('False positive rate')
plt.ylabel('True positive rate')
plt.title('ROC curve close-up')
plt.legend(loc='best')
plt.show()
  

Во-вторых, что касается моего комментария, вот пример одной попытки.Это можно сделать в Keras, или TF, или где угодно, хотя он делает это с помощью XGBoost.

Надеюсь, это поможет!

Комментарии:

1. Я думаю, что я ищу что-то большее в духе keras.io/getting-started/functional-api-guide/#more-examples (Модель общего видения), где я могу использовать одну потерю для обучения первой модели и другую потерю (основанную на точности) для обучения следующей. Возможно ли это?

Ответ №3:

Первая идея, которая у меня есть, — это грубая сила. Вы вычисляете в тестовом наборе метрику отдельно для каждого вашего ввода и соответствующего ему прогнозируемого результата.
Затем для каждого из них перебирайте значения для пороговых значений между 0 и 1, пока метрика не будет оптимизирована для данной пары ввода / прогнозирования.

Ответ №4:

Для многих популярных показателей качества классификации (точность, точность, отзыв и т. Д.) Вы просто не можете узнать оптимальный порог во время обучения вашей нейронной сети.

Это связано с тем, что эти показатели не поддаются дифференцированию — поэтому при обновлении градиента не удастся правильно установить пороговое значение (или любой другой параметр). Поэтому вы вынуждены оптимизировать плавную потерю (например, вероятность отрицательного логарифма) во время обучения большинства параметров, а затем настраивать порог с помощью поиска по сетке.

Конечно, вы можете придумать сглаженную версию своей метрики и оптимизировать ее (и иногда люди делают это). Но в большинстве случаев можно оптимизировать логарифмическую вероятность, получить хороший вероятностный классификатор и настроить пороговые значения поверх него. Например, если вы хотите оптимизировать точность, вам следует сначала как можно точнее оценить вероятности классов (чтобы приблизиться к идеальному байесовскому классификатору), а затем просто выбрать их argmax.

Комментарии:

1. Хм. Я согласен в принципе, но мне интересно, можете ли вы сделать приятный маленький трюк, подобный используемому с автокодерами — если у вас есть дискретный скрытый слой, вы можете использовать непрерывное приближение (которое достаточно близко к исходному дискретному распределению) и дифференцировать через это.