Skip to content
Published on

AMD GPU & ROCm完全分析:LLM推論でCUDAに挑めるか?

Authors

AMDが再び挑戦する

2020年代前半まで、AMDのGPUをMLワークロードに使うことは、ある種の苦行を自ら選ぶようなものでした。ROCmは不安定で、サポートされるライブラリが少なく、ドライバの問題が頻繁に発生しました。「CUDAでなければ無理」という認識が支配的でした。

しかし2023〜2024年を経て、状況が劇的に変わりました。AMD MI300Xは192GB HBM3メモリを搭載し、単一GPUで70Bパラメータモデルをfloat16で動かせるようになりました。ROCm 6.xからはPyTorchとvLLMの安定性が大幅に向上し、Microsoft、Meta、Hugging FaceがAMD GPUサポートを公式化したことで、エコシステムも急速に成長しています。

本記事では、AMD GPUアーキテクチャの内部を解剖し、ROCmソフトウェアスタックの仕組みを説明し、実際のLLMサービングシナリオでNVIDIAとどう比較されるかを正直に分析します。


1. AMD GPUアーキテクチャ:RDNA vs CDNA

AMDのGPUラインナップは、用途によって根本的に異なる2つのアーキテクチャに分かれます。

RDNA:ゲーミング最適化アーキテクチャ

RDNAファミリー(コンシューマーGPU):
- RX 7900 XTX (RDNA 3): 24GB GDDR6960 GB/s帯域幅
- RX 7900 XT (RDNA 3): 20GB GDDR6800 GB/s帯域幅
- グラフィックスレンダリング最適化(ラスタライゼーション、レイトレーシング)
- ゲーム性能最大化のためのキャッシュ構造
- MLワークロード対応:可能だが公式ROCmサポートは限定的

CDNA:コンピュート最適化アーキテクチャ(AI/HPC用)

CDNAは「Compute DNA」の略で、AMDがAI/HPCワークロードのために別途設計したアーキテクチャです。NVIDIAのデータセンターGPU(A100、H100)に直接対抗します。

CDNAファミリー(データセンターGPU):
┌─────────────────────────────────────────────────────────────────┐
AMD MI300XCDNA 32023年発売)                                 │
│                                                                 │
│  • 192GB HBM3メモリ(業界最大!)                               │
│    → H100 SXMの80GBの2.4倍                                      │
│  • 5.3 TB/sメモリ帯域幅                                         │
│    → H100 SXM3.35 TB/sの1.58倍                               │
│  • 304 Compute Units│  • 1,307 TFLOPS FP16│  • 655 TFLOPS FP32│  • MCM(マルチチップモジュール):GPU + CPU HBM統合             │
│                                                                 │
└─────────────────────────────────────────────────────────────────┘

MI300Xの主要なイノベーションは**MCM(Multi-Chip Module)**設計です。GPUダイとCPU HBMダイを1つのパッケージに統合し、超高速GPU-CPUメモリアクセスを可能にします。

MI300X対H100:コアスペック比較

                    AMD MI300X          NVIDIA H100 SXM
メモリ:             192GB HBM3          80GB HBM3
メモリ帯域幅:        5.3 TB/s            3.35 TB/s
FP16性能:           1,307 TFLOPS        1,979 TFLOPS
FP8性能:            2,614 TFLOPS        3,958 TFLOPS
AI加速器:           MFMA4世代 Tensor Core
TDP:               750W                700W
価格(推定):        ~$15,000-20,000     ~$30,000-40,000
メモリ優位:         ✅ 2.4倍大きい      -
コンピュート優位:   -~1.5倍速い
帯域幅優位:         ✅ 1.58倍高い       -

LLM推論ではメモリ帯域幅と容量がより重要な場合が多く、MI300Xは特に大規模モデルサービングで強みを発揮します。


2. ROCm:AMDのCUDA対抗ソフトウェアスタック

CUDAがNVIDIAの最も強力な競合優位であるならば、ROCmはAMDがそのギャップを埋めるための戦略的投資です。

ソフトウェアスタック比較

NVIDIAスタック:                        AMDスタック:
┌──────────────────────┐        ┌──────────────────────┐
PyTorch / JAX      │        │   PyTorch / JAXTensorFlow         │        │   TensorFlow└──────────┬───────────┘        └──────────┬───────────┘
           ↓                               ↓
