AI時代のためのGPUサバイバルツールキット
(journal.hexmos.com)- AI開発では、もはやCPU的な逐次実行だけでは十分ではなく、GPUの大規模並列処理モデルを理解してこそ、学習・推論性能を適切に扱える
- CPUは一般的な消費者向けでは2〜16個のコアを備え、単一スレッドや条件分岐を伴う処理に強く、GPUは数千個の小さなコアにより、行列演算・画像処理・ディープラーニングに有利
- AWSはP3/P4、P5/Inf1、G4、Amazon SageMakerのようなGPU実行環境を提供しており、p3.2xlargeは1時間あたり$3.06、p5.48xlargeは$98.32、g4dn.xlargeは$0.526程度
- NVIDIA CUDAは、GPUメモリ割り当て、データコピー、カーネル実行、コンパイルまで続く並列実行フローを開発者が直接扱えるようにする
- 配列加算、Mandelbrot生成、猫・犬分類CNNの例は、逐次ループをGPUスレッドに分割する方法を示しており、MandelbrotはCPUの4.07秒からGPUの0.0046秒へ短縮される
CPUの知識だけでは不十分な理由
- 多くの開発者は学習と問題解決をCPU中心の方法で身につけてきたが、CPUは基本的に逐次アーキテクチャに依存して動作する
- 従来のCPUは命令を線形に実行し、強力な少数のコアを単一スレッド性能に合わせて最適化する
- 複数の作業を同時に処理しなければならない状況では、逐次実行方式のため、各作業を順番に処理するコストが大きくなる
- マルチスレッディングで性能を高めることはできるが、CPUの基本的な設計思想はいまなお逐次実行に近い
AIモデルと並列処理
- Transformerのような現代のAIアーキテクチャは並列処理を活用して学習性能を高める
- RNNは逐次的に動作するが、GPTのようなTransformerは複数の単語を同時に処理できるため、学習効率とモデルの能力を高められる
- 並列学習はより大きなモデルを可能にし、より大きなモデルはより良い出力を生み出す基盤となる
- 並列性は自然言語処理だけでなく画像認識にも適用される
- AlexNetは、画像の複数の部分を同時に処理してパターンを識別する例である
- CPUは単一スレッド性能中心の設計のため、複雑なAIモデルに必要な大量の並列計算を効率よく分散・実行するのが難しい
GPUがボトルネックを減らす仕組み
- GPUはCPUの大きく強力なコアの代わりに、小さく特化したコアを多数使う構造で設計されている
- グラフィックスレンダリングや複雑な数学計算のように、同種の演算を大量に繰り返すワークロードでGPUの並列性がよく発揮される
- TensorFlowのようなディープラーニングフレームワークは、GPU性能を活用してモデルの学習と推論を高速化するよう最適化されている
- ニューラルネットワークの学習には多くの行列演算が含まれ、GPUは多数のコアでこうした演算を並列化するのに強い
CPUとGPUの役割の違い
-
CPU
- CPUは逐次処理に重点を置いて設計されており、1つの命令フローを線形に実行する作業に強い
- 汎用コンピューティング、システム処理、条件分岐を含む複雑なアルゴリズム処理に適している
- 消費者向けCPUは通常、2〜16個のコアという比較的少ないコア数を持つ
- 各コアは自身の命令セットを独立して処理できる
-
GPU
- GPUは並列アーキテクチャとして設計されており、多くのサブタスクを同時に処理するのに効率的である
- グラフィックスレンダリング、複雑な数学計算、並列化可能なアルゴリズム実行に有利である
- 作業をより小さな並列単位に分け、複数の演算を同時に処理する
- GPUコアは数千個に達することが多く、streaming multiprocessors(SMs)または類似の構造で構成される
- 画像・動画処理、ディープラーニング、科学シミュレーションのように大量のデータを同時に扱う作業に適している
AWSで選べるGPU環境
- AWSは機械学習のような作業に使えるさまざまなGPUインスタンスを提供している
-
汎用GPUインスタンス
-
推論最適化インスタンス
-
グラフィックス最適化インスタンス
- G4 instancesは、グラフィックス負荷の高い作業を処理するよう設計されている
- ビデオゲーム開発者はG4インスタンスでゲーム向け3Dグラフィックスをレンダリングできる
- g4dn.xlargeは1時間あたり**$0.526**で、16GBメモリのNVIDIA T4 GPUを1基使用する
-
マネージド機械学習サービス
- Amazon SageMakerは機械学習向けのマネージドサービスで、P3、P4、P5のようなGPUベースインスタンスへのアクセスを提供する
- SageMakerは、基盤インフラを直接管理せずに機械学習を始めたい組織に適している
- Amazon SageMaker料金ドキュメントが別途提供されている
NVIDIA CUDAの基本的な使い方
- CUDAはNVIDIAが開発した並列コンピューティングプラットフォーム兼プログラミングモデルであり、GPUアクセラレータを活用してアプリケーションを高速に実行できるようにする
- 例では、GPUメモリ割り当て、データコピー、カーネル実行、結果取得へと続くCUDA開発フローを示している
-
インストールの流れ
- CUDAからbase installerとdriver installerをダウンロードする
- ホームフォルダの
.bashrcに次の環境変数を追加するexport PATH="/usr/local/cuda-12.3/bin:$PATH"export LD_LIBRARY_PATH="/usr/local/cuda-12.3/lib64:$LD_LIBRARY_PATH"
- 次のコマンドを実行する
sudo apt-get install cuda-toolkitsudo apt-get install nvidia-gds
- 変更を適用するためにシステムを再起動する
-
便利な確認コマンド
lspci | grep VGA: システムのGPUを識別して一覧表示するnvidia-smi: NVIDIA GPUの使用率、温度、メモリ使用量などの詳細情報を提供するsudo lshw -C display: グラフィックスカードなどのディスプレイコントローラ情報を提供するinxi -G: GPUとディスプレイを含むグラフィックスサブシステム情報を表示するsudo hwinfo --gfxcard: システムのグラフィックスカードの詳細情報を確認するために使う
CUDAで配列加算を並列化する
- 配列加算はGPU並列化を説明するのに適した問題である
- 例の配列は
A = [1,2,3,4,5,6]、B = [7,8,9,10,11,12]で、結果はC = [8,10,12,14,16,18]である - CPU方式では、配列の要素を1つずつ巡回しながら加算を行う
- データが増えると逐次方式の時間が増え、GPUは
1+7、2+8、3+9のような演算を同時に実行できる - CUDAの例では
.cuカーネルファイルを使用する__global__はGPUで呼び出されるカーネル関数を表すvectorAddはa、b、cの3つの整数ポインタを受け取り、ベクトル加算を行うthreadIdx.xは現在のスレッドのインデックスを取得する- 各スレッドは対応する要素の和を
c[i]に保存する
main関数はGPUメモリ割り当て、データコピー、カーネル実行、結果コピーの順で進むcudaMallocでcudaA、cudaB、cudaCのメモリをGPUに割り当てるcudaMemcpyでa、bをhostからGPUへコピーするvectorAdd <<<1, sizeof(a) / sizeof(a[0])>>>でカーネルを実行する- 結果ベクトル
cudaCをGPUからhostへコピーする
- コンパイルと実行には
nvccコマンドを使用する - 全コードが提供されている
Pythonの画像生成でGPUを活用する
- Mandelbrot set生成は、特定の方程式における数値の挙動を基に複雑な視覚パターンを作る作業であり、リソース集約的である
- CPUベースのPython例では各ピクセルを巡回しながらMandelbrot値を計算し、1024×1536画像の生成に4.07秒かかる
- GPUアクセラレーション版はNumba libraryを使用する
@jitデコレータはPythonコードを機械語に変換するJust-In-Timeコンパイルを行うcuda.jitでmandel_gpuを作り、device=Trueを指定してGPU上で実行されるようにするmandel_kernelはCUDA GPU上で実行され、GPUスレッドにMandelbrot生成作業を分割する
create_fractal_gpuはGPUメモリ割り当て、スレッド・ブロック設定、GPUカーネル実行、同期、結果コピーを行うthreadsperblock = (16, 16)を使用するcuda.synchronize()でGPU処理の完了を待つd_image.copy_to_host(image)で結果をCPU側へコピーする
- GPU実行時間は0.0046秒で、CPUベースのコードよりはるかに高速に実行される
- 全コードが提供されている
GPUで猫・犬分類ニューラルネットワークを学習する
- GPUがAIでどのように使われるかを示すため、猫と犬を区別するニューラルネットワークの例が使われている
- 事前準備項目はCUDAとTensorFlowである
- TensorFlowは
pip install tensorflow[and-cuda]でインストールできる - データセットはKaggle Dogs vs. Catsを使用する
- ダウンロード後、猫と犬の画像を学習フォルダ内の別々のサブフォルダに整理する
- TensorFlowは
- モデルは畳み込みニューラルネットワーク(CNN)を使用する
- pandasとnumpyはデータ操作に使用する
Sequentialはニューラルネットワークのレイヤーを線形に積み重ねるために使うConvolution2D、MaxPooling2D、Dense、FlattenはCNN構成レイヤーであるImageDataGeneratorは学習中のリアルタイムデータ拡張に活用される
- 学習データは
ImageDataGeneratorでロードされる- 学習データには
rescale=1./255、shear_range=0.2、zoom_range=0.2、horizontal_flip=Trueが適用される - 入力画像は
(64, 64)サイズ、バッチサイズ32、二値分類モードに設定される
- 学習データには
- CNN構造は畳み込み、最大プーリング、フラット化、Denseレイヤー、sigmoid出力で構成される
- モデルは
adamオプティマイザ、binary_crossentropy損失、accuracy指標でコンパイルされる - 学習は
epochs=25、validation_steps=2000で実行され、classifier.save('trained_model.h5')で.h5ファイルに保存される - 推論コードは
trained_model.h5をロードして画像を(64, 64)に変換し、予測値が0.5以上ならdog、そうでなければcatと出力する - 全コードが提供されている
GPU活用の範囲
- AI時代にはGPU機能を無視することは難しく、開発者はGPUの能力をよりよく理解する必要がある
- 逐次アルゴリズムから並列化されたアルゴリズムへ移行するなかで、GPUは複雑な計算を高速化する道具になる
- GPUの並列処理能力は、AIと機械学習タスクにおける大規模データセットや複雑なニューラルネットワークアーキテクチャの処理に特に有利である
- GPUは従来の機械学習領域を超え、科学研究、シミュレーション、データ集約型作業にも使われる
- 並列処理能力は、創薬、気候モデリング、金融シミュレーションのようなさまざまな分野の問題解決に活用される
1件のコメント
Hacker Newsのコメント
この記事のコードは間違っている。CUDAカーネルがまったく呼び出されていない: https://github.com/RijulTP/GPUToolkit/blob/f17fec12e008d0d37...
JITコンパイルされたコードでMandelbrot集合を「計算」する時間の90%は、実際の計算ではなく関数のコンパイルに使われている
CUDAをきちんと学びたいなら、行列乗算の実装がよい練習になる。参考になるチュートリアルは https://cnugteren.github.io/tutorial/pages/page1.html と https://siboehm.com/articles/22/CUDA-MMM
32ビット浮動小数点ベクトルXとY、スカラーAを受け取り、各X[i]にAを掛けてからY[i]に加える: https://developer.nvidia.com/blog/six-ways-saxpy/
「すべての開発者が知るべき」と主張しているが、実際にはAIでGPUが使われる方法を扱った記事に近い。大半の開発者はAI開発者ではなく、AIと直接やり取りしたりGPUを直接使ったりもしない
さらに、GPUが存在するようになった中核的な理由である3Dグラフィックスはほとんど扱っていない
基本知識があれば、マネージャーに売り込まれる「AI」の話もよりよく理解できる
「隣接分野は必要ない」という態度は、学校でよく見かけたものだった。システム管理の側では同期たちがプログラミングを知らなくてもよいと言っていたが、実際にはスクリプティングが必要だったし、ソフトウェア開発の学校ではネットワークを知らなくてもよいと言っていたが、数年後には求人票にDevOpsが広く登場した
記事がおよそ1500語なら、勉強するつもりで読んでも12分ほどで、コード例を実行してみて2時間ほど使ったとしても大きな投資ではない。もちろん、その記事がよい入門書であるという前提は必要だ
curlで送る方法を知らないことを親しみを込めてからかっていたのを覚えている。今も組み込み開発者だが、その後バックエンド、フロントエンド、インフラをかなり学んだ。今後数年、業界全体でAIをめぐって似たような状況が起きる可能性は高そうだAIでPythonが支配的な理由は、Python-Cの関係がCPU-GPUの関係に似ているからだと思う
GPUは性能が非常に高いが直接コーディングするのが難しいため、人々はPyTorchのような高レベルAPI呼び出しでGPUを扱う
Cも性能は高いがコーディングが難しいため、PythonをCの上の抽象化レイヤーとして使う
人々がGPUをそこまで深く理解すべきかは明らかではない。AIの学習や運用の深部に入り込む場合でなければなおさらだし、Mooreの法則が終わってマルチスレッディングが速度向上の主な手段になれば、並列プログラミングのパラダイムに合わせた新しい言語が出てくる可能性は高い。Mojoがその出発点のように見える
単純な反復計算から、すべての命令が裏側でインテリジェントにすべてのCPUコアを並列活用し、可能な作業はGPUに渡すように設計される、といった形だ
こうした試みがすでにあったのか、そもそも可能なのか気になる
「CPUは複数のタスクに遭遇すると、各タスクを1つずつ処理するようにリソースを配分する」という説明は単純すぎる。CPUがまだその程度に単純だったらいいのに、と思ってしまうほどだ
記事がプログラミングモデルに焦点を当てるのは妥当だが、性能の観点で「CPUは命令を順次実行する」というのは基本的に間違っている。パイプラインは命令を並列実行するし、SIMDもあり、複数のコアが同じ問題を一緒に処理することもできる
大きな違いは、CPUが1つのスレッドを効率的に実行するために制御フロー処理へ多くのシリコンと電力を使う一方で、GPUはそのリソースをより多くの計算ユニットに使い、多数のスレッドを実行して制御フローとメモリ遅延を隠す点にある
CPUはシリアルコードに向いていてGPUはパラレルコードに向いている、という言い方はある程度正しいものの、かなり粗い近似です。数百ワット程度の同じような電力予算を想定すると、CPUには独立したタスクを1つずつ、ハイパースレッドまで含めて実行する「コア」が約100個あり、分岐予測とパイプライン化でメモリ遅延を隠します
GPUには「計算ユニット」が約100個あり、各ユニットは独立したタスク約80個を交互に実行し、別のタスクの次の命令を実行することでメモリ遅延を隠します
用語はかなり混乱していますし、CPUには256ビット幅のベクトルユニットが、GPUには2048ビット幅のベクトルユニットがある可能性が高いですが、少し離れて見ると両アーキテクチャはかなり似て見えます
名前はXeon Chiと呼べばよさそうです
ほとんどのプログラミング言語がCPUのような逐次処理に合わせて設計されている一方で、Erlang/ElixirはGPUのように並列性に合わせて設計されていると見るなら、Nx / Axonが伸びるのか気になります: https://github.com/elixir-nx/
購入ガイドが必要です。最低いくら必要なのか、予算帯ごとの最善の選択肢は何なのか知りたいです。問題は、その情報が時々変わることで、継続的に最新化されている資料があるのか分かりません
https://colab.google/
https://www.kaggle.com/docs/notebooks
https://www.paperspace.com/gradient/free-gpu
また「すべての開発者が知っておくべき」系のクリックベイト記事に戻ってきたのか
複雑さに正面から向き合うのが好きですし、コンピュータハードウェアのような分野における定量的な方法と定性的な細部の両方をある程度知っているので、ある分野の細部をきちんと教えてくれる記事は歓迎です
例えば「What every programmer should know about memory」をすべてのプログラマーが知るべきかは別として、優れたプログラマーならコンピュータが実際にどう動くのかについて感覚を持っているべきです。その記事から得られる核心である局所性は、速く、追いやすく、問題に合った良いコードの中で、しばしば自然に現れます
良い記事ですが、AWS P5インスタンスはP4d、P4deと同様、推論ではなく学習向けに明確に最適化されています。推論により適したインスタンスタイプは、それぞれT4とA10G GPUを使うG4dnとG5です
GPUプログラミングはほぼ初めてですが、この記事は面白く読めました。簡単な「犬か猫か」のニューラルネットワークを、これほど簡単に学習できるようになるまで進歩したことに驚きます