语言绑定的统一性

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

模型序列化

XGBoost C API 提供了几个用于序列化模型以进行持久存储的函数。这些保存的文件是向后兼容的,这意味着可以使用更新版本的 XGBoost 加载旧版本的 XGBoost 模型。如果模型格式发生变化,我们在 C++ 实现中有弃用通知,并在公共问题中跟踪状态。详情请参阅 模型输入输出简介

因此,这些被认为是稳定的,并且应该在不同语言绑定中工作。例如,在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 类将包含空信息。