2016-06-28 24 views
13

Il problema è che i dati del treno non possono essere inseriti nella RAM a causa della dimensione dei dati del treno. Quindi ho bisogno di un metodo che prima costruisca un albero su tutto il set di dati del treno, calcoli i residui costruisca un altro albero e così via (come l'albero con gradiente aumentato). Ovviamente se chiamo model = xgb.train(param, batch_dtrain, 2) in qualche ciclo - non sarà d'aiuto, perché in tal caso ricostruisce solo l'intero modello per ogni lotto.Come posso implementare la formazione incrementale per xgboost?

+0

Esempi dal repo 'xgboost': https://github.com/dmlc/xgboost/blob/master/tests/python/test_training_continuation.py –

risposta

16

Disclaimer: Sono nuovo anche per xgboost, ma penso di averlo capito.

Provare a salvare il modello dopo l'allenamento del primo lotto. Quindi, nelle esecuzioni successive, fornire il metodo xgb.train con il percorso file del modello salvato.

Ecco un piccolo esperimento che mi sono imbattuto di convincermi che funziona:

In primo luogo, dividere il set di dati Boston nella formazione e set di test. Quindi dividere il set di allenamento a metà. Adatta un modello con il primo tempo e ottieni un punteggio che servirà da punto di riferimento. Quindi montare due modelli con la seconda metà; un modello avrà il parametro aggiuntivo xgb_model. Se passare il parametro extra non ha fatto la differenza, allora ci aspettiamo che i loro punteggi siano simili .. Ma, fortunatamente, il nuovo modello sembra funzionare molto meglio del primo.

import xgboost as xgb 
from sklearn.cross_validation import train_test_split as ttsplit 
from sklearn.datasets import load_boston 
from sklearn.metrics import mean_squared_error as mse 

X = load_boston()['data'] 
y = load_boston()['target'] 

# split data into training and testing sets 
# then split training set in half 
X_train, X_test, y_train, y_test = ttsplit(X, y, test_size=0.1, random_state=0) 
X_train_1, X_train_2, y_train_1, y_train_2 = ttsplit(X_train, 
                y_train, 
                test_size=0.5, 
                random_state=0) 

xg_train_1 = xgb.DMatrix(X_train_1, label=y_train_1) 
xg_train_2 = xgb.DMatrix(X_train_2, label=y_train_2) 
xg_test = xgb.DMatrix(X_test, label=y_test) 

params = {'objective': 'reg:linear', 'verbose': False} 
model_1 = xgb.train(params, xg_train_1, 30) 
model_1.save_model('model_1.model') 

# ================= train two versions of the model =====================# 
model_2_v1 = xgb.train(params, xg_train_2, 30) 
model_2_v2 = xgb.train(params, xg_train_2, 30, xgb_model='model_1.model') 

print(mse(model_1.predict(xg_test), y_test))  # benchmark 
print(mse(model_2_v1.predict(xg_test), y_test)) # "before" 
print(mse(model_2_v2.predict(xg_test), y_test)) # "after" 

# 23.0475232194 
# 39.6776876084 
# 27.2053239482 

Fatemi sapere se qualcosa non è chiaro!

di riferimento: https://github.com/dmlc/xgboost/blob/master/python-package/xgboost/training.py

+1

Vorrei capire che model_2_v2 ha prestazioni peggiori rispetto al modello che utilizzava entrambi i set di dati contemporaneamente. Ma model_2_v2 è peggio di model_1 che è piuttosto strano perché diamo un nuovo set di dati che model_1 non ha visto, ma alla fine model_2_v2 si è comportato peggio ... Sembra che gli alberi potenziati non siano il modo migliore per eseguire l'apprendimento incrementale. @pikachau hai provato a usare model_1 invece di 'experiment.model'? –

+0

Potrebbe essere perché il set di dati è piuttosto piccolo (dimensione del campione = 150). Con un set di dati più grande, penso che model_2_v2 dovrebbe superare il modello_1. Oh, esperimento.model == model_1; Avrei dovuto renderlo più esplicito! – Alain

4

ora c'è (versione 0.6?) Un parametro process_update che potrebbe aiutare. Ecco un esperimento con esso:

import pandas as pd 
import xgboost as xgb 
from sklearn.model_selection import ShuffleSplit 
from sklearn.datasets import load_boston 
from sklearn.metrics import mean_squared_error as mse 

boston = load_boston() 
features = boston.feature_names 
X = boston.data 
y = boston.target 

X=pd.DataFrame(X,columns=features) 
y = pd.Series(y,index=X.index) 

# split data into training and testing sets 
rs = ShuffleSplit(test_size=0.3, n_splits=1, random_state=0) 
for train_idx,test_idx in rs.split(X): # this looks silly 
    pass 

train_split = round(len(train_idx)/2) 
train1_idx = train_idx[:train_split] 
train2_idx = train_idx[train_split:] 
X_train = X.loc[train_idx] 
X_train_1 = X.loc[train1_idx] 
X_train_2 = X.loc[train2_idx] 
X_test = X.loc[test_idx] 
y_train = y.loc[train_idx] 
y_train_1 = y.loc[train1_idx] 
y_train_2 = y.loc[train2_idx] 
y_test = y.loc[test_idx] 

xg_train_0 = xgb.DMatrix(X_train, label=y_train) 
xg_train_1 = xgb.DMatrix(X_train_1, label=y_train_1) 
xg_train_2 = xgb.DMatrix(X_train_2, label=y_train_2) 
xg_test = xgb.DMatrix(X_test, label=y_test) 

params = {'objective': 'reg:linear', 'verbose': False} 
model_0 = xgb.train(params, xg_train_0, 30) 
model_1 = xgb.train(params, xg_train_1, 30) 
model_1.save_model('model_1.model') 
model_2_v1 = xgb.train(params, xg_train_2, 30) 
model_2_v2 = xgb.train(params, xg_train_2, 30, xgb_model=model_1) 

params.update({'process_type': 'update', 
       'updater'  : 'refresh', 
       'refresh_leaf': True}) 
model_2_v2_update = xgb.train(params, xg_train_2, 30, xgb_model=model_1) 

print('full train\t',mse(model_0.predict(xg_test), y_test)) # benchmark 
print('model 1 \t',mse(model_1.predict(xg_test), y_test)) 
print('model 2 \t',mse(model_2_v1.predict(xg_test), y_test)) # "before" 
print('model 1+2\t',mse(model_2_v2.predict(xg_test), y_test)) # "after" 
print('model 1+update2\t',mse(model_2_v2_update.predict(xg_test), y_test)) # "after" 

uscita:

full train 17.8364309709 
model 1  24.8 
model 2  25.6967017352 
model 1+2 22.8846455135 
model 1+update2 14.2816257268 
+0

Qual è il modello finale o quello che dovrei usare? – tumbleweed

+2

Si desidera il modello con l'MSE più basso. Ma nota come 1 + update2 è inferiore al treno completo! Non mi è chiaro il motivo per cui dovrebbe essere così, quindi sarei sospettoso di questo risultato e gestirò un CV con più pieghe. – paulperry

2

ho creato a gist of jupyter notebook di dimostrare che il modello xgboost può essere addestrato in modo incrementale. Ho usato il set di dati di Boston per addestrare la modella. Ho fatto 3 esperimenti: apprendimento one shot, apprendimento one-iterativo, apprendimento incrementale iterativo. In formazione incrementale, ho passato i dati di Boston al modello in lotti di 50.

Il nocciolo della questione è che dovrete scorrere più volte i dati per far convergere il modello alla precisione raggiunta da un solo colpo (tutti i dati) di apprendimento.

Ecco il codice corrispondente per l'esecuzione dell'apprendimento incrementale iterativo con xgboost. Versione

batch_size = 50 
iterations = 25 
model = None 
for i in range(iterations): 
    for start in range(0, len(x_tr), batch_size): 
     model = xgb.train({ 
      'learning_rate': 0.007, 
      'update':'refresh', 
      'process_type': 'update', 
      'refresh_leaf': True, 
      #'reg_lambda': 3, # L2 
      'reg_alpha': 3, # L1 
      'silent': False, 
     }, dtrain=xgb.DMatrix(x_tr[start:start+batch_size], y_tr[start:start+batch_size]), xgb_model=model) 

     y_pr = model.predict(xgb.DMatrix(x_te)) 
     #print(' MSE [email protected]{}: {}'.format(int(start/batch_size), sklearn.metrics.mean_squared_error(y_te, y_pr))) 
    print('MSE [email protected]{}: {}'.format(i, sklearn.metrics.mean_squared_error(y_te, y_pr))) 

y_pr = model.predict(xgb.DMatrix(x_te)) 
print('MSE at the end: {}'.format(sklearn.metrics.mean_squared_error(y_te, y_pr))) 

XGBoost: 0,6