跳到内容

如何改进模型?

本文提供有关如何改进 YDF 模型的质量、速度和大小的建议。改进的程度将取决于数据集。在某些情况下,变化会很小,而在其他情况下,可能会很大。无法预先知道给定更改会产生多少改进。

本指南分为两章:优化模型质量优化模型速度。在大多数情况下,提高模型质量也会使其更大更慢,反之亦然。换句话说,模型的预测质量通常与其大小相关联。

对决策森林的工作原理有一个基本的了解有助于对其进行优化。欲了解更多信息,请参阅Google 的决策森林课程

超参数页面列出了并解释了可用的超参数。

随机森林还是梯度提升树?

随机森林 (RF) 和 梯度提升树 (GBT) 是用于训练决策森林的两种不同算法。每种算法都有其优点和缺点。总的来说,RF 比 GBT 更不容易过拟合,是小型数据集和具有大量输入特征的数据集的良好选择。另一方面,GBT 比 RF 学习效率更高。此外,GBT 模型通常比可比的 RF 模型小得多,推理速度也更快。

优化速度时,请使用 GBT。优化质量时,应同时测试两种算法。

警告:两种算法都有共同的超参数,例如树的数量和最大树深度。但是,这些超参数在每种算法中扮演着不同的角色,应相应地进行调优。例如,GBT 的最大树深度通常在 3 到 8 之间,而 RF 中很少小于 16。

优化模型质量

自动化超参数调优

自动化超参数调优是一种简单但昂贵的解决方案,可以提高模型质量。当完全超参数调优过于昂贵时,结合超参数调优和手动调优是一个很好的解决方案。

详细信息请参阅调优笔记本

超参数模板

YDF 学习器的默认超参数设置为重现最初发布的算法,新方法默认禁用。

因此,默认参数并未针对性能进行优化,这可能会导致合理但不理想的结果。为了在不理解这些超参数且无需运行超参数调优的情况下从最新的 YDF 算法中受益,YDF 提供了预配置的超参数模板

通过在学习器上调用hyperparameter_templates可以使用超参数模板。

# List the available templates for the GBT learner.
templates = ydf.GradientBoostedTreesLearner.hyperparameter_templates()
print(templates)

# Use the "better_defaultv1" template:
learner = ydf.GradientBoostedTreesLearner(**templates["better_defaultv1"], ...)

超参数模板也可在超参数页面上找到。请注意,不同的学习器有不同的模板。

增加树的数量

参数 num_trees 控制模型中的树数量。增加树的数量通常可以提高模型质量。默认情况下,YDF 训练 300 棵树的模型。对于高质量模型,使用 1000 棵或更多树有时很有价值。

注意:使用提前停止(默认行为)训练梯度提升树模型时,提前停止可能会将模型中的树数量减少到小于“num_trees”的值。

使用斜树

默认情况下,树是“正交”或“轴对齐”的,也就是说,每个切分/条件只测试一个特征。与此相反,斜树中的条件可以使用多个特征。斜切分通常可以提高性能,但训练速度较慢。

斜树训练成本更高。参数 num_projections_exponent 在训练时间和最终模型质量中起着重要作用(1 便宜,2 更好但更贵)。有关详细信息,请参阅DecisionTreeTrainingConfig 中的 SparseObliqueSplit

learner = ydf.RandomForestLearner(
  split_axis="SPARSE_OBLIQUE",
  sparse_oblique_normalization="MIN_MAX",
  sparse_oblique_num_projections_exponent=1.0,
  ...)

随机分类切分 (GBT 和 RF)

默认情况下,分类切分使用 CART 分类算法学习。随机分类算法是另一种解决方案,可以提高模型性能,但会牺牲模型大小。

learner = ydf.RandomForestLearner(categorical_algorithm="RANDOM", ...)

减少收缩率 [仅限 GBT]

“收缩率”,有时称为“学习率”,决定了 GBT 模型学习的速度。学习慢可以提高模型质量。shrinkage 默认值为 0.1。您可以尝试 0.05 或 0.02。

GBT 的其他有影响力的超参数

虽然所有超参数都可以提高模型质量,但某些超参数的影响比其他超参数更大。除了上述参数之外,以下是 GBT 最重要的参数:

  • use_hessian_gain (默认 False)。例如,尝试 use_hessian_gain=True
  • max_depth (默认 6)。例如,尝试 max_depth=5
  • num_candidate_attributes_ratio (默认 1)。例如,尝试 num_candidate_attributes_ratio=0.9
  • min_examples (默认 5)。例如,尝试 min_examples=10
  • growing_strategy (默认 "LOCAL")。例如,尝试 growing_strategy="BEST_FIRST_GLOBAL"

