我知道xgboost需要一阶梯度和二阶梯度,但是否有其他人使用过“mae”作为目标函数?
我知道xgboost需要一阶梯度和二阶梯度,但是否有其他人使用过“mae”作为目标函数?
先来点理论,抱歉!您要求MAE的梯度和Hessian矩阵,但是MAE不是连续二次可微的,因此试图计算一阶和二阶导数变得棘手。下面我们可以看到在x=0
处的“拐点”,这阻止了MAE的连续可微性。
此外,在所有良好行为的点上,二阶导数均为零。在XGBoost中,二阶导数用作叶权重的分母,当为零时会产生严重的数学错误。
鉴于这些复杂性,我们最好的办法是尝试使用其他的、表现良好的函数来近似MAE。让我们来看看。
我们可以看到上面有几个近似绝对值的函数。很明显,对于非常小的值,平方误差(MSE)是MAE的相当不错的近似。然而,我假设这对于您的用例来说是不足够的。
Huber损失是一个有很好文献记录的损失函数。但它不连续平滑,所以我们不能保证平滑的导数。我们可以使用伪-Huber函数来近似它。它可以在python XGBoost中实现如下:
import xgboost as xgb
dtrain = xgb.DMatrix(x_train, label=y_train)
dtest = xgb.DMatrix(x_test, label=y_test)
param = {'max_depth': 5}
num_round = 10
def huber_approx_obj(preds, dtrain):
d = preds - dtrain.get_labels() #remove .get_labels() for sklearn
h = 1 #h is delta in the graphic
scale = 1 + (d / h) ** 2
scale_sqrt = np.sqrt(scale)
grad = d / scale_sqrt
hess = 1 / scale / scale_sqrt
return grad, hess
bst = xgb.train(param, dtrain, num_round, obj=huber_approx_obj)
通过替换 obj=huber_approx_obj
可以使用其他功能。
Fair Loss 并没有很好的文档记录,但似乎表现不错。 公平损失函数为:
可以这样实现:
def fair_obj(preds, dtrain):
"""y = c * abs(x) - c**2 * np.log(abs(x)/c + 1)"""
x = preds - dtrain.get_labels()
c = 1
den = abs(x) + c
grad = c*x / den
hess = c*c / den ** 2
return grad, hess
这段代码是从Kaggle Allstate Challenge中第二名的解决方案中采用并进行了调整。
Log-Cosh 损失函数。
def log_cosh_obj(preds, dtrain):
x = preds - dtrain.get_labels()
grad = np.tanh(x)
hess = 1 / np.cosh(x)**2
return grad, hess
最后,您可以使用上述函数作为模板创建自己的定制损失函数。
警告:由于API更改,更新版本的XGBoost可能需要具有以下形式的损失函数:
def custom_objective(y_true, y_pred):
...
return grad, hess
对于上述的Huber损失函数,我认为梯度前面缺少了一个负号。应该是这样的:
grad = - d / scale_sqrt
我正在对大约正态分布的Y运行上述的huber/fair度量,但由于某种原因,在alpha <0的情况下(并且在公平情况下始终如此),结果预测将等于零...
np.cosh
对于某些输入可能会溢出,使用恒等式hess = 1- np.tanh(x)**2
将避免这些问题。 - chepyley = c * abs(x) - c**2 * np.log(abs(x)/c + 1)
给出。 - kadee