在Lightgbm中实现自定义Huber损失

时间:2019-04-22 11:49:21

标签: python lightgbm

我正在尝试实现Huber损失,以针对lightgbm中的MAPE损失进行定制。下面是我的代码。但是,当我尝试运行它时,所有预测都为零。代码有什么问题?似乎有些标尺可以对学习有所帮助,但我在互联网上看不到任何有关如何将其应用到自定义损失中的准则。你能帮我吗?

def my_loss(preds, dtrain):

   y_true = dtrain.get_label()
   d = (preds - y_true)
   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 

   hess = np.ones(len(preds))

return grad, hess

metrics = []
for i in my_cv:
   X_train = X.loc[i[0],:]
   y_train = y.loc[i[0]]
   X_test = X.loc[i[1],:]
   y_test = y.loc[i[1]]


   dtrain = xgb.Dataset(X_train, label=y_train, free_raw_data =False)


   params = {'max_depth': 10, 'learning_rate':0.05,'objective':None,
         'num_leaves':150, 'min_child_samples':5, 'nround':100,
         'monotone_constraints':lst_mon}

   mm = xgb.train(params, dtrain, fobj = my_loss)
   y_pred = mm.predict(X_train)

3 个答案:

答案 0 :(得分:1)

正确的功能:

def my_loss(preds, dtrain):

   y_true = dtrain.get_label()
   d = (preds - y_true)
   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

已删除hess = np.ones(len(preds))

答案 1 :(得分:0)

可能是强制monotone_constraints的结果。仅当您获得可接受的结果并想要改善它时,才应设置它们。经过对数据和结果的深入分析。

另外(在将代码复制到SO时可能只是一个错误),在损失函数中,由于hess = np.ones(len(preds)),所有hess值在整个训练过程中都是恒定的。

答案 2 :(得分:0)

休伯损失为defined

enter image description here

您实现的损失是其平滑近似值,即伪Huber损失: enter image description here

这种损失的问题是其二阶导数太接近于零。 为了加快算法速度,lightgbm使用Newton method's approximation来找到最佳叶子值:

y =-L'/ L''

(有关详细信息,请参见this blogpost)。

即他们找到了一个点,在该点上具有相同梯度和二阶导数的抛物线将达到最小值。如果损失函数是二次函数,这将为我们提供确切的最佳值。但是,对于Pseudo-Huber损失,牛顿的方法到处都有分歧:

|-L'(a)/ L''(a)| =(1 +(a / delta)** 2)* | a | > | a |,

因此,您获得的近似值始终比最小值远甚至比开始时的值还要远。

当您将np.ones用作粗麻布时,将得到-L'(a)作为零的估计值,它也不会收敛为零。

要正确地实现带有伪Huber损失的梯度增强,您必须放弃使用粗麻布,而使用常规梯度下降来找到最佳叶子值。您无法在lightgbm的自定义损失中做到这一点,但是lightgbm具有内置的Huber损失,因此您可以使用它。

相关问题