Modal - サーバーレスGPU/CPUコンピュートでAI/MLワークフローを高速化

中級 | 10分 で読める | 2026.04.24

公式ドキュメント

この記事の要点

• Pythonデコレータだけでサーバーレスコンテナ・GPU環境を起動
• 従量課金制でアイドル時のコスト0、秒単位課金で無駄を削減
• LLM推論・画像生成・バッチ処理・分散学習をシンプルなコードで実現

AI/MLワークロードの実行には高価なGPUインスタンスが必要ですが、常時起動させるとコストが膨らみます。Modalは、必要な時だけGPU/CPUを起動し、処理完了後は自動停止するサーバーレスプラットフォームとして、開発者のインフラ管理負担とコストを大幅に削減します。本記事では、Modalの特徴と実践的な利用方法を解説します。

Modalとは

Modalは、Pythonコードに数行のデコレータを追加するだけで、クラウド上のコンテナやGPUクラスタを自動起動するサーバーレスコンピュートプラットフォームです。開発者はDockerfile・Kubernetes設定・インフラ管理コードを一切書かずに、スケーラブルなAI/MLワークロードを実行できます。

主要な特徴

  • ゼロ管理: Dockerイメージ・依存関係・GPU設定をModalが自動管理
  • 秒単位課金: 実行時間のみ課金、アイドル時はコスト0
  • 高速コールドスタート: コンテナ起動が数秒、GPU環境も10秒以内
  • 並列スケーリング: 数千の並列タスクを自動でスケールアウト
  • 統合ストレージ: Volume・Dict・Queueなど永続化・共有ストレージを標準装備
  • スケジュール実行: cron式でバッチジョブを定期実行
  • Web UI: リアルタイムログ・メトリクス・コスト分析をダッシュボードで確認

ポイント: Modalは「サーバーレス」と「コンテナ」の良いところ取りをしています。AWS Lambdaのような手軽さで、コンテナ並みの柔軟性(GPU・任意の依存関係・長時間実行)を実現しています。

なぜModalが必要か

従来のML基盤構築には、以下の課題がありました。

従来の課題

  1. インフラ構築の複雑さ: Kubernetes・Docker・GPU設定を習得し、構成ファイルを大量に書く必要がある
  2. コスト管理の難しさ: GPUインスタンスを常時起動すると月額数万〜数十万円のコストが発生
  3. スケーリングの手間: 並列実行数に応じて手動でインスタンスを増減する必要がある
  4. 環境の再現性: ローカルと本番で依存関係・Pythonバージョンが異なるとエラーが発生

Modalはこれらをすべてコードレベルで解決し、Pythonの関数定義と同じ感覚でクラウドリソースを扱えます。

アーキテクチャ

flowchart TB
    subgraph Client["開発者環境"]
        A1["Python Script<br/>@app.function()"]
    end

    subgraph Modal["Modal Cloud"]
        B1["Scheduler"]
        B2["Container Pool"]
        B3["GPU Pool"]
        B4["Volume Storage"]
        B5["Log Aggregator"]
    end

    A1 -->|"modal run"| B1
    B1 --> B2
    B1 --> B3
    B2 --> B4
    B3 --> B4
    B2 --> B5
    B3 --> B5
  • Scheduler: 関数呼び出しをキューに積み、適切なコンテナ/GPUに割り当て
  • Container Pool: 各タスクを独立したコンテナで実行
  • GPU Pool: NVIDIA A100・H100等のGPUをオンデマンドで割り当て
  • Volume Storage: 複数タスク間でファイルを共有(モデル重み・データセット等)
  • Log Aggregator: すべてのログをリアルタイムで収集・表示

基本的な使い方

インストール

pip install modal
modal setup  # 初回のみ認証

最小限のサンプル

import modal

# Modalアプリを定義
app = modal.App("hello-modal")

# 関数をModalで実行
@app.function()
def hello(name: str) -> str:
    return f"Hello, {name}!"

# ローカルから呼び出し
@app.local_entrypoint()
def main():
    result = hello.remote("World")
    print(result)
modal run hello.py
# 出力: Hello, World!

このコードは、hello関数をModal上のコンテナで実行します。ローカルのPython環境とは完全に独立した環境で実行されるため、依存関係の競合が発生しません。

実践メモ: @app.function() デコレータを付けるだけで、ローカル関数がクラウド関数に変わります。呼び出しは .remote() メソッドで行います。

GPU推論の例

LLMや画像生成モデルをGPU上で実行する例です。

LLM推論(Transformers + GPU)

import modal

# GPUイメージを定義
image = (
    modal.Image.debian_slim()
    .pip_install("transformers", "torch", "accelerate")
)

app = modal.App("llm-inference")

# A100 GPUで実行
@app.function(
    image=image,
    gpu="A100",  # NVIDIA A100 GPU
    timeout=600,
)
def generate_text(prompt: str) -> str:
    from transformers import pipeline
    
    # モデルをロード(初回のみダウンロード)
    generator = pipeline(
        "text-generation",
        model="meta-llama/Llama-2-7b-chat-hf",
        device=0,
    )
    
    result = generator(prompt, max_length=100)
    return result[0]["generated_text"]

