【问题标题】:Performance of H2O predict() functionH2O predict() 函数的性能
【发布时间】:2018-01-14 19:21:08
【问题描述】:


我在 python 中使用 H2O 的 Random Forest Regression 模型。在评估其速度方面的性能时,我将其与 scikit-learn 的 RandomForestRegressor 进行了比较。

数据集包含约 20,000 行和 20 列数据。
我的机器运行带有 python 3.6 的 windows。

import time
import h2o
import pandas as pd
from h2o.estimators.random_forest import H2ORandomForestEstimator
from sklearn.ensemble import RandomForestRegressor

def timing(f):
    def wrap(*args):
        time1 = time.time()
        ret = f(*args)
        time2 = time.time()
        print('%s function took %0.3f ms' % (f.__name__ , (time2-time1)*1000.0))
        return ret
    return wrap


@timing
def predict_row(model, row):
    return model.predict(row)


# read data
h2o.init(max_mem_size = "8G")
h2o.remove_all() 
h2o_df = h2o.import_file(csv_path)
train, valid, test = h2o_df.split_frame([0.6, 0.2], seed=1234)
X = h2o_df.col_names[:-1]
y = h2o_df.col_names[-1]  


# random forest at H2O
rf_h2o = H2ORandomForestEstimator(model_id="rf_h2o_v1", ntrees=100, stopping_rounds=2, score_each_iteration=True, seed=1000000,
                             col_sample_rate_per_tree=0.3)
rf_h2o.train(X, y, training_frame=train, validation_frame=valid)


# random forest at sklearn
train_df = train[:-1].as_data_frame(use_pandas=True)
y_df = h2o_df[:,-1].as_data_frame(use_pandas=True)
y_df = y_df[y_df.index.isin(train_df.index)]
rf_sklearn = RandomForestRegressor(n_estimators=100, min_samples_leaf=3, oob_score=True, max_features=0.25)
rf_sklearn.fit(train_df, y_df)


# prediction comparison, let's take row #5 from the test set for example
row_h20 = test[5,:-1]
row_array = test[5,:-1].as_data_frame(use_pandas=True).values
rf_sklearn.predict(row_array)

# run 20 times and test performance on all iterations
for i in range(20):
    predict_row(rf_sklearn, row_array)
    predict_row(rf_h2o, row_h20)

当我运行此代码时,我通过 scikit-learn 获得了随机森林,其速度比 H2O 的模型快 X4-5 倍(6-7 毫秒,而最快迭代约为 30 毫秒)两种情况)。
我的问题是:

  1. 真的是这样吗?任何人都可以验证我没有做错什么吗?
    我知道 H2O 是基于 JVM 构建的,它不应该像闪电一样快,但我认为它们至少会和 scikit-learn 一样好。

  2. 我需要在回归算法中超快速地实现预测。有没有人有什么建议?
    scikit-learn / H2O 对我来说不是强制性的,但我需要一些可靠的东西。

