【AWS】ECS マネージドインスタンス × Python で GPU 処理を実行する

はじめに

システム開発第一事業部の大泉です。普段はエンジニアとして Python でバックエンドの開発を行っています。

この記事では、ECS マネージドインスタンスを使って GPU タスクを実行する方法をご紹介します。

aws.amazon.com

ECS で GPU タスクを実行する方法はいくつかあります。セルフマネージドな ECS on EC2 構成では、オートスケーリンググループ、起動テンプレート、メンテナンスなどを自分で管理する必要があります。

一方、ECS マネージドインスタンスを使うと、EC2 インスタンスやオートスケーリングなどのインフラ管理を AWS に委譲しつつ、GPU インスタンスを使って ECS タスクを実行できます。

さらに、ECS マネージドインスタンスで GPU インスタンスを使用すると、NVIDIA ドライバーと CUDA ツールキットがインスタンスに事前にインストールされます。そのため、セルフマネージド構成のように GPU 最適化 AMI(GPU-optimized AMI)や NVIDIA ドライバーを自分で管理する必要がありません。

GPU タスクでは簡単なデモを行い、コンテナ内の Python / PyTorch から GPU を利用できることを確認し、行列演算で CPU と GPU のベンチマークを行います。

構築手順

まず、ECS クラスターを作成します。インフラストラクチャには「マネージドインスタンス」を選択し、IAM ロールを選択します。 「インスタンスプロファイル」には AmazonEC2ContainerServiceforEC2Role がアタッチされた IAM ロール、「インフラストラクチャロール」には AmazonECSInfrastructureRolePolicyForManagedInstances がアタッチされた IAM ロールを選択します。 自動作成に任せると便利です。

次に GPU 対応インスタンスタイプを選択します。ここでは g5.xlarge を選択します。起動可能なインスタンスタイプは以下をご参照ください。

docs.aws.amazon.com

次にタスク定義を作成します。タスク定義では、作成したコンテナイメージを指定し、コンテナに GPU を割り当てる設定を行います。

タスクを起動する際、GPU インスタンスを選択したキャパシティプロバイダーを指定します。このキャパシティプロバイダーに従ってインスタンスが起動します。

インスタンス起動後、タスクの実行が開始します。

キャパシティプロバイダーではコンテナインスタンスが登録されていることを確認できます。

タスクの処理が完了し、正常終了しました。

サンプルアプリケーション

ECS 上で GPU が利用できるかを確認するため、Python と PyTorch を使った最小構成のコンテナを用意します。

ディレクトリ構成

ecs-gpu-demo/
├── Dockerfile
├── pyproject.toml
├── main.py
└── benchmark.py

Dockerfile

FROM public.ecr.aws/docker/library/python:3.14-slim

WORKDIR /app

COPY pyproject.toml ./
COPY main.py ./
COPY benchmark.py ./

RUN pip install --no-cache-dir --upgrade pip \
    && pip install --no-cache-dir . --extra-index-url https://download.pytorch.org/whl/cu124

CMD ["python", "main.py"]

pyproject.toml

[project]
name = "ecs-gpu-demo"
version = "0.1.0"
description = "Minimal ECS GPU demo for checking torch.cuda.is_available()"
requires-python = ">=3.14,<3.15"
dependencies = [
    "torch"
]

main.py

main.py では、Python / PyTorch の環境情報、CUDA の利用可否を確認し、その後にベンチマーク処理を呼び出します。

import platform
import sys

import torch

from benchmark import run_benchmark


def main() -> None:
    print("=== Python environment ===")
    print(f"Python: {sys.version}")
    print(f"Platform: {platform.platform()}")

    print("\n=== PyTorch environment ===")
    print(f"PyTorch version: {torch.__version__}")
    print(f"PyTorch CUDA version: {torch.version.cuda}")

    print("\n=== CUDA availability ===")
    cuda_available = torch.cuda.is_available()
    print(f"torch.cuda.is_available(): {cuda_available}")

    device_count = torch.cuda.device_count()
    print(f"torch.cuda.device_count(): {device_count}")

    run_benchmark()


