过拟合是复杂非线性算法中的一类问题,这篇文章将会介绍如何使用early stopping去避免XGBoost 中的过拟合问题。
通过阅读这篇文章你将会了解到:
early stopping是一种避免training data过拟合的方式。
如何在训练过程中监控XGBoost模型的性能,并绘制学习曲线。
如何使用early stopping在一个最佳的时间提前停止一个XGBoost模型的训练。
early stopping是一种避免training data过拟合的方式。
它的工作原理是监控在一个单独的测试数据集上训练的模型的性能,并在经过固定次数的训练迭代后,测试数据集上的性能没有改善时停止训练过程。
它试图通过自动选择拐点来避免过度拟合,在拐点处,随着模型开始过度拟合,测试数据集上的性能开始下降,而训练数据集上的性能继续提高。
性能度量可以是为训练模型而优化的损失函数(如对数损失),也可以是外部度量指标(如分类精度)。
使用XGBoost监控训练性能
XGBoost模型可以在训练过程中评估和报告模型在测试集上的性能
它通过训练模型并指定详细输出时,在调用model.fit()时指定测试数据集和评估度量来支持这种功能。
例如,我们可以在训练XGBoost模型时,输出一个独立测试集(eval_set)的二分类错误率(“error”),如下:
eval_set = [(X_test, y_test)]
model.fit(X_train, y_train, eval_metric="error", eval_set=eval_set, verbose=True)
XGBoost支持一套评估指标,不限于:
“rmse” 表示均方根误差。
“mae” 表示平均绝对误差.
“logloss” 用于二进制对数损失和“mlogloss”用于多类日志损失(交叉熵)
“error” 表示分类错误率
“auc” 表示ROC曲线下的面积
例如,我们可以演示如何在UCI机器学习存储库提供的Pima Indians onset of diabetes数据集上跟踪XGBoost模型的训练性能。
完整的例子如下:
# monitor training performance
from numpy import loadtxt
from xgboost import XGBClassifier
from sklearn.model_selection import train_test_split
from sklearn.metrics import accuracy_score
# load data
dataset = loadtxt('pima-indians-diabetes.csv', delimiter=",")
# split data into X and y
X = dataset[:,0:8]
Y = dataset[:,8]
# split data into train and test sets
X_train, X_test, y_train, y_test = train_test_split(X, Y, test_size=0.33, random_state=7)
# fit model no training data
model = XGBClassifier()
eval_set = [(X_test, y_test)]
model.fit(X_train, y_train, eval_metric="error", eval_set=eval_set, verbose=True)
# make predictions for test data
y_pred = model.predict(X_test)
predictions = [round(value) for value in y_pred]
# evaluate predictions
accuracy = accuracy_score(y_test, predictions)
print("Accuracy: %.2f%%" % (accuracy * 100.0))
运行此示例将在67%的数据上训练模型,并在33%的测试数据集上评估模型。
每次迭代都报告分类错误,最后报告分类精度。
下面提供了输出,为了简洁起见进行了截断。我们可以看到,在每次训练迭代中都会报告分类错误(在每个增强树被添加到模型之后)。
...
[89] validation_0-error:0.204724
[90] validation_0-error:0.208661
[91] validation_0-error:0.208661
[92] validation_0-error:0.208661
[93] validation_0-error:0.208661
[94] validation_0-error:0.208661
[95] validation_0-error:0.212598
[96] validation_0-error:0.204724
[97] validation_0-error:0.212598
[98] validation_0-error:0.216535
[99] validation_0-error:0.220472
Accuracy: 77.95%
回顾所有的输出,我们可以看到测试集上的模型性能保持不变,甚至在训练结束时变得更糟。
使用学习曲线评估XGBoost模型
我们可以在评估数据集上评估模型的性能,并将其绘制成图,从而深入了解学习是如何在训练中展开的。
在拟合XGBoost模型时,我们为eval_metric参数提供了一个X和y对数组。除了测试集,我们还可以提供训练数据集。这将提供一个关于模型在训练期间在train_data和test_data上的表现。
例如:
eval_set = [(X_train, y_train), (X_test, y_test)]
model.fit(X_train, y_train, eval_metric="error", eval_set=eval_set, verbose=True)
此外,通过调用model.evals_result()函数,将模型在每个评估集上的性能存储起来,并在训练之后由模型提供。这返回一个字典的评估数据集和分数,例如:
results = model.evals_result()
print(results)
打印如下结果(为简洁起见,进行了截短):
{
'validation_0': {'error': [0.259843, 0.26378, 0.26378, ...]},
'validation_1': {'error': [0.22179, 0.202335, 0.196498, ...]}
}
每个’ validation_0 ‘和’ validation_1 '都对应于在调用to fit()时向eval_set参数提供数据集的顺序。
访问一个特定的结果数组,如第一个数据集和误差度量,可以如下:
results['validation_0']['error']
此外,我们还可以为fit()函数的eval_metric参数提供一个度量数组,从而指定更多的评估度量,以便评估和收集。
然后,我们可以使用这些收集的性能度量来创建一个线图,并进一步了解模型在训练期间在训练和测试数据集中的表现。
下面是完整的代码示例,展示了如何将收集到的结果可视化到行图中。
# plot learning curve(学习曲线)
from numpy import loadtxt
from xgboost import XGBClassifier
from sklearn.model_selection import train_test_split
from sklearn.metrics import accuracy_score
from matplotlib import pyplot
# load data
dataset = loadtxt('pima-indians-diabetes.csv', delimiter=",")
# split data into X and y
X = dataset[:,0:8]
Y = dataset[:,8]
# split data into train and test sets
X_train, X_test, y_train, y_test = train_test_split(X, Y, test_size=0.33, random_state=7)
# fit model no training data
model = XGBClassifier()
eval_set = [(X_train, y_train), (X_test, y_test)]
model.fit(X_train, y_train, eval_metric=["error", "logloss"], eval_set=eval_set, verbose=True)
# make predictions for test data
y_pred = model.predict(X_test)
predictions = [round(value) for value in y_pred]
# evaluate predictions
accuracy = accuracy_score(y_test, predictions)
print("Accuracy: %.2f%%" % (accuracy * 100.0))
# retrieve performance metrics
results = model.evals_result()
epochs = len(results['validation_0']['error'])
x_axis = range(0, epochs)
# plot log loss
fig, ax = pyplot.subplots()
ax.plot(x_axis, results['validation_0']['logloss'], label='Train')
ax.plot(x_axis, results['validation_1']['logloss'], label='Test')
ax.legend()
pyplot.ylabel('Log Loss')
pyplot.title('XGBoost Log Loss')
pyplot.show()
# plot classification error
fig, ax = pyplot.subplots()
ax.plot(x_axis, results['validation_0']['error'], label='Train')
ax.plot(x_axis, results['validation_1']['error'], label='Test')
ax.legend()
pyplot.ylabel('Classification Error')
pyplot.title('XGBoost Classification Error')
pyplot.show()
运行此代码将在每个单元上report训练和测试数据集上的分类错误。我们可以通过在对fit()函数的调用中设置verbose=False(缺省值)来关闭此功能。
创建了两个图。第一个显示了训练和测试数据集中每个单元的XGBoost模型的对数损失。
第二幅图显示了XGBoost模型在训练和测试数据集中对每个单元的分类误差。
从logloss的表现来看,似乎有机会尽早停止学习,也许是在epoch 20到epoch 40左右。
我们在分类错误中也看到了类似的情况,在epoch 40左右,错误又升高了。
例如,我们可以检查在10个周期内对数损失没有改善,如下:
eval_set = [(X_test, y_test)]
model.fit(X_train, y_train, early_stopping_rounds=10, eval_metric="logloss", eval_set=eval_set, verbose=True)
如果提供了多个评估数据集或多个评估指标,那么early stop将使用列表中的最后一个。
下面提供了关于early stopping的完整性的完整示例。
# early stopping
from numpy import loadtxt
from xgboost import XGBClassifier
from sklearn.model_selection import train_test_split
from sklearn.metrics import accuracy_score
# load data
dataset = loadtxt('pima-indians-diabetes.csv', delimiter=",")
# split data into X and y
X = dataset[:,0:8]
Y = dataset[:,8]
# split data into train and test sets
seed = 7
test_size = 0.33
X_train, X_test, y_train, y_test = train_test_split(X, Y, test_size=test_size, random_state=seed)
# fit model no training data
model = XGBClassifier()
eval_set = [(X_test, y_test)]
model.fit(X_train, y_train, early_stopping_rounds=10, eval_metric="logloss", eval_set=eval_set, verbose=True)
# make predictions for test data
y_pred = model.predict(X_test)
predictions = [round(value) for value in y_pred]
# evaluate predictions
accuracy = accuracy_score(y_test, predictions)
print("Accuracy: %.2f%%" % (accuracy * 100.0))
运行这个例子提供了以下输出,为了简洁起见,进行了截断:
...
[35] validation_0-logloss:0.487962
[36] validation_0-logloss:0.488218
[37] validation_0-logloss:0.489582
[38] validation_0-logloss:0.489334
[39] validation_0-logloss:0.490969
[40] validation_0-logloss:0.48978
[41] validation_0-logloss:0.490704
[42] validation_0-logloss:0.492369
Stopping. Best iteration:
[32] validation_0-logloss:0.487297
我们可以看到模型在epoch 42停止训练(接近我们手工判断学习曲线所期望的),损失最大的模型在epoch 32观察到。
一般来说,选择early_stopping_round作为训练周期总数(本例中为10%)的合理函数,或者尝试与学习曲线图中可能观察到的拐点周期相对应,这是一个好主意。
总结
在本文中,您了解了有关监视性能和early stopping的内容。
您学习了:
在模型与训练数据过拟合之前,采用early stopping技术停止模型训练。
如何在训练过程中监控XGBoost模型的性能,并绘制学习曲线。
如何配置训练XGBoost模型时的early stopping。
文章原出处https://machinelearningmastery.com/avoid-overfitting-by-early-stopping-with-xgboost-in-python/