Как реализовать пользовательские журналы с идентичным поведением для двоичной цели в LightGBM? - PullRequest
1 голос
/ 26 октября 2019

Я пытаюсь реализовать свою собственную функцию потерь для двоичной классификации. Для начала я хочу воспроизвести точное поведение двоичной цели. В частности, я хочу, чтобы:

  • Потеря обеих функций имела одинаковую шкалу
  • Склон обучения и проверки достоверности аналогичен
  • Forex_Proba (X) возвращает вероятности

Это не относится к приведенному ниже коду:

import sklearn.datasets
import lightgbm as lgb
import numpy as np

X, y = sklearn.datasets.load_iris(return_X_y=True)
X, y = X[y <= 1], y[y <= 1]

def loglikelihood(labels, preds):
    preds = 1. / (1. + np.exp(-preds))
    grad = preds - labels
    hess = preds * (1. - preds)
    return grad, hess

model = lgb.LGBMClassifier(objective=loglikelihood)  # or "binary"
model.fit(X, y, eval_set=[(X, y)], eval_metric="binary_logloss")
lgb.plot_metric(model.evals_result_)

С целью = "двоичный":

enter image description here

С целью = логарифмическая вероятность, что наклон даже не ровный:

enter image description here

Кроме того, сигмоид должен быть применен к model.predict_proba(X) чтобы получить вероятности для логарифмического правдоподобия (как я выяснил из https://github.com/Microsoft/LightGBM/issues/2136).

Возможно ли получить такое же поведение с помощью пользовательской функции потерь? Кто-нибудь понимает, откуда все эти различия происходят?

1 Ответ

1 голос
/ 26 октября 2019

Если вы посмотрите, что model.predict_proba(X) возвращает в каждом случае, вы увидите, что встроенная модель binary_logloss возвращает вероятности, а пользовательская модель возвращает логиты.

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

Во-первых, давайте воспользуемся численно устойчивой сигмоидой:

def sigmoid(x):
    answer = np.where(x >= 0,
                     1. / (1. + np.exp(-x)),
                     np.exp(x) / (1. + np.exp(x)))
    return answer

def loglikelihood(labels, preds):
    preds = sigmoid(preds)
    grad = preds - labels
    hess = preds * (1. - preds)
    return grad, hess

def my_eval(labels, preds):
    preds = sigmoid(preds)
    loss = (- np.log(preds) * labels - np.log(1 - preds) * (1 - labels)).mean()
    return "error", loss, False

model1 = lgb.LGBMClassifier(objective='binary')
model1.fit(X, y, eval_set=[(X, y)], eval_metric="binary_logloss")
model2 = lgb.LGBMClassifier(objective=loglikelihood)
model2.fit(X, y, eval_set=[(X, y)], eval_metric=my_eval)

Теперь результаты совпадают.

...