web-dev-qa-db-ja.com

xgboostの増分トレーニングを実装するにはどうすればよいですか?

問題は、列車のデータサイズのために列車データをRAMに配置できないことです。したがって、最初に列車データセット全体で1つのツリーを構築し、残差を計算して別のツリーを構築し、 (グラデーションブーストツリーのように)明らかに、ループでmodel = xgb.train(param, batch_dtrain, 2)を呼び出すと-バッチごとにモデル全体を再構築するだけなので、役に立ちません。

27
Marat Zakirov

免責事項:私もxgboostを初めて使用しますが、これを理解したと思います。

最初のバッチでトレーニングした後、モデルを保存してみてください。次に、連続した実行で、保存されたモデルのファイルパスをxgb.trainメソッドに提供します。

これが動作することを確信させるために実行した小さな実験を次に示します。

最初に、ボストンデータセットをトレーニングセットとテストセットに分割します。次に、トレーニングセットを半分に分割します。前半でモデルを適合させ、ベンチマークとして機能するスコアを取得します。次に、2つのモデルを後半に適合させます。 1つのモデルには追加パラメーターxgb_modelがあります。余分なパラメーターを渡しても違いが得られない場合、それらのスコアは似ていると予想されます。しかし、幸いなことに、新しいモデルのパフォーマンスは最初のモデルよりもはるかに優れているようです。

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

不明な点がある場合はお知らせください!

参照: https://github.com/dmlc/xgboost/blob/master/python-package/xgboost/training.py

29
Alain

現在(バージョン0.6?)役立つprocess_updateパラメーターがあります。これを使った実験です:

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"

出力:

full train   17.8364309709
model 1      24.2542132108
model 2      25.6967017352
model 1+2    22.8846455135
model 1+update2  14.2816257268
12
paulperry

jupyterノートブックの要点 を作成して、xgboostモデルを段階的にトレーニングできることを示しました。ボストンデータセットを使用してモデルをトレーニングしました。ワンショット学習、反復ワンショット学習、反復増分学習の3つの実験を行いました。インクリメンタルトレーニングでは、サイズ50のバッチでボストンデータをモデルに渡しました。

Gist of the Gistは、モデルを1回のショット(すべてのデータ)学習によって達成される精度に収束させるために、データを複数回反復する必要があることです。

以下は、xgboostで反復インクリメンタル学習を行うための対応するコードです。

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 itr@{}: {}'.format(int(start/batch_size), sklearn.metrics.mean_squared_error(y_te, y_pr)))
    print('MSE itr@{}: {}'.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

6

xgb.train(....)を再度呼び出す以外に何も必要ないように見えますが、前のバッチからのモデル結果を提供します:

# python
params = {} # your params here
ith_batch = 0
n_batches = 100
model = None
while ith_batch < n_batches:
    d_train = getBatchData(ith_batch)
    model = xgb.train(params, d_train, xgb_model=model)
    ith_batch += 1

これは https://xgboost.readthedocs.io/en/latest/python/python_api.htmlenter image description here

3
Mobigital

問題がデータセットのサイズに関するものであり、インクリメンタル学習が本当に必要ない場合(たとえば、ストリーミングアプリを扱っていない場合)、 SparkまたはFlink。

この2つのフレームワークは、ディスクメモリを活用して、小さなRAMで非常に大きなデータセットをトレーニングできます。両方のフレームワークは、メモリの問題を内部的に処理します。 Flinkは最初に解決しましたが、Sparkは最近のリリースに追いついています。

を見てみましょう:

Paulperryのコードに、1行を「train_split = round(len(train_idx)/ 2)」から「train_split = len(train_idx)-50」に変更した場合。モデル1 + update2は14.2816257268から45.60806270012028に変更されます。そして、多くの「leaf = 0」はダンプファイルになります。

更新サンプルセットが比較的小さい場合、更新モデルは適切ではありません。 binary:logisticの場合、更新サンプルセットにクラスが1つしかない場合、更新されたモデルは使用できません。

0
Tao Cheng