xgboost 文档有错吗? (早期停止轮次以及最佳和最后一次迭代)
Posted
技术标签:
【中文标题】xgboost 文档有错吗? (早期停止轮次以及最佳和最后一次迭代)【英文标题】:Is the xgboost documentation wrong ? (early stopping rounds and best and last iteration) 【发布时间】:2019-04-28 05:56:53 【问题描述】:下面是一个关于 xgboost 提前停止轮次参数的问题,以及当它是拟合结束的原因时,它如何提供或不提供最佳迭代。
在 xgboost 文档中,可以在 scikit learn api 部分 (link) 中看到,当由于提前停止轮数参数而导致拟合停止时:
激活提前停止。验证错误至少需要每“early_stopping_rounds”轮减少一次才能继续训练。在 evals 中至少需要一项。如果有多个,将使用最后一个。返回上一次迭代的模型(不是最好的)。
reeding 时,返回的模型似乎不是最好的,而是最后一个。它说,要在预测时访问最好的,可以使用 ntree_limit 参数调用预测,并在拟合结束时给出 bst.best_ntree_limit。
从这个意义上说,它应该与 xgboost 的 train 以相同的方式工作,因为 scikitlearn api 的拟合似乎只是 train 和其他的嵌入。
在这里stack overflow discussion 或这里another discussion 进行了热烈的讨论
但是当我试图解决这个问题并检查它如何处理我的数据时,我没有找到我认为应该有的行为。事实上,我遇到的行为根本不是那些讨论和文档中描述的行为。
我这样称呼合适:
reg = xgb.XGBRegressor(n_jobs=6, n_estimators = 100, max_depth= 5)
reg.fit(
X_train,
y_train,
eval_metric='rmse',
eval_set=[(X_train, y_train), (X_valid, y_valid)],
verbose=True,
early_stopping_rounds = 6)
这是我最后得到的:
[71] validation_0-rmse:1.70071 validation_1-rmse:1.9382
[72] validation_0-rmse:1.69806 validation_1-rmse:1.93825
[73] validation_0-rmse:1.69732 validation_1-rmse:1.93803
Stopping. Best iteration:
[67] validation_0-rmse:1.70768 validation_1-rmse:1.93734
当我检查我使用的验证值时:
y_pred_valid = reg.predict(X_valid)
y_pred_valid_df = pd.DataFrame(y_pred_valid)
sqrt(mse(y_valid, y_pred_valid_df[0]))
我明白了
1.9373418403889535
如果拟合返回最后一次迭代而不是最好的迭代,它应该给出一个 1.93803 左右的 rmse,但它给出了一个 1.93734 的 rmse,这正是最好的分数。
我通过两种方式再次检查: [编辑] 我根据@Eran Moshe 的回答编辑了下面的代码
y_pred_valid = reg.predict(X_valid, ntree_limit=reg.best_ntree_limit)
y_pred_valid_df = pd.DataFrame(y_pred_valid)
sqrt(mse(y_valid, y_pred_valid_df[0]))
1.9373418403889535
即使我只用 68 个估算器调用合适的(知道最好的迭代器是第 67 个),所以我确信最后一个是最好的:
reg = xgb.XGBRegressor(n_jobs=6, n_estimators = 68, max_depth= 5)
reg.fit(
X_train,
y_train,
eval_metric='rmse',
eval_set=[(X_train, y_train), (X_valid, y_valid)],
verbose=True,
early_stopping_rounds = 6)
结果是一样的:
1.9373418403889535
因此,这似乎导致了这样一种想法,即,与文档以及关于它的众多讨论不同,xgboost 的适合性在被早期停止轮参数停止时,确实给出了最好的迭代器,而不是最后一个.
我错了吗,如果是,你在哪里以及如何解释我遇到的行为?
感谢关注
【问题讨论】:
【参考方案1】:那里有代码错误。
注意方法
reg.predict(X_valid, ntree_limit=reg.best_ntree_limit)
应该是
y_pred_valid = reg.predict(X_valid, ntree_limit=reg.best_ntree_limit)
所以实际上你在计算时进行了同样的比较
sqrt(mse(y_valid, y_pred_valid_df[0]))
Xgboost 的工作方式与您所读到的一样。 early_stopping_round = x
将一直训练直到在 x
连续轮次中没有改善。
当使用 ntree_limit=y
进行预测时,它将仅使用第一个 y
助推器。
【讨论】:
您提到的确实存在代码错误,我已更正,但它并没有改变我提出的问题。当我使用 ntree_limit 参数进行预测时,它仍然给出了最佳答案。为什么? 不,不是。我自己测试过很多次,你完全错了。但我使用的是 xgboost.train 而不是 XGBRegressor 包装器。也许测试直接使用 xgboost 没有环绕 是的!我特别询问了环绕,文档确认它应该给最后一个不是最好的迭代,即使有环绕。因此问题。 我认为他们不会为环绕方式使用不同的功能。它可能继承了原生 xgboost 包所做的相同计算。也许你应该去看看代码..【参考方案2】:我认为,没有错,只是不一致。
predict
方法的文档是正确的(例如,参见here)。要 100% 确定最好查看代码:xgb github,因此 predict
的行为与其文档中所述相同,但 fit
文档已过时。请将其作为问题发布到 XGB github 上,他们将修复文档,或者您将成为 XGB 贡献者:)
【讨论】:
事实上,我确实在XGB github上发布了一个关于这个问题的问题,但直到现在还没有任何答案。拭目以待 仅供参考,我提出了更正文档的请求并被接受。请参阅拉取请求 #3967:github.com/dmlc/xgboost/pull/3967【参考方案3】:更准确地说,据@Mykhailo Lisovyi 所说,scikit-learn api 部分中的文档非常不一致,因为 fit 段落告诉当早期停止轮发生时,最后一次迭代不是最好的,而是predict 段落告诉当在没有指定 ntree_limit 的情况下调用 predict 时,ntree_limit 等于 best_ntree_limit。
因此,在读取fit部分时,可能会认为调用predict时需要指定最佳iter,但读取predict部分时,默认给出最佳iter,它是最后一个如果需要,您必须指定它。
我在 xgboost 的 github 上发布了一个问题....等等看
[更新]:拉取请求已被接受:link
【讨论】:
以上是关于xgboost 文档有错吗? (早期停止轮次以及最佳和最后一次迭代)的主要内容,如果未能解决你的问题,请参考以下文章
场景应用:short s1 = 1; s1 = s1 + 1;有错吗? short s1 = 1; s1 += 1;有错吗?
场景应用:short s1 = 1; s1 = s1 + 1;有错吗? short s1 = 1; s1 += 1;有错吗?
6short s1 = 1; s1 = s1 + 1;有错吗?short s1 = 1; s1 += 1;有错吗?-Java面试题答案