生成预测

在 TensorFlow.org 上查看 在 Google Colab 中运行 在 GitHub 上查看 下载笔记本

欢迎使用 TensorFlow 决策森林 (TF-DF) 的 预测 Colab。在这个 Colab 中,您将学习使用 Python API 使用之前训练过的 TF-DF 模型生成预测的不同方法。

备注:此 Colab 中显示的 Python API 易于使用,非常适合实验。但是,其他 API(例如 TensorFlow Serving 和 C++ API)更适合生产系统,因为它们更快且更稳定。所有 Serving API 的完整列表可 在此 获得。

在这个 Colab 中,您将

  1. 在使用 pd_dataframe_to_tf_dataset 创建的 TensorFlow 数据集上使用 model.predict() 函数。
  2. 在手动创建的 TensorFlow 数据集上使用 model.predict() 函数。
  3. 在 Numpy 数组上使用 model.predict() 函数。
  4. 使用 CLI API 生成预测。
  5. 使用 CLI API 对模型的推理速度进行基准测试。

重要备注

用于预测的数据集应具有与用于训练的数据集 相同的特征名称和类型。否则,可能会引发错误。

例如,使用两个特征 f1f2 训练模型,并尝试在没有 f2 的数据集上生成预测将失败。请注意,将(某些或所有)特征值设置为“缺失”是可以的。同样,在 f2 是数值特征(例如,float32)的情况下训练模型,并将此模型应用于 f2 是文本(例如,字符串)特征的数据集将失败。

虽然 Keras API 进行了抽象,但在 Python 中实例化的模型(例如,使用 tfdf.keras.RandomForestModel())和从磁盘加载的模型(例如,使用 tf_keras.models.load_model())的行为可能不同。值得注意的是,Python 实例化的模型会自动应用必要的类型转换。例如,如果将 float64 特征馈送到期望 float32 特征的模型,则会隐式执行此转换。但是,对于从磁盘加载的模型,这种转换是不可能的。因此,训练数据和推理数据始终具有完全相同的类型非常重要。

设置

首先,我们安装 TensorFlow 决策森林...

pip install tensorflow_decision_forests

...,并导入此示例中使用的库。

import tensorflow_decision_forests as tfdf

import os
import numpy as np
import pandas as pd
import tensorflow as tf
import math

model.predict(...)pd_dataframe_to_tf_dataset 函数

TensorFlow 决策森林实现了 Keras 模型 API。因此,TF-DF 模型具有 predict 函数来生成预测。此函数以 TensorFlow 数据集 作为输入,并输出预测数组。创建 TensorFlow 数据集的最简单方法是使用 Pandastfdf.keras.pd_dataframe_to_tf_dataset(...) 函数。

以下示例展示了如何使用 pd_dataframe_to_tf_dataset 创建 TensorFlow 数据集。

pd_dataset = pd.DataFrame({
    "feature_1": [1,2,3],
    "feature_2": ["a", "b", "c"],
    "label": [0, 1, 0],
})

pd_dataset
tf_dataset = tfdf.keras.pd_dataframe_to_tf_dataset(pd_dataset, label="label")

for features, label in tf_dataset:
  print("Features:",features)
  print("label:", label)
Features: {'feature_1': <tf.Tensor: shape=(3,), dtype=int64, numpy=array([1, 2, 3])>, 'feature_2': <tf.Tensor: shape=(3,), dtype=string, numpy=array([b'a', b'b', b'c'], dtype=object)>}
label: tf.Tensor([0 1 0], shape=(3,), dtype=int64)
2024-04-20 11:14:51.301980: W tensorflow/core/framework/local_rendezvous.cc:404] Local rendezvous is aborting with status: OUT_OF_RANGE: End of sequence

注意:“pd”代表“pandas”。“tf”代表“TensorFlow”。

TensorFlow 数据集是一个输出一系列值的函数。这些值可以是简单的数组(称为张量)或组织成结构的数组(例如,组织在字典中的数组)。