┌──────────────────────┐        ┌──────────────────────┐
CUDAランタイム     │        │  ROCmランタイム (HIP)└──────────┬───────────┘        └──────────┬───────────┘
           ↓                               ↓
┌──────────────────────┐        ┌──────────────────────┐
│   cuDNN / cuBLAS     │        │  MIOpen / rocBLAS    │
│   cuSPARSE           │        │  rocSPARSE           │
│   cuFFT              │        │  rocFFT              │
└──────────┬───────────┘        └──────────┬───────────┘
           ↓                               ↓
┌──────────────────────┐        ┌──────────────────────┐
NVCCコンパイラ      │        │   hipccコンパイラ     │
PTXIR)          │        │   GCN ISA / AMDGCN└──────────┬───────────┘        └──────────┬───────────┘
           ↓                               ↓
┌──────────────────────┐        ┌──────────────────────┐
NVIDIA GPU        │        │     AMD GPU└──────────────────────┘        └──────────────────────┘

ROCmの設計原則はCUDAとの最大限の互換性です。torch.cuda APIを使ったPyTorchコードがAMD GPUでも変更なく動くことが目標です。


3. HIP:CUDA コードをAMDで実行する

HIP(Heterogeneous-compute Interface for Portability)はAMDが開発したC++ベースのプログラミングインターフェースです。CUDAコードとほぼ同一の文法を使います。

CUDAとHIPのコード比較

// CUDAコード(NVIDIA):
#include <cuda_runtime.h>

__global__ void vector_add(float* a, float* b, float* c, int n) {
    int idx = blockIdx.x * blockDim.x + threadIdx.x;
    if (idx < n) {
        c[idx] = a[idx] + b[idx];
    }
}

int main() {
    float *d_a, *d_b, *d_c;
    int n = 1024 * 1024;
    size_t size = n * sizeof(float);

    cudaMalloc(&d_a, size);
    cudaMalloc(&d_b, size);
    cudaMalloc(&d_c, size);

    cudaMemcpy(d_a, h_a, size, cudaMemcpyHostToDevice);
    vector_add<<<n/256, 256>>>(d_a, d_b, d_c, n);
    cudaMemcpy(h_c, d_c, size, cudaMemcpyDeviceToHost);

    cudaFree(d_a);
    return 0;
}
// HIPコード(AMD):CUDAとほぼ同一!
#include <hip/hip_runtime.h>

__global__ void vector_add(float* a, float* b, float* c, int n) {
    int idx = hipBlockIdx_x * hipBlockDim_x + hipThreadIdx_x;
    if (idx < n) {
        c[idx] = a[idx] + b[idx];
    }
}

int main() {
    float *d_a, *d_b, *d_c;
    int n = 1024 * 1024;
    size_t size = n * sizeof(float);

    hipMalloc(&d_a, size);           // cudaMalloc → hipMalloc
    hipMalloc(&d_b, size);
    hipMalloc(&d_c, size);

    hipMemcpy(d_a, h_a, size, hipMemcpyHostToDevice);  // プレフィックスのみ変更
    vector_add<<<n/256, 256>>>(d_a, d_b, d_c, n);      // 同じ <<<>>> 文法
    hipMemcpy(h_c, d_c, size, hipMemcpyDeviceToHost);

    hipFree(d_a);
    return 0;
}

HIPIFY:自動コード変換ツール

AMDはCUDA → HIPへの自動変換ツールHIPIFYを提供しています:

# HIPIFYを使ったCUDA → HIP変換
hipify-perl cuda_kernel.cu > hip_kernel.hip

# またはclangベースのHIPIFY
hipify-clang cuda_kernel.cu -- -I/usr/local/cuda/include

# 変換率:シンプルなCUDAコードは90%以上自動変換
# カスタムCUDAイントリンシックは手動変換が必要

# HIPコードのコンパイル
hipcc hip_kernel.hip -o hip_kernel

HIPの設計哲学:一度書いて、どこでも実行

HIPで書いたコードはAMDとNVIDIA両方で実行されます:

// 同じHIPコードが両プラットフォームで動作:
// AMD:    hipcc -arch=gfx942 kernel.hip   (MI300X)
// NVIDIA: hipcc --platform=nvidia kernel.hip  (CUDAとしてコンパイル)

