😸

Brev上でcuMLを使ってGPUが利用されることを確認してみた

に公開1

今回はNVIDIA Brev上で機械学習モデルを学習させ、GPUメモリが利用されることを確認してみました。Brevについては以下の記事をご覧ください。

https://zenn.dev/akasan/articles/686e4b3ef0b8ff

今回の検証内容

今回は以前投稿した以下の記事と同じことをBrev上で構築し、GPUメモリが消費されることを確認してみました。以前はGoogle Colab城で実行しておりGPUメモリが消費される様子を確認できていなかったので、今回はBrev城で確認します。

https://zenn.dev/akasan/articles/e7d9b92bf6dee2

環境構築

この検証ではBrev城で環境を構築します。Brevについては最初に添付した記事を参考に環境構築してください。

Brevインスタンス立ち上げ

BrevのインスタンスについてはL40S一つを利用したインスタンスを立ち上げました。

環境を立ち上げたら、インスタンス画面にある情報を元に、以下のコマンドを実行してください。なお、GPUメモリ使用量を監視するために二つのwindowで動作確認しました。

brev login --token ***  # ログイン処理
brev shell <instance name>

Python環境の構築

それではSSHでログインした後にPython環境を構築します。

まずはuvを公式のインストール方法に従い、以下の方法でインストールします。

curl -LsSf https://astral.sh/uv/install.sh | sh
sourece $HOME/.local/bin/env

次にプロジェクトを立ち上げます。

uv init cuml_sklearn_comp -p 3.12
cd cuml_sklearn_comp
uv add scikit-learn tqdm matplotlib

これに追加して、cuMLが含まれているRAPIDSをインストールします。以下のページの内容をもとにインストールします。今回はCUDA 12.0を利用しているので、以下のコマンドでライブラリをインストールします。

https://docs.rapids.ai/install/#selector

uv add \
    "cudf-cu12==25.10.*" "dask-cudf-cu12==25.10.*" "cuml-cu12==25.10.*" \
    "cugraph-cu12==25.10.*" "nx-cugraph-cu12==25.10.*" "cuxfilter-cu12==25.10.*" \
    "cucim-cu12==25.10.*" "pylibraft-cu12==25.10.*" "raft-dask-cu12==25.10.*" \
    "cuvs-cu12==25.10.*" "nx-cugraph-cu12==25.10.*"

なお、このままではlibnvrtc.so.12が不足しているらしく、こちらのイシューの内容をもとにツールキットをインストールしました。

wget https://developer.download.nvidia.com/compute/cuda/repos/ubuntu2004/x86_64/cuda-keyring_1.1-1_all.deb
sudo dpkg -i cuda-keyring_1.1-1_all.deb
sudo apt-get update
sudo apt-get -y install cuda-toolkit-12-3

プログラムの実装

今回は前回利用したソースコードをそのまま利用します。以下のコードになります。

cuml_sklearn_comp.py
import time
from tqdm import tqdm
import matplotlib.pyplot as plt
from sklearn.svm import SVC as SKSVC
from cuml.svm import SVC as CUMLSVC
from sklearn.neighbors import KNeighborsClassifier as SKKNeighborsClassifier
from cuml.neighbors import KNeighborsClassifier as CUMLKNeighborsClassifier
from sklearn.ensemble import RandomForestClassifier as SKRandomForestClassifier
from cuml.ensemble import RandomForestClassifier as CUMLRandomForestClassifier
from sklearn.datasets import make_classification
from sklearn.metrics import accuracy_score
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


params = {"max_depth": 10}
skrf = SKRandomForestClassifier(**params)
cumlrf = CUMLRandomForestClassifier(**params)

params = {"n_neighbors": 10}
skknn = SKKNeighborsClassifier(**params)
cumlknn = SKKNeighborsClassifier(**params)


params = {"C": 1.1}
sksvc = SKSVC(**params)
cumlsvc = CUMLSVC(**params)


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)


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.savefig("output.png")

cuMLとscikit-learnで同じモデルを同じパラメータで比較し、その精度と処理時間を計測します。最終的な結果はmatplotlibの画像として保存します。

プログラムの実行

それでは早速実行してみます。今回は私のローカルターミナルをtmuxでに分割し、片方でプログラムの実行を、もう片方でwatch -n 1 nvidia-smiでGPUメモリの使用量を確認します。なお、念のためプログラム実行前のGPUメモリ利用料が0であることを確認します。

それでは早速プログラムを実行してみます。

uv run cuml_sklearn_comp.py

実行している最中にnvidia-smiの結果を見ると、以下のようにGPUメモリが利用されていることが確認できました。

また、cuMLとscikit-learnの比較については前回と同様に精度を落とすことなく処理時間が増えることを抑えられているので、cuMLのパフォーマンスが優れていることを確認でいました。

まとめ

今回はBrev上でcuMLを利用するときにGPUが利用されることを確認できました。お手軽のインスタンスが起動できるだけでなく、GPUメモリをふんだんに利用してモデルを開発できるため、やはりGPUマシンでもモデル開発はいいなとあらためて感じました。

Discussion

AkasanAkasan

RAPIDSライブラリは全て入れる必要はおそらくないですが、今回はインストラクションに従ってインストールしました