cuMLとsklearnを簡易比較してみた
cuMLとは?
今回利用するcuMLを説明する前に、RAPIDSについて紹介します。RAPIDSとは公式の説明を引用すると
最も広く使用されているオープンソース データ ツール群と互換性のある API を備えた、GPU で高速化されたデータ サイエンスおよび AI ライブラリのオープンソース スイートです。データ パイプライン全体にわたりパフォーマンスを桁違いで大規模に高速化できます。
ということです。要は、NVIDIA GPUを効率よく使うためのライブラリをユースケースごとに提供してくれているということです。詳しくは以下の公式リンクを参照ください。
cuMLはRAPIDSの中でもMLモデルの作成などに利用できるライブラリとなっています。sklearnのようなAPIを提供しており、既存のsklearnを利用したプロジェクトであれば、ほとんどコードの変更をする必要なく利用できるのが特徴です。
cuMLを使って検証してみる
インストールについて
RAPIDSをインストールすればcuMLを利用できるのですが、環境ごとによってインストール方法が異なります。今回はGoogle Colabを利用することでインストールの手間を省略してご紹介します。個々の作業環境にて利用されたい場合は以下を参考に環境構築をしてください。
Google Colabの起動
RAPIDSのドキュメントにてGoogle Colabの環境を提供してくれていますので、今回はそちらを利用します。
Section 1: RAPIDS Quick Install
のPip
の項目でOpen in Colab
ボタンがあるのでそちらを選択してください。Google Colabが開かれると以下のような画面になると思います。
ここでSetup
の部分までご対応ください。Setupが完了するとRAPIDSが利用可能になり、cuMLもインポートできるようになります。試しに以下のコードを実行してみてください(セルでも用意されています)。
import cuml
cuml.__version__
実行時点の差はあるかもしれませんが、執筆時点では25.04.00
となります。
sklearnとの比較
いくつかのモデルを利用しながら、sklearnとcuMLの使い方を見ていきましょう。といってもほとんど使い勝手は変わらないです!
では、まずはモデルに入力するデータの生成ロジックを作りましょう。今回はsklearnで作成したデータをデータとして扱います。なお、cuMLではGPU上にロードされたデータだけでなく、NumPyのarrayを入力として受け付けることができます。
from sklearn.datasets import make_classification
from cuml.model_selection import train_test_split
def create_dataset(n_samples, n_features, n_classes):
X, y = make_classification (n_classes = n_classes,
n_features = n_features,
n_samples = n_samples,
random_state = 0 )
X_train, X_test, y_train, y_test = train_test_split( X, y, random_state = 0 )
return X_train, X_test, y_train, y_test
では次にいくつかモデルの使い方を抜粋してみます!
- RandomForestClassifier
from sklearn.ensemble import RandomForestClassifier as SKRandomForestClassifier
from cuml.ensemble import RandomForestClassifier as CUMLRandomForestClassifier
params = {"max_depth": 10}
skrf = SKRandomForestClassifier(**params)
cumlrf = CUMLRandomForestClassifier(**params)
- KNearest
from sklearn.neighbors import KNeighborsClassifier as SKKNeighborsClassifier
from cuml.neighbors import KNeighborsClassifier as CUMLKNeighborsClassifier
params = {"n_neighbors": 10}
skknn = SKKNeighborsClassifier(**params)
cumlknn = SKKNeighborsClassifier(**params)
- SVC
from sklearn.svm import SVC as SKSVC
from cuml.svm import SVC as CUMLSVC
params = {"C": 1.1}
sksvc = SKSVC(**params)
cumlsvc = CUMLSVC(**params)
パラメータは一つしかそれぞれ書いてないですが、基本的にsklearnで実装されていてcuMLで実装されているモデルのパラメータは同じものを指定できます。なので、import文でsklearnをcumlに置き換えると一部例外はあるかもしれませんが、基本的にcuML上のモデルを採用できます。
sklearnとcuMLの性能比較
それでは先ほど用意したデータ作成モジュールと上記3つのモデルを利用して、処理速度と性能について比較してみようと思います。実験条件は以下のように設定してみます。
- サンプル数を1,000 ~ 100,000まで10倍ずつ変更
- 特徴量は10で固定
- クラス数は2とする
この条件でテストをするためのコードを以下にまとめます。
import time
from sklearn.metrics import accuracy_score
from tqdm import tqdm
elapsed_times = {
"rf": {"sklearn": [], "cuml": []},
"knn": {"sklearn": [], "cuml": []},
"svc": {"sklearn": [], "cuml": []},
}
accuracies = {
"rf": {"sklearn": [], "cuml": []},
"knn": {"sklearn": [], "cuml": []},
"svc": {"sklearn": [], "cuml": []},
}
n_samples = (1_000, 10_000, 100_000)
model_params = {
"rf": {"max_depth": 5},
"knn": {"n_neighbors": 10},
"svc": {"C": 1.1},
}
model_classes = {
"rf": {
"sklearn": SKRandomForestClassifier,
"cuml": CUMLRandomForestClassifier,
},
"knn": {
"sklearn": SKKNeighborsClassifier,
"cuml": CUMLKNeighborsClassifier,
},
"svc": {
"sklearn": SKSVC,
"cuml": CUMLSVC,
},
}
for _n_samples in tqdm(n_samples):
X_train, X_test, y_train, y_test = create_dataset(_n_samples, n_features=10, n_classes=2)
for model_name, _model_params in tqdm(model_params.items(), leave=False):
sklearn_model = model_classes[model_name]["sklearn"](**_model_params)
cuml_model = model_classes[model_name]["cuml"](**_model_params)
# sklearnでモデル学習
st = time.time()
sklearn_model.fit(X_train, y_train)
predict = sklearn_model.predict(X_test)
accuracy = accuracy_score(y_test, predict)
et = time.time()
accuracies[model_name]["sklearn"].append(accuracy)
elapsed_times[model_name]["sklearn"].append(et - st)
# cuMLでモデル学習
st = time.time()
cuml_model.fit(X_train, y_train)
predict = cuml_model.predict(X_test)
accuracy = accuracy_score(y_test, predict)
et = time.time()
accuracies[model_name]["cuml"].append(accuracy)
elapsed_times[model_name]["cuml"].append(et - st)
この結果をグラフにするため、以下のコードを利用します。
import matplotlib.pyplot as plt
for i, model_name in enumerate(model_params.keys()):
plt.subplot(3, 2, 2*i+1)
plt.plot(n_samples, elapsed_times[model_name]["cuml"], color="red", label="cuML")
plt.plot(n_samples, elapsed_times[model_name]["sklearn"], color="blue", label="sklearn")
plt.xlabel("n_samples")
plt.ylabel("elapsed time[s]")
plt.legend()
plt.title(model_name)
plt.subplot(3, 2, 2*i+2)
plt.plot(n_samples, accuracies[model_name]["cuml"], color="red", label="cuML")
plt.plot(n_samples, accuracies[model_name]["sklearn"], color="blue", label="sklearn")
plt.xlabel("n_samples")
plt.ylabel("Accuracy")
plt.legend()
plt.title(model_name)
plt.subplots_adjust(wspace=0.5)
plt.show()
グラフを描画すると以下のような結果となりました。精度(右側)についてはどのモデルも基本的にsklearnとcuMLでは差はないことが確認できます。大きく違ったのは実行時間(左側)です。特にデータ数が多くなればなるほどその差は顕著に表れており、sklearnではデータ数が増えるとそれに従ってリニアに増えていますが、cuMLを利用するとその増分がかなり緩やかであり、その差分はほとんどありません。この結果から、精度を落とすことなく学習時間を高速にできることが想定されます。
まとめ
今回は、本当に簡単ではありますがcuMLについて紹介し、sklearnとの互換性についてもお見せできたかなと思います。特に学習時間がほとんど変わらないというのは実際に開発する際に大きなメリットとなるのではないでしょうか。本来であればハイパーパラメータチューニングをしたり、データタイプをcuMLに適した方法にした時と比較などをしたいですが、それはまた別の記事で紹介できたらと思います。
Discussion