语言绑定一致性
多年来,XGBoost 发展了许多不同的语言绑定,有些在主仓库中,有些则独立存在。许多特性和接口彼此不一致,本文旨在为语言绑定设计者提供一些指导方针和可操作项。
模型序列化
XGBoost C API 提供了一些函数,用于将模型序列化以进行持久存储。这些保存的文件是向后兼容的,这意味着可以使用较新版本的 XGBoost 加载较旧版本的 XGBoost 模型。如果模型格式发生变化,我们在 C++ 实现内部有弃用通知,并有公开议题用于跟踪状态。有关详细信息,请参见模型 IO 简介。
因此,这些功能被认为是稳定的,应该可以在不同的语言绑定中工作。例如,在 R 中训练的模型应该能在 C 或 Python 中完全运行。请不要向输出文件或缓冲区填充任何额外内容。
如果必须保存额外字段
首先检查该属性是否可以从模型的已知属性中检索。例如,在 scikit-learn 接口的
XGBClassifier
中有一个classes_
属性,可以通过 numpy.arange(n_classes) 获取,不需要保存到模型中。保持版本兼容性不是一件小事,我们仍然花费大量时间来维护它。如果不是必要,请不要增加复杂性。然后请考虑它是否具有普适性。例如,我们在模型序列化中为分类特征添加了 feature_types(这是 1.6 之后的新功能),无论语言绑定如何,该属性现在或将来都将有用。
如果字段很小,我们可以将其保存为模型属性(这是一个键值结构)。这些属性会被所有其他语言绑定忽略,主要是一个临时存储。
最后,如果可能的话,我们应该使用 UBJSON 作为默认输出格式(以免受旧二进制格式的困扰)。
训练续接
有些情况下,我们希望基于之前的模型继续训练。对于 boosting 树,这意味着添加新树或修改现有树。这可以是正常的模型更新、错误恢复或其他我们尚不知道的特殊情况。当这种情况发生时,训练迭代应该从 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 的 warnings
和 print()
函数来输出日志。我们希望保持日志记录与更大的社区原生集成,而不是使用 C++ 的 std::cerr
。
最少数据处理
XGBoost 主要是一个提供 boosting 算法实现的机器学习库。其他一些实现可能会隐含地执行某种数据处理,例如决定数据的编码,以及在训练前根据某些启发式方法转换数据。我们倾向于根据必要性而不是便利性来执行这些操作,以保持项目范围的明确界定。在可能的情况下,我们应该将这些功能留给第三方库,并考虑用户如何构建他们的流水线。例如,XGBoost 本身不应该对分类数据执行顺序编码,用户将选择适合其用例的编码器(例如内存外实现、分布式实现、已知映射等)。如果某些转换被确定为算法的一部分,我们可以将其放在核心内部而不是语言绑定中。例子包括目标编码或响应变量的草图。如果我们要支持它们,可以将其作为机器学习算法的一部分放在核心实现中。这与默认参数的原则一致,不同的绑定在给定相同的参数集和数据时,应该提供相似(如果不是完全相同)的结果。
特征信息
XGBoost 接受包含关于预测器元信息的数据结构,包括特征的名称和类型。示例输入包括 pandas.DataFrame
, R data.frame。我们有以下启发式方法:- 当输入数据结构包含此类信息时,我们相应地设置 DMatrix 的 feature_names 和 feature_types。- 当用户提供此信息作为明确参数时,用户提供的信息应覆盖数据结构提供的信息。- 当这两个来源都缺失时,DMatrix 类包含空信息。