🖥️

CUDAプログラミング学習環境をAzureで構築する

に公開

CUDAプログラミング学習環境をAzureのVMで構築する

1. はじめに

この記事では、主にGPUコーディングの勉強を目的とした、クラウド上のCUDAプログラミング環境構築の方法を紹介しています。GPUプログラミングの実行環境が欲しいが、Google Colabでは物足りなさを感じているという人の役に立てばと思っています。

なお、参考までにですが、私がCUDAプログラミング環境構築に至り、記事化しようとした背景です。

  • NVIDIAのCEO(革ジャン)お墨付きのGPUプログラミング教科書、Programming Massively Parallel Processors(以下、PMPPと勝手に略します)でCUDAプログラミングの学習を進めている→PMPP
  • PMPPはハンズオンアプローチと銘打っており、やはり手元で実行しながらGPUスループットの改善を確認したい。
  • 一方、クラウドの環境構築は経験が浅く、どう構築していいものかと途方に暮れていたのですが、個別構築ステップに関する記事は見つかるものの全体一気通貫のものは見当たらなかったです。
    • 同じような状況にいる人のお役に立てれば幸いです。

2. 仕様

今回構築する環境の技術仕様的なものをつらつらと記載します

  • 私の環境(接続元)はMac(M3Max)です
    • Windowsで手順が異なるのは、後述のSSHの接続方法くらいではないでしょうか
  • Azureを利用
    • 後述するVMの自動停止機能を簡単に利用できるため採用しました
    • また、私が多少なりとも操作に慣れていることも理由の一つです
    • その他のクラウドプロパイダー(AWS、Google Cloud等)のニーズがあれば調査したいと思います
  • VMのスペックは、勉強用なので、NVIDIA GPUが利用できる以下の最低スペックとしました
    • VM: Standard NC4as T4 v3 (4 vcpu 数、28 GiB メモリ)
  • セキュリティは、勉強用のため最低限の構成としています
  • OSはCUDA プログラミングのデファクト(?)のUbuntuとします
  • VMの操作はリモートデスクトップ(Windows App)を用います
  • CUDAコード実行は、PyCUDAをnotebook上で走らせる方法を選択
    • CUDAプログラミングの勉強のコアは、Kernelの記述という認識
    • 前後のデータ準備や出力は簡易的にpythonで済ますことにしました

3. VM作成手順

注意点

Step2のクォータの設定はMicrosoftによる承認が必要で、人間系で行われているそうで場合によっては数日かかることもあるそうです。週末に試そうと思ったら承認待ちで週末が終わってしまうかもしれないので、思い立ったら早めに申請だけしていまいましょう。(クォータ自体には課金は発生しないはずです)
また、当然ですがVMにはコストがかかります。停止すると課金はとまるため、後述する自動停止で起動しっぱなしを防止すると同時に、使わないときはすぐに停止しましょう。
あと、VM作成後にダウンロードできるSSH秘密キー(.pem)ファイルは再入手ができないので、無くさないようにしましょう。

前提

以下のVM作成手順は、ブラウザ上からAzureポータル経由で行います。

Step1: サブスクリプション作成

このページ等を参照しながら、Azureのサブスクリプションを払出してください。初めて利用する方は無料枠が使えるので、気軽にtryしてみると良いと思います。

なお、サブスクリプションとは?という方用にClaudeに簡単に解説してもらいました。巷のサブスクとはニュアンスが随分異なりますのでご注意。

Azureサブスクリプションは、Microsoftのクラウドサービスを使うための「契約」のようなものです。
お金の管理 - クラウドで使ったサービスの料金がまとめて請求される単位
権限の管理 - 誰がどのサービスを使えるかを決められる範囲
サービスをまとめる箱 - 仮想マシンやデータベースなどを整理して管理する大きな入れ物
料金プランを選べる - 使った分だけ払う、月額固定、無料お試しなどから選択可能
用途で分ける - 開発用と本番用、部署ごとなどで別々の契約にして管理を簡単にできる

Step2: クォータの申請(←時間がかかります)

Azureのサービスには、デフォルトでクォータと呼ばれる制限がかかっています。デフォルトの状態ではGPU利用可能なVMが使えないので、利用可能枠の確保を申請します。注意点に記載のとおり時間がかかりますので、早めに申請し気長に待ちましょう。

以下の手順でクォータの枠拡大を申請します。

  • Azure Portalにアクセス
  • サブスクリプション(鍵のマーク)を選択し、1.で払い出したサブスクリプションを選択
  • 左側のメニューから設定 > 使用量+クォータにアクセス
  • 検索窓にT4と入力のうえ、リージョンの全選択を解除しJapan EastまたはJapan Westを選択
  • Standar NCASv3_T4ファミリーが表示され「0のうち0を使用中」と表示されているので、右側の調整の列の「はい」をクリック
  • 「新しい制限」の枠に、今回払出しに必要な値4以上(上限は8)を入力し、送信。
  • 上記を送信すると対応できなかった旨のエラーが出ますが、めげずにサポートリクエストを作成します。
  • 要求の詳細が表示されますが特段触らずに「保存して続行」でリクエストを送信します。
  • 要求してしばらく経つと、リクエストが承認されます。気長に待ちましょう。
    • 私の場合は土曜日の昼にリクエストし1時間程度で承認されましたが、場合によっては数日かかることもあるようです。
  • リクエスト承認の連絡が来たら、要求したStandar NCASv3_T4ファミリーのクォータの制限を表示し、値が4以上になっていることを確認してください。

