並列コンピューティングを理解する: GPU と CPU を CUDA の役割とともに簡単に説明
導入
1996 年、NVIDIA は当初競合他社に遅れをとって 3D アクセラレータ市場に参入しました。しかし、絶え間ない学習と改善により、1999 年に GPU と呼ばれる最初のグラフィックス カードとして認識される GeForce 256 の導入により大きな成功を収めました。 GPU は当初ゲーム用に設計されましたが、後に数学、科学、工学の分野で数多くのビジネス アプリケーションに使用されるようになりました。
2003 年に、Ian Buck と彼のチームは、データ並列構造を組み込むことで C を拡張した、最初に広く受け入れられたプログラミング モデルである Brook を導入しました。バックはその後、NVIDIA で重要な役割を果たし、GPU 上の汎用コンピューティング用の最初の商用ソリューションである CUDA の 2006 年の立ち上げを主導しました。
CUDA は、Nvidia GPU と GPU ベースのアプリケーションの間の接続ブリッジとして機能し、TensorFlow や PyTorch などの一般的な深層学習ライブラリが GPU アクセラレーションを利用できるようにします。この機能はディープ ラーニング タスクを最適化するために非常に重要であり、現場で GPU を使用することの重要性を強調しています。現在、CUDA はあらゆる AI 開発に不可欠であると広く考えられており、あらゆる AI 開発パイプラインのソフトウェア コンポーネントです。
前提条件
基本的なコンピュータ アーキテクチャ
- CPU と GPU の概要とその主な機能を理解します。
- コア、スレッド、および計算の一般的な概念に精通していること。
-
並列処理の概要
- シリアル処理とパラレル処理の違いを理解します。
- 行列演算など、並列処理から恩恵を受けるタスクを認識します。
プログラミングの基礎
- Python や C/C++ などのプログラミング言語の基本的な知識。
- ループ、条件文、関数の経験。
CUDA の概要
- NVIDIA GPU での並列コンピューティングのフレームワークとしての CUDA についての高度な理解。
- 開発者が GPU 並列処理を利用するプログラムを作成できるようにする CUDA の役割を認識します。
並列コンピューティングとは何ですか?
簡単に言うと、並列コンピューティングは、単一の問題をより小さなチャンクに分割し、それぞれを同時に解決することで 1 つの問題を解決する方法です。並列コンピューティングでは、1 台の強力なコンピューターで 1 つの複雑なプロセスを完了させるのではなく、複数のコンピューターまたはプロセッサーを使用して、問題のさまざまな部分を同時に処理します。このコンサート アプローチにより、大規模なタスクを処理するプロセスが高速化され、タスクが効率的に処理されます。これは、何らかの目標を一緒に達成するために、同僚のチームがさまざまな任務を同時に処理するアプローチに似ています。小規模なワーカーを組み合わせることで、全体的な処理速度が飛躍的に向上します。
CUDA のより簡単な用語
Nvidia によって作成された CUDA または Compute Unified Device Architecture は、並列コンピューティング用のソフトウェア プラットフォームです。 2000 年代半ばにコンピューター グラフィックス、金融、データ マイニング、機械学習、科学技術コンピューティングなどのさまざまな分野で普及して以来、多くのビジネス上の問題で使用されてきました。 CUDA は、ほとんどのオペレーティング システムと互換性のある、専用のプログラミング言語を通じて高速コンピューティングを可能にします。
GPU と CPU の比較
CPU または中央処理装置は、サーバーまたはマシンの主要な計算ユニットとして機能します。このデバイスは、オペレーティング システムやアプリケーションのさまざまな計算タスクを実行することで知られています。 CPU は、コンピューター内で数学的および論理的な計算を実行する責任があります。このユニットの主な機能は、コードを実行し、ファイルのコピー、データの削除、ユーザー入力の処理などのタスクを処理することです。さらに、CPU はさまざまなコンピューター周辺機器間の通信の仲介者として機能し、それらが直接相互作用するのではなく CPU を経由することを保証します。
CPU はマルチタスクを実行できるように見えますが、CPU の各コアは一度に 1 つのタスクしか処理できません。各コアは独立した処理ユニットとして動作し、マルチタスクの能力はハードウェアのコアの数によって決まります。一般に、CPU あたり 2 ~ 8 コアあれば、素人が必要とするどのようなタスクにも十分対応できます。また、これらの CPU のパフォーマンスは非常に効率的であり、タスクが一度にではなく順番に実行されていることにも人間が気付かないほどです。 。これは、私たちが日常的に CPU を使用するほぼすべてのことに当てはまります。
一方、グラフィックス プロセッシング ユニット (GPU) は、CPU の汎用機能を超え、並列数学演算を効率的に処理できる特殊なハードウェア コンポーネントです。当初、GPU はゲームやアニメーションのグラフィックス レンダリング用に設計されましたが、現在では元の範囲を超えて幅広いタスクを実行できるように進化しています。ただし、どちらも特定のタスクを処理するように設計されたコンピューター ハードウェアです。
いくつかの生の数字を見てみましょう。最も先進的な消費者向け CPU システムには通常 16 コアが搭載されていると考えると、最も先進的な消費者向け GPU (Nvidia RTX 4090) には 16,384 個の CUDA コアが搭載されています。この違いは、18,432 個の CUDA コアを搭載した H100 を見るとさらに大きくなります。これらの CUDA コアは通常、個々の CPU コアよりも強力ではないため、直接比較することはできません。ただし、CUDA コアのボリュームを比較すると、CUDA コアが大量の計算を並行して処理するのに比較的理想的である理由がわかるはずです。
CPU と GPU を比較する場合、並列処理能力がある GPU のみに依存するのが得策のように思えるかもしれません。ただし、マルチタスク処理が常に最も効率的なアプローチであるとは限らないため、CPU の必要性は依然としてあります。また、GPU では単純すぎる一般的なコンピューティングにも CPU を使用します。特定のシナリオでは、タスクを順次実行する方が、並列処理よりも時間とリソースの効率が高くなります。 CUDA の利点は、特定のタスクに対して CPU 処理と GPU 処理をシームレスに切り替える機能にあります。この柔軟性により、プログラマはどのハードウェア コンポーネントをいつ使用するかを戦略的に決定できるため、コンピュータの動作に対する制御が強化されます。
GPUにおけるCUDAの役割
ターミナルに「nvidia-smi
」と入力すると、CUDA のバージョンと GPU 情報を確認できます。 Notebook セルでは、! を追加することでこれを行うことができます。行の先頭にあります。
!nvidia-smi
マシンに必要なものがすべてセットアップされていることを確認したら、Torch パッケージをインポートできます。また、Torch が適切にインストールされていることを確認し、CUDA と GPU を検出できることを確認するために使用できる優れた CUDA チェッカー機能もあります。
# import the necessary libraries
import torch
this line of code will true or false depending upon cuda availability
use_cuda = torch.cuda.is_available
この場合、「True」が返されます
または、
if torch.cuda.is_available():
device = torch.device('cuda')
else:
device = torch.device('cpu')
print("using", device, "device")
CUDA を使用すると、プログラマは、最新の GPU に存在する数千のコアを活用する並列アルゴリズムを設計および実装できます。この並列化は、科学研究、機械学習、ビデオ編集、データ処理などの計算量の多いタスクにとって非常に重要です。 CUDA は、開発者が GPU 上で直接実行されるコードを記述できるようにするプログラミング モデルと API セットを提供し、従来の CPU ベースのコンピューティングと比較して大幅なパフォーマンス向上の可能性を解き放ちます。 CUDA は、並列化可能なワークロードを GPU にオフロードすることで、GPU の計算能力を強化し、ハイパフォーマンス コンピューティング アプリケーションの進歩を推進する上で中心的な役割を果たします。
ソース
スピードテスト
cuda のバージョンと GPU に関する情報を取得してみましょう。
if device:
print('__CUDA VERSION:', torch.backends.cudnn.version())
print('__Number CUDA Devices:', torch.cuda.device_count())
print('__CUDA Device Name:',torch.cuda.get_device_name(0))
print('__CUDA Device Total Memory [GB]:',torch.cuda.get_device_properties(0).total_memory/1e9)
CUDA バージョン: 8302 __CUDA デバイスの数: 1 __CUDA デバイス名: NVIDIA RTX A4000 __CUDA デバイスの合計メモリ [GB]: 16.89124864
CPU と GPU のパフォーマンスを比較するために 3 つの速度テストを実施します。さらに、4 番目のテストでは、安定拡散を使用して合成データセットを生成し、A4000 GPU がタスクを正常に完了できる速度を測定します。
このデモを作成するために、NVIDIA RTX A4000 を使用することにしました。このデモは、どの GPU または CPU マシンでも動作するはずです。
マトリックスディビジョン
以下の Python コードは、CPU と GPU の両方を使用して行列除算を実行し、各デバイスでの演算にかかる時間を測定します。
このコードはランダムな行列を作成し、CPU 上で操作を実行し、その行列を GPU に転送して、GPU 上で同じ操作にかかる時間を測定します。 GPU のより正確なタイミング結果を得るために、ループはこのプロセスを 5 回繰り返します。 torch.cuda.synchronize() は、時間を測定する前に GPU 計算が完了していることを確認します。
import time
matrix_size = 43*15
create random matrix
x = torch.randn(matrix_size, matrix_size)
y = torch.randn(matrix_size, matrix_size)
print("######## CPU SPEED ##########")
start = time.time()
result = torch.div(x,y)
print(time.time() - start)
print("verify device:", result.device)
x_gpu = x.to(device)
y_gpu = y.to(device)
torch.cuda.synchronize()
for i in range(5):
print("######## GPU SPEED ##########")
start = time.time()
result_gpu = torch.div(x_gpu,y_gpu)
print(time.time() - start)
print("verify device:", result_gpu.device)
ご覧のとおり、GPU では CPU よりも計算が大幅に高速でした。
人工ニューラルネットワークを構築する
以下の Python コードは、CPU と GPU の両方を使用して単純なニューラル ネットワーク モデルを構築し、基本的な速度テストを示します。
import tensorflow as tf
import time
Generate random data
data_size = 10000
input_data = tf.random.normal([data_size, data_size])
Define a simple neural network model
model = tf.keras.Sequential([
tf.keras.layers.Dense(1000, activation='relu', input_shape=(data_size,)),
tf.keras.layers.Dense(1000, activation='relu'),
tf.keras.layers.Dense(1)
])
Compile the model
model.compile(optimizer='adam', loss='mse')
Function to test the speed of CPU and GPU
def speed_test(device):
with tf.device(device):
start_time = time.time()
model.fit(input_data, tf.zeros(data_size), epochs=1, batch_size=32, verbose=0)
end_time = time.time()
return end_time - start_time
Test CPU speed
cpu_time = speed_test('/CPU:0')
print("Time taken on CPU: {:.2f} seconds".format(cpu_time))
Test GPU speed
gpu_time = speed_test('/GPU:0')
print("Time taken on GPU: {:.2f} seconds".format(gpu_time))
畳み込みニューラル ネットワーク (CNN) を構築する
以下のコードは、TensorFlow を使用して MNIST データセット上で畳み込みニューラル ネットワーク (CNN) をトレーニングします。 speed_test
関数は、CPU と GPU の両方でトレーニングにかかった時間を測定し、パフォーマンスを比較できるようにします。
import tensorflow as tf
from tensorflow.keras import layers, models
import time
Load MNIST dataset
(train_images, train_labels), (test_images, test_labels) = tf.keras.datasets.mnist.load_data()
train_images = train_images.reshape((60000, 28, 28, 1)).astype('float32') / 255
test_images = test_images.reshape((10000, 28, 28, 1)).astype('float32') / 255
Define a simple CNN model
model = models.Sequential()
model.add(layers.Conv2D(32, (3, 3), activation='relu', input_shape=(28, 28, 1)))
model.add(layers.MaxPooling2D((2, 2)))
model.add(layers.Conv2D(64, (3, 3), activation='relu'))
model.add(layers.MaxPooling2D((2, 2)))
model.add(layers.Conv2D(64, (3, 3), activation='relu'))
model.add(layers.Flatten())
model.add(layers.Dense(64, activation='relu'))
model.add(layers.Dense(10, activation='softmax'))
Compile the model
model.compile(optimizer='adam',
loss='sparse_categorical_crossentropy',
metrics=['accuracy'])
Function to test the speed of CPU and GPU
def speed_test(device):
with tf.device(device):
start_time = time.time()
model.fit(train_images, train_labels, epochs=5, batch_size=64, validation_data=(test_images, test_labels), verbose=0)
end_time = time.time()
return end_time - start_time
Test CPU speed
cpu_time = speed_test('/CPU:0')
print("Time taken on CPU: {:.2f} seconds".format(cpu_time))
Test GPU speed
gpu_time = speed_test('/GPU:0')
print("Time taken on GPU: {:.2f} seconds".format(gpu_time))
安定した拡散を備えた合成感情データセットを作成する
次に、怒り、悲しみ、孤独、幸せなどのさまざまな感情の画像を 10 枚作成して、安定拡散を使用して合成データセットを作成してみます。データセットを再作成するには、以下の手順に従ってください。
以下のコードには GPU が必要であることに注意してください
まず、必要なライブラリをインストールする必要があります。
!pip install --upgrade diffusers transformers scipy
!pip install --quiet ipyplot
上記のライブラリをインストールしたら、必ずカーネルを再起動してください。再起動しないと機能しない可能性があります。
必要なパッケージをインストールし、事前トレーニング済みモデルのモデル ID を指定します。
文字列「cuda」を変数 device
に割り当てます。これは、コードが計算に CUDA 対応 GPU を使用することを意図していることを示します。
import torch
from torch import autocast
from diffusers import StableDiffusionPipeline
import ipyplot
import random
import os
import time
import matplotlib.pyplot as plt
model_id = "CompVis/stable-diffusion-v1-5"
device = "cuda"
変数 model_id
で指定された事前トレーニング済みモデルをロードして、StableDiffusionPipeline
クラスのインスタンスを作成します。 from_pretrained
メソッドは、モデルをインスタンス化し、利用可能な場合は事前トレーニングされた重みを読み込むために、深層学習フレームワークで一般的に使用されます。
pipe = StableDiffusionPipeline.from_pretrained(model_id)
pipe = pipe.to(device)
画像を保存するための特定のフォルダーを作成します。
os.makedirs('/notebooks/happy', exist_ok=True)
os.makedirs('/notebooks/sad', exist_ok=True)
os.makedirs('/notebooks/angry', exist_ok=True)
os.makedirs('/notebooks/surprised', exist_ok=True)
os.makedirs('/notebooks/lonely', exist_ok=True)
次のコード行では、StableDiffusionPipeline
を使用して、さまざまな感情や性別に応じた画像を生成します。これをループで実行し、感情ごとに 10 枚の画像を作成します。
# create different ethnic groups images
genders = ['male', 'female']
Create a dictionary that contains different emotions as keys, and the corresponding facial expressions as values.
emotion_prompts = {'happy': 'smiling',
'surprised': 'surprised, opened mouth, raised eyebrows',
'sad': 'frowning, sad face expression, crying',
'angry': 'angry, fierce, irritated',
'lonely': 'lonely, alone, lonesome'}
print("######## GPU SPEED ##########")
start = time.time()
loop through each emotions and create different images based on the prompts
for j in range(10):
for emotion in emotion_prompts.keys():
emotion_prompt = emotion_prompts[emotion]
gender = random.choice(genders)
prompt = 'Medium-shot portrait of {}, {}, front view, looking at the camera, color photography, '.format(gender, emotion_prompt) + \
'photorealistic, hyperrealistic, realistic, incredibly detailed, crisp focus, digital art, depth of field, 50mm, 8k'
negative_prompt = '3d, cartoon, anime, sketches, (worst quality:2), (low quality:2), (normal quality:2), lowres, normal quality, ((monochrome)), ' + \
'((grayscale)) Low Quality, Worst Quality, plastic, fake, disfigured, deformed, blurry, bad anatomy, blurred, watermark, grainy, signature'
image = pipe(prompt=prompt, negative_prompt=negative_prompt).images[0]
image.save('/notebooks/{}/{}.png'.format(emotion, str(j).zfill(4)))
print(time.time() - start)
次に、コードを実行して、A4000 GPU 速度でタスクにかかる時間を確認し、わずかな変更を加えて CPU 速度と比較してみましょう。
次に、パイプラインを CPU に配置するには、同じコードを実行する前に次のスニペットを使用するだけです。
pipe.to('cpu')
これにより、以下に示す CPU 時間が得られます。
見てわかるように、CPU は大幅に遅くなりました。これは、コンピューターでは画像が数値の配列として表現され、GPU で多数の並列プロセスを実行する方がはるかに効率的であるためです。
結果
このブログ投稿からのすべての分析の概要を次に示します。これらすべてのデータ操作および機械学習タスクにおいて、GPU は一貫して高速でした。
スピードテスト
Tasks | GPU | CPU |
---|---|---|
Matrix Operation | 5.8e-05(avg) | 0.00846 |
ANN | 2.78 | 23.30 |
CNN | 48.31 | 167.68 |
Stable Diffusion | 121.03 | 3153.04 |
結論
CUDA と NVIDIA GPU の組み合わせは、さまざまなアプリケーション ドメイン、特にディープ ラーニングの分野で支配的な地位を占めています。この組み合わせは、世界のいくつかのスーパー コンピューターに電力を供給するための基礎として機能します。
CUDA と NVIDIA GPU は、ディープ ラーニング、データ サイエンスと分析、ゲーム、金融、研究などの業界を成功裏に強化してきました。たとえば、ディープ ラーニングは高速コンピューティング、特に GPU や TPU などの特殊なハードウェアに大きく依存しています。
GPU を使用すると、トレーニング プロセスが大幅に加速され、数か月から 1 週間に短縮されます。 TensorFlow、PyTorch などのさまざまなディープ ラーニング フレームワークは、GPU サポートの CUDA とディープ ニューラル ネットワークの計算の cuDNN に依存しています。これらの基盤となるテクノロジーが向上すると、パフォーマンスの向上はフレームワーク間で共有されますが、複数の GPU およびノードに対するスケーラビリティにはフレームワーク間に差が存在します。
要約すると、ディープ ラーニングや AI 用の GPU を選択する際には、次のことが言えます。タスクで留意すべき点の 1 つは、GPU が CUDA をサポートしている必要があるということです。
記事をお読みいただければ幸いです。
参考文献
- 合成データを生成するためのコード リファレンス
- GPU コンピューティング能力
- CUDAとは何ですか?