// プラットフォーム検出コード
#ifdef __HIP_PLATFORM_AMD__
    // AMD固有の最適化
    __builtin_amdgcn_s_sleep(1);
#elif defined(__HIP_PLATFORM_NVIDIA__)
    // NVIDIA固有コード
    __nanosleep(1000);
#endif

4. AMD Compute Unit対NVIDIA SM:内部比較

アーキテクチャ詳細比較

NVIDIA H100 SM(Streaming Multiprocessor):
┌───────────────────────────────────────────────┐
128 CUDAコア(FP32演算ユニット)              │
64 FP64コア                                  │
4 Tensor Core(第4世代、FP8/FP16/BF16/INT8) │
8 LD/STユニット(Load/Store)│  228KB L1キャッシュ / 共有メモリ(設定可能)   │
65,536個の32ビットレジスタ                    │
│                                               │
│  単一SM FP16性能:~60 TFLOPS(ピーク)         │
└───────────────────────────────────────────────┘

AMD MI300X CU(Compute Unit):
┌───────────────────────────────────────────────┐
64 Stream Processors(SIMDベクターユニット)  │
64 FP64ユニット                              │
4 Matrix Cores(MFMA:Matrix Fused Multiply-Add)16 LD/STユニット                             │
│  64KB L1キャッシュ                            │
│  32KB LDS(Local Data Share = 共有メモリ)    │
65,536個の32ビットレジスタ                    │
│                                               │
MFMAAMDのTensor Core相当:│  v_mfma_f32_16x16x16f16(FP16行列積)         │
└───────────────────────────────────────────────┘

Wavefront対Warp

NVIDIAは32スレッドのグループをWarpと呼びますが、AMDは64スレッドのグループをWavefront(Wave64)と呼びます:

NVIDIA Warp:
- 32スレッドが同時実行(SIMT:Single Instruction, Multiple Threads)
- すべてのスレッドが同じ命令を実行

AMD Wavefront(Wave64):
- 64スレッドが同時実行
- Wave32モードもRDNA3MI300Xでサポート
- 大きいWavefront = データ並列性↑、分岐発散時に非効率↑
// HIPカーネルでWavefrontサイズを確認
__global__ void check_wavefront() {
    // AMDでは warpSize = 64(Wave32モードでは32)
    // NVIDIAでは常に warpSize = 32
    int lane = threadIdx.x % warpSize;
    printf("warpSize: %d, my lane: %d\n", warpSize, lane);
}

5. PyTorch on AMD(ROCm)

インストールと基本使用法

# ROCm対応PyTorchのインストール
# ROCm 6.0(2024年時点の安定最新バージョン)
pip install torch torchvision torchaudio \
  --index-url https://download.pytorch.org/whl/rocm6.0

# ROCm環境の確認
python -c "
import torch
print('PyTorchバージョン:', torch.__version__)
print('ROCm使用可能:', torch.cuda.is_available())  # AMDでもTrue!
print('ROCmバージョン:', torch.version.hip)
print('GPU数:', torch.cuda.device_count())
print('GPU名:', torch.cuda.get_device_name(0))
"
# 出力例:
# PyTorchバージョン: 2.3.0+rocm6.0
# ROCm使用可能: True  ← AMDでもcuda.is_available()がTrue!
# ROCmバージョン: 6.0.0
# GPU数: 1
# GPU名: AMD Instinct MI300X

# AMD GPUでテンソル演算
import torch
device = torch.device("cuda")  # "cuda"でAMD GPUでも動作!

x = torch.randn(1000, 1000, device=device)
y = torch.randn(1000, 1000, device=device)
z = torch.matmul(x, y)
print(z.shape)  # torch.Size([1000, 1000])

AMDが"cuda"名前空間を維持する理由: 何百万ものPyTorchコードベースがtorch.cudaを使用しています。これをtorch.hiptorch.rocmに変えると互換性が壊れます。AMDは意図的に同じAPIを使い、既存コードがAMD GPUで修正なく動くようにしました。

BF16とFlash Attentionのサポート

import torch

