今回は GBDT (Gradient Boosting Decision Tree) フレームワークのひとつである CatBoost について、いくつかの環境で同一のソースコードを使って学習にかかる時間を比較してみた。 きっかけは、最近入手した Apple M2 Pro を搭載した Mac mini が、どれくらいの性能を出せるのか気になったため。
使った Python とパッケージのバージョンは次のとおり。
$ python -V Python 3.9.16 $ pip list | egrep -i "(scikit-learn|catboost)" catboost 1.1.1 scikit-learn 1.2.2
もくじ
- もくじ
- 下準備
- ベンチマークについて
- Apple M2 Pro w/ macOS
- Apple M1 w/ macOS
- Intel Core i7-8700B w/ macOS
- Intel Core i7-12700 w/ Linux
- NVIDIA RTX 3060 w/ Linux
- NVIDIA Tesla A100 40GB w/ Linux
- まとめ
下準備
すべての環境で、あらかじめ CatBoost と scikit-learn をインストールしておく。
$ pip install catboost scikit-learn
その他、GPU を使う環境では CUDA Driver のインストールも必要になるけど、その部分は省略する。
ベンチマークについて
ベンチマークに使ったコードを以下に示す。
内容は、scikit-learn で二値分類のダミーデータを生成して、それを catboost.cv()
で学習する。
そして、固定の 10,000 イテレーションを実行するのにかかる時間を測定する。
import contextlib import logging import time import catboost from catboost import Pool from sklearn.datasets import make_classification from sklearn.model_selection import StratifiedKFold LOGGER = logging.getLogger(__name__) @contextlib.contextmanager def stopwatch(): """実行にかかる時間を測定するコンテキストマネージャ""" start = time.time() LOGGER.info("start: CatBoost") yield end = time.time() LOGGER.info("end: CatBoost") elapsed = end - start LOGGER.info("elapsed time: %.2f sec", elapsed) def main(): log_fmt = ( "%(process)d %(threadName)s %(name)s %(levelname)s %(message)s" ) logging.basicConfig(level=logging.INFO, format=log_fmt) # ダミーデータを生成する args = { "n_samples": 100_000, "n_features": 100, "n_informative": 20, "n_redundant": 0, "n_repeated": 0, "class_sep": 0.65, "n_classes": 2, "random_state": 42, "shuffle": False, } x, y = make_classification(**args) # Stratified 5-Fold の交差検証を想定する folds = StratifiedKFold( n_splits=5, shuffle=True, random_state=42, ) cat_train = Pool(x, label=y) cat_params = { "loss_function": "Logloss", "num_boost_round": 10_000, "metric_period": 1_000, # 学習に GPU を使う場合 # "task_type": "GPU", } with stopwatch(): catboost.cv( params=cat_params, pool=cat_train, folds=folds, # 時間を測るのが目的なので Early Stopping しない ) if __name__ == "__main__": main()
Apple M2 Pro w/ macOS
ここからは、実際にそれぞれの環境で実行していく。
まずは、きっかけとなった Apple M2 Pro のマシンから。 コア数は 12 (8 Performance Cores + 4 Efficient Cores) のモデルを使っている。 発売されたのは 2023 年になる。
環境は次のとおり。
$ sysctl -a | grep brand_string machdep.cpu.brand_string: Apple M2 Pro $ uname -srm Darwin 22.3.0 arm64 $ sw_vers ProductName: macOS ProductVersion: 13.2.1 BuildVersion: 22D68
ベンチマークを実行する。
$ python benchmark.py 67539 MainThread __main__ INFO start: CatBoost ... 67539 MainThread __main__ INFO end: CatBoost 67539 MainThread __main__ INFO elapsed time: 536.84 sec
実行には 536 秒かかった。
Apple M1 w/ macOS
続いては Apple M1 を載せたモデルでを試す。 M2 Pro と比べて 1 世代古く、コア数も 8 (4 Performance Cores + 4 Efficient Cores) と少ない。 発売されたのは 2020 年になる。
$ sysctl -a | grep brand_string machdep.cpu.brand_string: Apple M1 $ uname -srm Darwin 22.3.0 arm64 $ sw_vers ProductName: macOS ProductVersion: 13.2.1 BuildVersion: 22D68
同様に、ベンチマークを実行する。
$ python benchmark.py 7308 MainThread __main__ INFO start: CatBoost ... 7308 MainThread __main__ INFO end: CatBoost 7308 MainThread __main__ INFO elapsed time: 688.01 sec
こちらの環境では 688 秒かかった。
Apple M2 Pro に比べると約 28% 余計に時間がかかっている。 この差を大きいと見るか小さいと見るか。
Intel Core i7-8700B w/ macOS
続いては Intel の CPU を載せた最後の世代の Mac mini でも試す。 発売されたのは 2018 年になる。
$ sysctl -a | grep brand_string machdep.cpu.brand_string: Intel(R) Core(TM) i7-8700B CPU @ 3.20GHz $ uname -srm Darwin 22.3.0 x86_64 $ sw_vers ProductName: macOS ProductVersion: 13.2.1 BuildVersion: 22D68
実行する。
14256 MainThread __main__ INFO start: CatBoost ... 14256 MainThread __main__ INFO end: CatBoost 14256 MainThread __main__ INFO elapsed time: 850.76 sec
こちらは 850 秒かかった。 どうやら CatBoost の実行に関しては Intel CPU から Apple Silicon になって順当に性能が改善しているようだ。
Intel Core i7-12700 w/ Linux
続いては、割と最近のデスクトップ向けの x86 CPU でも比較しておく。 OS には Ubuntu 20.04 LTS を使った。
環境としてはオンプレマシンの Intel Core i7-12700 を使った。 Apple Silicon と同じようにヘテロジニアスマルチコアで 12 コア (8 Performance Cores + 4 Efficient Cores) のモデル。 発売されたのは 2022 年になる。
$ head /proc/cpuinfo | grep name model name : 12th Gen Intel(R) Core(TM) i7-12700 $ uname -srm Linux 5.15.0-60-generic x86_64 $ cat /etc/lsb-release DISTRIB_ID=Ubuntu DISTRIB_RELEASE=20.04 DISTRIB_CODENAME=focal DISTRIB_DESCRIPTION="Ubuntu 20.04.5 LTS"
なお、最近のデスクトップ向けの CPU は、同じモデルであっても供給する電力によってパフォーマンスが大きく変わってくる。 今回は PBT と MTP の両方に固定で 125W を設定している。
ベンチマークを実行する。
136812 MainThread __main__ INFO start: CatBoost ... 136812 MainThread __main__ INFO end: CatBoost 136812 MainThread __main__ INFO elapsed time: 394.81 sec
こちらは 394 秒かかった。
同じコア構成 (8 Performance Cores + 4 Performance Cores) の Apple M2 Pro と比較して約 26 % 時間が短縮されている。 ただし、Apple M2 Pro の消費電力は最大でも 60W なので約半分という点は留意する必要がある。
NVIDIA RTX 3060 w/ Linux
前述のオンプレマシンには NVIDIA RTX 3060 の GPU が載っている。 CatBoost は GPU を使った学習もできるため、試してみよう。
$ nvidia-smi Fri Mar 10 22:00:21 2023 +---------------------------------------------------------------------------------------+ | NVIDIA-SMI 530.30.02 Driver Version: 530.30.02 CUDA Version: 12.1 | |-----------------------------------------+----------------------+----------------------+ | GPU Name Persistence-M| Bus-Id Disp.A | Volatile Uncorr. ECC | | Fan Temp Perf Pwr:Usage/Cap| Memory-Usage | GPU-Util Compute M. | | | | MIG M. | |=========================================+======================+======================| | 0 NVIDIA GeForce RTX 3060 On | 00000000:01:00.0 Off | N/A | | 0% 50C P8 14W / 170W| 14MiB / 12288MiB | 0% Default | | | | N/A | +-----------------------------------------+----------------------+----------------------+ +---------------------------------------------------------------------------------------+ | Processes: | | GPU GI CI PID Type Process name GPU Memory | | ID ID Usage | |=======================================================================================| | 0 N/A N/A 1138 G /usr/lib/xorg/Xorg 9MiB | | 0 N/A N/A 1283 G /usr/bin/gnome-shell 2MiB | +---------------------------------------------------------------------------------------+
task_type
を GPU
に変更してベンチマークを実行する。
8379 MainThread __main__ INFO start: CatBoost ... 8379 MainThread __main__ INFO end: CatBoost 8379 MainThread __main__ INFO elapsed time: 816.01 sec
意外なことに GPU を使って学習すると 816 秒かかった。
何が意外かというと、以前であれば CatBoost は GPU を使わないと学習に長い時間がかかる印象を持っていたため。 もしかすると、最近のバージョンアップで CPU を使った学習速度に改善があったのかもしれない 1。 なお、CatBoost は CPU と GPU で使用できるパラメータやデフォルトのパラメータに差異が多い点には留意が必要になる。
NVIDIA Tesla A100 40GB w/ Linux
先ほど使ったのはコンシューマ向けで、しかもミドルレンジの GPU だった。 エンタープライズ向けのハイエンドを使ったらどうなるか気になったので、実際に試してみた。
以下の環境は Google Cloud の a2-highgpu-1g
インスタンスを用意した。
NVIDIA Tesla A100 の 40GB モデルを 1 基積んで、12 vCPU と 85GB のメモリが利用できる。
$ head /proc/cpuinfo | grep name model name : Intel(R) Xeon(R) CPU @ 2.20GHz $ uname -srm Linux 5.15.0-1030-gcp x86_64 $ cat /etc/lsb-release DISTRIB_ID=Ubuntu DISTRIB_RELEASE=20.04 DISTRIB_CODENAME=focal DISTRIB_DESCRIPTION="Ubuntu 20.04.5 LTS" $ nvidia-smi Fri Mar 10 10:20:35 2023 +-----------------------------------------------------------------------------+ | NVIDIA-SMI 510.47.03 Driver Version: 510.47.03 CUDA Version: 11.6 | |-------------------------------+----------------------+----------------------+ | GPU Name Persistence-M| Bus-Id Disp.A | Volatile Uncorr. ECC | | Fan Temp Perf Pwr:Usage/Cap| Memory-Usage | GPU-Util Compute M. | | | | MIG M. | |===============================+======================+======================| | 0 NVIDIA A100-SXM... Off | 00000000:00:04.0 Off | 0 | | N/A 34C P0 54W / 400W | 0MiB / 40960MiB | 27% Default | | | | Disabled | +-------------------------------+----------------------+----------------------+ +-----------------------------------------------------------------------------+ | Processes: | | GPU GI CI PID Type Process name GPU Memory | | ID ID Usage | |=============================================================================| | No running processes found | +-----------------------------------------------------------------------------+
ベンチマークを実行する。
11514 MainThread __main__ INFO start: CatBoost ... 11514 MainThread __main__ INFO end: CatBoost 11514 MainThread __main__ INFO elapsed time: 1251.17 sec
実行には 1251 秒かかった。
この結果は非直感的で、オンプレマシンの NVIDIA RTX 3060 よりも時間がかかっている。 もしかすると GPU 以外の何かで律速していたり、何らかのオーバーヘッドに由来するものかもしれない。 実行中の Utilization に関しては 70 ~ 80% 前後で NVIDIA RTX 3060 と大きな違いは見られなかった 2。
なお、上記のマシンは以下のコマンドで作成した。
$ gcloud compute instances create a100-vm \ --preemptible \ --zone=us-central1-a \ --machine-type=a2-highgpu-1g \ --accelerator=count=1,type=nvidia-tesla-a100 \ --image-project=deeplearning-platform-release \ --image-family=common-container-ubuntu-2004
まとめ
以下に、各環境ごとの実行時間をグラフで示す。 左側の 3 項目が macOS で、右側の 3 項目が Ubuntu の結果になっている。
分かったことを以下に示す。
- Mac における CatBoost の実行性能は最近の SoC で順当に改善はしているように見える
- ただし、性能を追い求めるならコアが多くて消費電力も大きい CPU と Linux を組み合わせた方が速い
- 少なくとも今回のベンチマークした条件においては学習に GPU を使うメリットは薄いように見える
いじょう。