Я хочу реализовать свои собственные функции проверки потерь и обучения с использованием lightGBM. В качестве отправной точки я хотел бы повторить реализацию sklearn. Но результаты моих пользовательских функций не дают одинаковую потерю проверки или одинаковые вероятности предсказания. Я использовал код, найденный в этом ответе: { ссылка }, а также вывел формулы для градиента и гессиана, выражая двоичный логлосс в терминах lo git, как видно из https://stats.stackexchange.com/a/205140 и https://stats.stackexchange.com/questions/157870/scikit-binomial-deviance-loss-function.
Мой код выглядит следующим образом:
import numpy as np
import sklearn
from sklearn.model_selection import train_test_split
from sklearn.metrics import confusion_matrix
from sklearn.datasets import make_classification
from lightgbm import LGBMClassifier
train_test_seed = 42
test_size = 0.20
validation_size = 0.25
X, y = make_classification(n_samples=1000, n_features=10)
# Get training, testing and validation data
X_train, X_test, y_train, y_test = train_test_split(
X, y, test_size=test_size, random_state=train_test_seed, stratify=y)
Xc_train, Xc_valid, yc_train, yc_valid = train_test_split(
X_train, y_train, test_size=validation_size, stratify=y_train)
def sigmoid(x):
# Numerically stable sigmoid
answer = np.where(x >= 0,
1. / (1. + np.exp(-x)),
np.exp(x) / (1. + np.exp(x)))
return answer
def my_eval(labels, preds):
# validation loss function
# Convert logits to probabilities
preds = sigmoid(preds)
# Compute loss
logloss = labels*np.log(preds)+(1-labels)*np.log(1-preds)
loss = -1.*logloss.mean()
return "error", loss, False
def my_logloss(labels, preds):
# Training evaluation, calculate gradients and hessians of loss
# Convert logits to probabilities
preds = sigmoid(preds)
# Compute gradients and hessians
grad = -(labels - preds)
hess = preds * (1. - preds)
return grad, hess
# Model with standard training loss
gbm = LGBMClassifier(learning_rate=0.05,
num_iterations=100,
max_bin=1000,
n_estimators=1000,
random_state=train_test_seed,
early_stopping_rounds=50,
scale_pos_weight=2.0,
importance_type='gain',
num_leaves=150,
objective='binary',
subsample=0.7,
colsample_bytree=0.6, )
# Fit standard model with standard binary logloss
gbm.fit(Xc_train, yc_train, eval_set=[
(Xc_valid, yc_valid)], verbose=10, eval_metric='binary_logloss')
# Model with my custom training loss
gbm_my = LGBMClassifier(learning_rate=0.05,
num_iterations=100,
max_bin=1000,
n_estimators=1000,
random_state=train_test_seed,
early_stopping_rounds=50,
scale_pos_weight=2.0,
importance_type='gain',
num_leaves=150,
objective=my_logloss,
subsample=0.7,
colsample_bytree=0.6, )
# Fit custom model with custom binary logloss
gbm_my.fit(Xc_train, yc_train, eval_set=[
(Xc_valid, yc_valid)], verbose=10, eval_metric=my_eval)
# Probabilities for both models
y_prob = gbm.predict_proba(X_test)
y_prob_test = sigmoid(gbm_my.predict_proba(X_test))
print(y_prob[:10])
print(y_prob_test[:10])
# Evaluate on test set
y_pred = gbm.predict(X_test)
# Predict gives the same results as sigmoid(predict_proba) >= 0.5
y_pred_test = gbm_my.predict(X_test)
# Confusion matrix for standard implementation
cm = confusion_matrix(y_test, y_pred)
print(cm)
# Confusion matrix for my custom implementation
cm_test = confusion_matrix(y_test, y_pred_test)
print(cm_test)
Но я все еще не получаю те же результаты от моей пользовательской реализации. Я получаю следующие потери проверки (напечатанные каждые 10 раундов), левое изображение - стандартная модель, а правое изображение - пользовательская модель:
Кроме того, прогнозируемые вероятности для каждого класса различны (первый массив - стандартная модель, второй массив - пользовательская модель):
Наконец, это дает две разные матрицы путаницы (первая матрица - стандартная модель, вторая - пользовательская модель):
Почему мой заказ реализация не дает те же результаты, что и реализация sklearn?
Код, который я реплицировал с Как реализовать пользовательские журналы с идентичным поведением двоичного объекта в LightGBM? имеет комментарий, говорящий " Кстати, log (sigmoid) также следует вычислять другим, численно устойчивым способом, мне просто лень это делать сейчас. См. https://timvieira.github.io/blog/post/2014/02/11/exp-normalize-trick/ ". Но я не нахожу в этом посте ничего о числовом стабильном журнале (сигмоиде), только о численно стабильном софтмаксе и сигмоиде. Я не могу добавить комментарий к вышеупомянутому комментарию, так как мне не хватает репутации.
Заранее благодарю за помощь!
Редактировать : Я попытался запустить LGBMClassifier
только с параметром objective
, но результаты между двумя моделями все еще различны.