LightGBM 中的 predict_proba() 函数在内部是如何工作的?

Jer*_* M. 10 python machine-learning probability scikit-learn lightgbm

这是在内部理解如何使用 预测类的概率LightGBM

其他包,如sklearn,为其分类器提供了详尽的细节。例如:

概率估计。

所有类的返回估计值按类的标签排序。

对于 multi_class 问题,如果 multi_class 设置为“多项式”,则使用 softmax 函数来查找每个类的预测概率。否则使用一对一的方法,即使用逻辑函数计算每个类的概率,假设它是正的。并在所有类中标准化这些值。

预测 X 的类别概率。

输入样本的预测类别概率计算为森林中树木的平均预测类别概率。单棵树的类概率是叶子中同一类样本的分数。

还有其他 Stack Overflow 问题提供了更多详细信息,例如:

我正在尝试为 LightGBM 的predict_proba功能揭示相同的细节。该文档未列出有关如何计算概率的详细信息。

该文件只是说明:

返回每个样本的每个类的预测概率。

源代码如下:

def predict_proba(self, X, raw_score=False, start_iteration=0, num_iteration=None,
                  pred_leaf=False, pred_contrib=False, **kwargs):
    """Return the predicted probability for each class for each sample.

    Parameters
    ----------
    X : array-like or sparse matrix of shape = [n_samples, n_features]
        Input features matrix.
    raw_score : bool, optional (default=False)
        Whether to predict raw scores.
    start_iteration : int, optional (default=0)
        Start index of the iteration to predict.
        If <= 0, starts from the first iteration.
    num_iteration : int or None, optional (default=None)
        Total number of iterations used in the prediction.
        If None, if the best iteration exists and start_iteration <= 0, the best iteration is used;
        otherwise, all iterations from ``start_iteration`` are used (no limits).
        If <= 0, all iterations from ``start_iteration`` are used (no limits).
    pred_leaf : bool, optional (default=False)
        Whether to predict leaf index.
    pred_contrib : bool, optional (default=False)
        Whether to predict feature contributions.

        .. note::

            If you want to get more explanations for your model's predictions using SHAP values,
            like SHAP interaction values,
            you can install the shap package (https://github.com/slundberg/shap).
            Note that unlike the shap package, with ``pred_contrib`` we return a matrix with an extra
            column, where the last column is the expected value.

    **kwargs
        Other parameters for the prediction.

    Returns
    -------
    predicted_probability : array-like of shape = [n_samples, n_classes]
        The predicted probability for each class for each sample.
    X_leaves : array-like of shape = [n_samples, n_trees * n_classes]
        If ``pred_leaf=True``, the predicted leaf of every tree for each sample.
    X_SHAP_values : array-like of shape = [n_samples, (n_features + 1) * n_classes] or list with n_classes length of such objects
        If ``pred_contrib=True``, the feature contributions for each sample.
    """
    result = super(LGBMClassifier, self).predict(X, raw_score, start_iteration, num_iteration,
                                                 pred_leaf, pred_contrib, **kwargs)
    if callable(self._objective) and not (raw_score or pred_leaf or pred_contrib):
        warnings.warn("Cannot compute class probabilities or labels "
                      "due to the usage of customized objective function.\n"
                      "Returning raw scores instead.")
        return result
    elif self._n_classes > 2 or raw_score or pred_leaf or pred_contrib:
        return result
    else:
        return np.vstack((1. - result, result)).transpose()
Run Code Online (Sandbox Code Playgroud)

我怎么能理解predict_proba函数LightGBM在内部是如何工作的?

fny*_*fny 7

LightGBM 与所有用于分类的梯度提升方法一样,本质上结合了决策树和逻辑回归。我们从表示概率的相同逻辑函数(又名 softmax)开始:

P(y = 1 | X) = 1/(1 + exp(Xw))

有趣的是,特征矩阵X是由决策树集合的终端节点组成的。然后这些都由 加权w,这是一个必须学习的参数。用于学习权重的机制取决于所使用的精确学习算法。同样,X 的构造也取决于算法。例如,LightGBM 引入了两个新颖的功能,它们比 XGBoost 赢得了性能改进:“基于梯度的单侧采样”和“独家功能捆绑”。但是,一般来说,每一行收集每个样本的终端叶子,列代表终端叶子。

所以这就是文档可以说的......

概率估计。

输入样本的预测类别概率计算为来自与提供的样本对应的决策树集合的加权终端叶的 softmax。

