如何使用概率而非类别标签训练XGBoost分类器?
如何在XGBoost中使用mixup数据增强的浮点型概率标签训练多分类模型?
我尝试用训练数据集和浮点型概率标签(比如[0,0.6,0.4,0]这种mixup增强生成的软标签)训练XGBoost多分类器,但调用model.fit()时出错——XGBoost的scikit-learn接口默认期望接收类别索引或整数独热标签,而非浮点概率分布。
附测试代码:
import xgboost as xgb import numpy as np # 生成随机训练数据 X = np.random.rand(100, 16) # 生成随机独热标签并转为浮点概率(模拟mixup生成的软标签) y_one_hot = np.random.randint(0, 4, size=(100,)) y = np.eye(4)[y_one_hot] y_proba = y / np.sum(y, axis=1, keepdims=True) # 简化原代码的循环逻辑 # 定义XGBoost分类器 model = xgb.XGBClassifier(objective='multi:softprob', num_class=4) # 训练时报错:标签格式不符合要求 model.fit(X, y_proba) # 测试部分(原代码) X_test = np.random.rand(10, 16) y_pred_proba = model.predict_proba(X_test) y_pred = np.argmax(y_pred_proba, axis=1)
解决方案:使用XGBoost原生API+自定义软标签损失函数
XGBoost的scikit-learn接口对标签格式限制严格,而原生API支持自定义目标函数,完美适配mixup的软标签场景。具体步骤如下:
1. 自定义多分类软标签的交叉熵损失与梯度计算
对于软标签(每个样本是类别的概率分布),需要实现基于交叉熵的损失函数,同时计算XGBoost所需的一阶梯度(损失对预测值的导数)和二阶导(梯度的导数)。
2. 使用DMatrix封装数据
DMatrix是XGBoost的原生数据结构,支持直接传入浮点型标签矩阵。
3. 调用原生train方法训练模型
传入自定义目标函数,替代默认的硬标签目标。
修改后的完整代码:
import xgboost as xgb import numpy as np # 生成随机训练数据 X = np.random.rand(100, 16) # 模拟mixup生成的软标签(浮点概率分布) y_one_hot = np.random.randint(0, 4, size=(100,)) y = np.eye(4)[y_one_hot] # 手动生成一个mixup样例,替换第一个样本的标签为软概率 y[0] = np.array([0, 0.6, 0.4, 0]) y_proba = y / np.sum(y, axis=1, keepdims=True) # 自定义多分类软标签的目标函数(交叉熵) def soft_multiclass_obj(preds, dtrain): # preds形状:(n_samples, num_class),是原始的logit输出 labels = dtrain.get_label().reshape(-1, 4) # 取出软标签,转为(n_samples,4) preds = preds.reshape(-1, 4) # 对logit做softmax,得到预测概率 exp_preds = np.exp(preds) probs = exp_preds / np.sum(exp_preds, axis=1, keepdims=True) # 计算交叉熵损失的梯度和二阶导 grad = probs - labels hess = probs * (1 - probs) # 展平为一维数组返回(XGBoost要求的格式) return grad.flatten(), hess.flatten() # 封装数据为DMatrix,注意标签传入浮点概率矩阵 dtrain = xgb.DMatrix(X, label=y_proba) # 设置训练参数 params = { 'max_depth': 3, 'eta': 0.1, 'silent': 1, 'num_class': 4, # 这里不需要指定objective,因为用了自定义目标 } # 训练模型 model = xgb.train(params, dtrain, num_boost_round=100, obj=soft_multiclass_obj) # 测试预测 X_test = np.random.rand(10, 16) dtest = xgb.DMatrix(X_test) y_pred_logit = model.predict(dtest) y_pred_proba = np.exp(y_pred_logit.reshape(-1,4)) / np.sum(np.exp(y_pred_logit.reshape(-1,4)), axis=1, keepdims=True) y_pred = np.argmax(y_pred_proba, axis=1) print("预测类别:", y_pred) print("预测概率分布:\n", y_pred_proba)
关键说明
- 自定义目标函数返回的
grad和hess必须是一维数组,因此需要对二维的梯度/二阶导矩阵做展平。 - 原生API的预测结果是logit值,需要手动做softmax转换为概率分布。
- 若需调整模型复杂度,可修改
params中的max_depth、eta等超参数。
内容的提问来源于stack exchange,提问作者Jeff Boker
相关产品推荐
相关产品推荐