Step3: VMの作成

VMを作成します。このステップが終了すると課金が発生し始めるので、作成後は利用しないときはまめに停止するようにしましょう。

  • Azure Portalのサービス一覧に仮想マシンのアイコンがあるのでクリック
  • 初めてVMを作成するときは以下の画面になるので作成 > Azure仮想マシンをクリック
  • 「基本」の設定タブからVMの詳細を入力します。基本的に最低限の構成としてます。また、Ubuntuは一応最新の24.04 LTSとしており、今のところ依存関係のトラブルは発生していないです。
  • ここでしれっとユーザー名が登録され、以後利用することになるので、ユーザー名は適切に設定のうえ忘れないようにしましょう。
  • ディスクの設定ですが、最低限のSSDで構成しました。
  • ネットワーク設定です。SSHを許可してください。
  • 管理設定です、ここで自動シャットダウンを有効にすることを強くお勧めします。
    • タイムゾーンを(UTC+09:00) 大阪、札幌、東京に設定のうえ、シャットダウンしたい時刻を入力してください。確実に寝てる時刻としておくとよいかと思います(私は深夜1時に設定)。
  • 他はそのままデプロイを実行すると「デプロイが完了しました」の旨のメッセージが出て、VMが利用できるようになります。
  • 【注意】デプロイ完了時にSSH秘密キー(.pemファイル)のダウンロード画面が表示されますので、これを無くさないように保存してください。
    • お左方として、以下のような具合でローカルディレクトリの配下に.sshフォルダを作り保存しておくのが一般的なようです
~/.ssh/xxx.pem

4. SSHの確立

デプロイしたVMは、まだコマンドラインでしか操作できません。SSHで接続し、Desktopやリモートデスクトップ等の必要資材をインストールします。

  • 前の手順で保存した.pemファイルのパスをコピーしておきます
  • 以下の画像を参考に、払出したVMのメニューから接続 > 接続 > ネイティブSSHを選択します
  • 一番上のセレクトボックスで接続元(今触っているPC)のOSを選択します。
  • 以下の操作はmacOS用であり、OSごとに異なりますが、画面の指示に従ってください。
  • 秘密キーのパスに、先ほどコピーした.pemファイルのパスを貼り付けます
  • ターミナルを起動し「chmodを使用して〜」のコマンドをコーピー&ペーストして実行します(初回接続時のみ)
  • 「指定された秘密キーを使用して〜」のコマンドをコピー&ペーストして実行すると、SSH接続が確立されます
    • なお、毎回この方法で接続するのは不便なので、~/.ssh/configを設定すると入力を省力化できます、必要なら調べてみてください。

5. リモートデスクトップ接続の構築

デスクトップをVMに導入の上、RDPで接続できる様にします。構築はこちらを参照しました↓
https://level69.net/archives/33102

Step1. Desktopの導入

SSHにて以下のコマンドを実行していきます。

  • パッケージ管理システムをアップデートのうえ、ubuntu-desktopを導入します。
    • desktopは他にも種類があるので、お好みで変更してください。
sudo apt update
sudo apt upgrade

sudo apt install ubuntu-desktop
  • xrdpというリモートデスクトップ接続用のパッケージを導入し、有効化します。
sudo apt install xrdp
sudo systemctl enable xrdp

Step2. 管理者権限の付与

RDPで接続後、接続したアカウントでsudoコマンドを実行したいので、接続するアカウントに管理者権限を付与します(auzreuserの部分はVMデプロイ時に設定したユーザー名に変更)

sudo gpasswd -a azureuser sudo

Step3. SSH接続終了(←忘れずに)

SSHによる操作はここで終了です。ちゃんとSSHを終了しておかないとRDP接続できないですが、忘れがちなので注意してください。

exit

Step4. ポートの穴あけ

VMに対してリモートデスクトップという「用途」での接続を許可するため、ポートの穴あけを行います。

  • 左側のメニューからネットワーク > ネットワーク設定を押下し、ポートルールの作成を押下
  • サービスのプルダウンからRDPを選択(3389が宛先ポートに追加されるはず)し、追加を押下。

Step5. RDP接続の設定