# BF16(BFloat16)サポートの確認
device = torch.device("cuda")
a = torch.randn(512, 512, dtype=torch.bfloat16, device=device)
b = torch.randn(512, 512, dtype=torch.bfloat16, device=device)
c = torch.matmul(a, b)  # MI300XでBF16 MFMAを使用

# AMD上でのFlash Attention(ROCm)
# flash-attnのROCmビルドをインストール
# pip install flash-attn --no-build-isolation

from flash_attn import flash_attn_func

q = torch.randn(2, 512, 8, 64, dtype=torch.float16, device=device)
k = torch.randn(2, 512, 8, 64, dtype=torch.float16, device=device)
v = torch.randn(2, 512, 8, 64, dtype=torch.float16, device=device)

# Flash AttentionはROCmでもサポート
out = flash_attn_func(q, k, v, dropout_p=0.0, causal=True)

6. AMD上でのLLMサービング:vLLMとllama.cpp

AMD MI300X上のvLLM

vLLMは2024年からAMD ROCmを公式サポートしています。PagedAttentionとcontinuous batchingがAMD GPUでも動作します。

# ROCm用vLLMのインストール
pip install vllm  # ROCm環境で自動的にROCmバージョンをインストール

# ソースからビルド
git clone https://github.com/vllm-project/vllm
cd vllm
pip install -e . --no-build-isolation  # ROCm環境を自動検出

# MI300XでLlama 3.1 70Bをサービング
python -m vllm.entrypoints.openai.api_server \
  --model meta-llama/Llama-3.1-70B-Instruct \
  --tensor-parallel-size 1 \
  --dtype float16 \
  --device cuda  # AMD GPUでも"cuda"を使用!

# 大きなモデル:4x MI300X(768GB)でINT8の405B
python -m vllm.entrypoints.openai.api_server \
  --model meta-llama/Llama-3.1-405B-Instruct \
  --tensor-parallel-size 4 \
  --quantization fp8 \
  --device cuda
# AMD上のvLLM Python API
from vllm import LLM, SamplingParams

# 単一MI300Xで70BをFP16でロード(192GB VRAMのおかげで可能!)
llm = LLM(
    model="meta-llama/Llama-3.1-70B-Instruct",
    dtype="float16",
    tensor_parallel_size=1,  # 単一MI300Xで十分
    gpu_memory_utilization=0.85,
)

sampling_params = SamplingParams(
    temperature=0.7,
    top_p=0.95,
    max_tokens=512,
)

prompts = ["Transformerにおけるattentionメカニズムを説明してください。"]
outputs = llm.generate(prompts, sampling_params)
for output in outputs:
    print(output.outputs[0].text)

llama.cpp on AMD

# ROCm対応llama.cppのビルド
git clone https://github.com/ggerganov/llama.cpp
cd llama.cpp
cmake -B build -DLLAMA_HIPBLAS=ON \
  -DCMAKE_HIP_ARCHITECTURES="gfx942"  # MI300Xアーキテクチャ
cmake --build build --config Release -j

# MI300XでLlama 3.1 70B Q4_K_Mを実行
./build/bin/llama-cli \
  -m models/llama-3.1-70b-q4_k_m.gguf \
  -p "ROCmアーキテクチャを説明してください" \
  -n 200 \
  --n-gpu-layers 999
# 予想:~15-20 tok/s(Q4_K_M、単一MI300X)
# FP16ロード時:~8-10 tok/s(より大きなモデル、より高品質)

# コンシューマー向けAMD RX 7900 XTXでは:
./build/bin/llama-cli -m models/llama-3.1-8b-q4_k_m.gguf ...
# 予想:~50-60 tok/s(RX 7900 XTX 24GB)

実測パフォーマンス比較表

GPUメモリLlama 3.1 70B FP16Llama 3.1 70B INT8備考
NVIDIA H100 SXM80GB HBM3~2,800 tok/s~3,200 tok/sバッチ処理スループット
AMD MI300X192GB HBM3~2,200 tok/s~2,800 tok/s単一GPU、FP16が可能!
NVIDIA A100 80GB80GB HBM2e~1,400 tok/s~1,600 tok/s-
AMD RX 7900 XTX24GB GDDR6OOM~600 tok/sQ4が必要
NVIDIA RTX 409024GB GDDR6XOOM~700 tok/sQ4が必要