以下示例展示了在玩具数据集上进行训练和推理(使用 predict

# Creating a training dataset in Pandas
pd_train_dataset = pd.DataFrame({
    "feature_1": np.random.rand(1000),
    "feature_2": np.random.rand(1000),
})
pd_train_dataset["label"] = pd_train_dataset["feature_1"] > pd_train_dataset["feature_2"] 

pd_train_dataset
# Creating a serving dataset with Pandas
pd_serving_dataset = pd.DataFrame({
    "feature_1": np.random.rand(500),
    "feature_2": np.random.rand(500),
})

pd_serving_dataset

让我们将 Pandas 数据帧转换为 TensorFlow 数据集

tf_train_dataset = tfdf.keras.pd_dataframe_to_tf_dataset(pd_train_dataset, label="label")
tf_serving_dataset = tfdf.keras.pd_dataframe_to_tf_dataset(pd_serving_dataset)

我们现在可以在 tf_train_dataset 上训练模型

model = tfdf.keras.RandomForestModel(verbose=0)
model.fit(tf_train_dataset)
[INFO 24-04-20 11:14:55.1176 UTC kernel.cc:1233] Loading model from path /tmpfs/tmp/tmpdosbv775/model/ with prefix 951a85e27c8d4048
[INFO 24-04-20 11:14:55.1550 UTC decision_forest.cc:734] Model loaded with 300 root(s), 12674 node(s), and 2 input feature(s).
[INFO 24-04-20 11:14:55.1551 UTC abstract_model.cc:1344] Engine "RandomForestOptPred" built
[INFO 24-04-20 11:14:55.1551 UTC kernel.cc:1061] Use fast generic engine
<tf_keras.src.callbacks.History at 0x7f96c017a7f0>

然后在 tf_serving_dataset 上生成预测

# Print the first 10 predictions.
model.predict(tf_serving_dataset, verbose=0)[:10]
array([[0.57999957],
       [0.13666661],
       [0.68666613],
       [0.        ],
       [0.        ],
       [0.        ],
       [0.        ],
       [0.        ],
       [0.        ],
       [0.00333333]], dtype=float32)

model.predict(...) 和手动 TF 数据集

在上一节中,我们展示了如何使用 pd_dataframe_to_tf_dataset 函数创建 TF 数据集。此选项很简单,但不适合大型数据集。相反,TensorFlow 提供了 多种选项 来创建 TensorFlow 数据集。以下示例展示了如何使用 tf.data.Dataset.from_tensor_slices() 函数创建数据集。

dataset = tf.data.Dataset.from_tensor_slices([1,2,3,4,5])

for value in dataset:
  print("value:", value.numpy())
value: 1
value: 2
value: 3
value: 4
value: 5
2024-04-20 11:14:59.117255: W tensorflow/core/framework/local_rendezvous.cc:404] Local rendezvous is aborting with status: OUT_OF_RANGE: End of sequence

TensorFlow 模型使用小批量训练:示例不是一次一个地馈送,而是分组到“批次”中。对于神经网络,批次大小会影响模型的质量,并且用户需要在训练期间确定最佳值。对于决策森林,批次大小不会影响模型。但是,出于兼容性原因,TensorFlow 决策森林期望数据集是批处理的。批处理使用 batch() 函数完成。

dataset = tf.data.Dataset.from_tensor_slices([1,2,3,4,5]).batch(2)

for value in dataset:
  print("value:", value.numpy())
value: [1 2]
value: [3 4]
value: [5]
2024-04-20 11:14:59.134734: W tensorflow/core/framework/local_rendezvous.cc:404] Local rendezvous is aborting with status: OUT_OF_RANGE: End of sequence

TensorFlow 决策森林期望数据集具有以下两种结构之一

  • 特征,标签
  • 特征,标签,权重

特征可以是单个二维数组(其中每列都是一个特征,每行都是一个示例),也可以是数组字典。

以下是与 TensorFlow 决策森林兼容的数据集示例

# A dataset with a single 2d array.
tf_dataset = tf.data.Dataset.from_tensor_slices(
    ([[1,2],[3,4],[5,6]], # Features
    [0,1,0], # Label
    )).batch(2)

