为 LightGBM 提供额外的自定义指标以实现早期停止

Kyl*_*ons 5 python lightgbm

我使用训练 API 在 LightGBM 中运行二元分类,并希望停止自定义指标,同时仍跟踪一个或多个内置指标。不过,尚不清楚这是否可能。

在这里我们可以禁用默认binary_logloss指标并仅跟踪我们的自定义指标:

import lightgbm as lgb

def my_eval_metric(...):
    ...

d_train = lgb.Dataset(...)
d_validate = lgb.Dataset(...)

params = {
    "objective": "binary",
    "metric": "custom",
}

evals_result = {}

model = lgb.train(
    params,
    d_train,
    valid_sets=[d_validate],
    feval=my_eval_metric,
    early_stopping_rounds=10,
    evals_result=evals_result,
)
Run Code Online (Sandbox Code Playgroud)

如果我们使用metric默认值,我们也会跟踪binary_logloss,但我们将停止两个指标,而不仅仅是我们的自定义指标:

params = {
    "objective": "binary",
    # "metric": "custom",
}
Run Code Online (Sandbox Code Playgroud)

我们可以first_metric_only 在 中设置params,但现在我们只会停止因为binary_logloss显然,这是第一个指标:

params = {
    "objective": "binary",
    "first_metric_only": True,
}
Run Code Online (Sandbox Code Playgroud)

其他可能有效但看起来很痛苦的事情:

  1. 在 sklearn API 中,您可以指定一个评估指标列表,其中散布着自定义指标的可调用项和内置指标的字符串;但是,我不想切换到 sklearn API。
  2. 我可以重新实现binary_logloss并将其作为自定义评估指标与我的其他自定义指标一起传递到列表中并使用first_metric_only;但是,似乎我不必这样做。

不起作用的事情:

  1. feval=[my_eval_metric, 'binary_logloss']lgb.train通话中。抱怨字符串不可调用。
  2. metric: [my_eval_metric, 'binary_logloss']params集合中。当训练以 开始时发出警告Unknown parameter: my_eval_metric,然后出现错误ValueError: For early stopping, at least one dataset and eval metric is required for evaluation

我是否遗漏了一些明显的东西,或者这是 LightGBM API 中的一个小漏洞?

这是版本 3.2.1。在 3.0.0 版本中,似乎完全不可能在训练 API 中传递多个自定义评估指标。我不确定那里的 sklearn API。

Jam*_*amb 11

如果您问“如何根据自定义评估指标函数执行提前停止?” ,可以通过将参数设置metric为字符串来实现"None"。这将导致 LightGBM 跳过基于目标函数的默认评估指标(binary_logloss在您的示例中),并且仅对您在 中提供的自定义指标函数执行早期停止feval

下面的示例 在 Python 3.8.8 上使用lightgbm==3.2.1和重现了此行为。scikit-learn==0.24.1

import lightgbm as lgb
from sklearn.datasets import load_breast_cancer
from sklearn.model_selection import train_test_split

X, y = load_breast_cancer(return_X_y=True)
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.1, random_state=42)

dtrain = lgb.Dataset(
    data=X_train,
    label=y_train
)

dvalid = lgb.Dataset(
    data=X_test,
    label=y_test,
    reference=dtrain
)

def _constant_metric(dy_true, dy_pred):
    """An eval metric that always returns the same value"""
    metric_name = 'constant_metric'
    value = 0.708
    is_higher_better = False
    return metric_name, value, is_higher_better

evals_result = {}

model = lgb.train(
    params={
        "objective": "binary",
        "metric": "None",
        "num_iterations": 100,
        "first_metric_only": True,
        "verbose": 0,
        "num_leaves": 8
    },
    train_set=dtrain,
    valid_sets=[dvalid],
    feval=_constant_metric,
    early_stopping_rounds=5,
    evals_result=evals_result,
)
Run Code Online (Sandbox Code Playgroud)

您可以在日志中看到,我提供的自定义指标函数是根据验证集进行评估的,并且训练在early_stopping_rounds连续几轮后停止,没有任何改进。

[LightGBM] [Warning] Auto-choosing col-wise multi-threading, the overhead of testing was 0.000846 seconds.
You can set `force_col_wise=true` to remove the overhead.
[1] valid_0's constant_metric: 0.708
Training until validation scores don't improve for 5 rounds
[2] valid_0's constant_metric: 0.708
[3] valid_0's constant_metric: 0.708
[4] valid_0's constant_metric: 0.708
[5] valid_0's constant_metric: 0.708
[6] valid_0's constant_metric: 0.708
Early stopping, best iteration is:
[1] valid_0's constant_metric: 0.708
Evaluated only: constant_metric
Run Code Online (Sandbox Code Playgroud)

如果您问“如何提供内置指标和自定义评估函数的组合并lgb.train()评估所有指标,但仅使用自定义指标来提前停止?” ...那么是的,从 3.2.1 开始不支持这一点lightgbm