web-dev-qa-db-fra.com

Xgboost-Comment utiliser "mae" comme fonction objective?

Je sais que xgboost a besoin d'un premier et d'un second dégradés, mais quelqu'un d'autre a utilisé "mae" comme fonction obj

13
Sam Qian

Un peu de théorie d'abord, désolé! Vous avez demandé le diplôme et le hessian pour le MAE; toutefois, le MAE n'est pas continuellement deux fois différentiable , donc essayer de calculer les dérivées première et seconde devient délicat. Ci-dessous, nous pouvons voir le "kink" au x=0 qui empêche le MAE d'être continuellement différentiable.

De plus, la dérivée seconde est zéro en tous les points où elle se comporte bien. Dans XGBoost, la dérivée seconde est utilisée comme dénominateur dans le poids des feuilles et, lorsqu'elle est nulle, crée de graves erreurs mathématiques.

Compte tenu de ces complexités, notre meilleur choix est d'essayer d'approximer le MAE en utilisant une autre fonction, bien comportée. Nous allons jeter un coup d'oeil.

 Some different loss functions

Nous pouvons voir ci-dessus qu'il existe plusieurs fonctions qui se rapprochent de la valeur absolue. Clairement, pour de très petites valeurs, l'erreur au carré (MSE) est une assez bonne approximation du MAE. Cependant, je suppose que cela n'est pas suffisant pour votre cas d'utilisation.

Huber La perte est une fonction de perte bien documentée. Cependant, comme ce n'est pas lisse, nous ne pouvons pas garantir des dérivés lisses. Nous pouvons l'approcher en utilisant la fonction Psuedo-Huber. Il peut être implémenté en python XGBoost comme suit,

import xgboost as xgb

dtrain = xgb.DMatrix(x_train, label=y_train)
dtest = xgb.DMatrix(x_test, label=y_test)

param = {'max_depth': 5}
num_round = 10

def huber_approx_obj(preds, dtrain):
    d = preds - dtrain.get_labels() #remove .get_labels() for sklearn
    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

bst = xgb.train(param, dtrain, num_round, obj=huber_approx_obj)  

Une autre fonction peut être utilisée en remplaçant le obj=huber_approx_obj

Fair Loss n'est pas bien documenté, mais il semble fonctionner plutôt bien. La fonction de perte équitable est:

 Fair Loss Function

Il peut être mis en œuvre en tant que tel,

def fair_obj(preds, dtrain):
    """y = c * abs(x) - c**2 * np.log(abs(x)/c + 1)"""
    x = preds - dtrain.get_labels()
    c = 1
    den = abs(x) + c
    grad = c*x / den
    hess = c*c / den ** 2
    return grad, hess

Ce code est pris et adapté à partir de la deuxième place solution dans le Kaggle Allstate Challenge. 

Log-Cosh Fonction de perte.

def log_cosh_obj(preds, dtrain):
    x = preds - dtrain.get_labels()
    grad = np.tanh(x)
    hess = 1 / np.cosh(x)**2
    return grad, hess

Enfin, vous pouvez créer vos propres fonctions de perte personnalisées en utilisant les fonctions ci-dessus comme modèles.

26
josh

Pour la perte de Huber ci-dessus, je pense qu'il manque un signe négatif au gradient. Devrait être comme 

grad = - d / scale_sqrt
0
hbar137