if __name__ == "__main__":
    main()

torch.cuda.is_available(): True は、PyTorch から CUDA が利用できることを示します。

torch.cuda.device_count(): 1 は、コンテナ内の PyTorch から GPU が 1 個見えていることを示します。

benchmark.py

benchmark.py では、CPU と GPU で同じ行列計算を実行し、処理時間を比較します。

import time

import torch


def benchmark(device: str, size: int = 4096, repeat: int = 10) -> float:
    print(f"\n=== Matrix multiplication on {device} ===")
    print(f"Matrix size: {size} x {size}")
    print(f"Repeat: {repeat}")

    a = torch.randn(size, size, device=device)
    b = torch.randn(size, size, device=device)

    # ウォームアップ: 最初の数回は初期化コストがかかるため、計測から除外する
    for _ in range(3):
        _ = a @ b

    if device == "cuda":
        torch.cuda.synchronize()

    start = time.perf_counter()

    for _ in range(repeat):
        _ = a @ b

    if device == "cuda":
        torch.cuda.synchronize()

    elapsed = time.perf_counter() - start
    print(f"Elapsed time: {elapsed:.4f} seconds")

    return elapsed


def run_benchmark() -> None:
    cpu_time = benchmark("cpu")
    gpu_time = benchmark("cuda")

    print("\n=== Benchmark result ===")
    print(f"CPU time: {cpu_time:.4f} seconds")
    print(f"GPU time: {gpu_time:.4f} seconds")
    print(f"Speedup: {cpu_time / gpu_time:.2f}x")

このベンチマークでは、4096 x 4096 の行列積を CPU と GPU でそれぞれ 10 回実行します。

成功時のログとベンチマーク結果

タスクが正常に GPU を利用できた場合、以下のようなログが出ます。

=== Python environment ===
Python: 3.14.6 (main, Jun 11 2026, 01:06:03) [GCC 14.2.0]
Platform: Linux-6.1.172-x86_64-with-glibc2.41

=== PyTorch environment ===
PyTorch version: 2.12.0+cu130
PyTorch CUDA version: 13.0

=== CUDA availability ===
torch.cuda.is_available(): True
torch.cuda.device_count(): 1

=== Matrix multiplication on cpu ===
Matrix size: 4096 x 4096
Repeat: 10
Elapsed time: 10.4833 seconds

=== Matrix multiplication on cuda ===
Matrix size: 4096 x 4096
Repeat: 10
Elapsed time: 0.3173 seconds

=== Benchmark result ===
CPU time: 10.4833 seconds
GPU time: 0.3173 seconds
Speedup: 33.04x

GPU demo completed successfully.

ベンチマークでは、CPU で約 10.48 秒、GPU で約 0.32 秒となり、約 33 倍高速に処理できました。

まとめ

この記事では、ECS マネージドインスタンスを使って GPU タスクを実行し、以下を確認しました。

  • GPU インスタンスタイプの選択、タスク定義での GPU 要求だけで GPU タスクが起動可能
  • マネージドインスタンスではオートスケーリンググループ、起動テンプレートの管理が不要
  • コンテナ内で torch.cuda.is_available(): Truetorch.cuda.device_count(): 1 となり、GPU が見えていることを確認できた
  • 4096 x 4096 の行列の積の計算では、 CPU と GPU でそれぞれ 10 回実行したところ、GPU が約 33 倍高速

GPU 共有やオートスケーリンググループを細かく制御したいなどの特殊な要件がない限り、マネージドインスタンスでの運用が手軽でおすすめです。

ECS で GPU タスクを試す際の選択肢として、参考になれば幸いです。

参考

docs.aws.amazon.com

docs.aws.amazon.com

docs.aws.amazon.com

テコテックの採用活動について

テコテックでは新卒採用、中途採用共に積極的に募集をしています。 採用サイトにて会社の雰囲気や福利厚生、募集内容をご確認いただけます。 ご興味を持っていただけましたら是非ご覧ください。 tecotec.co.jp