参数调优

本页包含针对不同场景的参数调优指南。

其他有用链接列表

针对叶子生长(最优优先)树的参数调优

LightGBM 使用 叶子生长 树生长算法,而许多其他流行工具使用深度优先树生长算法。与深度优先生长相比,叶子生长算法收敛速度更快。但是,如果不使用适当的参数,叶子生长可能会导致过拟合。

为了使用叶子生长树获得良好结果,以下是一些重要参数:

  1. num_leaves. 这是控制树模型复杂度的主要参数。理论上,我们可以设置 num_leaves = 2^(max_depth) 来获得与深度优先树相同数量的叶子。然而,这个简单的转换在实践中并不好。对于固定数量的叶子,叶子生长树通常比深度优先树深得多。不受约束的深度可能导致过拟合。因此,在尝试调优 num_leaves 时,我们应该让它小于 2^(max_depth)。例如,当 max_depth=7 时,深度优先树可以获得良好的准确率,但将 num_leaves 设置为 127 可能会导致过拟合,而将其设置为 7080 可能会获得比深度优先更好的准确率。

  2. min_data_in_leaf. 这是防止叶子生长树过拟合的一个非常重要的参数。其最优值取决于训练样本的数量和 num_leaves。将其设置为较大的值可以避免树生长过深,但可能导致欠拟合。在实践中,对于大型数据集,将其设置为数百或数千就足够了。

  3. max_depth. 您也可以使用 max_depth 显式地限制树的深度。如果您设置了 max_depth,也请显式地将 num_leaves 设置为某个值 <= 2^max_depth

为了更快的速度

增加计算资源

在可用系统上,LightGBM 使用 OpenMP 并行化许多操作。LightGBM 使用的最大线程数由参数 num_threads 控制。默认情况下,这将遵循 OpenMP 的默认行为(每个实际 CPU 核心一个线程,或者如果设置了环境变量 OMP_NUM_THREADS,则使用该值)。为了获得最佳性能,请将其设置为可用的**实际** CPU 核心数。

您可以通过使用具有更多可用 CPU 核心的机器来实现更快的训练。

使用分布式(多机)训练也可能减少训练时间。详情请参阅分布式学习指南

使用启用 GPU 的 LightGBM 版本

您可能会发现使用 LightGBM 的 GPU 版本进行训练速度更快。详情请参阅GPU 教程

构建更浅的树

LightGBM 的总训练时间随着添加的树节点总数增加而增加。LightGBM 提供了一些参数可以用来控制每棵树的节点数。

以下建议将加快训练速度,但可能会影响训练准确率。

减小 max_depth

此参数是一个整数,控制每棵树的根节点与叶子节点之间的最大距离。减小 max_depth 以减少训练时间。

减小 num_leaves

LightGBM 根据添加节点获得的增益向树中添加节点,而与深度无关。来自特性文档的此图说明了该过程。

Three consecutive images of decision trees, where each shows the tree with an additional two leaf nodes added. Shows that leaf-wise growth can result in trees that have some branches which are longer than others.

由于这种生长策略,仅使用 max_depth 来限制树的复杂度并不直接。num_leaves 参数设置了每棵树的最大节点数。减小 num_leaves 以减少训练时间。

增大 min_gain_to_split

当添加新的树节点时,LightGBM 选择增益最大的分割点。增益本质上是添加分割点后训练损失的减少量。默认情况下,LightGBM 将 min_gain_to_split 设置为 0.0,这意味着“没有太小的改进”。然而,在实践中,您可能会发现训练损失非常小的改进对模型的泛化误差没有显著影响。增大 min_gain_to_split 以减少训练时间。

增大 min_data_in_leafmin_sum_hessian_in_leaf

根据训练数据的大小和特征的分布,LightGBM 可能会添加仅描述少量观测值的树节点。在最极端的情况下,考虑添加一个仅包含训练数据中单个观测值的树节点。这非常不可能很好地泛化,并且很可能是过拟合的迹象。

这可以通过 max_depthnum_leaves 等参数间接预防,但 LightGBM 也提供了参数来帮助您直接避免添加这些过于特定的树节点。

  • min_data_in_leaf:要添加树节点,必须落入该节点中的最小观测值数量。

  • min_sum_hessian_in_leaf:叶子中观测值的 Hessian(目标函数对每个观测值求二阶导数)的最小总和。对于某些回归目标,这只是每个节点必须包含的记录的最小数量。对于分类目标,它代表概率分布的总和。关于如何理解此参数的值,请参阅此 Stack Overflow 回答,其中有很好的描述。

构建更少的树

减小 num_iterations

num_iterations 参数控制将执行的 boosting 轮数。由于 LightGBM 使用决策树作为学习器,这也可以视为“树的数量”。

如果您尝试更改 num_iterations,也请更改 learning_ratelearning_rate 对训练时间没有影响,但会影响训练准确率。一般来说,如果您减少 num_iterations,则应该增加 learning_rate

选择合适的 num_iterationslearning_rate 值高度依赖于数据和目标,因此这些参数通常通过超参数调优从一组可能的值中选择。

减小 num_iterations 以减少训练时间。

