LightGBM 常见问题


请将问题、功能请求和错误报告发布到 https://github.com/microsoft/LightGBM/issues

本项目主要由志愿者维护,请耐心等待。如果您的请求具有时效性,或者超过一个月没有收到回复,请在下方标记维护人员以寻求帮助。


LightGBM 通用问题

1. 在哪里可以找到更多关于 LightGBM 参数的详细信息?

请查看参数

2. 在拥有数百万特征的数据集上,训练不开始(或很久之后才开始)。

bin_construct_sample_cnt 使用较小的值,对 min_data 使用较大的值。

3. 在大型数据集上运行 LightGBM 时,我的计算机内存不足。

多种解决方案:将 histogram_pool_size 参数设置为您希望 LightGBM 使用的 MB 值(histogram_pool_size + 数据集大小 ≈ 使用的内存),降低 num_leaves 或降低 max_bin(参见 Microsoft/LightGBM#562)。

4. 我使用 Windows。应该使用 Visual Studio 还是 MinGW 编译 LightGBM?

Visual Studio 对 LightGBM 性能最佳

5. 使用 LightGBM GPU 时,多次运行无法重现结果。

这是正常且预期的行为,但您可以尝试使用 gpu_use_dp = true 来实现可重现性(参见 Microsoft/LightGBM#560)。您也可以使用 CPU 版本。

6. 更改线程数时,Bagging 无法重现。

LightGBM 的 Bagging 是多线程的,因此其输出取决于使用的线程数。目前没有解决方法

#2804 开始,bagging 结果不再依赖于线程数。因此此问题应在最新版本中得到解决。

7. 我尝试使用随机森林模式,LightGBM 崩溃了!

对于任意参数,这是预期行为。要启用随机森林,必须使用不等于 1 的 bagging_fractionfeature_fraction,以及一个 bagging_freq此主题包含一个示例。

8. 在多核系统上使用 LightGBM 处理超大数据集时,Windows 中的 CPU 使用率很低(例如 10%)。

请使用 Visual Studio,因为它可能比 MinGW 快 10 倍,特别是对于非常大的树。

9. 当我尝试使用 categorical_feature 参数指定类别列时,收到以下警告序列,但列中没有负值。

[LightGBM] [Warning] Met negative value in categorical features, will convert it to NaN
[LightGBM] [Warning] There are no meaningful features, as all feature values are constant.

您尝试通过 categorical_feature 传递的列可能包含非常大的值。LightGBM 中的类别特征受 int32 范围限制,因此您不能将大于 Int32.MaxValue (2147483647) 的值作为类别特征传递(参见 Microsoft/LightGBM#1359)。您应该首先将它们转换为从零到类别数的整数。

10. LightGBM 随机崩溃,错误信息类似:Initializing libiomp5.dylib, but found libomp.dylib already initialized.

OMP: Error #15: Initializing libiomp5.dylib, but found libomp.dylib already initialized.
OMP: Hint: This means that multiple copies of the OpenMP runtime have been linked into the program. That is dangerous, since it can degrade performance or cause incorrect results. The best thing to do is to ensure that only a single OpenMP runtime is linked into the process, e.g. by avoiding static linking of the OpenMP runtime in any library. As an unsafe, unsupported, undocumented workaround you can set the environment variable KMP_DUPLICATE_LIB_OK=TRUE to allow the program to continue to execute, but that may cause crashes or silently produce incorrect results. For more information, please see http://www.intel.com/software/products/support/.

可能原因:此错误表示您的机器上安装了多个 OpenMP 库,它们之间存在冲突。(错误消息中的文件扩展名可能因操作系统而异)。

如果您使用 Conda 分发的 Python,那么很可能是由于 Conda 的 numpy 包(其中包括 mkl 包)与系统范围的库冲突所致。在这种情况下,您可以更新 Conda 中的 numpy 包,或者通过在 Conda 环境文件夹 $CONDA_PREFIX/lib 中创建符号链接,将 Conda 的 OpenMP 库实例替换为系统范围的库实例。

解决方案:假设您使用的是安装了 Homebrew 的 macOS,以下命令会使用 Homebrew 安装的系统范围库的符号链接覆盖当前活跃的 Conda 环境中的 OpenMP 库文件

ln -sf `ls -d "$(brew --cellar libomp)"/*/lib`/* $CONDA_PREFIX/lib

上述描述的修复方法在 OpenMP 8.0.0 版本发布之前一直有效。从 8.0.0 版本开始,Homebrew 的 OpenMP 公式包含了 -DLIBOMP_INSTALL_ALIASES=OFF 选项,导致该修复方法不再有效。但是,您可以手动创建库别名的符号链接

for LIBOMP_ALIAS in libgomp.dylib libiomp5.dylib libomp.dylib; do sudo ln -sf "$(brew --cellar libomp)"/*/lib/libomp.dylib $CONDA_PREFIX/lib/$LIBOMP_ALIAS; done

另一种解决方法是彻底移除 Conda 包中的 MKL 优化

conda install nomkl

如果不是这种情况,那么您应该自行查找冲突的 OpenMP 库安装,并只保留其中一个。

11. 在 Linux 中同时使用多线程 (OpenMP) 和 forking 时,LightGBM 会挂起。

使用 nthreads=1 禁用 LightGBM 的多线程。OpenMP 存在一个错误,会导致激活多线程的 forked 会话挂起。一个更昂贵的解决方案是使用新进程而不是 forking,但请记住,创建新进程需要复制内存和加载库(例如:如果您想将当前进程 fork 16 次,那么您需要在内存中复制 16 份数据集)(参见 Microsoft/LightGBM#1789)。

如果 forked 会话中确实需要多线程,另一种选择是使用 Intel 工具链编译 LightGBM。Intel 编译器不受此错误影响。

对于 C/C++ 用户,在 fork 发生之前不能使用任何 OpenMP 功能。如果在 fork 发生之前使用了 OpenMP 功能(例如:使用 OpenMP 进行 forking),OpenMP 会在 forked 会话内部挂起。请使用新进程并根据需要复制内存,而不是 forking 创建新进程(或者,使用 Intel 编译器)。

如果云平台容器服务使用 Linux fork 在单个实例上运行多个容器,可能会导致 LightGBM 挂起。例如,LightGBM 在 AWS Batch 数组作业中挂起,该作业使用 ECS 代理管理多个运行中的作业。设置 nthreads=1 可以缓解此问题。

12. 为什么 LightGBM 默认不启用提前停止?

提前停止涉及选择一个验证集,这是一种特殊的保留集,用于在每次迭代后评估模型的当前状态,以判断训练是否可以停止。

LightGBM 中,我们决定要求用户直接指定此集合。将训练数据分割为训练集、测试集和验证集有许多选项。

适当的分割策略取决于任务和数据的领域,这些信息建模者拥有,但作为通用工具的 LightGBM 则没有。

13. LightGBM 支持直接从零基或一基 LibSVM 格式文件加载数据吗?

LightGBM 直接支持从零基 LibSVM 格式文件加载数据。

14. 使用 MinGW 编译 LightGBM 时,为什么 CMake 找不到编译器?

CMake Error: CMAKE_C_COMPILER not set, after EnableLanguage
CMake Error: CMAKE_CXX_COMPILER not set, after EnableLanguage

这是 CMake 在使用 MinGW 时的一个已知问题。最简单的解决方案是再次运行 cmake 命令,以绕过 CMake 的一次性阻塞。或者您可以将您的 CMake 版本升级到至少 3.17.0 版本。

有关更多详细信息,请参见 Microsoft/LightGBM#3060

15. 在哪里可以找到 LightGBM 的 logo 以在我的演示文稿中使用?

您可以在此处找到 LightGBM 不同文件格式和分辨率的 logo。

16. LightGBM 随机崩溃或操作系统在运行 LightGBM 期间或之后挂起。

可能原因:这种行为可能表明您的机器上安装了多个 OpenMP 库,它们之间存在冲突,类似于 FAQ #10

如果您使用的任何 Python 包依赖于 threadpoolctl,在这种情况下您也可能在日志中看到以下警告

/root/miniconda/envs/test-env/lib/python3.8/site-packages/threadpoolctl.py:546: RuntimeWarning:
Found Intel OpenMP ('libiomp') and LLVM OpenMP ('libomp') loaded at
the same time. Both libraries are known to be incompatible and this
can cause random crashes or deadlocks on Linux when loaded in the
same Python program.
Using threadpoolctl may cause crashes or deadlocks. For more
information and possible workarounds, please see
    https://github.com/joblib/threadpoolctl/blob/master/multiple_openmp.md

有关多个 OpenMP 实例之间冲突的详细描述,请参见以下文档

解决方案:假设您正在使用 LightGBM Python 包并使用 conda 作为包管理器,我们强烈建议使用 conda-forge 通道作为所有 Python 包安装的唯一来源,因为它包含用于解决 OpenMP 冲突的内置补丁。其他一些解决方法列在此处的“Workarounds for Intel OpenMP and LLVM OpenMP case”部分下。

如果不是这种情况,那么您应该自行查找冲突的 OpenMP 库安装,并只保留其中一个。

17. 加载 LightGBM 失败,错误信息类似:cannot allocate memory in static TLS block

加载 LightGBM 时,您可能会遇到如下错误。

lib/libgomp.so.1: cannot allocate memory in static TLS block

这最常发生在 aarch64 Linux 系统上。

gcc 的 OpenMP 库(libgomp.so)在动态加载时会尝试分配少量静态线程局部存储 (“TLS”)。

当加载器找不到足够大的内存块时,可能会发生此错误。

在 aarch64 Linux 上,进程和加载的库共享同一静态 TLS 池,这使得此类故障更可能发生。请参阅以下讨论

如果您在使用 lightgbm Python 包时遇到此问题,请尝试升级到至少 v4.6.0

对于较旧版本的 Python 包或其他 LightGBM API,通常可以通过加载 libgomp.so.1 来避免此问题。这可以通过直接设置环境变量 LD_PRELOAD 来完成,如下所示

export LD_PRELOAD=/root/miniconda3/envs/test-env/lib/libgomp.so.1

也可以通过更改其他库加载到进程中的顺序间接完成,这因编程语言和应用程序类型而异。

有关更多详细信息,请参阅以下讨论


R 包

1. 在之前的 LightGBM 模型训练过程中发生错误后,任何使用 LightGBM 的训练命令都无法工作。

在 R 包的旧版本(早于 v3.3.0)中,这种情况偶尔会发生,解决方案是运行 lgb.unloader(wipe = TRUE) 来移除所有 LightGBM 相关对象。关于此问题的一些讨论可以在 Microsoft/LightGBM#698 中找到。

v3.3.0 版本开始,这不再是必需的,并且函数 lgb.unloader() 已从 R 包中移除。

2. 我使用了 setinfo(),尝试打印我的 lgb.Dataset,然后 R 控制台死机了!

至少从 LightGBM v3.3.0 开始,此问题已解决,打印 Dataset 对象不会导致控制台死机。

在旧版本中,避免在调用 setinfo() 后打印 Dataset

从 LightGBM v4.0.0 开始,setinfo() 已被新方法 set_field() 替换。

3. error in data.table::data.table()...argument 2 is NULL

如果您在运行 lightgbm 时遇到此错误,您可能正面临与 #2715 以及后来的 #2989 中报告的相同问题。我们发现在某些情况下,使用 data.table 1.11.x 会导致此错误。要解决此问题,您可以将您的 data.table 版本升级到至少 1.12.0 版本。

4. package/dependency ‘Matrix’ is not available ...

2024 年 4 月,Matrix==1.7-0 发布到 CRAN。该版本的最低要求是 R (>=4.4.0){Matrix}{lightgbm} 的硬运行时依赖项,因此在任何早于 4.4.0 的 R 版本上,运行 install.packages("lightgbm") 会导致类似以下的结果。

package ‘Matrix’ is not available for this version of R

要在不升级到 R 4.4.0 或更高版本的情况下解决此问题,请手动安装较旧版本的 {Matrix}

install.packages('https://cran.r-project.org.cn/src/contrib/Archive/Matrix/Matrix_1.6-5.tar.gz', repos = NULL)

Python 包

1. 从 GitHub 使用 python setup.py install 安装时出现 Error: setup script specifies an absolute path

注意

自 v4.0.0 起,lightgbm 不支持直接调用 setup.py。此回答仅适用于早于 v4.0.0 的 lightgbm 版本。

error: Error: setup script specifies an absolute path:
/Users/Microsoft/LightGBM/python-package/lightgbm/../../lib_lightgbm.so
setup() arguments must *always* be /-separated paths relative to the setup.py directory, *never* absolute paths.

此错误应在最新版本中得到解决。如果您仍然遇到此错误,请尝试删除 Python 包中的 lightgbm.egg-info 文件夹并重新安装,或者查看 stackoverflow 上的此主题

2. 错误信息:Cannot ... before construct dataset

我看到类似以下的错误信息…

Cannot get/set label/weight/init_score/group/num_data/num_feature before construct dataset

但我已经通过一些代码构建了数据集,例如

train = lightgbm.Dataset(X_train, y_train)

或类似以下的错误信息

Cannot set predictor/reference/categorical feature after freed raw data, set free_raw_data=False when construct Dataset to avoid this.

解决方案:因为 LightGBM 构建 bin 映射器来构建树,并且同一个 Booster 中的训练集和验证集共享相同的 bin 映射器、类别特征和特征名称等,所以在构建 Booster 时会构建 Dataset 对象。如果您设置了 free_raw_data=True(默认),原始数据(以及 Python 数据结构)将被释放。因此,如果您想

  • 在构建数据集之前获取 label(或 weight/init_score/group/data),这与获取 self.label 相同;

  • 在构建数据集之前设置 label(或 weight/init_score/group),这与 self.label=some_label_array 相同;

  • 在构建数据集之前获取 num_data(或 num_feature),您可以使用 self.data 获取数据。然后,如果您的数据是 numpy.ndarray,请使用类似 self.data.shape 的代码。但不要在对 Dataset 进行子集操作后执行此操作,因为您将始终获得 None

  • 在构建数据集后设置 predictor(或 reference/categorical feature),您应该设置 free_raw_data=False 或使用相同的原始数据初始化一个 Dataset 对象。

3. 使用 pip install lightgbm 从 PyPI 安装 LightGBM 后,我随机遇到分段错误 (segfaults)。

我们正尽最大努力提供通用轮子(universal wheels),它们具有高运行速度,并且能同时兼容各种硬件、操作系统、编译器等。然而,有时不可能保证 LightGBM 在任何特定环境中的可用性(参见 Microsoft/LightGBM#1743)。

因此,如果遇到分段错误,您首先应该尝试的是使用 pip install --no-binary lightgbm lightgbm 从源代码编译。有关操作系统特定的先决条件,请参见 https://github.com/microsoft/LightGBM/blob/master/python-package/README.rst

此外,请随时在我们的 GitHub 仓库中提交新问题。我们总是单独查看每个案例,并尝试找到根本原因。

4. 我想通过 conda 安装 LightGBM。应该选择哪个通道?

我们强烈建议从 conda-forge 通道安装,而不是从 default 通道安装。

有关一些具体示例,请参阅此评论

此外,自 lightgbm==4.4.0 版本起,conda-forge 包自动支持基于 CUDA 的 GPU 加速。

5. 如何继承 scikit-learn 估计器?

对于 lightgbm <= 4.5.0,将相应的 lightgbm 类中的所有构造函数参数复制到您的自定义估计器的构造函数中。

对于更高版本,只需确保您的自定义估计器的构造函数调用了 super().__init__()

考虑下面的示例,它实现了一个允许创建截断预测的回归器。此模式适用于 lightgbm > 4.5.0

import numpy as np
from lightgbm import LGBMRegressor
from sklearn.datasets import make_regression

class TruncatedRegressor(LGBMRegressor):

    def __init__(self, **kwargs):
        super().__init__(**kwargs)

    def predict(self, X, max_score: float = np.inf):
        preds = super().predict(X)
        np.clip(preds, a_min=None, a_max=max_score, out=preds)
        return preds

X, y = make_regression(n_samples=1_000, n_features=4)

reg_trunc = TruncatedRegressor().fit(X, y)

preds = reg_trunc.predict(X)
print(f"mean: {preds.mean():.2f}, max: {preds.max():.2f}")
# mean: -6.81, max: 345.10

preds_trunc = reg_trunc.predict(X, max_score=preds.mean())
print(f"mean: {preds_trunc.mean():.2f}, max: {preds_trunc.max():.2f}")
# mean: -56.50, max: -6.81