バッチ処理スループット基準、単一リクエストのレイテンシは別途測定が必要


7. AMDの強みと現実的な弱点

強み1:圧倒的なメモリ容量

単一MI300X 192GBで可能なこと:
┌─────────────────────────────────────────────────────────────────┐
Llama 3.1 70B FP16ロード:~140GB → 可能!(52GBの余裕)         │
│   → 単一H100 SXMでは不可能(80GB制限)                          │
│                                                                 │
Llama 3.1 70B + 長いコンテキストKVキャッシュ:                  │
│   モデル~140GB + KVキャッシュ32Kコンテキスト~20GB = 160GB → 可能! │
│                                                                 │
Mixtral 8x7B MoE FP16~93GB → 単一カードで可能!              │
│                                                                 │
│ 実験的な100B+研究モデル:量子化なしでテスト可能                  │
└─────────────────────────────────────────────────────────────────┘

強み2:優れたメモリ帯域幅

LLM推論はメモリ帯域幅に制約されます(前述の通り)。MI300Xの5.3 TB/sはH100の3.35 TB/sより約58%高いです:

# 理論的な最大トークン生成速度の推定(メモリ帯域幅制限モデル)
# バッチサイズ1、単一トークン生成時

# 70B FP16モデル = 140GB
# 各トークン生成でウェイト全体を一度読む必要がある

def estimate_max_toks_per_sec(memory_bw_gbps, model_size_gb):
    """メモリ帯域幅制限下での理論的最大速度"""
    return memory_bw_gbps / model_size_gb

# MI300X: 5,300 GB/s / 140 GB = ~38 tok/s(理論的上限)
mi300x_est = estimate_max_toks_per_sec(5300, 140)
print(f"MI300X理論上限: {mi300x_est:.1f} tok/s")  # ~37.9

# H100 SXM: 3,350 GB/s / 140 GB = ~24 tok/s(理論的上限)
# 実際にはH100がより速い(コンピュート効率が高いため)
h100_est = estimate_max_toks_per_sec(3350, 140)
print(f"H100理論上限: {h100_est:.1f} tok/s")   # ~23.9

弱点1:CUDAエコシステムの格差

これがAMDの最大の課題です。CUDAの成熟度は15年間の最適化の歴史を持ちます:

CUDAエコシステム(2024年):              ROCmエコシステム(2024年):
- PyTorch:完全サポート- PyTorch:サポート ✅(安定性改善中)
- JAX:完全サポート ✅                   - JAX:実験的サポート ⚠️
- TensorFlow:完全サポート- TensorFlow:公式サポート- FlashAttention:高度最適化- FlashAttention:サポートだが遅い ⚠️
- cuDNNカーネル:15年最適化 ✅          - MIOpen:最適化進行中 ⚠️
- Triton:完全サポート- Triton on ROCm:サポート(性能差あり)⚠️
- BitsAndBytes:完全サポート- BitsAndBytes on ROCm:サポート- DeepSpeed:完全サポート- DeepSpeed on ROCm:サポート- vLLM:完全サポート ✅                  - vLLM on ROCm:公式サポート ✅(2024年〜)

弱点2:コンシューマーGPUのROCmサポート制限

AMD ROCmの公式サポートプラットフォームはLinux + MIシリーズデータセンターGPUに集中しています:

# ROCm 6.0公式サポートGPU(2024年時点):
# ✅ AMD Instinct MI300X
# ✅ AMD Instinct MI250X
# ✅ AMD Instinct MI210
# ✅ AMD Instinct MI100
# ⚠️ RX 7900 XTX:非公式サポート(多くのライブラリは動くが保証なし)
# ❌ RX 7800 XT以下:サポートが不安定

# コンシューマーGPUでROCmを強制使用
export HSA_OVERRIDE_GFX_VERSION=11.0.0  # RX 7900 XTX用
export ROCR_VISIBLE_DEVICES=0
rocminfo  # 検出されたGPU情報を出力

弱点3:ドライバの安定性

WindowsでのAMD GPU ROCmサポートは2024年時点でまだ限定的です。ほとんどのMLワークロードにはUbuntu 22.04 LTS + ROCmの組み合わせが推奨されます。


8. 実践設定:AMD ROCm環境の構築