使用提前停止

如果启用了提前停止,在每个 boosting 轮次后,模型的训练准确率会对照验证集进行评估,该验证集包含训练过程不可用的数据。然后将该准确率与前一 boosting 轮次的准确率进行比较。如果模型的准确率在连续若干轮次未能提升,LightGBM 将停止训练过程。

该“连续轮次数”由参数 early_stopping_round 控制。例如,early_stopping_round=1 表示“当验证集上的准确率首次未能提升时,停止训练”。

设置 early_stopping_round 并提供验证集,以可能减少训练时间。

考虑更少的分割

前几节中描述的参数控制着构建多少棵树以及每棵树构建多少个节点。通过减少将树节点添加到模型所需的时间,可以进一步减少训练时间。

以下建议将加快训练速度,但可能会影响训练准确率。

创建数据集时启用特征预过滤

默认情况下,当构建 LightGBM Dataset 对象时,会根据 min_data_in_leaf 的值过滤掉一些特征。

举个简单的例子,考虑一个包含 1000 个观测值的数据集,其中有一个名为 feature_1 的特征。feature_1 只有两个值:25.0(995 个观测值)和 50.0(5 个观测值)。如果 min_data_in_leaf = 10,则此特征没有分割点会导致有效分割,因为至少有一个叶子节点将只有 5 个观测值。

LightGBM 不会在每次迭代中重新考虑并忽略此特征,而是在训练前、构建 Dataset 时就过滤掉此特征。

如果通过设置 feature_pre_filter=False 覆盖了此默认行为,请将 feature_pre_filter=True 以减少训练时间。

创建数据集时减小 max_binmax_bin_by_feature

LightGBM 训练时将连续特征分桶到离散的 bin 中,以提高训练速度并减少训练内存需求。此分桶过程在 Dataset 构建期间进行一次。添加节点时考虑的分割数是 O(#feature * #bin),因此减少每个特征的 bin 数量可以减少需要评估的分割数量。

max_bin 控制特征将被分桶到的最大 bin 数。也可以通过传递 max_bin_by_feature 来按特征设置此最大值。

减小 max_binmax_bin_by_feature 以减少训练时间。

创建数据集时增大 min_data_in_bin

某些 bin 可能包含少量观测值,这意味着将该 bin 的边界作为可能的分割点进行评估不太可能对最终模型产生很大改变。您可以通过设置 min_data_in_bin 来控制 bin 的粒度。

增大 min_data_in_bin 以减少训练时间。

减小 feature_fraction

默认情况下,LightGBM 在训练过程中考虑 Dataset 中的所有特征。可以通过将 feature_fraction 设置为大于 0 且小于等于 1.0 的值来改变此行为。例如,将 feature_fraction 设置为 0.5 会告诉 LightGBM 在构建每棵树的开始时随机选择 50% 的特征。这减少了添加每个树节点需要评估的分割总数。

减小 feature_fraction 以减少训练时间。

减小 max_cat_threshold

LightGBM 使用自定义方法来查找分类特征的最佳分割点。在此过程中,LightGBM 探索将分类特征分成两组的分割点。这些有时被称为“k 对其余”分割。较高的 max_cat_threshold 值对应于更多的分割点和更大的可能搜索组大小。

减小 max_cat_threshold 以减少训练时间。

使用更少的数据

使用 Bagging (数据采样)

默认情况下,LightGBM 在每次迭代中使用训练数据中的所有观测值。也可以改为告诉 LightGBM 随机采样训练数据。这种对多个不重复随机样本进行训练的过程称为“bagging”。

bagging_freq 设置为一个大于 0 的整数,以控制抽取新样本的频率。将 bagging_fraction 设置为一个大于 0.0 且小于 1.0 的值,以控制样本大小。例如,{"bagging_freq": 5, "bagging_fraction": 0.75} 告诉 LightGBM“每 5 次迭代进行不重复重新采样,并抽取 75% 的训练数据样本”。

减小 bagging_fraction 以减少训练时间。

使用 save_binary 保存构建的数据集

这仅适用于 LightGBM 命令行界面(CLI)。如果您传递参数 save_binary,训练数据集和所有验证集将以 LightGBM 可理解的二进制格式保存。这可以加快下次训练的速度,因为构建 Dataset 时进行的分桶和其他工作无需重新执行。

为了更好的准确率

  • 使用较大的 max_bin(可能会较慢)

  • 使用较小的 learning_rate 和较大的 num_iterations

  • 使用较大的 num_leaves(可能导致过拟合)

  • 使用更大的训练数据

  • 尝试使用 dart

处理过拟合

  • 使用较小的 max_bin

  • 使用较小的 num_leaves

  • 使用 min_data_in_leafmin_sum_hessian_in_leaf

  • 通过设置 bagging_fractionbagging_freq 使用 bagging

  • 通过设置 feature_fraction 使用特征子采样

  • 使用更大的训练数据

  • 尝试使用 lambda_l1, lambda_l2min_gain_to_split 进行正则化

  • 尝试使用 max_depth 避免树生长过深

  • 尝试使用 extra_trees

  • 尝试增大 path_smooth