GPU計算の三銃士シリーズ 第1回
「CUDAをインストールしてください」
ディープラーニングのチュートリアルを始めると、真っ先にこの指示に出会う。言われるがままにインストールするけど、そもそもCUDAって何なのか?なぜGPUで計算するのにこれが必要なのか?
今回は、現代のAI開発に欠かせない「CUDA」の正体を徹底解説する。
TL;DR(忙しい人向けまとめ)
- CUDA = Compute Unified Device Architecture
- NVIDIAが2007年にリリースした並列コンピューティングプラットフォーム
- GPUを「絵を描く専用機」から「汎用計算機」に変えた革命的技術
- PyTorch、TensorFlowなどすべてのGPU対応AIフレームワークの土台
1. CUDAとは何か
公式定義
CUDAは「Compute Unified Device Architecture」の略で、NVIDIAが開発した並列コンピューティングプラットフォームおよびプログラミングモデルだ。
"CUDA (Compute Unified Device Architecture) is a proprietary parallel computing platform and application programming interface (API) that allows software to use certain types of graphics processing units (GPUs) for accelerated general-purpose processing, significantly broadening their utility in scientific and high-performance computing."
「CUDA(Compute Unified Device Architecture)は、NVIDIAが開発した独自の並列コンピューティングプラットフォームおよびAPIであり、特定のグラフィックスプロセッシングユニット(GPU)を汎用処理の高速化に使用できるようにし、科学計算やハイパフォーマンスコンピューティングにおけるGPUの活用範囲を大幅に広げた。」
— Wikipedia "CUDA" (https://en.wikipedia.org/wiki/CUDA)
ちょっと硬い定義だけど、要するに「GPUで普通のプログラムを動かすための仕組み」だ。
GPUは本来「絵を描く機械」だった
歴史を振り返ると、GPUの本来の仕事は「画面に絵を描くこと」だ。ゲームのグラフィックス、動画の再生、ウィンドウの描画。これらはすべて「大量のピクセルを同時に計算する」処理であり、GPUはそのために設計された。
ところが2000年代初頭、一部の研究者たちが気づいた。「この大量並列処理能力、グラフィックス以外にも使えるんじゃないか?」
NVIDIAの公式ドキュメントはこう述べている:
"In November 2006, NVIDIA® introduced CUDA®, a general purpose parallel computing platform and programming model that leverages the parallel compute engine in NVIDIA GPUs to solve many complex computational problems in a more efficient way than on a CPU."
「2006年11月、NVIDIAはCUDAを発表した。これはNVIDIA GPUの並列計算エンジンを活用し、多くの複雑な計算問題をCPUよりも効率的に解決するための汎用並列コンピューティングプラットフォームおよびプログラミングモデルである。」
— CUDA C++ Programming Guide (https://docs.nvidia.com/cuda/cuda-c-programming-guide/)
2. CUDAの歴史
始まりはスタンフォード大学
CUDAの起源は、スタンフォード大学の大学院生Ian Buckの研究に遡る。彼は「Brook」というGPU上で汎用計算を行うためのプログラミング言語を開発していた。
"The origins of CUDA trace back to the early 2000s, when Ian Buck, a computer science Ph.D. student at Stanford University, began experimenting with using GPUs for purposes beyond rendering graphics."
「CUDAの起源は2000年代初頭に遡る。スタンフォード大学のコンピュータサイエンス博士課程学生だったIan Buckが、グラフィックスレンダリング以外の目的でGPUを使う実験を始めたのがきっかけだ。」
— Wikipedia "CUDA" (https://en.wikipedia.org/wiki/CUDA)
2004年、NVIDIAはBuckを採用し、Brookの発展形としてCUDAの開発を開始。そして2007年、CUDAは正式にリリースされた。
2015年以降:AIブームとの融合
CUDAは当初、科学計算や物理シミュレーションなどに使われていた。しかし2015年頃から、ディープラーニングの爆発的な普及とともに、CUDAの重要性は飛躍的に高まった。
なぜか?ディープラーニングの計算は、本質的に「大量の行列演算」だからだ。これはまさにGPUの得意分野であり、CUDAはその能力を引き出すための鍵となった。
3. なぜGPUで計算するのか?
CPUとGPUの設計思想の違い
CPUとGPUの違いを一言で言うと:
- CPU = 少数精鋭の優等生(複雑な処理を順番にこなす)
- GPU = 大人数の作業員(単純な処理を大量に並列実行)
CPUは「分岐予測」「投機的実行」など、複雑な処理を高速化するための仕組みが満載だ。一方GPUは、同じような単純な計算を何千ものコアで同時に実行することに特化している。
具体例:行列の加算
1000×1000の行列AとBを足し算することを考えよう。
CPUの場合:
for i in range(1000):
for j in range(1000):
C[i][j] = A[i][j] + B[i][j]
100万回のループを順番に実行する。
GPUの場合:
100万個のスレッドを起動し、各スレッドが1つの要素を担当。全員が「同時に」計算を終える。
理論上、GPUは100万倍速い...というわけではないが、適切な問題では数十倍〜数百倍の高速化が実現する。
4. CUDAのプログラミングモデル
スレッド・ブロック・グリッド
CUDAプログラミングの基本単位は「スレッド」だ。このスレッドが階層的に組織されている。
Grid(グリッド)
├── Block 0(ブロック)
│ ├── Thread 0
│ ├── Thread 1
│ └── ...
├── Block 1
│ ├── Thread 0
│ ├── Thread 1
│ └── ...
└── ...
- Thread(スレッド): 最小の実行単位
- Block(ブロック): スレッドのグループ。同じブロック内のスレッドは「共有メモリ」を使って協調できる
- Grid(グリッド): ブロックのグループ。1つのカーネル(GPU関数)の実行単位
"Together, these three abstractions encourage the expression of programs in a way that scales transparently as GPU devices scale in their parallel execution resources."
「これら3つの抽象化により、GPUデバイスの並列実行リソースがスケールするのに応じて、プログラムも透過的にスケールする形で記述することが促される。」
— GPU Glossary (https://modal.com/gpu-glossary/device-software/cuda-programming-model)
カーネル(Kernel)とは
CUDAでGPU上で実行される関数を「カーネル」と呼ぶ。C++に似た構文で書ける。
// カーネル定義
__global__ void addVectors(float *a, float *b, float *c, int n) {
int i = blockIdx.x * blockDim.x + threadIdx.x;
if (i < n) {
c[i] = a[i] + b[i];
}
}
// カーネル呼び出し
addVectors<<<numBlocks, threadsPerBlock>>>(d_a, d_b, d_c, n);
<<<numBlocks, threadsPerBlock>>> という独特の構文で、何個のブロック・スレッドを使うかを指定する。
5. CUDAのメモリ階層
GPUには複数種類のメモリがあり、それぞれ速度とサイズが異なる。
| メモリ種類 | 速度 | サイズ | スコープ |
|---|---|---|---|
| レジスタ | 最速 | 最小 | スレッド固有 |
| 共有メモリ | 高速 | 小 | ブロック内共有 |
| L1/L2キャッシュ | 中速 | 中 | 自動管理 |
| グローバルメモリ | 低速 | 大 | 全スレッドからアクセス可 |
パフォーマンス最適化の鍵は、この階層を意識したメモリアクセスパターンだ。グローバルメモリへのアクセスは遅いので、できるだけ共有メモリを活用する。
"Shared memory – CUDA exposes a fast shared memory region that can be shared among threads. This can be used as a user-managed cache, enabling higher bandwidth than is possible using texture lookups."
「共有メモリ – CUDAはスレッド間で共有できる高速な共有メモリ領域を公開している。これはユーザー管理のキャッシュとして使用でき、テクスチャルックアップよりも高い帯域幅を実現できる。」
— Wikipedia "CUDA" (https://en.wikipedia.org/wiki/CUDA)
6. CUDA Toolkitの構成
CUDAをインストールすると、様々なツールとライブラリが一緒に入ってくる。
主要コンポーネント
| コンポーネント | 役割 |
|---|---|
| nvcc | CUDAコンパイラ。.cuファイルをコンパイル |
| CUDA Runtime | 実行時ライブラリ |
| cuBLAS | 線形代数ライブラリ(別記事で解説) |
| cuDNN | ディープラーニングライブラリ(別記事で解説) |
| cuFFT | 高速フーリエ変換 |
| cuRAND | 乱数生成 |
| Nsight | プロファイリング・デバッグツール |
バージョンの確認方法
# CUDAコンパイラのバージョン
nvcc --version
# 出力例:
# nvcc: NVIDIA (R) Cuda compiler driver
# Cuda compilation tools, release 12.1, V12.1.105
# GPUの状態とドライババージョン
nvidia-smi
# 出力例:
# +-----------------------------------------------------------------------------+
# | NVIDIA-SMI 535.86.05 Driver Version: 535.86.05 CUDA Version: 12.2 |
# +-----------------------------------------------------------------------------+
注意: nvidia-smiが表示するCUDAバージョンは「ドライバが対応している最大バージョン」であり、実際にインストールされているCUDA Toolkitのバージョンとは異なる場合がある。
7. CUDAとハードウェアの関係
Compute Capability(計算能力)
各NVIDIA GPUには「Compute Capability」というバージョン番号がある。これはGPUアーキテクチャの世代を表す。
| アーキテクチャ | Compute Capability | 代表的GPU |
|---|---|---|
| Kepler | 3.x | GTX 780, Tesla K80 |
| Maxwell | 5.x | GTX 980, Quadro M6000 |
| Pascal | 6.x | GTX 1080, Tesla P100 |
| Volta | 7.0 | Tesla V100 |
| Turing | 7.5 | RTX 2080, Quadro RTX |
| Ampere | 8.x | RTX 3090, A100 |
| Ada Lovelace | 8.9 | RTX 4090 |
| Hopper | 9.0 | H100 |
| Blackwell | 10.x | B200 |
CUDAプログラムをコンパイルする際、ターゲットとするCompute Capabilityを指定する。古いGPUで動かすには古いバージョンに対応したコードが必要になる。
Tensor Core
Volta世代(Compute Capability 7.0)以降のGPUには「Tensor Core」という特殊なユニットが搭載されている。これは行列演算に特化したハードウェアで、ディープラーニングの学習・推論を大幅に高速化する。
CUDAからTensor Coreを使うには、cuBLASやcuDNNといったライブラリを経由するのが一般的だ。
8. CUDAと競合技術
NVIDIA専用という制約
CUDAはNVIDIA GPUでしか動作しない。これは大きな制約であり、同時にNVIDIAの競争優位性でもある。
"CUDA competes with other GPU computing stacks: Intel OneAPI and AMD ROCm. Whereas Nvidia's CUDA is closed-source, Intel's OneAPI and AMD's ROCm are open source."
「CUDAは他のGPUコンピューティングスタックと競合している。Intel OneAPIとAMD ROCmだ。NVIDIAのCUDAがクローズドソースなのに対し、IntelのOneAPIとAMDのROCmはオープンソースである。」
— Wikipedia "CUDA" (https://en.wikipedia.org/wiki/CUDA)
代替技術
| 技術 | ベンダー | 対応ハードウェア |
|---|---|---|
| ROCm | AMD | AMD GPU |
| oneAPI | Intel | Intel GPU, CPU, FPGA |
| OpenCL | Khronos Group | 複数ベンダー(汎用) |
| Metal | Apple | Apple Silicon |
ただし、現時点ではCUDAのエコシステム(ライブラリ、ツール、コミュニティ)が圧倒的に充実しており、ディープラーニング分野ではデファクトスタンダードとなっている。
9. 実践:PyTorchでCUDAを使う
基本的な使い方
import torch
# CUDAが使えるか確認
print(torch.cuda.is_available()) # True なら使える
# GPUの数を確認
print(torch.cuda.device_count())
# 現在のGPU名を確認
print(torch.cuda.get_device_name(0))
# テンソルをGPUに転送
x = torch.randn(1000, 1000)
x_gpu = x.cuda() # または x.to('cuda')
# モデルをGPUに転送
model = MyModel()
model = model.cuda() # または model.to('cuda')
よくあるトラブル
問題1: CUDA out of memory
RuntimeError: CUDA out of memory. Tried to allocate 2.00 GiB
GPUメモリが足りない。バッチサイズを小さくするか、勾配チェックポイントを使う。
問題2: CUDA driver version is insufficient
CUDA driver version is insufficient for CUDA runtime version
GPUドライバが古い。nvidia-smiで確認し、ドライバを更新する。
問題3: no kernel image is available
no kernel image is available for execution on the device
PyTorchがビルドされた時のCUDAアーキテクチャと、実際のGPUが合っていない。PyTorchを適切なバージョンで再インストール。
10. まとめ
CUDAは、GPUを「絵を描く機械」から「汎用計算機」に変えた革命的技術だ。
- 2007年リリース: NVIDIAが開発した並列コンピューティングプラットフォーム
- プログラミングモデル: スレッド → ブロック → グリッドの階層構造
- メモリ階層: レジスタ、共有メモリ、グローバルメモリを使い分ける
- CUDA Toolkit: コンパイラ、ライブラリ、ツール一式を提供
- NVIDIA専用: 競合技術はあるが、エコシステムの充実度で圧倒
PyTorchやTensorFlowを使っている限り、CUDAを直接プログラミングする機会は少ないかもしれない。しかし、その「裏側」を知っていることで、エラーへの対処やパフォーマンスの最適化が格段に楽になる。
次回は、CUDAの上で動く高速行列演算ライブラリ「cuBLAS」を解説する。
参考資料
公式ドキュメント
- CUDA C++ Programming Guide - CUDA公式プログラミングガイド
- CUDA Toolkit Documentation - CUDA Toolkit全体のドキュメント
入門記事
- An Even Easier Introduction to CUDA - NVIDIA公式ブログの入門記事
歴史・背景
- Wikipedia - CUDA - CUDAの歴史と概要
シリーズ記事
- 第1回: CUDAってなんだ?(この記事)
- 第2回: cuBLASってなんだ?
- 第3回: cuDNNってなんだ?
- ハブ記事: GPU計算の三銃士シリーズ