serverless-modal について
serverless-modalは、PythonスクリプトからModal上でGPUトレーニング、評価、推論を実行するスキルです。単発ジョブ、API、バッチ処理、分散トレーニングの起動パターンを示し、実行前のコスト見積もりを必須とします。
主な機能
- 01Modalの起動スクリプトを生成
- 02トレーニング、推論、評価に対応
- 03バッチ処理とマルチGPUの例を提供
- 04実行前にコストを見積もり
- 05ボリュームまたは関数出力から結果を収集
- 06アプリとログを監視
活用シーン
- 01SSHインスタンスを管理せずGPU実験を実行
- 02常時稼働する推論APIをデプロイ
- 03並列GPU関数でデータセットを処理
- 04ファインチューニングやマルチGPU学習を実施
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ wanshuiyin/ auto-claude-code-research-in-sleep --skill serverless-modalインストール後、Claude Code で/serverless-modalを入力して読み込まれたか確認します。
詳細
Modal クラウド GPU — 学習と推論
タスク:$ARGUMENTS
概要
Modal はサーバーレス GPU クラウドです。SSH ベースのプラットフォーム(vast.ai、リモートサーバー)に対する主な利点は次のとおりです。
- 設定不要:SSH、Docker、ポートフォワーディングは不要です。Python を記述して →
modal runを実行すれば完了です。 - 自動でゼロにスケール:コードの実行が終了した瞬間に課金が停止します。アイドル状態のインスタンスはありません。
- ローカル優先:ノート PC から
modal runを実行できます。コード、データ、結果はローカルにとどまり、GPU 関数のみがリモートで実行されます。 - 再現可能な環境:依存関係はシステムレベルのパッケージではなく、コード内の
modal.Imageで宣言します。modal.Imageチェーンは、宣言的な環境仕様である../shared-references/compute-env-contract.mdのレンダリング形式として扱います。仕様の各フィールド(ベース、 順序付けられた pip フェーズ、環境変数、スモークプローブ)、.aris/compute/modal.mdの 同じenv:<name>@<specHash>台帳エントリー、長時間実行の前に行う同じ 3 段階の検証が対象です。
最適な用途:ローカル GPU がなく、CUDA コードのデバッグ、小規模テストの実行、実験のすばやい反復が必要なユーザー。5 ドルの無料枠(カード不要)でコードのデバッグに十分対応でき、30 ドル(カード登録が必要)で小規模な実験の実行の多くをカバーできます。
トレードオフ:Modal は一部の GPU クラスでは GPU の時間単価が vast.ai や Lightning より高くなりますが、セットアップ時間とアイドル時の課金が不要になるため、短時間から中時間のワークロードでは結果的に安くなることがよくあります。長時間の学習実行(4 時間超)では、時間単価の低い vast.ai を検討してください。
認証
pip install modal
modal setup # Opens browser login, writes token to ~/.modal.toml
# Verify:
modal run -q 'print("ok")'
- 登録:https://modal.com(GitHub/Google ログイン)
- 無料(カード不要):月額 5 ドル — 簡単なテストに十分です
- 無料(カード登録あり):月額 30 ドル — https://modal.com/settings で支払い方法を登録すると、無料枠を全額利用できます。誤って超過請求されないよう、ワークスペースの利用上限を設定してください(Settings → Usage → Spending Limit)
- 学術機関:1 万ドル分のクレジットを申請できます | スタートアップ:2 万 5 千ドル分のクレジットを申請できます
- シークレット:
modal secret create huggingface-secret HF_TOKEN=hf_xxxxx
推奨設定:カードを登録して月額 30 ドルの枠を利用できるようにしたら、すぐに利用上限(例:30 ドル)を設定し、無料枠を超えないようにしてください。上限に達すると、Modal はワークロードを一時停止します。
セキュリティに関する警告:カードの登録と利用上限の設定は、必ずブラウザーで https://modal.com/settings に直接アクセスして行ってください。Claude Code や CLI ツールを通じて、支払い情報、カード番号、請求情報を入力してはいけません。支払い操作に使用しても安全なのは、Modal の公式 Web サイトのみです。
料金(出典:modal.com/pricing、秒単位の課金)
| GPU | ドル/秒 | ≈ドル/時間 | VRAM | 帯域幅 GB/s | 無料枠 → 利用時間 |
|---|---|---|---|---|---|
| T4 | $0.000164 | $0.59 | 16GB | 300 | 約 8.5 時間($5)/50.8 時間($30) |
| L4 | $0.000222 | $0.80 | 24GB | 300 | 約 6.3 時間/37.5 時間 |
| A10 | $0.000306 | $1.10 | 24GB | 600 | 約 4.5 時間/27.3 時間 |
| L40S | $0.000542 | $1.95 | 48GB | 864 | 約 2.6 時間/15.4 時間 |
| A100-40GB | $0.000583 | $2.10 | 40GB | 1555 | 約 2.4 時間/14.3 時間 |
| A100-80GB | $0.000694 | $2.50 | 80GB | 2039 | 約 2.0 時間/12.0 時間 |
| H100 | $0.001097 | $3.95 | 80GB | 3352 | 約 1.3 時間/7.6 時間 |
| H200 | $0.001261 | $4.54 | 141GB | 4800 | 約 1.1 時間/6.6 時間 |
| B200 | $0.001736 | $6.25 | 192GB | 8000 | 約 0.8 時間/4.8 時間 |
CPU:$0.047/コア/時間 | RAM:$0.008/GiB/時間(通常、GPU が総コストの 90%以上を占めます)
!! コスト見積もりが必要です !!
実行のたびに、必ずコストを見積もり、ユーザーに提示して確認を得てください。
主なポイント:
- 推論のボトルネックは計算処理ではなくメモリ帯域幅です → 帯域幅の広い GPU の方が、全体として安くなることがよくあります
- 7~8B の BF16 推論には約 22GB の VRAMが必要です(重み 15G + KV キャッシュ 1G +オーバーヘッド)。T4(16GB)では足りません
- ベンチマークでは、H100 は L4 より安くなることがよくあります(11 倍高速ですが、価格は 5 倍にとどまります)
コスト見積もりテンプレート(実行のたびに必須)
Cost estimate (Modal):
Model: [name] ([params], [precision])
VRAM: ~[X]GB (weights + KV cache + overhead)
GPU: [type] ([VRAM]GB, $[X]/sec = $[X]/hr, bandwidth [X] GB/s)
Estimate: ~[N] min, ~$[X]
7~8B BF16 ベンチマークのコスト比較
| GPU | 速度 tok/s | ドル/時間 | 200tok のサンプル 1000 件のコスト | 所要時間 |
|---|---|---|---|---|
| H100 | 224 | $3.95 | $0.98 | 15 分 |
| A100-40GB | 104 | $2.10 | $1.12 | 32 分 |
| L4 | 20 | $0.80 | $2.22 | 167 分 |
ワークフロー
ステップ 1:タスクを分析 → コストを見積もる → GPU を選択する
ほかの GPU スキルと同様に分析します。モデルサイズから必要な VRAM を判断し、GPU を選び、所要時間を見積もってコストを計算します。上記の料金表を参照してください。
VRAM の目安:
| モデルサイズ | FP16 VRAM | 推奨 GPU |
|---|---|---|
| ≤3B | ~8GB | T4, L4 |
| 7-8B | ~22GB | L4, A10, A100-40GB |
| 13B | ~30GB | L40S, A100-40GB |
| 30B | ~65GB | A100-80GB, H100 |
| 70B | ~140GB | H100:2, H200 |
ステップ 2:Modal ランチャーを生成する
タスクの種類に応じて、適切なランチャースクリプトを生成します。
パターン A:単発 GPU 関数(トレーニング、評価、ベンチマーク)
run-experiment との連携で最も一般的なパターンです。既存のトレーニングスクリプトをラップします。
import modal
app = modal.App("experiment-name")
# One .pip_install() call per SPEC PHASE (chained calls install in order, so a
# pinned torch in the first call can't be dragged by packages in the second —
# the rendered form of compute-env-contract.md's ordered pip_phases):
image = (
modal.Image.debian_slim(python_version="3.11")
.pip_install("torch") # phase 1: pins
.pip_install("transformers", "accelerate", "datasets", "wandb") # phase 2
)
# Mount local project code into the container
local_code = modal.Mount.from_local_dir(".", remote_path="/workspace")
# Persistent volume for checkpoints and results
volume = modal.Volume.from_name("experiment-results", create_if_missing=True)
@app.function(
image=image,
gpu="A100-80GB", # Chosen based on Step 1 analysis
mounts=[local_code],
volumes={"/results": volume},
timeout=3600 * 6, # 6 hours max
secrets=[modal.Secret.from_name("wandb-secret")], # Optional
)
def train():
import subprocess
subprocess.run(
["python", "train.py", "--output_dir", "/results/run_001"],
cwd="/workspace",
check=True,
)
volume.commit() # Persist results to volume
@app.local_entrypoint()
def main():
train.remote()
print("Training complete. Results saved to Modal volume 'experiment-results'.")
実行:modal run launcher.py
パターン B:Web API(永続的な推論サービス)
import modal
app = modal.App("inference-api")
image = (
modal.Image.debian_slim(python_version="3.11")
.pip_install("torch") # phase 1: pins
.pip_install("transformers", "accelerate") # phase 2
)
@app.cls(image=image, gpu="L40S")
@modal.concurrent(max_inputs=10)
class InferenceAPI:
@modal.enter()
def load_model(self):
from transformers import AutoModelForCausalLM, AutoTokenizer
self.tokenizer = AutoTokenizer.from_pretrained("meta-llama/Llama-3.2-1B")
self.model = AutoModelForCausalLM.from_pretrained(
"meta-llama/Llama-3.2-1B", device_map="auto"
)
@modal.fastapi_endpoint(method="POST")
def generate(self, request: dict):
inputs = self.tokenizer(request.get("prompt", ""), return_tensors="pt").to("cuda")
outputs = self.model.generate(**inputs, max_new_tokens=256)
return {"text": self.tokenizer.decode(outputs[0], skip_special_tokens=True)}
デプロイ:modal deploy app.py
パターン C:vLLM による高性能推論
import modal, subprocess
app = modal.App("vllm-server")
image = modal.Image.debian_slim(python_version="3.11").pip_install("vllm")
VOLUME = modal.Volume.from_name("model-cache", create_if_missing=True)
MODEL = "Qwen/Qwen3-4B"
@app.function(image=image, gpu="H100", volumes={"/models": VOLUME}, timeout=3600)
@modal.concurrent(max_inputs=100)
@modal.web_server(port=8000)
def serve():
subprocess.Popen(["python", "-m", "vllm.entrypoints.openai.api_server",
"--model", MODEL, "--download-dir", "/models", "--port", "8000"])
パターン D:バッチ並列処理(データセットに対する map 処理)
@app.function(image=image, gpu="T4", timeout=600)
def process_item(item: dict) -> dict:
# ... process one item ...
return {"result": "processed"}
@app.local_entrypoint()
def main():
results = list(process_item.map([{"id": i} for i in range(1000)]))
パターン E:LoRA ファインチューニング
@app.function(
image=image, gpu="A100-80GB", volumes={"/output": volume},
timeout=3600 * 6, secrets=[modal.Secret.from_name("huggingface-secret")],
)
def train():
# ... transformers + peft + trl training code ...
trainer.save_model("/output/final")
volume.commit()
パターン F:マルチ GPU 分散トレーニング
@app.function(image=image, gpu="H100:4", volumes={"/output": volume}, timeout=3600 * 12)
def train_distributed():
import subprocess
subprocess.run(["accelerate", "launch", "--num_processes", "4",
"--mixed_precision", "bf16", "train.py"], check=True)
ステップ 3:実行する
modal run launcher.py # One-shot execution (most common for experiments)
modal deploy app.py # Persistent service deployment
ステップ 4:検証と監視
modal app list # List running apps
modal app logs <app-name> # Stream logs
ステップ 5:結果を収集する
結果の収集方法は、使用したパターンによって異なります。
ボリュームベース(トレーニングに推奨):
# Download results from volume after run completes
# Option A: In the launcher script, copy results to local mount before exit
# Option B: Use modal volume commands
modal volume ls experiment-results
modal volume get experiment-results /run_001/results.json ./results/
標準出力/戻り値ベース(評価/ベンチマーク用): 結果はターミナルに出力されるか、関数から返されます。すでにローカルにあります。
ステップ 6:クリーンアップ
Modal は自動的にゼロまでスケールダウンするため、インスタンスを手動で破棄する必要はありません。ただし、使用していないリソースはクリーンアップしてください。
modal app stop <app-name> # Stop a deployed service
modal volume rm <volume-name> # Delete a volume when done
CLI リファレンス
modal run app.py # Run once
modal deploy app.py # Deploy persistent service
modal app logs <app> # View logs
modal app list # List apps
modal app stop <app> # Stop
modal volume ls # List volumes
modal volume get <vol> <remote> <local> # Download from volume
modal secret create NAME KEY=VALUE # Create secret
主なヒント
- GPU のフォールバック:
gpu=["H100", "A100-80GB", "L40S"]— Modal は順番に試します - マルチ GPU:
gpu="H100:4"(最大 8 GPU、コストは GPU 数に比例して増加します) - ボリューム:永続ストレージには
modal.Volume.from_name("x", create_if_missing=True)を使用します @modal.enter()はコンテナごとに一度モデルを読み込みます | 並行リクエストには@modal.concurrent()を使用します- 長時間のトレーニング:
timeout=3600 * Nを設定します(デフォルトは 5 分です) - ローカルコード:
modal.Mount.from_local_dir(".", remote_path="/workspace") - W&B との連携:
secrets=[modal.Secret.from_name("wandb-secret")]を指定し、スクリプト内でwandb.init()を呼び出します
他のスキルとの組み合わせ
/run-experiment "train model" <- detects gpu: modal, calls /serverless-modal
-> /serverless-modal <- analyzes task, generates launcher, runs
-> Results returned locally or to Modal Volume
-> No destroy step needed (auto scale-to-zero)
/serverless-modal <- standalone: any Modal GPU workload
/serverless-modal "deploy vLLM" <- inference service deployment
CLAUDE.md の例
## Modal
- gpu: modal # tells run-experiment to use Modal serverless
- modal_gpu: A100-80GB # optional: override GPU selection (default: auto-select)
- modal_timeout: 21600 # optional: max seconds (default: 6 hours)
- modal_volume: my-results # optional: named volume for results persistence
SSH キー、Docker イメージ、インスタンス管理は不要です。pip install modal && modal setup を実行するだけです。
コスト保護:
modal setupの後、ブラウザーで https://modal.com/settings にアクセスし(CLI 経由では絶対に行わないでください)、支払い方法を登録すると、月額 30 ドルの無料枠が利用できます(カードを登録しない場合は月額 5 ドルのみ)。次に、ワークスペースの利用上限を無料枠と同額に設定してください。上限に達すると Modal がワークロードを自動的に一時停止するため、予期しない請求を防げます。