有关更多详细信息,您必须深入研究 boosting、XGBoost 和最后的 LightGBM 论文的细节,但考虑到您提供的其他文档示例,这似乎有点繁重。


Mig*_*ejo 5

简短说明

下面我们可以看到每个方法在后台调用的内容的说明。首先,predict_proba()LGBMClassifierpredict()方法是从调用方法LGBMModel(它继承自它)。

LGBMClassifier.predict_proba() (inherits from LGBMModel)
  |---->LGBMModel().predict() (calls LightGBM Booster)
          |---->Booster.predict()
Run Code Online (Sandbox Code Playgroud)

然后,它predict()从 LightGBM Booster(Booster类)调用该方法。为了调用这个方法,首先应该训练Booster。

基本上,这Booster是通过调用它的predict()方法为每个样本生成预测值的方法。请参阅下文,详细了解此助推器的工作原理。

详细说明或 LightGBM Booster 是如何工作的?

我们试图回答 LightGBM 助推器如何工作的问题?通过浏览 Python 代码,我们可以大致了解它是如何训练和更新的。但是,还有一些我无法解释的 LightGBM 的 C++ 库的进一步参考。但是,解释了 LightGBM 的 Booster 工作流程的一般概览。

A. 初始化和训练 Booster

_BoosterLGBMModel通过调用初始化train()函数,对595线sklearn.py我们看下面的代码

self._Booster = train(params, train_set,
                      self.n_estimators, valid_sets=valid_sets, valid_names=eval_names,
                      early_stopping_rounds=early_stopping_rounds,
                      evals_result=evals_result, fobj=self._fobj, feval=feval,
                      verbose_eval=verbose, feature_name=feature_name,
                      callbacks=callbacks, init_model=init_model)
Run Code Online (Sandbox Code Playgroud)

注意train()来自engine.py

在里面train()我们看到 Booster 已初始化(第231行)

# construct booster
try:
    booster = Booster(params=params, train_set=train_set)
...
Run Code Online (Sandbox Code Playgroud)

并在每次训练迭代时更新(第 242 行)。

for i in range_(init_iteration, init_iteration + num_boost_round):
     ...
     ... 
     booster.update(fobj=fobj)
     ...
Run Code Online (Sandbox Code Playgroud)

B. 效果如何booster.update()

要了解该update()方法的工作原理,我们应该转到basic.py 的第 2315。在这里,我们看到此函数将 Booster 更新为一次迭代

两种更新 booster 的替代方法,具体取决于您是否提供目标函数。

  • 目标函数是 None

在第 2367 行,我们得到以下代码

if fobj is None:
    ...
    ...
    _safe_call(_LIB.LGBM_BoosterUpdateOneIter(
               self.handle,
               ctypes.byref(is_finished)))
    self.__is_predicted_cur_iter = [False for _ in range_(self.__num_dataset)]
    return is_finished.value == 1
Run Code Online (Sandbox Code Playgroud)

请注意,由于fobj未提供目标函数 ( ),它通过调用LGBM_BoosterUpdateOneIterfrom来更新 booster _LIB。简而言之,_LIB就是加载的C++LightGBM 库。

什么是_LIB

_LIB是一个通过调用(basic.py 的第 29存储加载的 LightGBM 库的变量。_load_lib()

然后_load_lib()通过在您的系统上找到lib_lightgbm.dll(Windows) 或lib_lightgbm.so(Linux)的路径来加载 LightGBM 库。

  • 提供的目标函数

当遇到自定义对象函数时,我们得到以下情况

else:
    ...
    ...
    grad, hess = fobj(self.__inner_predict(0), self.train_set)
Run Code Online (Sandbox Code Playgroud)

其中__inner_predict()是 LightGBM 的 Booster 的一种方法(有关该类的更多详细信息,请参见 basic.py 中的第 1930 行Booster),它预测训练和验证数据。在里面__inner_predict()basic.py 的第 3142)我们看到它调用LGBM_BoosterGetPredictfrom_LIB来获取预测,即,

_safe_call(_LIB.LGBM_BoosterGetPredict(
                self.handle,
                ctypes.c_int(data_idx),
                ctypes.byref(tmp_out_len),
                data_ptr))
Run Code Online (Sandbox Code Playgroud)

最后,在更新range_(init_iteration, init_iteration + num_boost_round)时间后,将训练助推器。因此, Booster.predict()可以由 调用LightGBMClassifier.predict_proba()

注意。助力器被训练成模型拟合步骤的一部分,通过especifically LGBMModel.fit(),见线595 sklearn.py用于代码的细节。