for features, label in tf_dataset:
  print("features:", features)
  print("label:", label)
features: tf.Tensor(
[[1 2]
 [3 4]], shape=(2, 2), dtype=int32)
label: tf.Tensor([0 1], shape=(2,), dtype=int32)
features: tf.Tensor([[5 6]], shape=(1, 2), dtype=int32)
label: tf.Tensor([0], shape=(1,), dtype=int32)
2024-04-20 11:14:59.152655: W tensorflow/core/framework/local_rendezvous.cc:404] Local rendezvous is aborting with status: OUT_OF_RANGE: End of sequence
# A dataset with a dictionary of features.
tf_dataset = tf.data.Dataset.from_tensor_slices(
    ({
    "feature_1": [1,2,3],
    "feature_2": [4,5,6],
    },
    [0,1,0], # Label
    )).batch(2)

for features, label in tf_dataset:
  print("features:", features)
  print("label:", label)
features: {'feature_1': <tf.Tensor: shape=(2,), dtype=int32, numpy=array([1, 2], dtype=int32)>, 'feature_2': <tf.Tensor: shape=(2,), dtype=int32, numpy=array([4, 5], dtype=int32)>}
label: tf.Tensor([0 1], shape=(2,), dtype=int32)
features: {'feature_1': <tf.Tensor: shape=(1,), dtype=int32, numpy=array([3], dtype=int32)>, 'feature_2': <tf.Tensor: shape=(1,), dtype=int32, numpy=array([6], dtype=int32)>}
label: tf.Tensor([0], shape=(1,), dtype=int32)
2024-04-20 11:14:59.171912: W tensorflow/core/framework/local_rendezvous.cc:404] Local rendezvous is aborting with status: OUT_OF_RANGE: End of sequence

让我们使用第二个选项训练模型。

tf_dataset = tf.data.Dataset.from_tensor_slices(
    ({
    "feature_1": np.random.rand(100),
    "feature_2": np.random.rand(100),
    },
    np.random.rand(100) >= 0.5, # Label
    )).batch(2)

model = tfdf.keras.RandomForestModel(verbose=0)
model.fit(tf_dataset)
[INFO 24-04-20 11:14:59.3750 UTC kernel.cc:1233] Loading model from path /tmpfs/tmp/tmp208me4tj/model/ with prefix b7fe9aaae54944c5
[INFO 24-04-20 11:14:59.3979 UTC decision_forest.cc:734] Model loaded with 300 root(s), 7574 node(s), and 2 input feature(s).
[INFO 24-04-20 11:14:59.3979 UTC kernel.cc:1061] Use fast generic engine
<tf_keras.src.callbacks.History at 0x7f968c13e8e0>

可以使用 predict 函数直接在训练数据集上进行预测

# The first 10 predictions.
model.predict(tf_dataset, verbose=0)[:10]
array([[0.9366659 ],
       [0.42999968],
       [0.9266659 ],
       [0.31999978],
       [0.70999944],
       [0.2133332 ],
       [0.13333328],
       [0.836666  ],
       [0.10666663],
       [0.53333294]], dtype=float32)

model.predict(...)model.predict_on_batch() 可以用于字典。

在某些情况下,predict 函数可以使用数组(或数组字典)而不是 TensorFlow 数据集。

以下示例使用先前训练的模型和 NumPy 数组字典。

# The first 10 predictions.
model.predict({
    "feature_1": np.random.rand(100),
    "feature_2": np.random.rand(100),
    }, verbose=0)[:10]
array([[0.5366663 ],
       [0.19666655],
       [0.2233332 ],
       [0.99999917],
       [0.3233331 ],
       [0.3866664 ],
       [0.71999943],
       [0.40666637],
       [0.73333275],
       [0.10999996]], dtype=float32)

在前面的示例中,数组会自动进行批处理。或者,可以使用 predict_on_batch 函数来确保所有示例都在同一个批次中运行。

# The first 10 predictions.
model.predict_on_batch({
    "feature_1": np.random.rand(100),
    "feature_2": np.random.rand(100),
    })[:10]
