LightGBM使用Tweedie损失函数;我对使用的梯度和海森矩阵感到困惑。

5
我正在研究LightGBM中的自定义目标函数,发现复制内置函数是一个好的起点。LightGBM用于计算Tweedie度量的方程式(https://github.com/microsoft/LightGBM/blob/1c27a15e42f0076492fcc966b9dbcf9da6042823/src/metric/regression_metric.hpp#L300-L318)似乎与我在网上找到的Tweedie损失定义(https://towardsdatascience.com/tweedie-loss-function-for-right-skewed-data-2c5ca470678f)相匹配,但它们进行了奇怪的exp(ln(score))处理,我猜测这是为了数值稳定性。然而,他们对斜率和黑塞的方程式似乎直接在得分的对数上完成(https://github.com/microsoft/LightGBM/blob/1c27a15e42f0076492fcc966b9dbcf9da6042823/src/objective/regression_objective.hpp#L702-L732)。
gradients[i] = -label_[i] * e^((1 - rho_) * score[i]) + e^((2 - rho_) * score[i]);

我期望梯度会出现在哪里:

gradients[i] = -label_[i] * score[i]^(- rho_) + score[i]^(1 - rho_);

我的猜测是LightGBM在处理分数时将其视为ln(score),例如使用参数reg_sqrt,但我找不到文档中描述这一点的地方。

无论如何,我已尝试重新创建它们的公式和自己的计算作为自定义目标函数,但两者都似乎不起作用:

library(lightgbm)
library(data.table)

# Tweedie gradient with variance = 1.5, according to my own math
CustomObj_t1 <- function(preds, dtrain) {
  labels <- dtrain$getinfo('label')
  grad <- -labels * preds^(-3/2) + preds^(-1/2)
  hess <- 1/2 * (3*labels*preds^(-5/2) - preds^(-3/2))
  return(list(grad = grad, hess = hess))
}

# Tweedie gradient with variance = 1.5, recreating code from LightGBM github
CustomObj_t2 <- function(preds, dtrain) {
  labels <- dtrain$getinfo('label')
  grad <- -labels*exp(-1/2*preds) + exp(1/2*preds)
  hess <- -labels*(-1/2)*exp(-1/2*preds) + 1/2*exp(1/2*preds)
  return(list(grad = grad, hess = hess))
}

params = list(objective = "tweedie",
              seed = 1,
              metric = "rmse")

params2 = list(objective = CustomObj_t1,
               seed= 1,
               metric = "rmse")

params3 = list(objective = CustomObj_t2,
               seed= 1,
               metric = "rmse")

# Create data
set.seed(321)
db_Custom = data.table(a=runif(2000), b=runif(2000))
db_Custom[,X := (a*4+exp(b))]

# break into test and training sets
db_Test = db_Custom[1:10]
db_Custom=db_Custom[11:nrow(db_Custom),]

FeatureCols = c("a","b")

# Create dataset
ds_Custom <- lgb.Dataset(data.matrix(db_Custom[, FeatureCols, with = FALSE]), label = db_Custom[["X"]])  

# Train
fit = lgb.train(params, ds_Custom, verb=-1)
#print("  ")
fit2 = lgb.train(params2, ds_Custom, verb=-1)
#print("  ")
fit3 = lgb.train(params3, ds_Custom, verb=-1)

# Predict
pred = predict(fit, data.matrix(db_Test[, FeatureCols, with = FALSE]))
db_Test[, prediction := pmax(0, pred)]

pred2 = predict(fit2, data.matrix(db_Test[, FeatureCols, with = FALSE]))
db_Test[, prediction2 := pmax(0, pred2)]

pred3 = predict(fit3, data.matrix(db_Test[, FeatureCols, with = FALSE]))
db_Test[, prediction3 := pmax(0, pred3)]

print(db_Test[,.(X,prediction,prediction2,prediction3)])

我得到了结果(期望预测2或预测3与预测结果非常相似):
"X"                "prediction"   "prediction2" "prediction3"
4.8931646234958     4.89996556839721    0   1.59154656425556
6.07328897031702    6.12313647937047    0   1.81022588429474
2.05728566704078    2.06824004875244    0   0.740577102751491
2.54732526765174    2.50329903656292    0   0.932517774958986
4.07044099941395    4.07047912554207    0   1.39922723582939
2.74639568121359    2.74408567443232    0   1.01628212910587
3.47720295158928    3.49241414141969    0   1.23049599462599
2.92043718858535    2.90464303454649    0   1.0680618051659
4.44415913080697    4.43091665909845    0   1.48607456777287
4.96566318066753    4.97898586895233    0   1.60163901781479

我有什么遗漏吗?是我的计算或编码有误吗?


我找到了这个链接:https://github.com/microsoft/LightGBM/issues/3155。我猜这可能是我一直在尝试解决的对数问题的答案,但不幸的是,我不知道他们是如何得出这个梯度计算公式的。 - Dima Zhylko
1个回答

0

根据链接的git页面和您的prediction3列,似乎如果对该列进行指数运算,则其值非常接近于0和1列。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接