Mímisbrunnr知恵の泉

← MLOps 一覧

🎓 レベル:標準 | 重要度:A(必須)

📎 前提:デプロイパターン(バッチ・オンライン・ストリーミング) | 関連:レイテンシとスループットのトレードオフ

要点(BLUF)

1. オンラインサービングの最小要件

API としてモデルを出すなら、最低限これらが要ります:

要件なぜ必要か
起動時ロードリクエスト毎ロードは致命的遅延。1度だけ読む
入力検証不正な特徴量数・型を弾く(422 で返す)
ヘルスチェックロードバランサ・k8s が生死を判定する
メタデータ公開どのモデル・版が動いているかを確認できる
変換器同梱前処理ごとロードしてスキュー防止

2. 図解:サービングの構成

flowchart LR
  C["クライアント"] -->|"POST predict(JSON)"| API["サービングAPI(FastAPI)"]
  API --> V["入力スキーマ検証"]
  V --> M["メモリ常駐モデル(起動時ロード)"]
  M --> R["予測+確率+遅延を応答"]
  LB["ロードバランサ"] -->|"GET health で生死判定"| API
  REG["モデルレジストリ Production"] -.->|"起動時にロード"| M

ポイントは、モデルがメモリに常駐し、レジストリの Production 版(モデルレジストリとモデルのライフサイクル)を起動時に読むこと。ヘルスチェックでロードバランサが生死を見ます。

3. REST と gRPC

REST(JSON over HTTP)gRPC(Protobuf over HTTP/2)
遅延普通低い
デバッグ容易(curl で叩ける)やや手間(専用クライアント)
型安全緩い厳格(スキーマ定義)
向き外部公開・汎用内部の高スループット連携

迷ったら REST。マイクロサービス間の高頻度・低遅延通信が必要なら gRPC を足します。

4. 動く最小例:FastAPI による最小サービング

labs/04_serving/ に、学習済みパイプライン(前処理+分類器)を丸ごとロードして予測を返す最小サービングを置きました。中核は「起動時に1度ロードPydantic で入力検証」です:

# serve.py(抜粋)
MODEL = joblib.load(HERE / "model.joblib")     # 起動時に1度だけ
META = json.loads((HERE / "model_meta.json").read_text(encoding="utf-8"))
N_FEATURES = META["n_features"]

class PredictRequest(BaseModel):
    features: List[float]
    @field_validator("features")
    @classmethod
    def check_len(cls, v):
        if len(v) != N_FEATURES:
            raise ValueError(f"features must have length {N_FEATURES}, got {len(v)}")
        return v

@app.post("/predict")
def predict(req: PredictRequest):
    X = np.array(req.features).reshape(1, -1)
    proba = float(MODEL.predict_proba(X)[0, 1])
    return {"prediction": int(proba >= 0.5), "probability": round(proba, 4)}

smoke_test.py が「学習 → uvicorn 起動 → 疎通 → 予測 → バリデーション」を自動実行します。実行結果:

[health] {'status': 'ok', 'model': 'demo_classifier', 'version': 1}
[metadata] n_features=4 acc=0.95
[predict] pred=1 prob=1.0 latency_ms=0.818
[batch] n=64 latency_ms=0.383 per_item_ms=0.006
[validation] 不正入力のstatus=422(422が正しい)

SMOKE TEST PASSED

出力の意味:API が起動し、ヘルスチェックが ok を返し、単一予測(1件 0.818ms)と64件バッチ予測が動きました。注目はバッチの1件あたり遅延が 0.006ms と単一の100分の1以下なこと——まとめて推論するほど単価が下がる(レイテンシとスループットのトレードオフ)。さらに特徴量数が違う不正入力は 422 で弾かれ、壊れた入力がモデルに届きません。これが「起動時ロード+入力検証」を備えた最小オンラインサービングの骨格です。

5. 運用の勘所

なぜそうするのか

「起動時ロード」を鉄則にするのは、オンラインサービングの価値が低遅延の即時応答にあるからです。モデルのロードは重い処理で、これをリクエスト毎に行えば応答が数百ミリ秒〜秒単位に膨らみ、オンラインである意味が消えます。一度メモリに常駐させ、リクエストでは推論計算だけを行う——この分離が低遅延を支えます。入力検証を置くのは、壊れた入力でモデルが予測不能な値を返し、下流を汚染するのを防ぐためです。

⚠️ よくある落とし穴

対応 lab

関連ノート