ようやくリモートデスクトップでの接続まで辿り着きました。筆者はAzureとの親和性がよさそうという安直な理由でWindows Appを用いていますが、他のクライアントでも接続の手順は同様と思われますので、お好みのものを用いてください。

  • App StoreでWindows Appを入手します
  • Azure Portalにて、今回構築しているVMの概要からパブリックIPアドレスを確認し、クリップボードにコピーします。
  • Windows Appを起動し、左側のメニューからDevicesを選択、右上の+ボタンからAdd PCを選択し押下。
  • PC nameに先ほどコピーしたVMのパブリックIPアドレスを貼り付け、以下必要な設定を行ったらAddを押下。
    • 必要に応じCredentialsにVMのユーザーIDとパスワードを登録しておくと、毎回の入力の手間が省けます。
    • また、RDPの画面表示や操作について色々いじれるので、気になる場合は調べながら調整してください。
  • 今後はWindows App起動時に表示される画面から追加したVMをダブルクリックするだけで、AVDに接続できます。

エラーが出る場合のチェック項目

  • SSHはちゃんと切断(exit)していますか?
  • VMを起動してから十分(5分ほど)時間が経っていますか?
    • 性能控えめなので、立ち上がり遅いです。

6. Python実行環境準備

Python実行環境を用意します。仮想環境を有効化しないとエラーで弾かれるので、まずは仮想環境を用意します。また、使いやすいのでJupyterLabも導入します。以下の操作はVMのターミナルから実行します。

  • ターミナルを起動します。一応以下に手順を記載します。
    • VMのデスクトップの左上のこのボタンをクリック、もしくはMacなら⌘キーを押下
    • 下にアプリ一覧が表示されるので、ターミナルをクリック
  • pipを導入します
sudo apt install python3-pip
  • 仮想環境を構築します。cuda_envは好きな名前に変えてください。
sudo apt install python3-venv
python3 -m venv cuda_env
source cuda_env/bin/activate # 仮想環境の有効化
pip3 install -U pip setuptools wheel
  • Jupyter labを導入します
pip3 install Jupyter
pip3 install jupyterlab

export PATH="$HOME/.local/bin:$PATH"
  • PyCUDAを導入します。
pip install PyCUDA
  • numpyがホストとGPU間のやり取りで必須なので、導入します
pip install numpy

7. CUDA環境の導入

CUDAドライバ・Toolkitを導入します。以下の操作はVMのターミナルから実行します。このページを参考にしました→
https://kottas.hatenablog.com/entry/2019/02/02/000000

  • 以下のコマンドで推奨ドライバを確認します
ubuntu-drivers devices
  • recommendedと表示されているドライバの番号(nvidia-driver-XXX)を確認します(以下の画像なら535)
  • 上記で調べたドライバの番号XXXを反映し、以下のコマンドでドライバをインストールします。
sudo apt install nvidia-driver-535
  • CUDAコードを実行するためにCUDA Toolkitを導入します。
sudo apt install nvidia-cuda-toolkit

8. 動作確認

超簡単な行列乗算プログラムを実行してみましょう。ノートブックでの実行例です。

  • 実験の準備をします。
import numpy as np
import pycuda.autoinit
import pycuda.driver as cuda
from pycuda.compiler import SourceModule

# CUDA kernalの定義
kernel_code = """
__global__ void MatrixMulKernel(
    float* M, float* N, float* P, int Width
    ){
        int row = blockIdx.y * blockDim.y + threadIdx.y;
        int col = blockIdx.x * blockDim.x + threadIdx.x;
        if ((row < Width) && (col < Width)) {
            float Pvalue = 0;
            for (int k = 0; k < Width; ++k) {
                Pvalue += M[row * Width + k] * N[k * Width + col];
            }
            P[row * Width + col] = Pvalue;
        }
    }
"""

# 行列のサイズ
Width = 4096
# ランダムな行列の生成
M = np.random.randn(Width, Width).astype(np.float32)
N = np.random.randn(Width, Width).astype(np.float32)

# 出力用の行列
P = np.zeros((Width, Width), dtype=np.float32)

# カーネル関数をコンパイルし格納
module = SourceModule(kernel_code)
matrix_mul_kernel = module.get_function("MatrixMulKernel")

# block sizeとgrid sizeを設定
block_size = 16
grid_size = int(np.ceil(Width / block_size))
  • GPUでの処理を実行します。処理時間の計測も行います。
%%time
matrix_mul_kernel(
    cuda.InOut(M), cuda.InOut(N), cuda.Out(P), np.int32(Width),
    block=(block_size, block_size, 1),
    grid=(grid_size, grid_size)
)
  • 比較様にnumpy(CPU)で同じ処理を行います。
%%time
P_cpu = np.dot(M, N)
  • 結果を比較し、GPUコードによる処理が適切に行われているか検証。
print("max error:", np.max(np.abs(P - P_cpu)))

実行結果は以下の様な具合になると思います。

CUDAカーネルは何も工夫していないものですが、高度にチューニングされているnumpyのCPU実行に勝っています、やったね!

7. まとめ

以上の手順で、手元にGPUマシンがなくてもCUDAプログラミングを実行できる環境が整いました。Google Colabと比較しさまざまなプロファイリングツールが使えるので、それらを駆使しながらPPMPの学習を進めたいと思います。

何か認識誤り等ありましたらご指摘頂けますと幸いです。

Discussion