【问题讨论】:

    标签: python performance python-3.x machine-learning h2o


    【解决方案1】:

    H2O 使用数据并行来实现规模和效率,这里的行数非常少,所以并行工作的线程数可能很低。

    当行数更多(百万+)时,H2O 在速度和规模方面具有优势。

    您可以使用内置的 Water Meter(在 Linux 上)或“top”或其他性能监控工具来查看有多少线程在工作。如果你打开 H2O Flow Web UI,在解析数据后,你可以看到详细的 Frame Distribution Summary 细分(见下文)。

    对于此示例,我提取的数据集有 43,978 行和 31 列。您可以看到每列的块数为 1。这意味着我的数据并行度级别仅为 1,并且只有 1 个线程将工作。 H2O 旨在高效处理更大的数据集。

    【讨论】:

    • 谢谢,不知道。但是它与单行的预测有什么关系呢?请允许我澄清一下:我的代码设计为每秒运行数千次 API 调用以进行预测,其中每个预测请求都由一行组成。听起来您所描述的内容在这种情况下只会影响训练时间而不影响预测时间。
    • 对于该用例,您应该从 H2O 导出 MOJO 或 POJO 并使用它来进行预测。它们适用于一次一行的实时用例。我不会使用完整的 H2O,它对于一次一行的用例会有很多开销。见docs.h2o.ai/h2o/latest-stable/h2o-genmodel/javadoc/index.html
    【解决方案2】:

    我认为基准测试存在一些问题:

    • 在 H2O 中,你有 col_sample_rate_per_tree=0.3,而在 sklearn 中,你有 max_features=0.25。您应该将 H2O 中的 col_sample_rate 设置为与 sklearn 中的 max_features 相同的值。在 sklearn 中使用更少的功能将使 sklearn 训练得更快。
    • 在 sklearn 中,您有 min_samples_leaf=3,但 min_rows(H2O 等效项)默认为 1。这些应设置为相同的值。它们都默认为 1,因此您可能应该将它们都保留为默认值。设置 min_samples_leaf=3 将强制 sklearn 更快地停止构建树(因此训练会更快)。
    • 请勿将stopping_rounds=2 设置在H2O 中。
    • 在 sklearn 与 H2O 中还有许多其他参数具有不同的默认值。
    • 我建议在每次迭代中运行带有和不带有评分的基准,看看它如何影响性能(参考 H2O 中的 score_each_iteration 和 sklearn 中的 oob_score)。
    • 我假设您的数据仅包含数字特征,但如果您使用包含分类特征的数据集,sklearn 将要求您对这些特征进行一次热编码,这可能会大大增加您的训练时间,具体取决于每个分类特征的级别数。

    也就是说,在小型数据集上,sklearn 仍有可能比 H2O 训练得更快。 H2O 在设计时考虑了可扩展性,因此当您使用更多训练数据时,您将开始看到 H2O(相对于其他工具)的价值。随着训练规模的增加,在这个benchmark 中,H2O 随机森林与其他工具的比较有一个很好的图表(下面的屏幕截图)。这仅适用于单个数据集,因此不能推广到所有情况,但它很好地证明了 sklearn 等工具如何随着训练规模的增加而开始崩溃(sklearn RF 在此特定的 1M 行后内存不足)基准)。

    【讨论】:

    • 谢谢,测试了你写的东西,但是 H2O 在单行预测任务上仍然明显落后。我的数据也具有分类特征,我试图避免在分类上滥用 sklearn,这就是为什么我一直在寻找替代方案。
    【解决方案3】:

    6-7 毫秒与约 30 毫秒的差异可能是由于进行 REST API 调用的开销所致。

    为了在生产环境中进行预测,23 毫秒确实很重要,我认为建议使用 POJO 或 MOJO。您正在使用随机森林,因此应该使用 MOJO,因为根据https://github.com/h2oai/h2o-3/blob/master/h2o-docs/src/product/howto/MOJO_QuickStart.md,它们可以显着提高速度

    如果您只是为了评估 H2O 的速度而进行测试,您还应该对一个非常大的数据集或更复杂的模型进行比较。例如。如果差异是 2.006 秒和 2.030 秒,您可以停止担心,继续做更重要的事情。

    【讨论】:

    • 谢谢!但我的需要是能够回复多个单值预测请求,并快速处理它们。没有开销,因为我在本地测试了这两个模型而没有任何调用。但我肯定会尝试 Mojo/Pojo 并报告调查结果。
    • H2O 没有“本地”。当您运行 Python API 命令时,它会进行 REST API 调用并将其发送到 H2O 服务器(用 Java 编写)。当您的 H2O 服务器在 localhost 上运行时,20 毫秒的开销听起来是对的,不是吗?
    • 是的,我明白你的意思。所以,在那种情况下,听起来我将无法低于这个阈值。
    • 正如我所说,如果 REST API 调用的 23 毫秒开销是很大的开销,那么您应该使用 MOJO。请参阅docs.h2o.ai/h2o/latest-stable/h2o-docs/productionizing.html 了解它的各种使用方式。如果您尝试一下,我很想看看结果。
    • 好的,所以我刚刚发现了CatBoost,它运行 GBM 而不是随机森林(这是我一直在寻找的)。它给了我更好的结果,并且每次调用不到 1 毫秒就可以进行预测。到目前为止,推荐!
    【解决方案4】:

    我遇到了类似的问题。我已经编写了我的 H2O 预测代码,一次只做一个预测。表现令人失望。这是因为为 H2O 进行设置需要相当多的开销,包括构建 H2O 数据框。

    为了让事情变得合理,我将几个数据行批量化为一次预测,现在我得到了很好的性能。

    LeDell 博士发布的图表清楚地显示了各种平台遇到的各种开销,有时开销很大。

    OP 需要设置基准以反映他们真正期望如何使用模型:开销是否更重要(不太可能),或者每次预测的时间是否更重要。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2023-03-16
      • 2017-07-31
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-01-22
      相关资源
      最近更新 更多