【问题标题】:How to implement custom logloss with identical behavior to binary objective in LightGBM?如何在 LightGBM 中实现与二进制目标具有相同行为的自定义 logloss?
【发布时间】:2020-11-22 03:07:42
【问题描述】:

我正在尝试实现我自己的二元分类损失函数。首先,我想重现二元目标的确切行为。我特别希望:

  • 两个函数的损失具有相同的规模
  • 训练和验证斜率相似
  • predict_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_)

使用objective="binary":

使用objective=loglikelihood,坡度甚至都不是平滑的:

此外,必须将 sigmoid 应用于 model.predict_proba(X) 以获得对数似然的概率(正如我从 https://github.com/Microsoft/LightGBM/issues/2136 得出的那样)。

是否可以使用自定义损失函数获得相同的行为?有人了解所有这些差异的来源吗?

【问题讨论】:

    标签: machine-learning lightgbm


    【解决方案1】:

    查看model.predict_proba(X)在每种情况下的输出,我们可以看到内置的binary_logloss模型返回概率,而自定义模型返回logits。

    内置的评估函数将概率作为输入。为了适应自定义目标,我们需要一个自定义评估函数,它将 logits 作为输入。

    你可以这样写。我已经更改了 sigmoid 计算,以便在 logit 是一个大的负数时它不会溢出。

    def loglikelihood(labels, logits):
        #numerically stable sigmoid:
        preds = np.where(logits >= 0,
                     1. / (1. + np.exp(-logits)),
                     np.exp(logits) / (1. + np.exp(logits)))
        grad = preds - labels
        hess = preds * (1. - preds)
        return grad, hess
    
    def my_eval(labels, logits):
        #numerically stable logsigmoid:
        logsigmoid = np.where(logits >= 0, 
                              -np.log(1 + np.exp(-logits)),
                              logits - np.log(1 + np.exp(logits)))
        loss = (-logsigmoid + logits * (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)
    

    现在结果是一样的。

    【讨论】:

    • 非常酷,谢谢。那么我假设在这种情况下没有办法让 predict_proba 返回概率?
    • 我不知道。
    • 这个术语grad = preds - labelshess = preds * (1. - preds) 是什么的一阶和二阶导数?
    • @Milind Dalvi ,二进制 logloss:loss = log(preds) * labels + log(1 - preds) * (1 - labels) , preds = sigmoid(logits)。 grad = d loss / d logits, hess = d^2 loss / d^2 logits
    • loss = - log(preds) * labels - log(1 - preds) * (1 - labels)
    猜你喜欢
    • 2021-10-10
    • 1970-01-01
    • 2023-03-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-09-23
    • 1970-01-01
    相关资源
    最近更新 更多