Docker環境構成(推奨)

# ROCm Dockerイメージを使用(最も安定した方法)
docker pull rocm/pytorch:rocm6.0_ubuntu22.04_py3.10_pytorch_2.1.1

# GPUアクセス権を付与してコンテナを実行
docker run -it \
  --device=/dev/kfd \
  --device=/dev/dri \
  --group-add video \
  --security-opt seccomp=unconfined \
  --cap-add=SYS_PTRACE \
  -v $(pwd):/workspace \
  rocm/pytorch:rocm6.0_ubuntu22.04_py3.10_pytorch_2.1.1 \
  /bin/bash

# コンテナ内で確認
python -c "import torch; print(torch.cuda.is_available(), torch.version.hip)"

ベアメタルインストール

# Ubuntu 22.04 LTSにROCm 6.0をインストール
# ステップ1:AMD ROCmパッケージリポジトリを追加
wget https://repo.radeon.com/amdgpu-install/6.0/ubuntu/jammy/amdgpu-install_6.0.60000-1_all.deb
sudo dpkg -i amdgpu-install_6.0.60000-1_all.deb

# ステップ2:ROCmのインストール
sudo amdgpu-install --usecase=hiplibsdk,rocm,ml

# ステップ3:ユーザーをrenderとvideoグループに追加
sudo usermod -aG render,video $USER

# ステップ4:再ログインして確認
rocminfo | grep "Name:"
# Agent 2: gfx942  (MI300X)

# ステップ5:PyTorch ROCmのインストール
pip install torch torchvision torchaudio \
  --index-url https://download.pytorch.org/whl/rocm6.0

9. AMD対NVIDIA:2024-2025年の現実的な比較

ワークロード別の推奨事項

ワークロードAMD MI300XNVIDIA H100推奨
70Bモデルの単一GPUサービング✅ FP16で直接ロード可能❌ 80GB制限AMD
405Bモデルのサービング2枚で可能最低3枚必要AMD
大規模バッチスループット良い非常に良いNVIDIA
単一リクエストのレイテンシ良い非常に良いNVIDIA
モデルのファインチューニング可能より成熟NVIDIA
コスト効率30-40%安い高価AMD
ソフトウェアの安定性急速に改善中非常に成熟NVIDIA
Windowsサポート限定的完全サポートNVIDIA

実際の採用事例(2024年)

  • Microsoft Azure:AIサービスにMI300Xを導入(AMD GPUインスタンスを提供開始)
  • Meta:特定のAIワークロードにMI300Xの導入を検討
  • Hugging Face:モデルハブとライブラリのROCmサポートを改善
  • Oracle Cloud:OCI Compute MI300Xインスタンスを提供

結論:AMDを選ぶべきシナリオ

AMD MI300Xが優れている場合:

  • 単一GPUで可能な限り大きなモデルを動かしたい場合
  • 実験環境でスループットよりメモリ容量が重要な場合
  • NVIDIAと比べて30-40%の予算節約が必要な場合
  • すでにAMDハードウェアの契約がある場合

NVIDIA H100を維持すべき場合:

  • プロダクションの安定性が最優先の場合
  • 最新のMLライブラリをすぐに使う必要がある場合
  • Windowsベースの開発環境が必要な場合
  • チーム全体がCUDAの専門知識を持っている場合

まとめ

AMDは「とりあえずCUDAを使おう」という評価から脱却し、真剣なCUDAの代替として台頭してきました。MI300Xの192GB HBM3は単なるスペック自慢ではなく、具体的なユースケースを切り開きます。FP16の70Bモデルを単一カードで量子化なしにサービングすること、これは現在NVIDIAの単一カードでは不可能なことです。

ソフトウェアエコシステムの面ではNVIDIAがまだリードしていますが、ROCm 6.xとvLLMの公式AMDサポートによりギャップは急速に縮まっています。2026年現在、AMDは「使えるが不安定」から「実用的で競争力がある」レベルに成長しました。

MLインフラチームにとっては、NVIDIAのH100をデフォルトとして維持しながら、メモリ容量がボトルネックとなる特定の大規模モデルサービングワークロードにMI300Xを導入するハイブリッド戦略を検討する価値があります。競争が激化するほど、エンジニアにとっての選択肢が増えることは良いことです。