语言绑定的统一性

XGBoost 多年来开发了许多不同的语言绑定,其中一些在主存储库中,而另一些则独立存在。许多功能和接口彼此不一致,本文档旨在为语言绑定设计者提供一些指导方针和可操作的项目。

模型序列化

XGBoost C API 暴露了一些用于将模型序列化以进行持久存储的函数。这些保存的文件是向后兼容的,这意味着可以使用较新的 XGBoost 版本加载较旧的 XGBoost 模型。如果模型格式发生变化,我们在 C++ 实现中有弃用通知,并有公开问题来跟踪状态。有关详细信息,请参阅模型 IO 简介

因此,这些被认为是稳定的,并且应该跨语言绑定工作。例如,在 R 中训练的模型应该在 C 或 Python 中完全正常运行。请不要在输出文件或缓冲区中添加任何内容。

如果必须保存额外的字段

  • 首先审查是否可以从模型的已知属性中检索该属性。例如,scikit-learn 接口中的 XGBClassifier 有一个 classes_ 属性,可以通过 numpy.arange(n_classes) 获得,无需保存到模型中。保持版本兼容性并非易事,我们仍在花费大量时间来维护它。请不要在不必要的情况下使其复杂化。

  • 然后请考虑它是否具有通用性。例如,我们已经为分类特征添加了 feature_types 到模型序列化中(这是 1.6 之后的新功能),无论语言绑定如何,该属性都将有用或将来有用。

  • 如果字段很小,我们可以将其保存为模型属性(这是一个键值结构)。这些属性被所有其他语言绑定忽略,并且主要是一个临时存储。

  • 最后,我们应该在有机会时使用 UBJSON 作为默认输出格式(不受旧二进制格式的束缚)。

训练继续

有些情况下,我们希望基于以前的模型训练模型,对于提升树来说,这要么是添加新树,要么是修改现有树。这可以是正常的模型更新、错误恢复或我们尚不知道的其他特殊情况。当发生这种情况时,训练迭代应该从 0 开始,而不是从模型的最后一次提升轮次开始。0 是一个特殊的迭代次数,我们在此迭代期间执行一些额外的检查,例如标签是否有效。这些检查可能很昂贵,但对于消除静默错误是必要的。保持迭代从零开始使我们能够为每个输入数据只执行一次这些检查。

推理

由于历史原因,在撰写本文时,推理函数在语言绑定之间相当不一致,但这使得我们在未来的开发中更需要考虑一致性。

  • 首先,是输出形状。XGBoost 中有一个相对较新的参数叫做 strict_shape,很少使用。我们希望将其作为默认行为,但由于兼容性问题而未能实现。有关详细信息,请参阅预测。简而言之,如果指定,XGBoost C++ 实现可以输出具有正确形状的预测,而不是让语言绑定来处理。

  • 目前,关于提前停止的策略在各种接口之间不一致。有些考虑 best_iteration 属性,而另一些则不考虑。我们应该正式规定,未来所有接口在推理时都应使用 best_iteration,除非用户明确指定了 iteration_range 参数。

参数命名

存在许多参数命名约定,一些 XGBoost 接口试图与更大的社区保持一致。例如,R 包可能支持 max.depth=3 这样的参数命名,而 Spark 包可能支持 MaxDepth=3。这些都没问题,让用户保持其管道一致性更好。然而,在支持命名变体时,正常的 XGBoost 命名方式也应该得到支持,这意味着无论使用何种语言,max_depth=3 都应该是一个有效参数。如果有人编写重复参数 max.depth=3, max_depth=3,则应优先选择明确的错误,而不是优先选择其中之一。

默认参数

像许多其他机器学习库一样,XGBoost 的所有参数都可以从数据中推断或具有默认值。绑定不应该复制这些默认值,而应该让 XGBoost 核心决定。当参数键未传递到 C++ 核心时,XGBoost 将相应地选择默认值。这些默认值不一定是最优的,但它们是为了保持一致性。如果有了新的默认参数选择,我们可以在核心内部更改它,它将自动传播到所有绑定。在给定相同参数集和数据的情况下,各种绑定应努力生成相同的模型。一个例外是 num_boost_rounds,它只存在于高级绑定中,并且有各种别名,例如 n_estimators。它的默认值目前几乎是任意的,我们还没有找到一个好的默认值。

日志记录

XGBoost 内置了默认的日志记录器,它可以作为绑定特定日志记录设施的包装器。例如,Python 绑定注册了一个回调,以使用 Python warningsprint() 函数输出日志。我们希望保持日志记录对更大的社区来说是原生的,而不是使用 C++ 的 std::cerr

最少的数据操作

XGBoost 主要是一个提供提升算法实现的机器学习库。其他一些实现可能会隐式执行某种数据操作,例如决定数据的编码,以及在训练之前根据某些启发式方法转换数据。我们更倾向于根据需要而不是方便来保持这些操作,以明确项目范围。只要有可能,我们应该将这些功能留给第三方库,并考虑用户如何构建他们的管道。例如,XGBoost 本身不应该对分类数据执行序数编码,用户将选择适合其用例的编码器(例如内存外实现、分布式实现、已知映射等)。如果某些转换被决定作为算法的一部分,我们可以将其放在核心内部而不是语言绑定中。例如目标编码或响应变量的草图。如果我们要支持它们,我们可以将其放在核心实现中作为 ML 算法的一部分。这与默认参数的原则相同,各种绑定在给定相同参数集和数据的情况下应提供相似(如果不是相同)的结果。

特征信息

XGBoost 接受包含预测器元数据(包括特征名称和类型)的数据结构。示例输入是 pandas.DataFrame,R data.frame。我们有以下启发式方法: - 当输入数据结构包含此类信息时,我们相应地为 DMatrix 设置 feature_namesfeature_types。 - 当用户将此信息作为显式参数提供时,用户提供版本应覆盖数据结构提供的版本。 - 当这两个来源都缺失时,DMatrix 类包含空信息。