MLキャパシティとコストプランニング
翻訳についての注記: 本ドキュメントは英語原文
16-ml-systems/14-ml-capacity-cost-planning.mdを日本語に翻訳したものです。コードブロック、YAML、表内の技術用語は原文のまま維持しています。
TL;DR
MLのキャパシティプランニングは、2つの高価なひねりを加えた普通のキャパシティプランニングです: アクセラレータは高価で分割不能なリソースであり、モデルの仕事は分散が大きい。数学は依然として第一原理です: リクエストレート、サービス時間、並行数、稼働率、メモリ、帯域、キューイング。しかしボトルネックはワークロードによって異なります。オンライン推論は通常、p99レイテンシ、バッチ待ち、モデルロード時間、アクセラレータメモリ、特徴量フェッチのファンアウトに支配されます。バッチ推論はスループットと予測あたりコストに支配されます。訓練はアクセラレータ時間、データI/O、チェックポインティング、クラスタスケジューリングに支配されます。中心的なルールは、ダッシュボードがたまたま表示する平均メトリクスではなく、ボトルネックとなるリソースと、プロダクトが経験するパーセンタイルに対してサイズすることです。GPU提供では、それは通常、キュー深度、バッチレイテンシ、GPUメモリ、稼働率を意味します — CPUではなく。
重要な単位
すべてのMLキャパシティ推定は4つの単位から始まります:
requests/second incoming prediction or training examples
seconds/request service time per item or batch
bytes/request features, embeddings, prompts, outputs
accelerator memory model weights + activations + batch/KV/cache stateここから残りを導出します:
concurrency = arrival_rate × latency (Little's law)
throughput_per_replica = batch_size / batch_service_time
replicas = peak_rps / safe_throughput_per_replica
cost_per_prediction = hourly_cost / predictions_per_hour数字は最初は正確である必要はありません。明示的である必要があります。見える仮定を持つ誤った推定は訂正できます。推定のないアーキテクチャは、そのコストを本番で発見します。
提供レジームごとにキャパシティの目標は異なる
最初のキャパシティの決定はハードウェアではありません。提供レジームです。
| レジーム | 目標 | 主な制約 | 典型的なメトリクス |
|---|---|---|---|
| オンライン同期 | ユーザーリクエスト内で回答 | p99レイテンシ | p99、タイムアウト率、キュー待ち |
| オンライン非同期 | イベント後すぐに処理 | キューのラグ | エンドツーエンドのラグ、バックログ |
| バッチスコアリング | 期限までに安く完了 | スループット/コスト | 予測数/時、実行あたりコスト |
| 訓練 | 期限までにアーティファクトを生産 | アクセラレータ時間+I/O | 訓練所要時間、実行あたりコスト |
日次の解約スコアはオンラインGPU提供を必要としません。チェックアウトの不正判断は必要とします。鮮度を満たす最も安いレジームに仕事を移すことが、MLシステムで最もレバレッジの高いコスト最適化です。
オンライン推論のサイジング
オンライン推論では、レイテンシ予算とピークトラフィックから始めます。
例:
Peak traffic: 12,000 RPS
End-to-end p99 budget: 120 ms
Budget allocation:
ingress/auth 10 ms
feature fetch 35 ms
inference 45 ms
postprocess/logging 15 ms
network/headroom 15 ms1つのモデルレプリカが32のバッチを20msで処理できるなら、その理論スループットは:
32 / 0.020s = 1,600 predictions/sしかし理論スループットは安全なスループットではありません。高稼働率ではキューイング遅延が爆発します。安全な目標が65%稼働率なら:
safe_throughput = 1,600 × 0.65 ≈ 1,040 predictions/s
replicas = 12,000 / 1,040 ≈ 12 replicas次に障害とデプロイのヘッドルームを加えます。サービスが1レプリカまたは1AZの喪失を生き延び、ローリングデプロイを支えなければならないなら、12では足りません。最終的な数はトポロジー次第で16〜20レプリカかもしれません。
鍵は、バッチスループットとレイテンシ予算が相互作用することです。より大きなバッチはスループットを上げますが、キュー待ちを加えます。バッチ待ちをモデル化せずに最大バッチスループットを使うキャパシティ計画は、設計からして楽観的です。
動的バッチングのキャパシティ
動的バッチングには2つのノブがあります: 最大バッチサイズと最大待ち時間。キャパシティプランニングは両方を考慮しなければなりません。
max_batch_size = 32
max_wait = 5 ms
batch_compute_time = 20 ms高負荷下ではバッチはすぐに満たされ、サービスは32/20msのスループットに近づきます。低負荷下ではリクエストは5msフルに待ち、より小さなバッチで走り、稼働率を下げます。バースト的な負荷下ではキューが振動し、p99が跳ね得ます。
単純なサイジングルール:
per_replica_capacity ≈ effective_batch_size / (batch_compute_time + average_batch_wait)しかしp99の計画は、平均待ちではなくテールの待ちを使わなければなりません。最大待ちが5msでも、バーストのキューイングがリクエストがバッチに入る前に30msを加えるなら、GPU稼働率が健全に見えても推論予算は吹き飛んでいます。
監視すべきもの:
- キュー深度、
- キュー待ちのp50/p95/p99、
- 実効バッチサイズ、
- バッチ計算時間、
- タイムアウト/ドロップ率、
- GPU稼働率とメモリ。
CPUは、GPUバウンドの推論の飽和シグナルではありません。
メモリサイジング: ハードリミット
アクセラレータメモリは硬いキャパシティ境界です。バッチが収まらなければ、レプリカはクラッシュするか仕事を拒否します。スループットの前にメモリを見積もること。
total_memory = model_weights
+ runtime_overhead
+ activation_memory(batch_size, input_shape)
+ cache_memory
+ fragmentation_headroom古典的なニューラル推論では、アクティベーションメモリはバッチサイズと入力サイズとともに成長します。LLMでは、KVキャッシュはシーケンス長と並行トークン数とともに成長します。レコメンデーションシステムでは、埋め込みテーブルがメモリを支配するかもしれず、特徴量キャッシュはモデルサーバーの外にあるかもしれません。
メモリキャパシティの問いは:
max_safe_batch = floor((device_memory - weights - overhead - headroom) / per_item_activation)ヘッドルームを使うこと。メモリ断片化、可変の入力サイズ、フレームワークのワークスペースは、ぴったりの適合を危険にします。ベンチマークで動くバッチサイズが、本番の入力形状の分散の下ではOOMするかもしれません。
実際のサイジング例がハードリミットを可視化します:
device_memory = 24 GiB
model_weights = 7.5 GiB
runtime/framework overhead = 1.5 GiB
workspace/fragmentation = 2.0 GiB
safety headroom = 3.0 GiB
available_for_activations = 24 - 7.5 - 1.5 - 2.0 - 3.0 = 10 GiB
per_item_activation_p95 = 220 MiB
max_safe_batch_p95 = floor(10 GiB / 220 MiB) ≈ 46本番の入力サイズに長いテールがあるなら、p99または明示的な最大入力ポリシーを使います:
per_item_activation_p99 = 410 MiB
max_safe_batch_p99 = floor(10 GiB / 410 MiB) ≈ 24正しいバッチサイズは46ではなく24かもしれません。オンラインサービスはテールを生き延びなければならないからです。もうひとつの有効な設計は入力サイズの上限またはバケット化です: 小さな入力はバッチ46を使い、大きな入力はバッチ16の別プールにルーティングする。アンチパターンは、平均的な入力でベンチマークし、p99のトラフィックでモデルサーバーがOOMすることを発見することです。
特徴量フェッチのファンアウトが推論を支配し得る
多くのML提供システムはモデルバウンドではありません。特徴量バウンドです。
5つのストアから40の特徴量をフェッチするリクエストは、推論よりネットワークI/Oに多くの時間を使い得ます。キャパシティプランニングはフィーチャーストアのQPSとファンアウトを含まなければなりません:
prediction_rps = 12,000
feature_groups_per_prediction = 5
online_feature_qps = 60,000 group reads/s各グループ読み取りが内部で複数パーティションにファンアウトするなら、バックエンドの負荷はさらに高い。キャッシュヒット率を加えます:
backend_qps = prediction_rps × feature_groups × (1 - cache_hit_rate)90%ヒット率では:
12,000 × 5 × 0.10 = 6,000 backend reads/s50%ヒット率では:
12,000 × 5 × 0.50 = 30,000 backend reads/sつまりキャッシュヒット率の退行は、トラフィック増ゼロでバックエンド負荷を5倍にし得ます。特徴量フェッチのキャパシティは推論の計画に属します。
コールドスタートとウォームキャパシティ
モデルレプリカにはロード時間があります。大きなモデルは重みをメモリにロードするのに数十秒から数分かかるかもしれません。ウォームでないキャパシティは即座には利用できません。
需要が1分で5,000 RPS急増し得て、レプリカが準備完了まで2分かかるなら、反応的なオートスケーリングはSLOを救えません。キャパシティはすでにウォームであるか、十分早く予測されていなければなりません。
warmup_time = 120s
scale_signal_lead_time must be > 120sこれはスケールダウンのポリシーを変えます。普通のWebサービスは積極的にスケールダウンできます。モデルサービスはしばしばウォームプールを保ちます。コールドスタートのレイテンシのコストが、アイドルキャパシティのコストより高いからです。
キャパシティ計画は以下を述べるべきです:
- 最小ウォームレプリカ数、
- スケールアップのシグナルと閾値、
- 期待されるウォームアップ時間、
- スケールダウンの遅延、
- コールドスタートのユーザーへの影響、
- スケールトゥゼロが許されるか。
レイテンシクリティカルな大きなモデルでは、スケールトゥゼロは通常偽りの経済です。
バッチ推論のサイジング
バッチスコアリングはスループットの計画です。問いは: ジョブは受容可能なコストで期限前に完了できるか?
例:
Users to score: 200M
Deadline: 4 hours
Required throughput: 200M / (4 × 3600) ≈ 13,900 predictions/s1ワーカーが安全に2,000予測/秒をスコアできるなら:
workers = 13,900 / 2,000 ≈ 7 workersストラグラーとリトライのヘッドルームを加えて、10をプロビジョンします。次にコストを見積もります:
10 workers × 4 hours × $3/hour = $120 per runバッチ推論はしばしばI/Oバウンドになります。特徴量の読み取り、予測の書き込み、候補セットのシャッフルがモデル計算を支配し得ます。パイプラインのステージごとにスループットを測定すること:
read features → preprocess → inference → write outputs最も遅いステージがスループットを決めます。推論が50,000/秒でも書き込みが10,000/秒なら、GPUを買い足しても何も変わりません。
訓練コストの計画
訓練コストは、アクセラレータ数×実時間+ストレージとオーケストレーションのオーバーヘッドです。
training_cost = accelerator_count × hours × hourly_rate
+ CPU/memory overhead
+ storage/read costs
+ experiment multiplierチームを驚かせるのは実験の乗数です。1回の訓練実行は安いかもしれません。ハイパーパラメータ探索はそれを掛け算します。
base run: 8 GPUs × 6h × $4/h = $192
50 trials with early stopping at 40% average length:
50 × 0.4 × $192 = $3,840
weekly search: ≈ $200K/yearコスト計画は訓練パイプラインに付随すべきです。すべての実行が、推定コスト、実際のコスト、データセットサイズ、アクセラレータタイプ、稼働率、理由を記録します。コストの異常はしばしばパイプラインのバグを明らかにします: データが倍になった、キャッシュがミスした、分散訓練が遅くなった、スポットインスタンスが使われなくなった、ハイパーパラメータ探索が爆発した。
訓練のスループットとI/O
訓練中のアクセラレータ稼働率は、しばしばデータI/Oに制限されます。GPUがバッチを待つなら、学習なしにコストが燃えます。
データ需要を見積もります:
batch_size = 1024 examples
example_size = 200 KB
steps_per_second = 20
data_rate = 1024 × 200KB × 20 ≈ 4 GB/sストレージパスが持続的に4 GB/sを供給できなければ、GPUはアイドルします。修正には以下があります:
- 適切なサイズのファイルへのデータのシャーディング、
- フルスキャン用のシーケンシャルフォーマット、
- ローカルNVMeキャッシング、
- プリフェッチと並列データローダー、
- 計算とストレージのコロケーション、
- 例ごとのリモート読み取りの回避。
したがって訓練のキャパシティはGPUクォータだけではありません。GPU+ストレージ帯域+CPU前処理+ネットワークです。
分散訓練のスケーリング効率
GPUを追加しても訓練時間は線形には減りません。通信が成長します。
speedup_N = single_gpu_time / N_gpu_time
scaling_efficiency = speedup_N / N8 GPUが6倍のスピードアップを与えるなら、効率は75%です。64 GPUが20倍なら、効率は31%です。有用な訓練ステップあたりのコストは、より小さなジョブより悪いかもしれません。
キャパシティ計画は、訓練所要時間だけでなく、ドルあたりスループットを測定すべきです。キュー待ちと通信オーバーヘッドが大きなジョブを無駄にするため、正解が「より少ないGPUでより長く」であることもあります。プロダクトの期限が無駄を正当化することもあります。トレードを明示的にすること。
マルチテナントGPUクラスタ
共有MLクラスタはスケジューリングシステムです。ポリシーなしでは、1チームが他を飢えさせられます。
必要な統制:
| 統制 | 目的 |
|---|---|
| クォータ | チームの支出と使用量を制限 |
| フェアシェア | 恒久的な独占なしにアイドルキャパシティを配分 |
| 優先度クラス | 本番の再訓練が実験をプリエンプトできるように |
| ギャングスケジューリング | 分散ジョブを全部一度に開始するか、まったく開始しない |
| チェックポインティング | プリエンプションを安全に |
| アイドル検出 | 進捗なしにGPUを握るジョブを殺す |
| 予算アラート | 暴走する探索を止める |
ギャングスケジューリングは決定的に重要です。8 GPUを必要とする分散ジョブは7では進捗できません。部分的な割り当てはクラスタをデッドロックさせ得ます: ジョブが残りを待ちながら一部のGPUを保持する。全か無かの割り当てがこれを避けます。
マルチテナントクラスタには、クォータだけでなく公平性のコントラクトも必要です:
gpu_cluster_policy:
quota_window: weekly
teams:
search:
guaranteed_gpu_hours: 1200
max_burst_gpus: 64
budget_usd: 18000
fraud:
guaranteed_gpu_hours: 800
max_burst_gpus: 32
budget_usd: 12000
priority_classes:
production_retraining:
preemptible: false
max_queue_wait: 30m
launch_blocking_experiment:
preemptible: true
max_queue_wait: 4h
exploratory_notebook:
preemptible: true
max_runtime: 6h
preemption:
require_checkpoint_age_below: 15m
grace_period: 5m
idle_detection:
gpu_utilization_below: 5%
duration: 20m
action: notify_then_killフェアシェアのスケジューリングは2つの問いに別々に答えるべきです: クラスタが忙しいとき何が保証されるか、そして忙しくないとき誰がアイドルキャパシティを日和見的に使えるか。この区別がなければ、硬直したクォータの下でクラスタがアイドルするか、1チームが共有GPUに居座ってそれを効率と呼ぶかのどちらかです。
予測あたりコスト
提供コストは、予測あたりコストまたは1,000予測あたりコストに還元されるべきです。
cost_per_prediction = hourly_instance_cost / predictions_per_hour例:
GPU instance: $4/hour
Throughput: 1,000 predictions/s = 3.6M/hour
Cost: $4 / 3.6M = $0.0000011 per prediction10%稼働率では:
effective throughput: 360K/hour
Cost: $4 / 360K = $0.000011 per prediction稼働率の10倍の低下は、単価の10倍の上昇を生みます。だからこそバッチング、統合、適正サイジングが、多くの普通のサービスよりML提供にとって重要なのです。
モデルサーバーだけでなく、提供スタック全体を含めること:
unit_cost = (model_server_cost
+ feature_store_incremental_cost
+ cache_cost
+ logging/storage_cost
+ monitoring_cost) / predictions例:
model servers: 16 replicas × $4/h = $64/h
feature store load: = $18/h
prediction logging: 12K rps × 2KB × storage = $6/h
monitoring/vendor: = $4/h
total: = $92/h
predictions/hour: 12,000 × 3600 = 43.2M
cost/prediction: $92 / 43.2M ≈ $0.00000213
cost/1K predictions: ≈ $0.00213この視点は誤解を招く最適化を捕まえます。フィーチャーストアの負荷を倍にしながらモデルのGPUコストを半分にするのは勝利ではありません。節約された計算より高くつくキャッシュを追加してp99を下げることは、プロダクトの価値次第で正当化されるかもしれないし、されないかもしれません。
CPU対GPUのクロスオーバー
GPUが自動的に安い・速いわけではありません。クロスオーバーは、モデルサイズ、トラフィック、レイテンシ予算、達成可能なバッチングに依存します。
この比較を使うこと:
CPU fleet cost at required p99 and RPS
vs
GPU fleet cost at required p99 and RPS, including warm idle capacity低トラフィックの小さなモデルはしばしばCPUに属します。5%稼働率のGPUは、通常、数台のCPUノードより悪い。量子化、蒸留、プルーニング、コンパイルは、CPUを実行可能にするかGPUのサイズを減らすことで、クロスオーバーを動かせます。
ハードウェアの決定はモデルごとであるべきで、プラットフォーム全体のイデオロギーであってはなりません。
ヘッドルームポリシー
MLサービスには以下のための明示的なヘッドルームが必要です:
- バーストトラフィック、
- モデルのロード/ウォームアップ時間、
- ローリングデプロイ、
- シャドウ/カナリアのトラフィック、
- 依存先の劣化、
- AZまたはノードの障害、
- 通常より大きな入力、
- オンラインのピークと重なるバッチジョブ。
サンプルポリシー:
Online inference:
steady peak GPU utilization ≤ 65%
queue wait p99 ≤ 10ms
tolerate one replica loss per pool
keep previous production model warm during rollout
Training cluster:
reserve 20% for production retraining
experimental jobs preemptible
distributed jobs require gang schedulingヘッドルームはプロダクトの機能です。バーストを障害ではなく一瞬の揺らぎに変えるものです。
ML提供のオープンループ負荷テスト
クローズドループの負荷テストはテールレイテンシを過小評価します。クローズドループのテストでは、各クライアントは応答を受け取ってから次のリクエストを送るので、サービスが遅くなるとテストは自動的に提供負荷を減らします。実際のトラフィックは、あなたのキューが伸びても礼儀正しく減速したりしません。
オープンループの負荷生成を使うこと: 応答とは独立に、固定された到着スケジュールでリクエストを送り、キューイングの崩壊を測定します。
load_test:
mode: open_loop
endpoint: fraud_authorization
traffic_shape:
warmup: 5m at 2k_rps
steady: 15m at 12k_rps
burst: 2m at 18k_rps
recovery: 10m at 12k_rps
request_mix:
p50_feature_count: 35
p95_feature_count: 60
p99_large_input_share: 2%
success_criteria:
p99_latency_ms: <=120
queue_wait_p99_ms: <=10
timeout_rate: <=0.1%
gpu_oom_count: 0
feature_store_error_rate: <=0.05%
fallback_rate: <=1%
compare:
baseline_model: fraud_classifier:v41
candidate_model: fraud_classifier:v42負荷テストは、本番に近い特徴量ファンアウト、キャッシュヒット率、入力サイズ分布、ロギングパスを保存すべきです。ウォーム済みのモデルサーバーに小さな特徴量ベクトルを送る合成テストは、ベンチマークを測定しているのであって、本番システムではありません。
オープンループのテストはオートスケーリングの真実も暴きます。レプリカのウォームに120秒かかり、バーストが90秒続くなら、そのバーストにオートスケーリングは無関係です。ウォームなヘッドルームかアドミッション制御だけがp99を守れます。
障害モード
GPU推論のためのCPUベースのオートスケーリングは、CPUがボトルネックではないため、遅すぎるか、まったくスケールしません。防御: キュー深度、キュー待ち、GPU稼働率、メモリ、タイムアウト率でスケールする。
平均レイテンシでの計画は、バッチング、ファンアウト、キューイングによるp99違反を見逃します。防御: p95/p99に対してサイズし、バーストトラフィックをテストする。
コールドスタートのキャパシティ幻想は、起動中でまだ提供していないレプリカを数えます。防御: ウォームプールと、ウォームアップ時間を認識した予測的スケールアップ。
フィーチャーストアのボトルネックは、特徴量フェッチが飽和しているのにモデルサーバーを買い足します。防御: 特徴量QPS、キャッシュヒット率、ファンアウトをキャパシティの数学に含める。
分散下のGPU OOMは、平均入力サイズでテストするが、本番は長いまたは大きな入力を送ります。防御: 最悪ケースの入力境界とヘッドルームでのメモリサイジング。
訓練GPUの飢餓は、データロードを待つアクセラレータに支払います。防御: データスループットを測定し、プリフェッチし、正しくシャードし、ローカルにキャッシュする。
ハイパーパラメータのコスト爆発は、安いベース実行を大きな請求書に掛け算します。防御: 探索ごとの予算、早期停止、トライアルの上限、コストのロギング。
部分割り当てによるクラスタのデッドロックは、分散ジョブに一部の(しかし全部ではない)GPUを与えます。防御: ギャングスケジューリング。
シャドウトラフィックの過負荷は、ロールアウト中に推論と特徴量の負荷を倍にします。防御: シャドウをサンプルし、リソースを分離し、ロールアウトのオーバーヘッドをヘッドルームに含める。
判断のフレームワーク
あらゆるMLワークロードについて、答えてください:
- これはオンライン、非同期、バッチ、訓練のどれか? どんな鮮度または期限が必要か?
- ピークの到着レートは何で、どのパーセンタイルのレイテンシまたは完了期限が重要か?
- ボトルネックは何か: モデル計算、メモリ、特徴量フェッチ、ストレージI/O、ネットワーク、スケジューラ?
- ベンチマークの最大値ではなく、目標稼働率での安全なレプリカあたりスループットは?
- モデルのロード時間を踏まえて、どれだけのウォームキャパシティが必要か?
- 期待される稼働率での予測あたりコストまたは訓練実行あたりコストは?
- 障害、デプロイ、カナリア、バーストのためにどれだけのヘッドルームが必要か?
- ユーザーに見えるメトリクスが壊れる前に、どのメトリクスがスケールアップをトリガーするか?
- キャパシティが尽きたとき何が起きるか — キュー、シェッド、フォールバック、フェイルクローズ?
- オープンループでバースト形状の負荷の下で、推定をどう検証するか?
これらに答えられない計画はキャパシティプランニングではありません。クラウドの請求書とp99が友好的であることを祈っているだけです。
要点
- MLキャパシティプランニングは依然として、リクエストレート、サービス時間、並行数、稼働率、メモリ、帯域、キューイングです — しかしボトルネックのリソースはしばしばアクセラレータメモリか特徴量I/Oです。
- まず提供レジームを選ぶこと。鮮度が許すなら、バッチはオンラインより安い。
- オンライン推論のサイジングは、平均スループットではなく、p99レイテンシ、キュー待ち、安全な稼働率、ウォームアップ時間を使わなければなりません。
- 動的バッチングはレイテンシを稼働率と交換します。実効バッチサイズとテールのキュー待ちを測定すること。
- アクセラレータメモリはハードリミットです。モデルの重み、アクティベーション、キャッシュ、入力の分散が安全なバッチサイズを決めます。
- 特徴量フェッチのファンアウトは推論を支配し得るので、QPSとレイテンシの予算に含めなければなりません。
- 訓練コストはアクセラレータ時間×実験数です。しばしばハイパーパラメータ探索が本当の請求書です。
- 訓練のスループットはしばしばGPUのFLOPsではなくデータI/Oでボトルネックします。
- 共有GPUクラスタには、クォータ、フェアシェア、優先度、チェックポインティング、ギャングスケジューリング、アイドルジョブの強制が必要です。
- 予測あたりコストは、モデルサーバーのインスタンスだけでなく、フィーチャーストア、ロギング、キャッシング、監視を含むべきです。
- テールレイテンシの確信にはオープンループの負荷テストが必要です。クローズドループのテストはキューの崩壊を隠します。
- 稼働率が落ちれば予測あたりコストは直接上がります。ハードウェアを適正サイズにし、CPU/GPUのクロスオーバーを測定すること。
参考文献
- キャパシティプランニングと概算見積もり
- モデルサービング
- 訓練パイプライン
- The Tail at Scale — Dean & Barroso, 2013
- Clipper: A Low-Latency Online Prediction Serving System — Crankshaw et al., NSDI 2017
- NVIDIA Triton Inference Server Documentation
- FinOpsとコストエンジニアリング