以下以多分类问题为例,分别解释。
该方法使用xgboost原生接口,一般使用形式为:
import xgboost as xgb
dtrain = xgb.DMatrix(Train_data, label=Train_label)
dval = xgb.DMatrix(Val_data, label=Val_label)
params = {'booster': 'gbtree',
'num_class': 8,
'seed': 777,
'objective': 'multi:softprob',
'eta': 0.05,
'gamma': 0.1,
'min_child_weight': 3,
'max_depth': 5,
'lambda': 10,
'subsample': 0.8,
'colsample_bytree': 0.4,
'colsample_bylevel': 0.7,
'tree_method': 'exact'
}
watchlist = [(dtrain, 'train'), (dval, 'eval')]
evals_result = {}
xgboost_clf = xgb.train(params=params, dtrain=dtrain, num_boost_round=250, evals=watchlist, evals_result=evals_result)
xgboost原生接口的损失函数”objective“可以使用模型里面自带的。对于多分类问题来说,可以使用"multi:softmax"和“multi:prob"。前者输出标签,后者输出多分类概率。当需要自定义损失函数时,只需要将参数中的”objective“指定为自定义的损失函数名即可。举一个栗子:
def custom_loss(y_pred, dTrain):
# 获取真实标签, 是一个一维的
y_true = dtrain.get_label()
# 由于模型输进来的y_pred为 [样本数量,类别数量] 形状的,因此根据我的需要,我将真实标签修改为[样本数量,类别数量] 形状的one-hot矩阵
y_true_one_hot = np.eye(8)[y_true.astype(int)]
# 模型输出没有过激活函数,这里自己加了一个softmax过程
y_pred = np.exp(y_pred) * (1 / np.expand_dims(np.sum(np.exp(y_pred), axis=1), axis=-1))
# 自定义一阶导grad和二阶导hess的求解方法。如果自定义的损失函数过于复杂,只知道怎么写损失函数但不会求一阶和二阶导,可以使用from scipy.misc import derivative等进行辅助求解。
grad = y_pred - y_true_one_hot
hess = y_pred * (1 - y_pred)
return grad, hess
然后将参数中的”objective“改为自定义的损失函数:
params = {'booster': 'gbtree',
'num_class': 8,
'seed': 777,
'objective': custom_loss,
'eta': 0.05,
'gamma': 0.1,
'min_child_weight': 3,
'max_depth': 5,
'lambda': 10,
'subsample': 0.8,
'colsample_bytree': 0.4,
'colsample_bylevel': 0.7,
'tree_method': 'exact'
}
也可以写进xgb.train里面:
xgboost_clf = xgb.train(params=params, dtrain=dtrain, obj=custom_loss, num_boost_round=250, evals=watchlist, evals_result=evals_result)
首先需要写自定义的函数体:
def my_acc(y_pred, dTrain):
# 首先获取真实标签
y_true = dtrain.get_label()
# 由于模型输出的y_pred为概率,因此需要将其转化成预测标签
y_pred = np.argmax(y_pred, axis=1)
# 写自己需要的评价指标
acc = round(accuracy_score(y_true, y_pred), 6)
# 注意,此处需要返回评价指标名字和评价指标的值
return 'acc', acc
在xgb.train中添加一个参数custom_metric,
xgboost_clf = xgb.train(params=params, dtrain=dtrain, num_boost_round=250, custom_metric=my_acc, evals=watchlist, evals_result=evals_result)
该方法使用xgboost的sklearn接口,一般使用形式为:
from xgboost.sklearn import XGBClassifier
xgboost_clf = XGBClassifier(min_child_weight=3,max_depth=5,
objective='multi:softprob', num_class=8, eval_metric='merror', subsample=0.8, learning_rate=0.05, n_estimators=100, random_state=777,
colsample_bytree=0.4)
eval_set = [(Train_data, Train_label), (Val_data, Val_label)]
xgboost_clf.fit(Train_data, Train_label, eval_set=eval_set, verbose=True)
类似于原生接口,XGBClassifier中的objective参数和eval_metric分别对应着损失函数和评价指标,可以通过修改这两个参数为自定义的函数名来达到自定义的目的。
但是,基于sklearn接口的自定义函数体需要注意一些,与原生接口的写法稍有不一致。
# ********注意!!!这里的模型输入给损失函数的输入就不一致, 且y_pred在后,真实标签在前。********
def custom_loss(y_true, y_pred):
# ********注意!!!y_true直接为一维的真实标签,不需要再手动获取********
# 由于模型输进来的y_pred为 [样本数量,类别数量] 形状的,因此根据我的需要,我将真实标签修改为[样本数量,类别数量] 形状的one-hot矩阵
y_true_one_hot = np.eye(8)[y_true.astype(int)]
# 模型输出没有过激活函数,这里自己加了一个softmax过程
y_pred = np.exp(y_pred) * (1 / np.expand_dims(np.sum(np.exp(y_pred), axis=1), axis=-1))
# 自定义一阶导grad和二阶导hess的求解方法。如果自定义的损失函数过于复杂,只知道怎么写损失函数但不会求一阶和二阶导,可以使用from scipy.misc import derivative等进行辅助求解。
grad = y_pred - y_true_one_hot
hess = y_pred * (1 - y_pred)
return grad, hess
# ********注意!!!这里的模型输入给评价函数的输入就不一致, 且y_pred在后,真实标签在前。********
def my_acc(y_true, y_pred):
# ********注意!!!y_true直接为一维的真实标签,不需要再手动获取********
# 由于模型输出的y_pred为概率,因此需要将其转化成预测标签
y_pred = np.argmax(y_pred, axis=1)
# 写自己需要的评价指标
acc = round(accuracy_score(y_true, y_pred), 6)
# ********注意!!!此处只需要返回评价指标的值********
return acc
# 保存模型
xgboost_clf.save_model("./model/xgboost_v1.0.json")
# 加载模型
model = xgb.Booster()
model.load_model('model/xgboost_v1.0.json')
此处需要注意的是,由于我们的损失函数和评价指标都是自定义的函数,因此如果需要加载模型后继续对模型进行训练优化,必须保证在加载模型的同一个py文件中,存在自定义的损失函数和评价指标函数,否则无法使用。
首先需要安装好import ml.dmlc.xgboost4j.java库,可以通过maven等进行导入(此处如有需要请自行百度)
import ml.dmlc.xgboost4j.java.XGBoost;
private Booster model = null;
model = XGBoost.loadModel(“model/xgboost_v1.0.json”);