cumlを用いてGPUでxgboostの学習を高速化できるか試す

学習時間は3.45倍短くなり、コードの変更はパラメータのみでここまで高速化可能だ。

Xgboostによる推論高速化

前回のブログではxgboostの推論がcumlで高速化できるかを試してみました。

推論速は約7倍ほど早くなりました。

今回は下記のコードを参考にしました。

https://github.com/rapidsai/xgboost-conda/blob/branch-0.13/notebooks/XGBoost_Demo.ipynb

環境構築、動作環境は前回の記事を参考にしてください。

コードの動作確認

必要なライブラリをインポートします。

import numpy as np; print('numpy Version:', np.__version__)
import pandas as pd; print('pandas Version:', pd.__version__)
import xgboost as xgb; print('XGBoost Version:', xgb.__version__)

動作確認のために簡易的なデータを作成します。

def simulate_data(m, n, k=2, numerical=False):
    if numerical:
        features = np.random.rand(m, n)
    else:
        features = np.random.randint(2, size=(m, n))
    labels = np.random.randint(k, size=m)
    return np.c_[labels, features].astype(np.float32)

行数、列数、カテゴリ数を設定します。

n_rows = int(1e5)
n_columns = int(100)
n_categories = 2

簡易データを作成し、サイズを確認します。行数:100000、列数:100のデータが作成されます。

dataset = simulate_data(n_rows, n_columns, n_categories)
print(dataset.shape)

データ・セットとラベルに分けて、学習データ、検証データにわけます。80%を学習データにしています。

# identify shape and indices
n_rows, n_columns = dataset.shape
train_size = 0.80
train_index = int(n_rows * train_size)

# split X, y
X, y = dataset[:, 1:], dataset[:, 0]
del dataset

# split train data
X_train, y_train = X[:train_index, :], y[:train_index]

# split validation data
X_validation, y_validation = X[train_index:, :], y[train_index:]

学習データ、検証データのサイズを確認します。

# check dimensions
print('X_train: ', X_train.shape, X_train.dtype, 'y_train: ', y_train.shape, y_train.dtype)
print('X_validation', X_validation.shape, X_validation.dtype, 'y_validation: ', y_validation.shape, y_validation.dtype)

下記のような結果になります。

X_train:  (80000, 100) float32 y_train:  (80000,) float32
X_validation (20000, 100) float32 y_validation:  (20000,) float32

numpyのデータをDMatrix形式のデータに変更して、xgboostで学習できるフォーマットにします。

labelにラベルデータを設定します。

下記に読み込み可能なデータフォーマットが記述されています。

https://xgboost.readthedocs.io/en/latest/python/python_intro.html#data-interface

%%time

dtrain = xgb.DMatrix(X_train, label=y_train)
dvalidation = xgb.DMatrix(X_validation, label=y_validation)

CPUでの動作確認

xgboostで動作するためのパラメータ設定をします。

n_gpus:使用するGPU数を設定しています。

learning_task_params = {‘eval_metric’: ‘auc’, ‘objective’: ‘binary:logistic’}:評価関数とロス関数を設定します。’auc’は2値分類の評価指標で用いられます。単純な精度だとデータ数が多い方に引っ張られるのでこの指標が用いられます。

AUCの詳細はこちらです。

‘binary:logistic’:2値分類をロジスティック回帰で学習するための設定です。

設定可能なパラメータはこちらです。

# instantiate params
params = {}

# general params
general_params = {'silent': 1}
params.update(general_params)

# booster params
n_gpus = 0
booster_params = {}

if n_gpus != 0:
    booster_params['tree_method'] = 'gpu_hist'
    booster_params['n_gpus'] = n_gpus
params.update(booster_params)

# learning task params
learning_task_params = {'eval_metric': 'auc', 'objective': 'binary:logistic'}
params.update(learning_task_params)
print(params)

ラウンド数と評価時に使用するデータ・セットを設定します。

# model training settings
evallist = [(dvalidation, 'validation'), (dtrain, 'train')]
num_round = 10

先程設定したパラメータと学習データ、ラウンド数、評価用データを設定します。

%%time

bst = xgb.train(params, dtrain, num_round, evallist)

下記のように学習が進みます。検証データのAUCは下がっているので過学習気味に動作していることが分かります。

[0]	validation-auc:0.50170	train-auc:0.54351
[1]	validation-auc:0.50031	train-auc:0.55798
[2]	validation-auc:0.49861	train-auc:0.57013
[3]	validation-auc:0.49702	train-auc:0.58140
[4]	validation-auc:0.49760	train-auc:0.58997
[5]	validation-auc:0.49710	train-auc:0.59731
[6]	validation-auc:0.49406	train-auc:0.60425
[7]	validation-auc:0.49455	train-auc:0.61112
[8]	validation-auc:0.49474	train-auc:0.61777
[9]	validation-auc:0.49324	train-auc:0.62314

学習にかかった時間は6.97 秒でした。

GPUでの動作確認

GPUが1枚あるのでn_gpusを1に設定します。GPUが1枚あると下記が設定されます。

  • booster_params[‘tree_method’] = ‘gpu_hist’ :木作成のメソッドを設定しています。
  • 下記のように木を作成するのですが、特徴量のヒストグラムを作成して分割点を決めないと木構造のようなデータを作成できません。このヒストグラム作成をGPUによって高速化したい場合に’gpu_hist’を設定します。

最初のヒストグラムは特徴量ごとに作成します。

下記のように作成したヒストグラムで分けた範囲のデータでヒストグラムを作成を繰り返します。

より詳細を把握したい方は LightGBM: A Highly Efficient Gradient Boosting Decision Tree のAlgorithm 1: Histogram-based Algorithmを参照ください。

  • booster_params[‘n_gpus’] = n_gpus:GPUの枚数を設定します。
# instantiate params
params = {}

# general params
general_params = {'silent': 1}
params.update(general_params)

# booster params
n_gpus = 1
booster_params = {}

if n_gpus != 0:
    booster_params['tree_method'] = 'gpu_hist'
    booster_params['n_gpus'] = n_gpus
params.update(booster_params)

# learning task params
learning_task_params = {'eval_metric': 'auc', 'objective': 'binary:logistic'}
params.update(learning_task_params)
print(params)

CPUの場合と同様にラウンド数と評価時に使用するデータ・セットを設定します。

# model training settings
evallist = [(dvalidation, 'validation'), (dtrain, 'train')]
num_round = 10

CPUの場合と同様に学習します。

%%time

bst = xgb.train(params, dtrain, num_round, evallist)

下記のように学習が進みます。GPUの場合も同様に検証データのAUCは下がっているので過学習気味に動作していることが分かります。

[0]	validation-auc:0.50170	train-auc:0.54351
[1]	validation-auc:0.50031	train-auc:0.55798
[2]	validation-auc:0.49861	train-auc:0.57013
[3]	validation-auc:0.49702	train-auc:0.58140
[4]	validation-auc:0.49760	train-auc:0.58997
[5]	validation-auc:0.49710	train-auc:0.59731
[6]	validation-auc:0.49406	train-auc:0.60425
[7]	validation-auc:0.49455	train-auc:0.61112
[8]	validation-auc:0.49474	train-auc:0.61777
[9]	validation-auc:0.49324	train-auc:0.62314

学習時間は2.02秒でした。

学習時間は3.45倍短くなっています。

コードの変更はパラメータのみでここまで高速化できています。

Xgboostの学習と推論を高速化できることが分かったぞ

Close Bitnami banner
Bitnami