@app.local_entrypoint()
def main():
    result = generate_text.remote("Explain quantum computing in simple terms:")
    print(result)
modal run llm_inference.py

このコードは、A100 GPUを起動してLlama 2モデルで推論を実行し、処理完了後にGPUを自動停止します。

ポイント: gpu="A100" を指定するだけでGPU環境が用意されます。Dockerイメージの手動ビルドやCUDA設定は不要で、Modalが自動で最適化します。

並列実行とバッチ処理

複数のタスクを並列実行する例です。

画像バッチ処理

import modal

image = modal.Image.debian_slim().pip_install("Pillow", "requests")

app = modal.App("batch-image-processing")

# 複数タスクを並列実行
@app.function(image=image, cpu=2)
def process_image(url: str) -> dict:
    from PIL import Image
    import requests
    from io import BytesIO
    
    # 画像をダウンロード
    response = requests.get(url)
    img = Image.open(BytesIO(response.content))
    
    # リサイズ
    img_resized = img.resize((800, 600))
    
    return {
        "url": url,
        "original_size": img.size,
        "resized_size": img_resized.size,
    }

@app.local_entrypoint()
def main():
    image_urls = [
        "https://example.com/image1.jpg",
        "https://example.com/image2.jpg",
        # ... 1000個のURL
    ]
    
    # .map()で並列実行
    results = list(process_image.map(image_urls))
    
    for result in results:
        print(result)

.map()メソッドは、引数のリストを並列に処理し、自動的にタスク数を調整します。

注意: 並列実行数はプランによって制限されます。無料プランでは同時実行数に上限があるため、大規模バッチ処理には有料プランを検討してください。

Web API化

Modal関数をHTTP APIとして公開できます。

FastAPIとの統合

import modal
from fastapi import FastAPI
from pydantic import BaseModel

image = modal.Image.debian_slim().pip_install("fastapi[standard]")

app = modal.App("api-server")

# FastAPIインスタンス
web_app = FastAPI()

class PredictionRequest(BaseModel):
    text: str

class PredictionResponse(BaseModel):
    sentiment: str
    score: float

@web_app.post("/predict")
def predict(request: PredictionRequest) -> PredictionResponse:
    # ダミー推論(実際はモデルを使用)
    return PredictionResponse(
        sentiment="positive",
        score=0.95,
    )

# ModalでAPIを公開
@app.function(image=image)
@modal.asgi_app()
def fastapi_app():
    return web_app
modal deploy api.py
# 出力: https://your-app.modal.run

このコードは、FastAPI アプリケーションを Modal 上で公開します。スケーリング・ロードバランシング・HTTPS証明書がすべて自動設定されます。

実践メモ: modal deploy コマンドで常時起動のエンドポイントを作成できます。リクエストがない時は自動スリープし、リクエストが来ると数秒で起動します。

スケジュール実行

定期的にバッチジョブを実行する例です。

毎日データ収集

import modal
from datetime import datetime

app = modal.App("scheduled-scraper")

# 毎日午前3時に実行
@app.function(schedule=modal.Cron("0 3 * * *"))
def daily_scraper():
    print(f"Running scraper at {datetime.now()}")
    
    # データ収集処理
    # ...
    
    print("Scraper finished")
modal deploy scheduled_scraper.py

デプロイ後、Modal側で自動的にスケジュールされたタスクが実行されます。

Volumeによる永続化

モデル重みやデータセットをVolume(永続ストレージ)に保存し、複数実行間で再利用できます。

モデル重みのキャッシュ

import modal

# Volumeを定義
volume = modal.Volume.from_name("model-cache", create_if_missing=True)

image = modal.Image.debian_slim().pip_install("transformers", "torch")

app = modal.App("model-cache-demo")

@app.function(
    image=image,
    gpu="T4",
    volumes={"/cache": volume},  # /cacheにVolumeをマウント
)
def load_model():
    from transformers import AutoModelForCausalLM, AutoTokenizer
    
    model_name = "gpt2"
    cache_dir = "/cache/models"
    
    # 初回のみダウンロード、2回目以降はキャッシュから読み込み
    tokenizer = AutoTokenizer.from_pretrained(model_name, cache_dir=cache_dir)
    model = AutoModelForCausalLM.from_pretrained(model_name, cache_dir=cache_dir)
    
    # Volumeを永続化
    volume.commit()
    
    return "Model loaded successfully"

@app.local_entrypoint()
def main():
    result = load_model.remote()
    print(result)

初回実行時はモデルをダウンロードしてVolumeに保存し、2回目以降はVolumeから読み込むため、ダウンロード時間を短縮できます。

ポイント: Volumeは複数の関数・実行間で共有されるため、大きなモデル重みやデータセットを毎回ダウンロードする必要がありません。

ModalとAWS Lambdaの比較

Modalと似た用途で使われるAWS Lambdaとの違いを理解しておくと、適切なプラットフォームを選択できます。