array([[0.3433331 ],
       [0.42333302],
       [0.9466659 ],
       [0.38333306],
       [0.21666653],
       [0.10999996],
       [0.09333331],
       [0.23999985],
       [0.13999994],
       [0.36999974]], dtype=float32)

使用 YDF 格式进行推理

此示例展示了如何运行使用 CLI API 训练的 TF-DF 模型(其他服务 API 之一)。我们还将使用基准测试工具来衡量模型的推理速度。

让我们先训练并保存模型

model = tfdf.keras.GradientBoostedTreesModel(verbose=0)
model.fit(tfdf.keras.pd_dataframe_to_tf_dataset(pd_train_dataset, label="label"))
model.save("my_model")
[WARNING 24-04-20 11:15:00.0298 UTC gradient_boosted_trees.cc:1840] "goss_alpha" set but "sampling_method" not equal to "GOSS".
[WARNING 24-04-20 11:15:00.0299 UTC gradient_boosted_trees.cc:1851] "goss_beta" set but "sampling_method" not equal to "GOSS".
[WARNING 24-04-20 11:15:00.0299 UTC gradient_boosted_trees.cc:1865] "selective_gradient_boosting_ratio" set but "sampling_method" not equal to "SELGB".
[INFO 24-04-20 11:15:00.4645 UTC kernel.cc:1233] Loading model from path /tmpfs/tmp/tmp_gpxt9u3/model/ with prefix 307d0dfd7bcd4058
[INFO 24-04-20 11:15:00.4725 UTC quick_scorer_extended.cc:911] The binary was compiled without AVX2 support, but your CPU supports it. Enable it for faster model inference.
[INFO 24-04-20 11:15:00.4729 UTC kernel.cc:1061] Use fast generic engine
INFO:tensorflow:Assets written to: my_model/assets
INFO:tensorflow:Assets written to: my_model/assets

让我们也将数据集导出到 csv 文件

pd_serving_dataset.to_csv("dataset.csv")

让我们下载并解压缩 Yggdrasil Decision Forests CLI 工具。

wget https://github.com/google/yggdrasil-decision-forests/releases/download/1.0.0/cli_linux.zip
unzip cli_linux.zip
--2024-04-20 11:15:01--  https://github.com/google/yggdrasil-decision-forests/releases/download/1.0.0/cli_linux.zip
Resolving github.com (github.com)... 140.82.114.3
Connecting to github.com (github.com)|140.82.114.3|:443... connected.
HTTP request sent, awaiting response... 302 Found
Location: https://objects.githubusercontent.com/github-production-release-asset-2e65be/360444739/bfcd0b9d-5cbc-42a8-be0a-02131875f9a6?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=AKIAVCODYLSA53PQK4ZA%2F20240420%2Fus-east-1%2Fs3%2Faws4_request&X-Amz-Date=20240420T111501Z&X-Amz-Expires=300&X-Amz-Signature=01381b3c5a69d831a4be54e2fef635b848ca9b5aaeeac6822698c6acf5f93240&X-Amz-SignedHeaders=host&actor_id=0&key_id=0&repo_id=360444739&response-content-disposition=attachment%3B%20filename%3Dcli_linux.zip&response-content-type=application%2Foctet-stream [following]
--2024-04-20 11:15:01--  https://objects.githubusercontent.com/github-production-release-asset-2e65be/360444739/bfcd0b9d-5cbc-42a8-be0a-02131875f9a6?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=AKIAVCODYLSA53PQK4ZA%2F20240420%2Fus-east-1%2Fs3%2Faws4_request&X-Amz-Date=20240420T111501Z&X-Amz-Expires=300&X-Amz-Signature=01381b3c5a69d831a4be54e2fef635b848ca9b5aaeeac6822698c6acf5f93240&X-Amz-SignedHeaders=host&actor_id=0&key_id=0&repo_id=360444739&response-content-disposition=attachment%3B%20filename%3Dcli_linux.zip&response-content-type=application%2Foctet-stream
Resolving objects.githubusercontent.com (objects.githubusercontent.com)... 185.199.111.133, 185.199.110.133, 185.199.109.133, ...
Connecting to objects.githubusercontent.com (objects.githubusercontent.com)|185.199.111.133|:443... connected.
HTTP request sent, awaiting response... 200 OK
Length: 31516027 (30M) [application/octet-stream]
Saving to: ‘cli_linux.zip’