注意:当使用 growing_strategy=LOCAL(默认)训练模型时,调优 max_depth 参数(默认 6)通常是有益的。当使用 growing_strategy=BEST_FIRST_GLOBAL 训练模型时,最好不要限制 max_depth(默认 -1),而是调优 max_num_nodes 参数。

禁用验证数据集 (仅限 GBT)

默认情况下,如果未提供验证数据集,梯度提升树学习器会从训练数据集中提取 10% 的数据来构建验证数据集,以控制提前停止(即当模型开始过拟合时停止训练)。

对于小型数据集和大型数据集,最好使用所有数据进行训练(因此禁用提前停止)。在这种情况下,应调优 num_trees 参数。

learner = ydf.GradientBoostedTreesLearner(validation_ratio=0.0, ...)

警告:禁用提前停止可能会导致模型过拟合。为避免这种情况,首先启用提前停止运行训练,以确定最佳树数量。例如,如果提前停止在训练结束前从未触发,您可能可以禁用它(并使用额外的数据进行训练)。如果提前停止总是在给定树数量附近触发,您也可以这样做。请记住,更改任何其他超参数都需要重新测试提前停止的行为。

优化模型速度(和大小)

模型的速度和大小受到输入特征数量、树数量和平均树深度的限制。

您可以使用 benchmark 方法测量模型的推理速度。

model.benchmark(dataset)

结果示例

Inference time per example and per cpu core: 0.702 us (microseconds)
Estimated over 441 runs over 3.026 seconds.
* Measured with the C++ serving API. Check model.to_cpp() for details.

从随机森林切换到梯度提升树

随机森林模型比梯度提升树模型大得多且慢得多。当速度很重要时,请使用梯度提升树模型。

# Before
learner = ydf.RandomForestLearner(...)

# After
learner = ydf.GradientBoostedTreesLearner(...)

减少树的数量

参数 num_trees 控制模型中的树数量。减少此参数会减小模型大小,但会牺牲模型质量。

注意:使用提前停止(默认行为)训练梯度提升树模型时,提前停止可能会将模型中的树数量减少到小于“num_trees”的值。

当使用 growing_strategy="BEST_FIRST_GLOBAL" 进行训练时,最好不要限制最大树数量,而是优化 max_num_nodes

移除模型调试数据

YDF 模型包含用于模型解释和调试的元数据。此元数据不用于模型推理,可以丢弃以减小模型大小。移除此数据通常会使模型大小减少约 50%。移除此数据不会提高模型的速度。

要训练不含元数据的模型,请将学习器构造函数参数 pure_serving_model 设置为 True

learner = ydf.GradientBoostedTreesLearner(pure_serving_model=True, ...)

如果使用 CLI API,可以使用 edit_model CLI 工具移除元数据

# Remove the meta-data from the model
./edit_model --input=/tmp/model_with_metadata --output=/tmp/model_without_metadata --pure_serving=true

# Look at the size of the model
du -h /tmp/model_with_metadata
du -h /tmp/model_without_metadata

在随机森林中设置 winner_take_all_inference=False

随机森林学习器的 winner_take_all_inference 参数默认设置为 True。这确保了默认情况下,YDF 随机森林等同于 Breiman 最初的随机森林。

但是,在许多情况下,winner_take_all=False 可以减小随机森林模型的大小并提高其质量。

learner = ydf.RandomForestLearner(winner_take_all=False, ...)

设置 maximum_model_size_in_memory_in_bytes=...

参数 maximum_model_size_in_memory_in_bytes 控制模型在 RAM 中的最大大小。通过设置此值,您可以控制模型的最终大小。

模型在 RAM 中的大小可能大于模型在磁盘上的大小。加载模型时使用的 RAM 对应于模型在 RAM 中的大小。运行模型推理之前,模型会被编译成一种通常更小的格式。

# Model limited to 10GB
learner = ydf.RandomForestLearner(maximum_model_size_in_memory_in_bytes=10e+9, ...)

不同的学习算法强制执行最大大小的方式不同。

增加收缩率 [仅限 GBT]

“收缩率”,有时称为“学习率”,决定了 GBT 模型学习的速度。学习过快通常会导致较差的结果,但会生成更小、训练更快、运行更快的模型。shrinkage 默认值为 0.1。您可以尝试 0.15 甚至 0.2。