modal-serverless-gpu について
ModalのサーバーレスGPUクラウドで機械学習ワークロードを実行するためのガイドです。Pythonによる環境定義、自動スケーリング、永続ストレージ、APIデプロイを扱います。
主な機能
- 01複数GPUのオンデマンド利用
- 02Pythonでのクラウド環境定義
- 03ゼロから複数GPUへの自動スケーリング
- 04Web APIエンドポイントのデプロイ
- 05永続ストレージとシークレット管理
- 06並列処理とスケジュール実行
活用シーン
- 01GPUでの学習や推論の実行
- 02機械学習モデルのAPI化
- 03バッチデータ処理
- 04定期的なMLジョブの実行
インストール
コマンドをコピーしてターミナルで実行します。
$
npx skills add https:/ / github.com/ davila7/ claude-code-templates --skill modal-serverless-gpuインストール後、Claude Code で/modal-serverless-gpuを入力して読み込まれたか確認します。
同梱ファイルreferences/advanced-usage.mdreferences/troubleshooting.md
詳細
Modal サーバーレス GPU
Modal のサーバーレス GPU クラウドプラットフォームで ML ワークロードを実行するための包括的なガイドです。
Modal を使うタイミング
Modal を使うとよい場合:
- インフラを管理せずに GPU を多用する ML ワークロードを実行したいとき
- ML モデルを自動スケーリングする API としてデプロイしたいとき
- バッチ処理ジョブ(トレーニング、推論、データ処理)を実行したいとき
- アイドル時のコストをかけず、秒単位の従量課金で GPU を利用したいとき
- ML アプリケーションのプロトタイピングを素早く行いたいとき
- スケジュールジョブ(cron のようなワークロード)を実行したいとき
主な機能:
- サーバーレス GPU: T4、L4、A10G、L40S、A100、H100、H200、B200 をオンデマンドで利用可能
- Python ネイティブ: インフラを YAML ではなく Python コードで定義
- 自動スケーリング: ゼロまでスケールダウンし、100 基以上の GPU へ即座にスケールアップ
- 1 秒未満のコールドスタート: Rust ベースのインフラにより、コンテナを高速に起動
- コンテナキャッシュ: イメージレイヤーをキャッシュし、迅速な反復開発を実現
- Web エンドポイント: 関数を、ダウンタイムなしで更新できる REST API としてデプロイ
代わりに検討できるサービス:
- RunPod: 永続的な状態を持つ、長時間稼働するポッド向け
- Lambda Labs: 予約制の GPU インスタンス向け
- SkyPilot: マルチクラウドのオーケストレーションとコスト最適化向け
- Kubernetes: 複雑なマルチサービスアーキテクチャ向け
クイックスタート
インストール
pip install modal
modal setup # Opens browser for authentication
GPU を使った Hello World
import modal
app = modal.App("hello-gpu")
@app.function(gpu="T4")
def gpu_info():
import subprocess
return subprocess.run(["nvidia-smi"], capture_output=True, text=True).stdout
@app.local_entrypoint()
def main():
print(gpu_info.remote())
実行: modal run hello_gpu.py
基本的な推論エンドポイント
import modal
app = modal.App("text-generation")
image = modal.Image.debian_slim().pip_install("transformers", "torch", "accelerate")
@app.cls(gpu="A10G", image=image)
class TextGenerator:
@modal.enter()
def load_model(self):
from transformers import pipeline
self.pipe = pipeline("text-generation", model="gpt2", device=0)
@modal.method()
def generate(self, prompt: str) -> str:
return self.pipe(prompt, max_length=100)[0]["generated_text"]
@app.local_entrypoint()
def main():
print(TextGenerator().generate.remote("Hello, world"))
コアコンセプト
主要コンポーネント
| コンポーネント | 用途 |
|---|---|
App | 関数とリソースのコンテナ |
Function | コンピュートスペックを持つサーバーレス関数 |
Cls | ライフサイクルフックを持つクラスベースの関数 |
Image | コンテナイメージの定義 |
Volume | モデルやデータを保存する永続ストレージ |
Secret | 認証情報を安全に保存する仕組み |
実行モード
| コマンド | 説明 |
|---|---|
modal run script.py | 実行して終了 |
modal serve script.py | ライブリロードを使った開発 |
modal deploy script.py | 永続的なクラウドへのデプロイ |
GPU の設定
利用可能な GPU
| GPU | VRAM | 適した用途 |
|---|---|---|
T4 | 16GB | 低コストの推論、小規模モデル |
L4 | 24GB | 推論、Ada Lovelace アーキテクチャ |
A10G | 24GB | トレーニング/推論、T4 比で 3.3 倍高速 |
L40S | 48GB | 推論に推奨(コストパフォーマンスが最良) |
A100-40GB | 40GB | 大規模モデルのトレーニング |
A100-80GB | 80GB | 非常に大規模なモデル |
H100 | 80GB | 最速、FP8 + Transformer Engine |
H200 | 141GB | H100 から自動アップグレード、4.8TB/s の帯域幅 |
B200 | 最新 | Blackwell アーキテクチャ |
GPU 指定のパターン
# Single GPU
@app.function(gpu="A100")
# Specific memory variant
@app.function(gpu="A100-80GB")
# Multiple GPUs (up to 8)
@app.function(gpu="H100:4")
# GPU with fallbacks
@app.function(gpu=["H100", "A100", "L40S"])
# Any available GPU
@app.function(gpu="any")
コンテナイメージ
# Basic image with pip
image = modal.Image.debian_slim(python_version="3.11").pip_install(
"torch==2.1.0", "transformers==4.36.0", "accelerate"
)
# From CUDA base
image = modal.Image.from_registry(
"nvidia/cuda:12.1.0-cudnn8-devel-ubuntu22.04",
add_python="3.11"
).pip_install("torch", "transformers")
# With system packages
image = modal.Image.debian_slim().apt_install("git", "ffmpeg").pip_install("whisper")
永続ストレージ
volume = modal.Volume.from_name("model-cache", create_if_missing=True)
@app.function(gpu="A10G", volumes={"/models": volume})
def load_model():
import os
model_path = "/models/llama-7b"
if not os.path.exists(model_path):
model = download_model()
model.save_pretrained(model_path)
volume.commit() # Persist changes
return load_from_path(model_path)
Web エンドポイント
FastAPI エンドポイントのデコレーター
@app.function()
@modal.fastapi_endpoint(method="POST")
def predict(text: str) -> dict:
return {"result": model.predict(text)}
フル ASGI アプリ
from fastapi import FastAPI
web_app = FastAPI()
@web_app.post("/predict")
async def predict(text: str):
return {"result": await model.predict.remote.aio(text)}
@app.function()
@modal.asgi_app()
def fastapi_app():
return web_app
Web エンドポイントの種類
| デコレーター | ユースケース |
|---|---|
@modal.fastapi_endpoint() | 単純な関数を API 化 |
@modal.asgi_app() | フルな FastAPI/Starlette アプリ |
@modal.wsgi_app() | Django/Flask アプリ |
@modal.web_server(port) | 任意の HTTP サーバー |
動的バッチ処理
@app.function()
@modal.batched(max_batch_size=32, wait_ms=100)
async def batch_predict(inputs: list[str]) -> list[dict]:
# Inputs automatically batched
return model.batch_predict(inputs)
シークレット管理
# Create secret
modal secret create huggingface HF_TOKEN=hf_xxx
@app.function(secrets=[modal.Secret.from_name("huggingface")])
def download_model():
import os
token = os.environ["HF_TOKEN"]
スケジューリング
@app.function(schedule=modal.Cron("0 0 * * *")) # Daily midnight
def daily_job():
pass
@app.function(schedule=modal.Period(hours=1))
def hourly_job():
pass
パフォーマンス最適化
コールドスタートの軽減
@app.function(
container_idle_timeout=300, # Keep warm 5 min
allow_concurrent_inputs=10, # Handle concurrent requests
)
def inference():
pass
モデル読み込みのベストプラクティス
@app.cls(gpu="A100")
class Model:
@modal.enter() # Run once at container start
def load(self):
self.model = load_model() # Load during warm-up
@modal.method()
def predict(self, x):
return self.model(x)
並列処理
@app.function()
def process_item(item):
return expensive_computation(item)
@app.function()
def run_parallel():
items = list(range(1000))
# Fan out to parallel containers
results = list(process_item.map(items))
return results
共通の設定
@app.function(
gpu="A100",
memory=32768, # 32GB RAM
cpu=4, # 4 CPU cores
timeout=3600, # 1 hour max
container_idle_timeout=120,# Keep warm 2 min
retries=3, # Retry on failure
concurrency_limit=10, # Max concurrent containers
)
def my_function():
pass
デバッグ
# Test locally
if __name__ == "__main__":
result = my_function.local()
# View logs
# modal app logs my-app
よくある問題
| 問題 | 解決策 |
|---|---|
| コールドスタートの遅延 | container_idle_timeout を増やし、@modal.enter() を使用 |
| GPU の OOM | より大きな GPU(A100-80GB)を使用し、勾配チェックポイントを有効化 |
| イメージのビルド失敗 | 依存関係のバージョンを固定し、CUDA の互換性を確認 |
| タイムアウトエラー | timeout を増やし、チェックポイントを追加 |
参考資料
- 高度な使い方 - マルチ GPU、分散トレーニング、コスト最適化
- トラブルシューティング - よくある問題と解決策
Resources
- Documentation: https://modal.com/docs
- Examples: https://github.com/modal-labs/modal-examples
- Pricing: https://modal.com/pricing
- Discord: https://discord.gg/modal
コメント
Markdown 対応