XGB-16:自定义目标和评估指标

2024-03-05 05:28

本文主要是介绍XGB-16:自定义目标和评估指标,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

概述

XGBoost被设计为一个可扩展的库。通过提供自定义的训练目标函数和相应的性能监控指标,可以扩展它。本文介绍了如何为XGBoost实现自定义的逐元评估指标和目标。

注意:

排序不能自定义

在接下来的两个部分中,将逐步介绍如何实现平方对数误差(Squared Log Error,SLE)目标函数

1 2 [ log ⁡ ( p r e d + 1 ) − log ⁡ ( l a b e l + 1 ) ] 2 \frac{1}{2}[\log(pred + 1) - \log(label + 1)]^2 21[log(pred+1)log(label+1)]2

以及它的默认评估指标均方根对数误差(Root Mean Squared Log Error,RMSLE

1 N [ log ⁡ ( p r e d + 1 ) − log ⁡ ( l a b e l + 1 ) ] 2 \sqrt{\frac{1}{N}[\log(pred + 1) - \log(label + 1)]^2} N1[log(pred+1)log(label+1)]2

定制目标函数

尽管XGBoost本身已经原生支持这些功能,但为了演示的目的,使用它来比较自己实现的结果和XGBoost内部实现的结果。完成本教程后,应该能够为快速实验提供自己的函数。最后,将提供一些关于非恒等链接函数的注释,以及在scikit-learn接口中使用自定义度量和目标的示例。

如果计算所述目标函数的梯度:

g = ∂ o b j e c t i v e ∂ p r e d = log ⁡ ( p r e d + 1 ) − log ⁡ ( l a b e l + 1 ) p r e d + 1 g = \frac{\partial{objective}}{\partial{pred}} = \frac{\log(pred + 1) - \log(label + 1)}{pred + 1} g=predobjective=pred+1log(pred+1)log(label+1)

以及 hessian(目标的二阶导数):

h = ∂ 2 o b j e c t i v e ∂ p r e d = − log ⁡ ( p r e d + 1 ) + log ⁡ ( l a b e l + 1 ) + 1 ( p r e d + 1 ) 2 h = \frac{\partial^2{objective}}{\partial{pred}} = \frac{ - \log(pred + 1) + \log(label + 1) + 1}{(pred + 1)^2} h=pred2objective=(pred+1)2log(pred+1)+log(label+1)+1

在模型训练过程中,目标函数起着重要的作用:基于模型预测和观察到的数据标签(或目标),提供梯度信息,包括一阶和二阶梯度。因此,有效的目标函数应接受两个输入,即预测值和标签。对于实现SLE,定义:

import numpy as np
import xgboost as xgb
from typing import Tupledef gradient(predt: np.ndarray, dtrain: xgb.DMatrix) -> np.ndarray:'''Compute the gradient squared log error.'''y = dtrain.get_label()return (np.log1p(predt)-np.log1p(y)) / (predt+1)def hessian(predt: np.ndarray, dtrain: xgb.DMatrix) -> np.ndarray:'''Compute the hessian for squared log error.'''y = dtrain.get_label()return ((-np.log1p(predt)+np.log1p(y)+1) /np.power(predt+1, 2))def squared_log(predt: np.ndarray,dtrain: xgb.DMatrix) -> Tuple[np.ndarray, np.ndarray]:'''Squared Log Error objective. A simplified version for RMSLE used asobjective function.'''predt[predt < -1] = -1 + 1e-6grad = gradient(predt, dtrain)hess = hessian(predt, dtrain)return grad, hess

在上面的代码片段中,squared_log是想要的目标函数。它接受一个numpy数组predt作为模型预测值,以及用于获取所需信息的训练DMatrix,包括标签和权重(此处未使用)。然后,在训练过程中,通过将其作为参数传递给xgb.train,将此目标函数用作XGBoost的回调函数:

xgb.train({'tree_method': 'hist', 'seed': 1994},   # any other tree method is fine.dtrain=dtrain,num_boost_round=10,obj=squared_log)

注意,在定义目标函数时,从预测值中减去标签或从标签中减去预测值,这是很重要的。如果发现训练错误上升而不是下降,这可能是原因。

定制度量函数

因此,在拥有自定义目标函数之后,还需要一个相应的度量标准来监控模型的性能。如上所述,SLE 的默认度量标准是 RMSLE。同样,定义另一个类似的回调函数作为新的度量标准:

def rmsle(predt: np.ndarray, dtrain: xgb.DMatrix) -> Tuple[str, float]:''' Root mean squared log error metric.'''y = dtrain.get_label()predt[predt < -1] = -1 + 1e-6elements = np.power(np.log1p(y) - np.log1p(predt), 2)return 'PyRMSLE', float(np.sqrt(np.sum(elements) / len(y)))

与目标函数类似,度量也接受 predtdtrain 作为输入,但返回度量本身的名称和一个浮点值作为结果。将其作为 custom_metric 参数传递给 XGBoost:

xgb.train({'tree_method': 'hist', 'seed': 1994,'disable_default_eval_metric': 1},dtrain=dtrain,num_boost_round=10,obj=squared_log,custom_metric=rmsle,evals=[(dtrain, 'dtrain'), (dtest, 'dtest')],evals_result=results)

能够看到 XGBoost 打印如下内容:

[0] dtrain-PyRMSLE:1.37153  dtest-PyRMSLE:1.31487
[1] dtrain-PyRMSLE:1.26619  dtest-PyRMSLE:1.20899
[2] dtrain-PyRMSLE:1.17508  dtest-PyRMSLE:1.11629
[3] dtrain-PyRMSLE:1.09836  dtest-PyRMSLE:1.03871
[4] dtrain-PyRMSLE:1.03557  dtest-PyRMSLE:0.977186
[5] dtrain-PyRMSLE:0.985783 dtest-PyRMSLE:0.93057
...

注意,参数 disable_default_eval_metric 用于禁用 XGBoost 中的默认度量。

完整可复制的源代码参阅定义自定义回归目标和度量的演示。

转换链接函数

在使用内置目标函数时,原始预测值会根据目标函数进行转换。当提供自定义目标函数时,XGBoost 不知道其链接函数,因此用户需要对目标和自定义评估度量进行转换。对于具有身份链接的目标,如平方误差squared error,这很简单,但对于其他链接函数,如对数链接或反链接,差异很大。

在 Python 包中,可以通过 predict 函数中的 output_margin 参数来控制预测的行为。当使用 custom_metric 参数而没有自定义目标函数时,度量函数将接收经过转换的预测,因为目标是由 XGBoost 定义的。然而,当同时提供自定义目标和度量时,目标和自定义度量都将接收原始预测。以下示例比较了多类分类模型中两种不同的行为。首先,我们定义了两个不同的 Python 度量函数,实现了相同的底层度量以进行比较。其中 merror_with_transform 在同时使用自定义目标时使用,否则会使用更简单的 merror,因为 XGBoost 可以自行执行转换。

import xgboost as xgb
import numpy as npdef merror_with_transform(predt: np.ndarray, dtrain: xgb.DMatrix):"""Used when custom objective is supplied."""y = dtrain.get_label()n_classes = predt.size // y.shape[0]# Like custom objective, the predt is untransformed leaf weight when custom objective# is provided.# With the use of `custom_metric` parameter in train function, custom metric receives# raw input only when custom objective is also being used.  Otherwise custom metric# will receive transformed prediction.assert predt.shape == (d_train.num_row(), n_classes)out = np.zeros(dtrain.num_row())for r in range(predt.shape[0]):i = np.argmax(predt[r])out[r] = iassert y.shape == out.shapeerrors = np.zeros(dtrain.num_row())errors[y != out] = 1.0return 'PyMError', np.sum(errors) / dtrain.num_row()

仅当想要使用自定义目标并且 XGBoost 不知道如何转换预测时才需要上述函数。多类误差函数的正常实现是:

def merror(predt: np.ndarray, dtrain: xgb.DMatrix):"""Used when there's no custom objective."""# No need to do transform, XGBoost handles it internally.errors = np.zeros(dtrain.num_row())errors[y != out] = 1.0return 'PyMError', np.sum(errors) / dtrain.num_row()

接下来需要自定义 softprob 目标:

def softprob_obj(predt: np.ndarray, data: xgb.DMatrix):"""Loss function.  Computing the gradient and approximated hessian (diagonal).Reimplements the `multi:softprob` inside XGBoost."""# Full implementation is available in the Python demo script linked below...return grad, hess

最后可以使用 objcustom_metric 参数训练模型:

Xy = xgb.DMatrix(X, y)
booster = xgb.train({"num_class": kClasses, "disable_default_eval_metric": True},m,num_boost_round=kRounds,obj=softprob_obj,custom_metric=merror_with_transform,evals_result=custom_results,evals=[(m, "train")],
)

如果不需要自定义目标,只是想提供一个XGBoost中不可用的指标:

booster = xgb.train({"num_class": kClasses,"disable_default_eval_metric": True,"objective": "multi:softmax",},m,num_boost_round=kRounds,# Use a simpler metric implementation.custom_metric=merror,evals_result=custom_results,evals=[(m, "train")],
)

使用multi:softmax来说明转换后预测的差异。使用softprob时,输出预测数组的形状是(n_samples, n_classes),而对于softmax,它是(n_samples, )。关于多类目标函数的示例也可以在创建自定义多类目标函数的示例中找到。此外,更多解释请参见Intercept。

Scikit-Learn 接口

XGBoost的scikit-learn接口提供了一些工具,以改善与标准的scikit-learn函数的集成,用户可以直接使用scikit-learn的成本函数(而不是评分函数):

from sklearn.datasets import load_diabetes
from sklearn.metrics import mean_absolute_errorX, y = load_diabetes(return_X_y=True)
reg = xgb.XGBRegressor(tree_method="hist",eval_metric=mean_absolute_error,
)
reg.fit(X, y, eval_set=[(X, y)])

对于自定义目标函数,用户可以在不访问DMatrix的情况下定义目标函数:

def softprob_obj(labels: np.ndarray, predt: np.ndarray) -> Tuple[np.ndarray, np.ndarray]:rows = labels.shape[0]classes = predt.shape[1]grad = np.zeros((rows, classes), dtype=float)hess = np.zeros((rows, classes), dtype=float)eps = 1e-6for r in range(predt.shape[0]):target = labels[r]p = softmax(predt[r, :])for c in range(predt.shape[1]):g = p[c] - 1.0 if c == target else p[c]h = max((2.0 * p[c] * (1.0 - p[c])).item(), eps)grad[r, c] = ghess[r, c] = hgrad = grad.reshape((rows * classes, 1))hess = hess.reshape((rows * classes, 1))return grad, hessclf = xgb.XGBClassifier(tree_method="hist", objective=softprob_obj)

参考

  • https://xgboost.readthedocs.io/en/latest/tutorials/custom_metric_obj.html
  • https://xgboost.readthedocs.io/en/latest/python/examples/custom_rmsle.html#sphx-glr-python-examples-custom-rmsle-py

这篇关于XGB-16:自定义目标和评估指标的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/775445

相关文章

【前端学习】AntV G6-08 深入图形与图形分组、自定义节点、节点动画(下)

【课程链接】 AntV G6:深入图形与图形分组、自定义节点、节点动画(下)_哔哩哔哩_bilibili 本章十吾老师讲解了一个复杂的自定义节点中,应该怎样去计算和绘制图形,如何给一个图形制作不间断的动画,以及在鼠标事件之后产生动画。(有点难,需要好好理解) <!DOCTYPE html><html><head><meta charset="UTF-8"><title>06

烟火目标检测数据集 7800张 烟火检测 带标注 voc yolo

一个包含7800张带标注图像的数据集,专门用于烟火目标检测,是一个非常有价值的资源,尤其对于那些致力于公共安全、事件管理和烟花表演监控等领域的人士而言。下面是对此数据集的一个详细介绍: 数据集名称:烟火目标检测数据集 数据集规模: 图片数量:7800张类别:主要包含烟火类目标,可能还包括其他相关类别,如烟火发射装置、背景等。格式:图像文件通常为JPEG或PNG格式;标注文件可能为X

自定义类型:结构体(续)

目录 一. 结构体的内存对齐 1.1 为什么存在内存对齐? 1.2 修改默认对齐数 二. 结构体传参 三. 结构体实现位段 一. 结构体的内存对齐 在前面的文章里我们已经讲过一部分的内存对齐的知识,并举出了两个例子,我们再举出两个例子继续说明: struct S3{double a;int b;char c;};int mian(){printf("%zd\n",s

Spring 源码解读:自定义实现Bean定义的注册与解析

引言 在Spring框架中,Bean的注册与解析是整个依赖注入流程的核心步骤。通过Bean定义,Spring容器知道如何创建、配置和管理每个Bean实例。本篇文章将通过实现一个简化版的Bean定义注册与解析机制,帮助你理解Spring框架背后的设计逻辑。我们还将对比Spring中的BeanDefinition和BeanDefinitionRegistry,以全面掌握Bean注册和解析的核心原理。

Oracle type (自定义类型的使用)

oracle - type   type定义: oracle中自定义数据类型 oracle中有基本的数据类型,如number,varchar2,date,numeric,float....但有时候我们需要特殊的格式, 如将name定义为(firstname,lastname)的形式,我们想把这个作为一个表的一列看待,这时候就要我们自己定义一个数据类型 格式 :create or repla

【JavaScript】LeetCode:16-20

文章目录 16 无重复字符的最长字串17 找到字符串中所有字母异位词18 和为K的子数组19 滑动窗口最大值20 最小覆盖字串 16 无重复字符的最长字串 滑动窗口 + 哈希表这里用哈希集合Set()实现。左指针i,右指针j,从头遍历数组,若j指针指向的元素不在set中,则加入该元素,否则更新结果res,删除集合中i指针指向的元素,进入下一轮循环。 /*** @param

PR曲线——一个更敏感的性能评估工具

在不均衡数据集的情况下,精确率-召回率(Precision-Recall, PR)曲线是一种非常有用的工具,因为它提供了比传统的ROC曲线更准确的性能评估。以下是PR曲线在不均衡数据情况下的一些作用: 关注少数类:在不均衡数据集中,少数类的样本数量远少于多数类。PR曲线通过关注少数类(通常是正类)的性能来弥补这一点,因为它直接评估模型在识别正类方面的能力。 精确率与召回率的平衡:精确率(Pr

HTML5自定义属性对象Dataset

原文转自HTML5自定义属性对象Dataset简介 一、html5 自定义属性介绍 之前翻译的“你必须知道的28个HTML5特征、窍门和技术”一文中对于HTML5中自定义合法属性data-已经做过些介绍,就是在HTML5中我们可以使用data-前缀设置我们需要的自定义属性,来进行一些数据的存放,例如我们要在一个文字按钮上存放相对应的id: <a href="javascript:" d

[数据集][目标检测]血细胞检测数据集VOC+YOLO格式2757张4类别

数据集格式:Pascal VOC格式+YOLO格式(不包含分割路径的txt文件,仅仅包含jpg图片以及对应的VOC格式xml文件和yolo格式txt文件) 图片数量(jpg文件个数):2757 标注数量(xml文件个数):2757 标注数量(txt文件个数):2757 标注类别数:4 标注类别名称:["Platelets","RBC","WBC","sickle cell"] 每个类别标注的框数:

一步一步将PlantUML类图导出为自定义格式的XMI文件

一步一步将PlantUML类图导出为自定义格式的XMI文件 说明: 首次发表日期:2024-09-08PlantUML官网: https://plantuml.com/zh/PlantUML命令行文档: https://plantuml.com/zh/command-line#6a26f548831e6a8cPlantUML XMI文档: https://plantuml.com/zh/xmi