CLI 和 C++ 用户手册
本页面深入介绍了 Yggdrasil Decision Forests (YDF) 的 CLI API。本页内容通常不是使用 YDF 所必需的,但它将帮助用户加深理解和使用高级选项。
新用户应首先查看 快速开始。
这里介绍的大多数概念也适用于其他 API,特别是 C++ API。
数据集
数据集 是 示例 的列表。数据集可以存储在内存中、磁盘上,或者即时生成。数据集中的示例是 有序的,即数据集中的一个示例可以通过其在数据集中的 索引 明确标识。
属性(在其他库中也称为 特征、变量 或 列)指的是表格数据集中某一特定信息。例如,一个人的 年龄、姓名 和 出生国家 都是属性。
每个属性都有一个 语义(也称为 类型)。语义决定了模型如何使用该属性。例如,年龄(例如,出生后的年数)通常是 数值型,而 国家(例如,ISO 3166 国家代码)是分类型的。
YDF 支持以下语义:
-
NUMERICAL:数值。通常用于具有完整顺序的量或计数。例如,一个人的年龄,或袋子中的物品数量。可以是浮点数或整数。缺失值用 NaN 表示。
-
CATEGORICAL:分类值。通常用于具有有限可能值集的类型/类别,且无顺序。例如,集合 {RED, BLUE, GREEN} 中的颜色 RED。可以是字符串或整数。在内部,分类值存储为 int32,因此应小于 ~2B。
-
CATEGORICAL_SET:分类值的集合。非常适合表示分词后的文本。与 CATEGORICAL 不同,CATEGORICAL_SET 中的项目数量可以变化,且每个项目的顺序/索引无关紧要。
-
BOOLEAN:布尔值。类似于 CATEGORICAL,但只有两个可能值。
-
DISCRETIZED_NUMERICAL:自动离散化为箱的数值。离散化数值特征比(非离散化)数值特征训练速度更快。如果这些特征的唯一值数量少于箱数,从模型的角度来看,离散化是无损的。如果这些特征的唯一值数量大于箱数,从模型的角度来看,离散化是有损的。有损离散化可以减少模型的质量,有时也可能增加(由于正则化)模型的质量。
-
HASH:字符串值的哈希。当仅值之间的相等性重要(而不是值本身)时使用。目前,仅用于排名问题中的组,例如查询/文档问题中的查询。哈希计算使用 farmhash。
示例 是 属性 值的集合。以下是一个包含三个属性的 示例:
"attribute_1": 5.1 # NUMERICAL
"attribute_2": "CAT" # CATEGORICAL 存储为字符串
"attribute_3": [1, 2, 3] # CATEGORICAL-SET 存储为整数
数据规范(或简称 dataspec)是属性列表的定义。此定义包含数据集中每个属性的名称、语义和元数据。dataspec 存储为 ProtoBuffer(参见其定义在 dataset/data_spec.proto
)。可以使用 show_dataspec
CLI 命令以可读方式打印 dataspec。
Google ProtoBuffers 在 YDF 中广泛用于配置。与 XML 或 JSON 类似,Protobuf 是一种用于数据交换的语言无关序列化格式。Protobuf 可以是文本或二进制格式。YDF 配置始终是包含文本格式 Protobuf V2 的文件。
Protobuf 总是附带一个列出允许字段名称和类型的 Protobuf 定义。在本文档中,几个示例包含 Protobuf 文本和相应 Protobuf 定义的链接。
以下是 Protobuf 及其相应 Protobuf 定义的示例:
Protobuf
Protobuf 定义
message MyMessage{
optional int32 field_a = 1 [default = 5];
optional float field_b = 2 [default = 8.0];
}
在定义中,每个字段都分配有一个唯一的整数 ID,格式为 <字段名称> = <字段 ID> [默认= <默认值>]
。
这是 部署配置(稍后将解释的分布式训练配置)的 Protobuf 定义。
dataspec 示例:
记录数: 1
列数: 3
按类型划分的列数:
NUMERICAL: 1 (33%)
CATEGORICAL: 1 (33%)
CATEGORICAL_SET: 1 (33%)
列:
NUMERICAL: 6 (40%)
0: "feature_1" NUMERICAL 均值:38.5816
CATEGORICAL: 1 (33%)
1: "feature_2" CATEGORICAL 有字典 词汇量:2 零-ood-项 最频繁:"CAT" 1 (50%)
CATEGORICAL_SET: 1 (33%)
2: "feature_3" CATEGORICAL_SET 整数化
术语:
nas: 不可用(即缺失)值的数量。
ood: 字典外。
manually-defined: 由用户手动定义的属性类型,即类型不是自动推断的。
tokenized: 属性值通过分词获得。
has-dict: 属性附加到字符串字典,例如存储为字符串的分类属性。
vocab-size: 唯一值的数量。
columns {
name: "attribute_1"
type: NUMERICAL
numerical {
mean: 10
}
}
columns {
name: "attribute_2"
type: CATEGORICAL
categorical {
items {
key: "CAT"
value { index: 1 }
}
items {
key: "COT"
value { index: 2 }
}
}
}
columns {
name: "attribute_3"
type: CATEGORICAL_SET
categorical_set {
is_already_integerized: true
}
}
dataspec已经通过dataspec推理工具(即infer_dataspec
)自动创建。如果dataspec的某些部分推断不正确,用户可以使用dataspec指南(参见dataset/data_spec.proto
)覆盖它。
例如,默认情况下,看起来像整数的值会被检测为数值型。然而,表示ENUM值的整数值更适合作为分类型。以下是一个dataspec指南的示例,它强制所有名称以"enum_"前缀开头的属性被检测为分类型。
以下两个示例展示了使用CLI和C++ API进行dataspec推断:
CLI
infer_dataspec --dataset=csv:/my/dataset.csv --output=dataspec.pbtxt
# 人类可读的dataspec描述。
show_dataspec --dataspec=dataspec.pbtxt
C++
using namespace yggdrasil_decision_forests;
dataset::proto::DataSpecification data_spec;
dataset::CreateDataSpec("csv:/my/dataset.csv", false, guide, &data_spec);
# 人类可读的dataspec描述。
std::cout << dataset::PrintHumanReadable(data_spec);
数据集路径和格式
数据集的格式由数据集文件路径中的前缀和冒号(":")指定。例如,csv:/path/to/my/dataset.csv
是一个指向csv文件的数据集路径。
支持的格式有:
csv:
: CSV文件。tfrecord+tfe:
: 包含序列化TensorFlow Example protobuffers的GZIP压缩TensorFlow Record文件。
单个数据集可以分为多个文件。拆分数据集可以加快数据集读取速度。根据经验,单个数据集文件不应超过100MB。可以使用分片、全局匹配和逗号分隔来指定数据集的文件列表。以下是包含多个文件的数据集路径示例:
csv:/path/to/my/dataset.csv@10
csv:/path/to/my/dataset_*.csv
csv:/path/to/my/dataset_1.csv,/path/to/my/dataset_1.csv
此外,逗号分隔可以与分片/全局匹配结合使用。例如:csv:/1/data.csv*,/2/data.csv*
。
学习器和模型
YDF使用学习器和模型的概念进行操作。学习器是一个函数(在数学意义上),它接受一个数据集并输出一个模型。模型是一个函数,它接受一个示例并输出一个预测。
在模型-学习器抽象中,学习算法和一组超参数是学习器,而训练好的模型是模型。
模型可以存储在内存或磁盘上。可以使用show_model命令显示有关模型的信息(例如输入特征、标签、验证分数、学习器)。
模型还包含元数据。元数据不用于计算预测。相反,用户或工具可以查询此元数据进行分析(例如特征重要性、训练损失)。可以使用edit_model工具删除模型元数据。
模型可以编译成(服务)引擎。引擎是一个没有元数据且内部结构优化用于快速推理的模型。虽然模型是平台无关的,但引擎与特定硬件绑定(例如需要GPU或AVX512指令)。引擎推理的速度比标准模型推理快几个数量级。
C++方法model.BuildFastEngine()
将模型编译为当前硬件上最有效的引擎。cli/benchmark_inference
工具可以测量模型和兼容服务引擎的推理速度。
学习器从TrainingConfig proto实例化。TrainingConfig定义了标签、输入特征、任务、学习器类型和学习超参数。
通用超参数(GHPs)是TrainingConfig protobuffer的替代表示。GHP是一个字符串到值的映射,适用于快速配置和自动超参数优化。GHPs由TensorFlow Decision Forests(TF-DF)使用:
超参数页面列出了学习器及其超参数。 可选地,可以为学习者配置一个部署规范。部署规范定义了训练期间使用的计算资源,包括线程数或工作节点数(在分布式训练的情况下)。更改部署配置(或不提供任何配置)可能会影响训练速度,但不会影响最终模型:使用相同学习者但不同部署规范训练的两个模型保证是相同的。
默认情况下,学习者配置为使用6个线程进行本地训练。
学习者的日志目录是一个可选目录,用于指定学习者导出学习过程信息的位置。这些信息是学习者特定的,可能包括图表、表格和HTML报告,有助于理解模型。学习者的日志目录没有定义的结构,因为不同的学习者可以导出不同类型的信息。
以下两个示例展示了使用CLI和C++ API训练模型的过程(参见上文如何在dataspec.pbtxt
文件中创建dataspec):
CLI
cat <<EOF > hparams.pbtxt
task: CLASSIFICATION
label: "income"
learner: "GRADIENT_BOOSTED_TREES"
EOF
train \
--dataset=csv:/my/dataset.csv \
--dataspec=dataspec.pbtxt \
--config=hparams.pbtxt \
--output=/my/model
# 模型的人类可读描述。
show_model --model=dataspec.pbtxt
C++
using namespace yggdrasil_decision_forests;
dataset::proto::DataSpecification data_spec = ... // 之前的示例。
// 配置训练。
model::proto::TrainingConfig config;
config.set_task(model::proto::CLASSIFICATION);
config.set_label("income");
config.set_learner("GRADIENT_BOOSTED_TREES");
// 实例化学习者。
std::unique_ptr<model::AbstractLearner> learner;
CHECK_OK(model::GetLearner(config, &learner));
// 训练
std::unique_ptr<model::AbstractModel> model = learner->Train("csv:/my/dataset.csv", data_spec);
// 将模型导出到磁盘。
CHECK_OK(model::SaveModel("/my/model", model.get()));
// 模型的人类可读描述。
std::string description;
model->AppendDescriptionAndStatistics(false, &description);
std::cout << description;
为了最小化二进制文件大小并支持自定义学习算法和模型,模型和学习者依赖于注册机制:用户可以通过依赖注入限制或扩展支持的模型和学习者列表。
所有官方支持的模型和学习者可以通过依赖项yggdrasil_decision_forests/model:all_models
和yggdrasil_decision_forests/learners:all_learners
分别注入。
元学习者
学习者可以组合。包含另一个学习者的学习者称为元学习者。这包括超参数优化学习者、校准学习者、集成学习者和特征选择学习者。
模型/学习者评估
模型评估可以通过evaluate
CLI命令或model::AbstractModel::Evaluate
C++函数实现。
以下两个示例展示了使用CLI和C++ API评估模型的过程:
CLI
C++
using namespace yggdrasil_decision_forests;
std::unique_ptr<model::AbstractModel> model = ... // 之前的示例。
// 加载数据集。
dataset::VerticalDataset dataset;
CHECK_OK(LoadVerticalDataset("csv:/my/dataset.csv", model->data_spec(), &dataset));
// 评估模型。
utils::RandomEngine rnd;
metric::proto::EvaluationResults evaluation = model->Evaluate(dataset, {}, &rnd);
// 以人类可读格式导出评估结果。
std::string text_report;
metric::AppendTextReport(evaluation, &text_report);
std::cout << text_report;
学习者评估包括评估学习者训练的一个或多个模型(例如交叉验证;C++(参见model::EvaluateLearner))。当数据集较小时(例如少于50k个样本,或学习者不稳定时),学习者评估比模型评估更准确。
模型分析
show_model
CLI命令显示有关模型的以下信息:
- 模型的输入特征和标签。
- 每个特征的变量重要性。
- 模型的详细或汇总结构(例如节点数量)。
- 兼容的服务引擎。
- 训练日志。
或者,可以直接使用TensorFlow Decision Forests Python检查器以编程方式可视化和分析模型。有关更多详细信息,请参阅检查和调试笔记本。可以使用Yggdrasil模型转换为TensorFlow Decision Forests模型。
tfdf.keras.core.yggdrasil_model_to_keras_model
函数。调用 model.summary()
显示的信息与 show_model
CLI 相同。
变量重要性
变量重要性通过 CLI(show_model
)、C++ API(model.GetVariableImportance()
)和 Python API(tfdf.inspector.make_inspector(path).variable_importances()
)获取。
可用的变量重要性包括:
模型无关
MEAN_{INCREASE,DECREASE}_IN_{metric}
:通过排列重要性估计的移除特征后的指标变化。根据学习算法和超参数,变量重要性可以通过验证、交叉验证或袋外数据计算。例如,特征的MEAN_DECREASE_IN_ACCURACY
是打乱特征值导致的准确率下降(越大,特征越重要)。例如,MEAN_DECREASE_IN_AUC_3_VS_OTHERS
是当将标签类别“3”与其他类别比较时,AUC 的预期下降。
决策森林特定
-
SUM_SCORE
:使用特定特征的分裂分数总和。越大,特征越重要。 -
NUM_AS_ROOT
:使用特定特征的根节点数量。越大,特征越重要。 -
NUM_NODES
:使用特定特征的节点数量。越大,特征越重要。 -
INV_MEAN_MIN_DEPTH
:特征在所有树路径中首次出现的最小深度的平均值的倒数(即 1/(1+x))。注意:MEAN_MIN_DEPTH
已被移除。
自动超参数调优
优化学习器的超参数可以提高模型的质量。选择最佳超参数可以通过手动方式(参见如何改进模型)或使用自动超参数优化器(HPO)来完成。HPO 通过一系列试错计算自动选择最佳超参数。
查看示例目录中的超参数调优示例。
HPO 是一个带有 HYPERPARAMETER_OPTIMIZER
键配置的元学习器,用于优化子学习器。它支持本地和分布式训练。
HPO 的各个方面可以进行配置。主要的配置选项包括:
- 搜索空间:要优化的超参数集合。
- 评估协议:如何评估一组超参数,例如自评估、交叉验证。
- 优化器:用于在搜索空间中导航的优化算法。
以下示例展示了梯度提升树模型的超参数优化器的 TrainingConfig 配置。
任务: 分类
学习器: "超参数优化器"
标签: "收入"
[yggdrasil_decision_forests.model.hyperparameters_optimizer_v2.proto
.hyperparameters_optimizer_config] {
最终模型重训练: true # 调优后重新训练模型。
优化器 {
# 新超参数值是随机生成的。
优化器键: "随机"
[yggdrasil_decision_forests.model.hyperparameters_optimizer_v2.proto
.random] {
试验次数: 25 # 25次随机试验。
}
}
# 要优化的基础学习器。
基础学习器 {
# 注意:无需配置基础学习器的标签和输入特征。
# 这些值会自动从HPO配置中复制。
学习器: "梯度提升树"
[yggdrasil_decision_forests.model.gradient_boosted_trees.proto
.gradient_boosted_trees_config] {
# 树的数量是固定的。
树的数量: 100
}
}
基础学习器部署 {
# 每个候选学习器在一个线程上运行。
线程数: 1
}
# 要优化的超参数列表。
搜索空间 {
字段 {
名称: "候选属性比例"
离散候选值 {
可能值 { 实数: 1.0 }
可能值 { 实数: 0.8 }
可能值 { 实数: 0.6 }
}
}
字段 {
名称: "使用海森增益"
离散候选值 {
可能值 { 分类: "true" }
可能值 { 分类: "false" }
}
}
字段 {
名称: "生长策略"
离散候选值 {
可能值 { 分类: "局部" }
可能值 { 分类: "最佳优先全局" }
}
子字段 {
父离散值 {
可能值 { 分类: "局部" }
}
名称: "最大深度"
离散候选值 {
可能值 { 整数: 4 }
可能值 { 整数: 5 }
可能值 { 整数: 6 }
可能值 { 整数: 7 }
}
}
子字段 {
父离散值 {
可能值 { 分类: "最佳优先全局" }
}
名称: "最大节点数"
离散候选值 {
可能值 { 整数: 16 }
可能值 { 整数: 32 }
可能值 { 整数: 64 }
可能值 { 整数: 128 }
}
}
}
}
}
分布式训练
分布式训练 指的是在多台计算机上训练模型。 分布式训练在大数据集(例如,>10M 样本)或昂贵的学习算法(例如,超参数调优)中特别有价值。
当使用分布式训练时,执行“训练”操作的进程(即运行 learner->Train()
函数的程序,或运行 train
CLI 命令的进程)成为管理者。其余的工作由工作者执行。工作者是工作者二进制文件的实例。
并非所有学习器都支持分布式训练。例如,GRADIENT_BOOTED_TREES
学习器不支持分布式训练,但 DISTRIBUTED_GRADIENT_BOOSTED_TREES
支持。一些学习器(例如,HYPERPARAMETER_OPTIMIZER
)同时支持分布式和非分布式训练。
以下学习器支持分布式训练:
-
DISTRIBUTED_GRADIENT_BOOSTED_TREES
:梯度提升树模型的精确分布式训练。 -
HYPERPARAMETER_OPTIMIZER
:模型的超参数自动优化。
在大数据集上训练时,建议将数据集分成多个文件。有关更多详细信息,请参阅数据集路径和格式部分。
以下是使用 DISTRIBUTED_GRADIENT_BOOSTED_TREES
算法进行分布式训练的示例。
训练数据集是一组位于 /remote/dataset/
远程目录中的 csv 文件。例如:
ls /remote/dataset/
> /remote/dataset/train_0.csv
> /remote/dataset/train_1.csv
> /remote/dataset/train_2.csv
...
> /remote/dataset/train_1000.csv
因此,数据集路径为 csv:/remote/dataset/train_*.csv
。
重要的是,对于 DISTRIBUTED_GRADIENT_BOOSTED_TREES 算法(不同的算法有不同的约束),所有工作者都应该能够访问此数据集。
训练配置如下:
train_config.pbtxt
learner: "DISTRIBUTED_GRADIENT_BOOSTED_TREES"
task: CLASSIFICATION
label: "income"
[yggdrasil_decision_forests.model.distributed_gradient_boosted_trees.proto
.distributed_gradient_boosted_trees_config] {
}
通过配置分布式执行引擎(DEE)并设置 DeploymentConfig 中的 cache_path
字段来启用分布式训练。DEE 定义了工作者数量以及如何访问它们(例如,IP 地址列表)。
以下是配置为分布式训练的 DeploymentConfig 示例:
deploy_config.pbtxt
# work_directory 是一个所有工作者都可以访问的远程目录。
cache_path: "/remote/work_directory"
num_threads: 8 # 每个工作者将运行 8 个线程。
try_resume_training: true # 允许训练中断并恢复。
distribute {
implementation_key: "GRPC"
[yggdrasil_decision_forests.distribute.proto.grpc] {
socket_addresses {
# 配置 3 个工作者。
addresses { ip: "192.168.0.10" port: 8123 }
addresses { ip: "192.168.0.11" port: 8123 }
addresses { ip: "192.168.0.12" port: 8123 }
}
}
}
在启动分布式训练之前,您需要启动工作者。在此示例中,我们配置了 3 个工作者在三台不同的计算机上运行。在每台计算机上,我们需要使用相应的端口启动一个工作者进程。例如:
# 通过 ssh 连接到 192.168.0.10,然后运行:
# 下载并解压工作者二进制文件。
wget https://github.com/google/yggdrasil-decision-forests/releases/download/1.0.0/cli_linux.zip
unzip cli_linux.zip
# 启动工作者
./grpc_worker_main --port=8123
有关更多详细信息,请参阅 yggdrasil_decision_forests/utils/distribute/implementations/grpc/grpc.proto。
一旦工作者启动,就可以在管理者上启动训练:
# 在管理者上。
# 检查所有配置文件是否可用
ls
> train_config.pbtxt
> deploy_config.pbtxt
# 确定数据集的 dataspec
# 有关更多详细信息,请参阅 "CLI / 快速入门" 中的 "创建 dataspec" 部分。
./infer_dataspec \
--dataset=csv:/remote/dataset/train_*.csv \
--output=dataspec.pbtxt
# 启动分布式训练。
./train \
--dataset=csv:/remote/dataset/train_*.csv \
--dataspec=dataspec.pbtxt \
--config=train_config.pbtxt\
--deployment=deploy_config.pbtxt\
--output=model
此示例 通过在同一台机器上运行所有工作者来演示分布式训练。这实际上不是分布式训练,但这是测试它的简单方法。
上述示例使用了 GRPC
DEE。不同的 DEE 决定了分布式训练的方式。
计算原语被执行。DEE的选择不会影响有效训练的模型。
例如,TensorFlow Decision Forests使用TF_DIST DEE,它可以运行TensorFlow参数服务器的分布式计算。TF_DIST DEE支持套接字地址和TF_CONFIG配置。
推荐在CLI或C++ API中使用GRPC分布引擎。当使用TensorFlow Decision Forests接口时,GRPC和TF_DIST都是可行的选项(各有优缺点)。
特征工程
改进特征对于模型质量至关重要。为了简单性(YDF只做一件事)和执行效率(直接代码执行通常比中间表示执行快得多),YDF核心库不包含可定制的处理组件,除了文本分词。
注册类
Yggdrasil决策森林的源代码分为模块。不同的模块实现不同的功能,如学习算法、模型、数据集格式支持等。
模块通过Bazel依赖规则的注册机制进行控制:要启用一个模块,应将对该模块的依赖添加到代码的任何cc_library
或cc_binary
中。请注意,添加模块也会增加二进制文件的大小。
为了简单起见,yggdrasil_decision_forests/cli
中的CLI工具是用所有可用模块编译的。
当使用C++ API时,应手动添加对模块的依赖。例如,要支持RANDOM_FOREST
模型的训练,二进制文件/库需要依赖于"yggdrasil_decision_forests/learner/random_forest"规则。
类型为“没有用键...注册的类”或“类池中未知项...”的错误表明缺少对所需模块的依赖。
Yggdrasil决策森林还定义了包含某种类型所有模块的模块组。例如,规则yggdrasil_decision_forests/learner:all_learners
注入了所有可用的学习算法(包括上面提到的:random_forest
)。
以下是可用模块路径和注册键的列表。
学习算法
- learner/cart CART
- learner/distributed_gradient_boosted_trees DISTRIBUTED_GRADIENT_BOOSTED_TREES
- learner/gradient_boosted_trees GRADIENT_BOOSTED_TREES
- learner/random_forest RANDOM_FOREST
- learner/hyperparameters_optimizer HYPERPARAMETER_OPTIMIZER
模型
- model/gradient_boosted_trees GRADIENT_BOOSTED_TREES
- model/random_forest RANDOM_FOREST
推理引擎
- serving/decision_forest:register_engines
数据集IO
- dataset:csv_example_reader FORMAT_CSV(仅读取)
- dataset:csv_example_writer FORMAT_CSV(仅写入)
- dataset:tf_example_io_tfrecord FORMAT_TFE_TFRECORD
- dataset:capacitor_example_reader FORMAT_CAPACITOR
- dataset:tf_example_io_recordio FORMAT_TFE_RECORDIO
- dataset:tf_example_io_sstable FORMAT_TFE_SSTABLE
分布式计算后端
- utils/distribute/implementations/multi_thread MULTI_THREAD
- utils/distribute/implementations/grpc GRPC
- tensorflow_decision_forests/tensorflow/distribute:tf_distribution TF_DIST
梯度提升树学习器的损失
- learner/gradient_boosted_trees/loss/loss_imp_*
高级功能
大多数YDF高级文档都写在.h
头文件(对于库)和.cc
头文件(对于CLI工具)中。~~~