cli_linux.zip       100%[===================>]  30.06M   174MB/s    in 0.2s    

2024-04-20 11:15:01 (174 MB/s) - ‘cli_linux.zip’ saved [31516027/31516027]

Archive:  cli_linux.zip
  inflating: README                  
  inflating: cli.txt                 
  inflating: train                   
  inflating: show_model              
  inflating: show_dataspec           
  inflating: predict                 
  inflating: infer_dataspec          
  inflating: evaluate                
  inflating: convert_dataset         
  inflating: benchmark_inference     
  inflating: edit_model              
  inflating: synthetic_dataset       
  inflating: grpc_worker_main        
  inflating: LICENSE                 
  inflating: CHANGELOG.md

最后,让我们进行预测

备注

  • TensorFlow Decision Forests (TF-DF) 基于 Yggdrasil Decision Forests (YDF) 库,TF-DF 模型内部始终包含 YDF 模型。将 TF-DF 模型保存到磁盘时,TF-DF 模型目录包含一个名为 assets 的子目录,其中包含 YDF 模型。此 YDF 模型可用于所有 YDF 工具。在下一个示例中,我们将使用 predictbenchmark_inference 工具。有关更多详细信息,请参阅 模型格式文档
  • YDF 工具假设数据集类型使用前缀指定,例如 csv:。有关更多详细信息,请参阅 YDF 用户手册
./predict --model=my_model/assets --dataset=csv:dataset.csv --output=csv:predictions.csv
[INFO abstract_model.cc:1296] Engine "GradientBoostedTreesQuickScorerExtended" built
[INFO predict.cc:133] Run predictions with semi-fast engine

现在我们可以查看预测结果

pd.read_csv("predictions.csv")

可以使用 基准测试推理 工具来衡量模型的推理速度。

# Create the empty label column.
pd_serving_dataset["__LABEL"] = 0
pd_serving_dataset.to_csv("dataset.csv")
!./benchmark_inference \
  --model=my_model/assets \
  --dataset=csv:dataset.csv \
  --batch_size=100 \
  --warmup_runs=10 \
  --num_runs=50
[INFO benchmark_inference.cc:245] Loading model
[INFO benchmark_inference.cc:248] The model is of type: GRADIENT_BOOSTED_TREES
[INFO benchmark_inference.cc:250] Loading dataset
[INFO benchmark_inference.cc:259] Found 3 compatible fast engines.
[INFO benchmark_inference.cc:262] Running GradientBoostedTreesGeneric
[INFO decision_forest.cc:639] Model loaded with 49 root(s), 2661 node(s), and 2 input feature(s).
[INFO benchmark_inference.cc:262] Running GradientBoostedTreesQuickScorerExtended
[INFO benchmark_inference.cc:262] Running GradientBoostedTreesOptPred
[INFO decision_forest.cc:639] Model loaded with 49 root(s), 2661 node(s), and 2 input feature(s).
[INFO benchmark_inference.cc:268] Running the slow generic engine
batch_size : 100  num_runs : 50
time/example(us)  time/batch(us)  method
----------------------------------------
         0.44275          44.275  GradientBoostedTreesQuickScorerExtended [virtual interface]
         0.79825          79.825  GradientBoostedTreesOptPred [virtual interface]
           1.877           187.7  GradientBoostedTreesGeneric [virtual interface]
          4.4463          444.62  Generic slow engine
----------------------------------------

在此基准测试中,我们可以看到不同推理引擎的推理速度。例如,“time/example(us) = 0.6315”(在不同的运行中可能会发生变化)表示一个示例的推理需要 0.63 微秒。也就是说,模型每秒可以运行约 160 万次。