項目ModalAWS Lambda
言語Python中心多言語対応
GPU対応ネイティブ対応非対応(別サービス必要)
実行時間制限数時間〜無制限15分まで
コールドスタート数秒〜10秒数ミリ秒〜数秒
依存関係任意(コンテナ)サイズ制限あり
料金秒単位課金ミリ秒単位課金

軽量なAPI処理ならLambda、AI/MLワークロードや長時間バッチならModalが適しています。

ModalとKubernetesの比較

Kubernetesと比べると、Modalは以下の点で優れています。

項目ModalKubernetes
セットアップ数分数日〜数週間
設定ファイルPythonコードのみYAML大量
スケーリング自動(設定不要)手動設定が必要
GPU管理自動複雑なCRD設定
コスト最適化自動停止・起動手動でノード管理

ただし、Kubernetesは他のクラウドサービス(データベース・キューイング等)との統合が柔軟なため、既存のKubernetes環境があり、細かい制御が必要ならKubernetes、速さと手軽さを優先するならModalを選択します。

実践的なユースケース

1. LLM推論API

import modal

image = modal.Image.debian_slim().pip_install("transformers", "torch", "fastapi[standard]")

app = modal.App("llm-api")

# モデルをグローバルで保持
@app.cls(
    image=image,
    gpu="A100",
    volumes={"/cache": modal.Volume.from_name("llm-models", create_if_missing=True)},
)
class LLMInference:
    @modal.enter()
    def load_model(self):
        from transformers import pipeline
        
        self.generator = pipeline(
            "text-generation",
            model="meta-llama/Llama-2-7b-chat-hf",
            device=0,
            cache_dir="/cache",
        )
    
    @modal.method()
    def generate(self, prompt: str, max_length: int = 100) -> str:
        result = self.generator(prompt, max_length=max_length)
        return result[0]["generated_text"]

@app.local_entrypoint()
def main():
    model = LLMInference()
    result = model.generate.remote("Explain AI in simple terms:")
    print(result)

@app.clsを使うと、モデルを1回だけロードし、複数の推論リクエストで再利用できます。

2. 動画処理バッチ

import modal

image = modal.Image.debian_slim().pip_install("opencv-python", "ffmpeg-python")

app = modal.App("video-processing")

@app.function(
    image=image,
    cpu=4,
    memory=8192,
    timeout=3600,
)
def process_video(video_url: str) -> dict:
    import cv2
    import requests
    from io import BytesIO
    
    # 動画をダウンロード
    response = requests.get(video_url)
    
    # OpenCVで処理
    # ... (フレーム抽出・圧縮等)
    
    return {
        "video_url": video_url,
        "frames": 120,
        "duration": 60,
    }

@app.local_entrypoint()
def main():
    video_urls = [
        "https://example.com/video1.mp4",
        "https://example.com/video2.mp4",
        # ... 100個
    ]
    
    results = list(process_video.map(video_urls))
    print(results)

3. データパイプライン

import modal

app = modal.App("data-pipeline")

@app.function(schedule=modal.Cron("0 * * * *"))  # 毎時
def extract_data():
    # データ抽出
    return ["data1", "data2"]

@app.function()
def transform_data(data: list) -> list:
    # データ変換
    return [d.upper() for d in data]

@app.function()
def load_data(data: list):
    # データベースに保存
    print(f"Loaded {len(data)} records")

# パイプライン実行
@app.local_entrypoint()
def pipeline():
    raw_data = extract_data.remote()
    transformed = transform_data.remote(raw_data)
    load_data.remote(transformed)

料金と制限

Modalはフリープランと有料プランを提供しています(具体的な価格は公式サイトで確認してください)。

フリープラン(目安)

  • 月間実行時間: 限定的
  • GPU: T4など低価格GPU
  • 並列実行数: 数個まで

有料プラン(目安)

  • 月間実行時間: 従量課金(秒単位)
  • GPU: A100・H100など高性能GPU
  • 並列実行数: 数千まで
  • サポート: 優先サポート

実践メモ: Modalは使った分だけ課金されるため、開発時はフリープラン、本番では必要な時だけ有料プランに切り替える運用が可能です。

まとめ

Modalは、Pythonデコレータだけでサーバーレスコンテナ・GPU環境を起動できる革新的なプラットフォームです。従来のML基盤構築で必要だったKubernetes・Docker・GPU設定を完全に抽象化し、開発者はビジネスロジックに集中できます。

Modalを選ぶべきケース

  • LLM推論・画像生成などGPUが必要なワークロード
  • バッチ処理を並列化してコストを最適化したい
  • インフラ管理を極限まで減らしたい
  • 従量課金でアイドル時のコストを0にしたい
  • Pythonで完結するワークフロー

ModalはPythonコードに数行のデコレータを追加するだけで、数千の並列タスクをGPU上で実行できます。AI/MLの民主化を加速するプラットフォームとして、今後さらに普及が進むと予想されます。

関連記事

この技術を体系的に学びたいですか?

未来学では東証プライム上場企業のITエンジニアが24時間サポート。月額24,800円から、退会金0円のオンラインIT塾です。

メールで無料相談する
← 一覧に戻る