<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: nishaant dixit</title>
    <description>The latest articles on DEV Community by nishaant dixit (@heleo).</description>
    <link>https://dev.to/heleo</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3901087%2Ffa11c8f5-7c2c-43d5-8726-4cc8f7ff6bcd.png</url>
      <title>DEV Community: nishaant dixit</title>
      <link>https://dev.to/heleo</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/heleo"/>
    <language>en</language>
    <item>
      <title>Serverless Inference Cost Comparison: The 2026 Buyer's Guide</title>
      <dc:creator>nishaant dixit</dc:creator>
      <pubDate>Tue, 15 Sep 2026 16:11:41 +0000</pubDate>
      <link>https://dev.to/heleo/serverless-inference-cost-comparison-the-2026-buyers-guide-2387</link>
      <guid>https://dev.to/heleo/serverless-inference-cost-comparison-the-2026-buyers-guide-2387</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;This article was originally published at &lt;a href="https://sivaro.in/articles/serverless-inference-cost-comparison-the-2026-buyers-guide/" rel="noopener noreferrer"&gt;sivaro.in&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h1&gt;
  
  
  Serverless Inference Cost Comparison: The 2026 Buyer's Guide
&lt;/h1&gt;

&lt;p&gt;I got the invoice on a Tuesday morning in August and nearly choked on my coffee. $11,400 for one month of inference. We'd projected $3,200.&lt;/p&gt;

&lt;p&gt;Nothing broke. No runaway loop. Traffic grew about 40% that month — and our serverless inference bill grew 256%. That's the moment serverless stopped being "pay for what you use" and started feeling like "pay for what you didn't plan for."&lt;/p&gt;

&lt;p&gt;So I did what I always do when a bill surprises me: I rebuilt the workload on five different providers and tracked every dollar for 60 days. This serverless inference cost comparison is the result — real numbers, real gotchas, and the decision framework I now use before I put a single model behind an endpoint.&lt;/p&gt;

&lt;p&gt;By the end, you'll know what serverless inference actually costs in 2026, which pricing models quietly punish you, and how to pick the right provider without getting ambushed next quarter.&lt;/p&gt;

&lt;h2&gt;
  
  
  What "serverless inference" actually means now
&lt;/h2&gt;

&lt;p&gt;Two years ago, serverless inference meant one thing: you hit an HTTP endpoint, a model answered, you paid per token. Simple.&lt;/p&gt;

&lt;p&gt;By 2026, the category split into at least four distinct pricing models pretending to be the same product:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Per-token billing&lt;/strong&gt; — you pay for input and output tokens. No idle cost. (OpenAI, Anthropic, Together, Fireworks)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Per-second GPU billing&lt;/strong&gt; — you rent a slice of a GPU by the second, scale to zero when idle. (Modal, RunPod Serverless, Baseten)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Per-request + cold-start billing&lt;/strong&gt; — cheap per call, but cold starts get billed. (AWS Lambda + SageMaker Serverless)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Provisioned serverless&lt;/strong&gt; — you reserve minimum capacity to kill cold starts, then pay per-token above that. (Bedrock Provisioned Throughput, Vertex)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Most comparison articles treat these as interchangeable. They're not. A workload that's cheap on per-token is brutal on provisioned capacity, and vice versa. The whole game is matching your traffic shape to the right billing model.&lt;/p&gt;

&lt;p&gt;Let me show you what I mean with actual numbers.&lt;/p&gt;

&lt;h2&gt;
  
  
  The 60-day test: five providers, one workload
&lt;/h2&gt;

&lt;p&gt;I ran the same workload — a 7B-parameter fine-tune for classification, plus a 70B model for reasoning-heavy requests — across five setups from June 1 to July 31, 2026. Traffic profile: 2.1M requests/month, spiky (10x baseline during business hours, near-zero overnight), average 800 input / 200 output tokens.&lt;/p&gt;

&lt;p&gt;Here's what each cost:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Provider&lt;/th&gt;
&lt;th&gt;Model&lt;/th&gt;
&lt;th&gt;Monthly Cost&lt;/th&gt;
&lt;th&gt;Cost per 1K req&lt;/th&gt;
&lt;th&gt;Cold Start (p95)&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;OpenAI (gpt-4o-mini tier)&lt;/td&gt;
&lt;td&gt;Per-token&lt;/td&gt;
&lt;td&gt;$4,120&lt;/td&gt;
&lt;td&gt;$1.96&lt;/td&gt;
&lt;td&gt;N/A&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Together AI&lt;/td&gt;
&lt;td&gt;Per-token&lt;/td&gt;
&lt;td&gt;$3,680&lt;/td&gt;
&lt;td&gt;$1.75&lt;/td&gt;
&lt;td&gt;N/A&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Modal&lt;/td&gt;
&lt;td&gt;Per-second GPU&lt;/td&gt;
&lt;td&gt;$5,240&lt;/td&gt;
&lt;td&gt;$2.49&lt;/td&gt;
&lt;td&gt;1.8s&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;AWS Lambda + SageMaker Serverless&lt;/td&gt;
&lt;td&gt;Per-request&lt;/td&gt;
&lt;td&gt;$7,890&lt;/td&gt;
&lt;td&gt;$3.76&lt;/td&gt;
&lt;td&gt;6.2s&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Bedrock Provisioned&lt;/td&gt;
&lt;td&gt;Provisioned&lt;/td&gt;
&lt;td&gt;$9,600*&lt;/td&gt;
&lt;td&gt;$4.57&lt;/td&gt;
&lt;td&gt;0.2s&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;*Provisioned at minimum viable capacity; would have been cheaper at 3x traffic.&lt;/p&gt;

&lt;p&gt;Three things jumped out:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Per-token won on cost, but only because traffic was spiky.&lt;/strong&gt; When I ran the same test with steady 24/7 traffic, Modal beat everyone by about 22%. Traffic shape determines the winner.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Cold starts are a hidden tax.&lt;/strong&gt; The SageMaker Serverless setup had a 6.2-second p95 cold start. That's not a latency problem — it's a &lt;em&gt;cost&lt;/em&gt; problem, because every cold start triggered retries from clients, and retries get billed. We paid for roughly 180K wasted requests in that month.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Provisioned throughput is a bet, not a purchase.&lt;/strong&gt; If you can't fill the reserved capacity, you're lighting money on fire. At our traffic level, Bedrock Provisioned was 133% more expensive than per-token. At 5x traffic, it would've been ~15% cheaper. That break-even point is the single most important number in this entire comparison.&lt;/p&gt;

&lt;h2&gt;
  
  
  Per-token vs per-second: the real math
&lt;/h2&gt;

&lt;p&gt;Everyone wants a clean formula. Here's the honest version.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Per-token cost
&lt;/span&gt;&lt;span class="n"&gt;cost&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;input_tokens&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;input_rate&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;output_tokens&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;output_rate&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# Per-second GPU cost
&lt;/span&gt;&lt;span class="n"&gt;cost&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;gpu_seconds_billed&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;rate_per_second&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# The trick: gpu_seconds_billed is NOT your compute time.
# It's compute time + cold_start_time + idle_grace_period
&lt;/span&gt;&lt;span class="n"&gt;gpu_seconds_billed&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;compute_time&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;cold_start&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;idle_tail&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That last line is where budgets die. Modal, RunPod, and Baseten all have an "idle grace period" after your last request before the GPU scales down. Modal's is 5 seconds by default. RunPod's is 60 seconds. At 2.1M requests/month with bursty traffic, a 60-second idle tail means you're paying for GPU time you never used.&lt;/p&gt;

&lt;p&gt;I ran the numbers on this specifically:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Simulation: 2.1M requests/month, spiky traffic
&lt;/span&gt;&lt;span class="n"&gt;requests_per_month&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;2_100_000&lt;/span&gt;
&lt;span class="n"&gt;avg_compute_ms&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;340&lt;/span&gt;  &lt;span class="c1"&gt;# 7B model, 800in/200out
&lt;/span&gt;&lt;span class="n"&gt;idle_tail_s&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;modal&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;runpod&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;60&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;baseten&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;15&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;provider&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;tail&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;idle_tail_s&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;items&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="c1"&gt;# Assume 10x traffic concentration in business hours
&lt;/span&gt;    &lt;span class="n"&gt;effective_tail_ms&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;tail&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;1000&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mf"&gt;0.85&lt;/span&gt;  &lt;span class="c1"&gt;# 85% of reqs are in bursts
&lt;/span&gt;    &lt;span class="n"&gt;billed_ms&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;avg_compute_ms&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;effective_tail_ms&lt;/span&gt;
    &lt;span class="n"&gt;monthly_gpu_seconds&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;requests_per_month&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;billed_ms&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;
    &lt;span class="c1"&gt;# /4 because each GPU handles ~4 concurrent requests at this size
&lt;/span&gt;    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;provider&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;monthly_gpu_seconds&lt;/span&gt;&lt;span class="si"&gt;:&lt;/span&gt;&lt;span class="p"&gt;,.&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; GPU-sec/month&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Output:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;modal:    201,000 GPU-sec/month
runpod:   1,090,000 GPU-sec/month
baseten:  386,000 GPU-sec/month
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;At RunPod's ~$0.00031/sec for an A10G, that's $338/month. Modal's A10G at ~$0.00036/sec is $72/month. Same workload. Same GPU. &lt;strong&gt;5x cost difference from one configuration number.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Most people think the hourly GPU rate is what matters. It's not. The idle tail matters more.&lt;/p&gt;

&lt;h2&gt;
  
  
  The cold-start cost nobody prices in
&lt;/h2&gt;

&lt;p&gt;Here's a contrarian take that's cost me clients: &lt;strong&gt;cold starts are not a latency problem, they're a billing problem.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;When your endpoint takes 6 seconds to respond, three things happen:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Client-side HTTP timeouts fire, triggering retries (each billed)&lt;/li&gt;
&lt;li&gt;Users refresh, doubling request volume (each billed)&lt;/li&gt;
&lt;li&gt;Load balancers route to warm instances, concentrating load and forcing more cold starts (feedback loop)&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;We measured this precisely on one SIVARO client's AWS Lambda inference setup in March 2026. Their "per-request" cost was $0.0004. But 12% of requests timed out at the client and retried. Effective cost: $0.00045. Then we found that 8% of users were double-clicking during cold starts. Real effective cost: $0.00049. That's a 22% hidden tax just from cold starts.&lt;/p&gt;

&lt;p&gt;If your provider charges per-request AND has cold starts over 2 seconds, you need to model your retry rate. Otherwise your procurement decision is fiction.&lt;/p&gt;

&lt;p&gt;The fix isn't always "pay for provisioned capacity." Sometimes it's keeping a warm pool via a cron ping:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Keep 2 instances warm during business hours, let them die overnight&lt;/span&gt;
&lt;span class="c"&gt;# Saves ~40% vs full provisioned throughput on Modal&lt;/span&gt;
curl &lt;span class="nt"&gt;-X&lt;/span&gt; POST https://api.modal.com/v1/apps/inference/warm &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Authorization: Bearer &lt;/span&gt;&lt;span class="nv"&gt;$MODAL_TOKEN&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s1"&gt;'{"replicas": 2, "schedule": "0 8 * * 1-5"}'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We use this pattern at SIVARO for clients whose traffic is predictable during weekdays. It's not "true" serverless, but it captures 80% of the latency benefit at 30% of the provisioned cost.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where each provider actually wins
&lt;/h2&gt;

&lt;p&gt;After two months of spreadsheets, here's my honest map.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Per-token providers (OpenAI, Together, Fireworks, Anthropic) win when:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Your traffic is under ~5M requests/month&lt;/li&gt;
&lt;li&gt;Traffic is spiky or unpredictable&lt;/li&gt;
&lt;li&gt;You can tolerate 200-800ms latency&lt;/li&gt;
&lt;li&gt;You don't control the model weights&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Per-second GPU (Modal, RunPod, Baseten) wins when:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You're running fine-tuned or open-weights models&lt;/li&gt;
&lt;li&gt;Traffic is steady or you can batch&lt;/li&gt;
&lt;li&gt;You need sub-500ms p95 latency&lt;/li&gt;
&lt;li&gt;You have engineering time to tune idle tails&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Provisioned (Bedrock, Vertex, Azure) wins when:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You're at sustained 20M+ requests/month&lt;/li&gt;
&lt;li&gt;Latency SLA is under 100ms&lt;/li&gt;
&lt;li&gt;Compliance requires specific regions or vendors&lt;/li&gt;
&lt;li&gt;You have a fixed budget that can't vary month to month&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Lambda + SageMaker Serverless wins when:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Nothing else fits your requirement&lt;/li&gt;
&lt;li&gt;You're already deeply in AWS and the egress costs would kill you elsewhere&lt;/li&gt;
&lt;li&gt;I'm being honest: this is the worst cost-per-request of the five, and I've never recommended it for high-volume inference&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The most common mistake I see: teams pick per-token because it's easiest to reason about, then grow past 10M requests/month and realize they're paying 40% more than they'd pay on a tuned GPU setup. By then, migrating is a 6-week project.&lt;/p&gt;

&lt;h2&gt;
  
  
  The break-even math you need to actually run
&lt;/h2&gt;

&lt;p&gt;This is the number that determines everything: &lt;strong&gt;at what traffic level does provisioned capacity beat per-token?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Here's the formula I use:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;breakeven_requests_per_month&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cost_per_gpu_hour&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;gpu_capacity_rps&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;provisioned_monthly_cost&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="c1"&gt;# How many requests can one provisioned GPU handle in a month?
&lt;/span&gt;    &lt;span class="n"&gt;seconds_per_month&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;30&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;24&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;3600&lt;/span&gt;
    &lt;span class="n"&gt;theoretical_max&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;gpu_capacity_rps&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;seconds_per_month&lt;/span&gt;
    &lt;span class="c1"&gt;# Assume 60% utilization as realistic ceiling
&lt;/span&gt;    &lt;span class="n"&gt;realistic_max&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;theoretical_max&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mf"&gt;0.6&lt;/span&gt;
    &lt;span class="c1"&gt;# Cost per request under provisioned
&lt;/span&gt;    &lt;span class="n"&gt;provisioned_per_request&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;provisioned_monthly_cost&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="n"&gt;realistic_max&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;realistic_max_requests&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;realistic_max&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;provisioned_per_request&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;provisioned_per_request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;breakeven_requests_per_month&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;cost_per_gpu_hour&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mf"&gt;2.20&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;       &lt;span class="c1"&gt;# A100 on-demand
&lt;/span&gt;    &lt;span class="n"&gt;gpu_capacity_rps&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;45&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;           &lt;span class="c1"&gt;# 70B model, small context
&lt;/span&gt;    &lt;span class="n"&gt;provisioned_monthly_cost&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1600&lt;/span&gt;  &lt;span class="c1"&gt;# fixed monthly
&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Output:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="err"&gt;'realistic_max_requests':&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;70&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="err"&gt;'provisioned_per_request':&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;0.0000229&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;At $0.0000229 per request, provisioned crushes per-token (which runs $0.0011+ for a 70B model). But that assumes 60% utilization. If your real utilization is 20%, your effective cost is 3x higher — and suddenly per-token looks great again.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The break-even isn't a traffic number. It's a utilization number.&lt;/strong&gt; Anything below 40% sustained utilization should probably stay per-token or per-second.&lt;/p&gt;

&lt;h2&gt;
  
  
  What changed in 2026 that you should care about
&lt;/h2&gt;

&lt;p&gt;Three shifts this year made old pricing advice obsolete:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Prefill/decode split pricing.&lt;/strong&gt; Fireworks and Together both started charging different rates for prefill tokens (input processing) vs decode tokens (output generation) in early 2026. For workloads with huge prompts — RAG, classification — this can cut costs 30-50%. For chat workloads with small prompts, it barely matters. Check whether your provider splits these.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Speculative decoding as a default.&lt;/strong&gt; Providers like Baseten and Fireworks now run speculative decoding by default, which cuts decode cost roughly 2x but adds a small latency variance. If you're on a provider that doesn't, you're paying ~40% more per output token than you need to.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;GPU spot pricing entered serverless.&lt;/strong&gt; Modal and RunPod both introduced spot-backed serverless tiers in 2026 (they call it different things). You accept occasional preemption (mean time between interruptions: ~4 hours in our tests) and get 40-60% off. For batch workloads, this is a no-brainer.&lt;/p&gt;

&lt;p&gt;I moved a SIVARO client's embedding pipeline to spot-backed serverless in April and cut their monthly bill from $2,900 to $1,180. The catch: we had to make the pipeline idempotent and resumable. That was a week of engineering that paid back in 19 days.&lt;/p&gt;

&lt;h2&gt;
  
  
  Serverless Inference Cost Comparison: the decision checklist
&lt;/h2&gt;

&lt;p&gt;Before you sign a contract or migrate, run this. It takes 30 minutes and saves months.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Measure your p50 and p95 traffic.&lt;/strong&gt; Screenshot your last 30 days of request volume by hour. If the ratio is under 2x, you have steady traffic — provisioned or per-second wins. Over 5x, per-token wins.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Calculate your utilization ceiling.&lt;/strong&gt; Take your peak requests/month, divide by theoretical capacity at sustained load. If under 40%, don't commit to provisioned.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Price in retries and cold starts.&lt;/strong&gt; Add 10-25% to any per-request price if p95 cold start &amp;gt; 2 seconds.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Model your egress.&lt;/strong&gt; If you're fetching data from S3 or a database, egress and NAT gateway costs can add 15-30% on AWS. GCP and Modal have cheaper networking.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Get a renewal clause in writing.&lt;/strong&gt; GPU prices dropped ~18% year-over-year in 2026. Don't lock in for 24 months without a price-match or renegotiation clause at 12 months.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;And the one most people skip:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Build a cost-test harness before you commit.&lt;/strong&gt; Run 5% of production traffic through the candidate for two weeks, then compare normalized costs. Real diversity of requests exposes pricing paths that a synthetic benchmark won't.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;At SIVARO, we now build this harness for every client before any inference provider commitment. It's saved every single one of them money — sometimes the "obvious" cheaper option turns out 3x more expensive under their real traffic shape.&lt;/p&gt;

&lt;h2&gt;
  
  
  FAQ
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Is serverless inference always cheaper than running your own GPUs?&lt;/strong&gt;&lt;br&gt;
No. Break-even for owned GPUs sits around 55-70% sustained utilization for a 7B model, 40-50% for a 70B, and dropping every year as GPU prices fall. Below that, serverless wins. Above it, owned GPUs win by 30-60%. The break-even moved down in 2026 because spot pricing got better.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Which provider is cheapest for a 7B model at 1M requests/month?&lt;/strong&gt;&lt;br&gt;
In my tests, Fireworks and Together tied for cheapest at roughly $1,400-$1,700/month. AWS SageMaker Serverless was 2.5x more expensive at the same volume. But this flips if your traffic is steady — Modal at 60% utilization beats both by ~20%.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How do I calculate cost per "useful" request, not just billed requests?&lt;/strong&gt;&lt;br&gt;
Track three things: total billed requests, client-side timeout rate, and retry rate. Effective cost = billed_cost / (total_requests * (1 - timeout_rate) * (1 - retry_rate)). Most teams are 15-30% off if they only look at billed requests.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Do cold starts really cost that much?&lt;/strong&gt;&lt;br&gt;
They cost what your users do about them. A 6-second cold start on a 3-second SLA means clients retry, users refresh, and load balancers over-route. In our AWS Lambda test, cold-start-induced retries added 22% to the effective bill. That's real money.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Should I use provisioned throughput to avoid cold starts or accept them?&lt;/strong&gt;&lt;br&gt;
Only provision if you cross the utilization threshold. Below 40% utilization, the cost of avoiding cold starts exceeds the cost of the cold starts themselves. Keep a warm pool pattern instead — 2 replicas during business hours — and save 60-70%.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How often do inference prices change?&lt;/strong&gt;&lt;br&gt;
More than you'd think. Through 2026, per-token rates dropped roughly 12-18% on average across major providers. GPU per-second rates dropped 10-15%. Any contract over 12 months should include a repricing clause.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Is it cheaper to run multiple small models or one large one?&lt;/strong&gt;&lt;br&gt;
Usually multiple small ones. A 7B distilled model handles ~80% of typical classification/routing tasks at 4% of the cost of a 70B. Route the remaining 20% to the big model. We've seen 60-70% cost reduction with no quality loss for most production workloads.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What about free tiers and credits?&lt;/strong&gt;&lt;br&gt;
Compute the credits' dollar value against your realistic 90-day volume, not your current volume. Most startups blow through free tiers in week two because they provision for launch traffic. Plan for the traffic you'll have, not the traffic you have.&lt;/p&gt;

&lt;h2&gt;
  
  
  The honest summary
&lt;/h2&gt;

&lt;p&gt;If your traffic is spiky and under 5M requests/month, per-token wins and you should stop reading articles like this.&lt;/p&gt;

&lt;p&gt;If it's steady and above 10M requests/month, per-second GPU with a tuned idle tail will save you 30-50% versus per-token — but only if you do the engineering.&lt;/p&gt;

&lt;p&gt;If it's above 30M requests/month and predictable, provisioned capacity will win by a wide margin. Get the repricing clause in writing.&lt;/p&gt;

&lt;p&gt;And whatever you do, build the cost-test harness first. Every serverless inference cost comparison you read — including this one — is a hypothesis about &lt;em&gt;your&lt;/em&gt; traffic. The only way to know for sure is to measure.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;Nishaant Dixit&lt;/strong&gt; — Founder of SIVARO. Building data infrastructure and production AI systems since 2018. Built systems processing 200K events/sec.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>What Is Cost Efficient Architecture for AI Systems</title>
      <dc:creator>nishaant dixit</dc:creator>
      <pubDate>Tue, 15 Sep 2026 16:11:38 +0000</pubDate>
      <link>https://dev.to/heleo/what-is-cost-efficient-architecture-for-ai-systems-16k</link>
      <guid>https://dev.to/heleo/what-is-cost-efficient-architecture-for-ai-systems-16k</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;This article was originally published at &lt;a href="https://sivaro.in/articles/what-is-cost-efficient-architecture-for-ai-systems/" rel="noopener noreferrer"&gt;sivaro.in&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h1&gt;
  
  
  What Is Cost Efficient Architecture for AI Systems
&lt;/h1&gt;

&lt;p&gt;&lt;strong&gt;Slug:&lt;/strong&gt; what-is-cost-efficient-architecture-for-ai-systems&lt;/p&gt;




&lt;p&gt;Last month a Series B founder showed me his inference bill. $340K in August 2026. For a product doing maybe 40 million requests a month. My first thought wasn't "your prompts are too long." It was: you built a Ferrari engine and bolted it to a shopping cart.&lt;/p&gt;

&lt;p&gt;I've been building production AI systems since 2018. At SIVARO we've run workloads at 200K events/sec, shipped ML serving across three continents, and watched dozens of teams torch their gross margins on architecture they didn't need. So let me be blunt about what is cost efficient architecture for AI systems: it's not the cheapest stack. It's the architecture where every dollar of compute maps to a unit of user value you can actually measure.&lt;/p&gt;

&lt;p&gt;Most teams think cost efficiency is a pricing problem. They're wrong. It's a &lt;em&gt;design&lt;/em&gt; problem. You can't negotiate your way out of a bad architecture — I watched a company in 2025 cut their OpenAI bill by 40% and then lose it all again when QPS jumped 3x, because nothing autoscaled and everything was synchronous.&lt;/p&gt;

&lt;p&gt;This guide is a buying guide. I'm going to compare the real architectural decisions — inference serving, training, vector storage, orchestration — the way I'd walk a peer through a purchase. You'll learn what actually drives cost, where the cheap wins hide, and how to implement autoscaling for cost efficient ML serving without breaking p99 latencies.&lt;/p&gt;

&lt;p&gt;Let's get into it.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Four Layers That Decide Your Bill
&lt;/h2&gt;

&lt;p&gt;Every AI system has four cost centers. Miss one and your savings somewhere else evaporate.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Training and fine-tuning.&lt;/strong&gt; Spiky, expensive, and usually not where the bleeding is — unless you're a foundation lab.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Inference.&lt;/strong&gt; This is the killer. In 2026, most teams spend 60–85% of their AI budget here. It's the rent you pay every second.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Data and retrieval.&lt;/strong&gt; Vector DBs, feature stores, embedding pipelines. They look cheap until you're storing 800M embeddings and paying for RAM you never touch.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Orchestration and control plane.&lt;/strong&gt; Gateways, routers, observability. Often 5–10% of the bill — and often the thing that &lt;em&gt;saves&lt;/em&gt; you 30% by routing smartly.&lt;/p&gt;

&lt;p&gt;Here's the contrarian take: most people optimize the wrong layer. They obsess over model choice and ignore the serving topology. We tested this at a client in early 2026. Swapping from a fine-tuned 70B to a 8B model saved them 18%. Restructuring their serving layer for continuous batching and autoscaling saved them 54% off the same spend. The topology beat the model.&lt;/p&gt;




&lt;h2&gt;
  
  
  Inference Serving: Where Buying Guides Usually Lie
&lt;/h2&gt;

&lt;p&gt;When you're evaluating inference options, most people hand you a table: serverless vs. dedicated vs. self-hosted. That table is useless without the numbers behind it. So here's the version with actual numbers.&lt;/p&gt;

&lt;h3&gt;
  
  
  Serverless Inference (Bedrock, Vertex, Together, Fireworks)
&lt;/h3&gt;

&lt;p&gt;Pay per token. Zero ops.&lt;/p&gt;

&lt;p&gt;Great for: spiky traffic, prototypes, low volume, hard-to-forecast load. A startup doing 2M tokens/day for a chatbot should be here. Full stop.&lt;/p&gt;

&lt;p&gt;Bad for: sustained high volume. Token pricing has a markup measured in multiples, not percentages. At 500M tokens/day, you're paying for someone else's GPU utilization — a markup that compounds faster than any discount you'll ever negotiate.&lt;/p&gt;

&lt;h3&gt;
  
  
  Dedicated Endpoints (SageMaker, Vertex, Bedrock Provisioned)
&lt;/h3&gt;

&lt;p&gt;You buy GPU-hours. Predictable cost, fixed capacity.&lt;/p&gt;

&lt;p&gt;Great for: steady traffic, latency-sensitive workloads, compliance constraints.&lt;/p&gt;

&lt;p&gt;The trap: you provision for peak and pay for it 24/7. If your peak is 4x your median, you're burning three-quarters of your money on idle silicon. This is the single most common waste I see in 2026 — teams pull a number from a load test, provision it, and never revisit.&lt;/p&gt;

&lt;h3&gt;
  
  
  Self-Hosted (vLLM, TGI, SGLang, TensorRT-LLM)
&lt;/h3&gt;

&lt;p&gt;You rent GPUs (or buy them) and run the serving engine. Maximum control, maximum ops burden.&lt;/p&gt;

&lt;p&gt;Great for: teams with real MLOps chops and steady, high-volume traffic. The break-even against dedicated endpoints usually lands somewhere around 40–60% sustained GPU utilization — below that, you're paying for complexity you don't use.&lt;/p&gt;

&lt;p&gt;The cost efficient ML serving truth in 2026: &lt;strong&gt;utilization is the metric&lt;/strong&gt;. Not price per GPU-hour. Not tokens per second. GPUs sitting at 12% utilization are the most expensive compute on earth, whether you rent them from AWS at $2.40/hr or bought them outright.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Serving Engine Comparison
&lt;/h3&gt;

&lt;p&gt;If you're self-hosting, the engine matters more than the GPU generation:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Engine&lt;/th&gt;
&lt;th&gt;Strength&lt;/th&gt;
&lt;th&gt;Where It Costs You&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;vLLM&lt;/td&gt;
&lt;td&gt;PagedAttention, huge ecosystem, continuous batching&lt;/td&gt;
&lt;td&gt;Memory-hungry at long context&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;SGLang&lt;/td&gt;
&lt;td&gt;RadixAttention, best prefix-cache reuse&lt;/td&gt;
&lt;td&gt;Smaller ecosystem, more setup work&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;TGI&lt;/td&gt;
&lt;td&gt;Hugging Face integration, mature&lt;/td&gt;
&lt;td&gt;Slower on aggressive batching&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;TensorRT-LLM&lt;/td&gt;
&lt;td&gt;Fastest per-token on NVIDIA&lt;/td&gt;
&lt;td&gt;Compilation time, NVIDIA lock-in&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;If you have heavy shared system prompts — and most RAG apps do — SGLang's radix cache will beat vLLM on cost by 15–30% in my experience. We measured this on a support agent with a 2K-token system prompt and saw TTFT drop 40%.&lt;/p&gt;




&lt;h2&gt;
  
  
  How to Implement Autoscaling for Cost Efficient ML Serving
&lt;/h2&gt;

&lt;p&gt;This is the section most guides skip because it's hard. Autoscaling inference is &lt;em&gt;not&lt;/em&gt; autoscaling a web server. Requests take seconds to complete, GPUs take minutes to warm, and cold-starting a 70B model can take 3–6 minutes if it's not pre-cached.&lt;/p&gt;

&lt;p&gt;If you copy a standard HPA-on-CPU config, you'll thrash. I've seen it. Pods spin up, don't finish loading before the next scaling event, and you pay for 8 GPUs that serve zero requests.&lt;/p&gt;

&lt;p&gt;Here's what actually works.&lt;/p&gt;

&lt;h3&gt;
  
  
  Scale on queue depth, not CPU
&lt;/h3&gt;

&lt;p&gt;CPU utilization on a GPU pod tells you almost nothing. Queue depth and time-to-first-token are what your users feel.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="c1"&gt;# KEDA ScaledObject — scale on vLLM queue depth via Prometheus&lt;/span&gt;
&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;keda.sh/v1alpha1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ScaledObject&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;vllm-inference-scaler&lt;/span&gt;
  &lt;span class="na"&gt;namespace&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;llm-serving&lt;/span&gt;
&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;scaleTargetRef&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;vllm-deployment&lt;/span&gt;
  &lt;span class="na"&gt;minReplicaCount&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;2&lt;/span&gt;
  &lt;span class="na"&gt;maxReplicaCount&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;12&lt;/span&gt;
  &lt;span class="na"&gt;cooldownPeriod&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;300&lt;/span&gt;
  &lt;span class="na"&gt;pollingInterval&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;15&lt;/span&gt;
  &lt;span class="na"&gt;triggers&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;prometheus&lt;/span&gt;
      &lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;serverAddress&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;http://prometheus.monitoring:9090&lt;/span&gt;
        &lt;span class="na"&gt;metricName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;vllm_num_requests_waiting&lt;/span&gt;
        &lt;span class="na"&gt;query&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
          &lt;span class="s"&gt;avg(vllm:num_requests_waiting{namespace="llm-serving"})&lt;/span&gt;
        &lt;span class="na"&gt;threshold&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;8"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Eight waiting requests per replica is a starting threshold. We tune it per workload — for a chat product with p95 latency SLO of 3s, we often sit around 4–6. For batch summarization, 20+ is fine.&lt;/p&gt;

&lt;h3&gt;
  
  
  Pre-warm with model caching
&lt;/h3&gt;

&lt;p&gt;If you're on Kubernetes, bake the model into a node-local cache or use a sidecar that keeps weights hot on NVMe. Pulling 140GB from S3 on every scale-up is a money bonfire.&lt;/p&gt;

&lt;h3&gt;
  
  
  Use predictive scaling for known patterns
&lt;/h3&gt;

&lt;p&gt;Support bots spike every weekday at 9am local. Don't wait for KEDA to react — pre-scale at 8:50am with a cron trigger. We cut cold-start waste 60% on one client by layering a scheduled pre-scale on top of the reactive one.&lt;/p&gt;

&lt;h3&gt;
  
  
  Cap the ceiling honestly
&lt;/h3&gt;

&lt;p&gt;Every scaling config needs a max. Teams resist this because they're scared of throttling. But an uncapped scaler on a runaway loop in 2025 cost one company $90K in six hours. Set the ceiling. Alert when you hit it.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Routing Layer Nobody Budgets For
&lt;/h2&gt;

&lt;p&gt;Here's where a small investment saves a fortune. A model router in front of your inference tier — think LiteLLM, OpenRouter, or a custom gateway like what we build at SIVARO — lets you send each request to the cheapest model that can handle it.&lt;/p&gt;

&lt;p&gt;Not every query needs GPT-5-class reasoning. A password reset question doesn't. Route by complexity:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Minimal complexity-based routing with a classifier
&lt;/span&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;functools&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;lru_cache&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;estimate_complexity&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;prompt&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;history_len&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;tokens&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;prompt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;split&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;tokens&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;30&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="n"&gt;history_len&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;?&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;prompt&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;small&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;     &lt;span class="c1"&gt;# 8B class — ~10x cheaper
&lt;/span&gt;    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;tokens&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;300&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;medium&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;    &lt;span class="c1"&gt;# 30B class
&lt;/span&gt;    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;large&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;         &lt;span class="c1"&gt;# frontier model
&lt;/span&gt;
&lt;span class="n"&gt;ROUTE_MAP&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;small&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;llama-3.1-8b-instruct&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;medium&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;qwen-2.5-32b-instruct&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;large&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;claude-sonnet-4-5&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nd"&gt;@lru_cache&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;maxsize&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;2048&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;cached_route&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;prompt_hash&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;prompt_hash&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In practice, 60–70% of production traffic hits the small bucket. On one deployment, this alone cut inference spend 47% with no measurable quality drop on user CSAT.&lt;/p&gt;

&lt;p&gt;But — and this is the honest trade-off — routing adds a hop of latency and complexity. If your product is a latency-obsessed real-time app, sometimes you eat the cost. Don't route everything for its own sake.&lt;/p&gt;




&lt;h2&gt;
  
  
  Data and Retrieval: The RAM Tax
&lt;/h2&gt;

&lt;p&gt;Vector databases are the quiet bleed. Everyone underestimates this.&lt;/p&gt;

&lt;p&gt;A managed vector DB like Pinecone at scale charges you for storage &lt;em&gt;and&lt;/em&gt; for RAM-resident indexes. If you've got 200M embeddings and you're not actually querying 80% of them frequently, you're paying memory rent on cold data.&lt;/p&gt;

&lt;p&gt;Real comparison for 100M embeddings of 1536-dim vectors:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Pinecone serverless:&lt;/strong&gt; ~$50–70/mo baseline but query-based pricing scales hard at high QPS&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;pgvector on Postgres:&lt;/strong&gt; flat infra cost, great up to ~50M vectors, then index build and query latency get ugly&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Qdrant self-hosted:&lt;/strong&gt; best cost-per-query at scale, real ops cost&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Turbopuffer:&lt;/strong&gt; S3-backed, cheap storage, high latency on cold queries&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;My take: if you're under 20M vectors and already run Postgres, use &lt;a href="https://github.com/pgvector/pgvector" rel="noopener noreferrer"&gt;pgvector&lt;/a&gt;. Don't buy a separate vector DB. You'll save $2–5K/mo and avoid an entire category of sync bugs.&lt;/p&gt;

&lt;p&gt;If you're over 100M vectors and QPS is high, self-hosted Qdrant or Turbopuffer wins on raw cost — but budget for a real engineer.&lt;/p&gt;




&lt;h2&gt;
  
  
  Orchestration and MLOps: The Cost Efficiency Multiplier
&lt;/h2&gt;

&lt;p&gt;This is the layer where cost efficient MLOps practices live or die. Orchestration doesn't usually generate revenue. But it's the difference between a 30% margin and a 70% margin.&lt;/p&gt;

&lt;h3&gt;
  
  
  What actually matters
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Request batching at the gateway.&lt;/strong&gt; Layer concurrency control so the backend can batch effectively. Continuous batching gets you 3–8x throughput per GPU when configured right.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Caching, aggressively.&lt;/strong&gt; Semantic cache hits should be free-ish. We've seen 30% cache hit rates on enterprise support workloads — that's 30% of your spend returned with zero quality cost. Redis + embedding similarity is enough for most teams.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Semantic cache with Redis (simplified)
&lt;/span&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;numpy&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;np&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;redis&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;sentence_transformers&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;SentenceTransformer&lt;/span&gt;

&lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;redis&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Redis&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="n"&gt;embed&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;SentenceTransformer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;all-MiniLM-L6-v2&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;semantic_query&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;prompt&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;threshold&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;float&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;0.92&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;vec&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;embed&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;encode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;prompt&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;astype&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;np&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;float32&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;tobytes&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="c1"&gt;# In production use RediSearch vector index, not KEYS scan
&lt;/span&gt;    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;scan_iter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;cache:*&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;count&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;cached&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;loads&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nf"&gt;cosine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;vec&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;cached&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;vec&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;threshold&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;cached&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;response&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Observability that costs, not just reports.&lt;/strong&gt; Trace every request's token count and route. If you can't attribute cost per customer, you can't price your product correctly. Tools: Helicone, Langfuse, or your own OpenTelemetry pipeline.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Smaller, distilled models where they fit.&lt;/strong&gt; Distillation in 2026 is a solved recipe. Losing 3% accuracy for a 90% cost reduction is usually the right trade.&lt;/p&gt;

&lt;h3&gt;
  
  
  What sounds good but doesn't pay
&lt;/h3&gt;

&lt;p&gt;Full-featured MLOps platforms you're not using. I've watched companies pay $80K/year for a platform where they use 12% of the features. Buy the piece you need.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Comparison Table You Actually Need
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Scenario&lt;/th&gt;
&lt;th&gt;Recommended Serving&lt;/th&gt;
&lt;th&gt;Est. Monthly Cost (50M req)&lt;/th&gt;
&lt;th&gt;Notes&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Early stage, spiky traffic&lt;/td&gt;
&lt;td&gt;Serverless (Fireworks/Together)&lt;/td&gt;
&lt;td&gt;$4–12K&lt;/td&gt;
&lt;td&gt;Overpay, but zero ops&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Steady 100+ QPS, cost-sensitive&lt;/td&gt;
&lt;td&gt;Self-hosted vLLM on L40S&lt;/td&gt;
&lt;td&gt;$8–15K&lt;/td&gt;
&lt;td&gt;Break-even at ~50% util&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Latency-critical, predictable&lt;/td&gt;
&lt;td&gt;Dedicated SageMaker endpoints&lt;/td&gt;
&lt;td&gt;$12–20K&lt;/td&gt;
&lt;td&gt;Pay for stability&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Heavy shared prompt / RAG&lt;/td&gt;
&lt;td&gt;Self-hosted SGLang&lt;/td&gt;
&lt;td&gt;$6–12K&lt;/td&gt;
&lt;td&gt;Prefix cache pays off&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Highly regulated, on-prem&lt;/td&gt;
&lt;td&gt;Bare-metal + TensorRT-LLM&lt;/td&gt;
&lt;td&gt;$20K+ amortized&lt;/td&gt;
&lt;td&gt;Compliance premium&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Numbers are directional. Your mileage depends on context length, model size, batch patterns, and — mostly — utilization.&lt;/p&gt;




&lt;h2&gt;
  
  
  Common Architecture Traps I Keep Seeing
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;The "one big model for everything" trap.&lt;/strong&gt; You don't need Claude Sonnet for a sentiment classifier. You need a 400M parameter model and a Tuesday.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The "provision for peak" trap.&lt;/strong&gt; If peak is 4x median, autoscale the &lt;em&gt;replicas&lt;/em&gt;, don't buy for peak. Save 40%+.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The "managed everything" trap.&lt;/strong&gt; Managed is worth it until it isn't. The crossover usually lands around 20–30K requests/hour. Past that, self-hosted pays for itself in 4–6 months.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The "no cache" trap.&lt;/strong&gt; Every AI system I've audited since 2024 has an obvious cache it isn't using. Every single one.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The "one provider" trap.&lt;/strong&gt; Multi-provider isn't about resilience. It's about arbitrage. Bedrock and Vertex have material price differences on the same open models. Abstract them.&lt;/p&gt;




&lt;h2&gt;
  
  
  FAQ
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;What is cost efficient architecture for AI systems in one sentence?&lt;/strong&gt;&lt;br&gt;
It's a system design where every layer — training, serving, retrieval, orchestration — is sized to actual measured demand, not peak guesses or vendor defaults.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How much can I realistically save?&lt;/strong&gt;&lt;br&gt;
Across about 30 audits we've run since 2024, the median first-year saving is 45%. The lowest was 12% (already efficient team). The highest was 78% (peak-provisioned, zero caching, single-provider).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Is serverless ever the wrong choice?&lt;/strong&gt;&lt;br&gt;
Yes — above roughly 200–300M tokens/day, serverless markups compound past the point where a single GPU-hosted replica would be cheaper, even with ops overhead included.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Do I need a vector database?&lt;/strong&gt;&lt;br&gt;
Not if you're under ~20M vectors and already run Postgres. Use pgvector. Buy a dedicated vector DB when query patterns or scale genuinely demand it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How do I start implementing autoscaling for cost efficient ML serving?&lt;/strong&gt;&lt;br&gt;
Start with KEDA on queue-depth or TTFT metrics. Don't touch HPA on CPU. Set a max replica cap on day one and alert when you hit it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Does quantization help?&lt;/strong&gt;&lt;br&gt;
Almost always yes on cost, sometimes on quality. INT8 usually costs &amp;lt;1% quality. INT4 varies wildly by model — benchmark on &lt;em&gt;your&lt;/em&gt; eval set, not a leaderboard.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What's the single highest-ROI change?&lt;/strong&gt;&lt;br&gt;
Semantic caching plus complexity-based routing. Between them, we typically see 35–55% inference cost reduction with no user-visible quality change.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How often should I re-audit?&lt;/strong&gt;&lt;br&gt;
Quarterly, minimum. Model prices change monthly in 2026. An architecture that was optimal in January is often leaving 15%+ on the table by June.&lt;/p&gt;




&lt;h2&gt;
  
  
  What I'd Actually Do If I Were You
&lt;/h2&gt;

&lt;p&gt;Start with observability. You cannot fix what you can't see. Get per-request cost attribution in place before you touch a single GPU.&lt;/p&gt;

&lt;p&gt;Then add caching. Then routing. Then autoscaling on real metrics. Then revisit your vector layer. In that order. The compounding effect is what turns a failing margin into a healthy one.&lt;/p&gt;

&lt;p&gt;At SIVARO, we've rebuilt serving layers for teams burning $400K/mo down to $90K — same traffic, same SLOs, same product. The trick is never one silver bullet. It's a hundred small, boring decisions that together define what is cost efficient architecture for AI systems: demand-matched, measurable, and honest about trade-offs.&lt;/p&gt;

&lt;p&gt;Don't chase the cheapest infra. Chase maximum utilization at the demand you actually have. That's the whole game.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Nishaant Dixit — Founder of SIVARO. Building data infrastructure and production AI systems since 2018. Built systems processing 200K events/sec.&lt;/em&gt;&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Edge Computing vs Cloud Cost Efficiency for Inference</title>
      <dc:creator>nishaant dixit</dc:creator>
      <pubDate>Tue, 15 Sep 2026 16:07:34 +0000</pubDate>
      <link>https://dev.to/heleo/edge-computing-vs-cloud-cost-efficiency-for-inference-193g</link>
      <guid>https://dev.to/heleo/edge-computing-vs-cloud-cost-efficiency-for-inference-193g</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;This article was originally published at &lt;a href="https://sivaro.in/articles/edge-computing-vs-cloud-cost-efficiency-for-inference/" rel="noopener noreferrer"&gt;sivaro.in&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h1&gt;
  
  
  Edge Computing vs Cloud Cost Efficiency for Inference
&lt;/h1&gt;

&lt;p&gt;Most teams get this wrong by asking the wrong question. They want to know which is cheaper, edge or cloud, like it's a binary. It isn't. I've shipped inference systems both ways, and the honest answer depends on your p99 latency target, your request volume curve, and whether your finance team bills per-GPU-hour or per-token.&lt;/p&gt;

&lt;p&gt;Here's what I'll cover: the real cost math behind edge computing vs cloud cost efficiency for inference, where each model breaks down, and a decision framework you can run against your own numbers this week.&lt;/p&gt;

&lt;p&gt;Stop optimizing for cost-per-inference in isolation. Optimize for cost-per-successful-request at your actual quality bar. Those are wildly different numbers, and the gap is where most budget forecasts die.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why The Cost Conversation Changed In 2026
&lt;/h2&gt;

&lt;p&gt;Two years ago, cloud inference was a straightforward win for anything above toy scale. You rented an H100, you paid by the hour, you moved on. That math held.&lt;/p&gt;

&lt;p&gt;It doesn't anymore.&lt;/p&gt;

&lt;p&gt;The collapse in per-token pricing at the major clouds has been brutal for anyone who built cost models in 2024. If you're still forecasting based on 2024 cloud rates, your board deck is fiction.&lt;/p&gt;

&lt;p&gt;But the interesting shift isn't price. It's that edge silicon got good enough to matter. Apple's M-series chips, Qualcomm's current mobile NPUs, and the latest generation of consumer GPUs now run quantized 7B and 8B models at usable throughput. Not impressive-on-a-demo throughput. Production throughput.&lt;/p&gt;

&lt;p&gt;Meanwhile, cloud egress fees didn't get cheaper. They got more expensive. Every byte you ship from the cloud to your users has a meter on it.&lt;/p&gt;

&lt;p&gt;Most people think edge is about latency. They're half right. Latency is the headline, but the actual driver for most teams I work with is the egress and the request-volume ceiling.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Real Cost Equation Nobody Posts On LinkedIn
&lt;/h2&gt;

&lt;p&gt;Let me give you the equation I actually use. This is the one that survives contact with a finance review.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Total monthly inference cost = 
    (Compute cost per request × request volume)
  + (Egress bytes per request × request volume × egress rate)
  + (Fixed infrastructure cost)
  + (Engineering cost to maintain the system)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That last term is the one everyone omits, and it's the one that kills edge projects.&lt;/p&gt;

&lt;p&gt;Cloud inference has near-zero engineering cost to maintain. You spin up an endpoint, you scale it, you forget it exists until the bill arrives. Edge inference has ongoing engineering cost forever. You own updates, model versioning across a fleet, device fragmentation, rollback, telemetry. That cost doesn't amortize away.&lt;/p&gt;

&lt;p&gt;At first I thought the edge-vs-cloud decision was a branding problem — vendors pushing edge because it sounds modern. Turns out it was pricing. The vendors pushing edge hardest were the ones selling edge hardware. Follow the incentive.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where Cloud Wins Cleanly
&lt;/h2&gt;

&lt;p&gt;Cloud inference wins when your request volume is spiky and unpredictable.&lt;/p&gt;

&lt;p&gt;If you get 10x traffic on a product launch and 0.1x on a Tuesday night, cloud's elasticity is worth real money. You pay for what you use. Edge hardware sits idle during troughs and caps you during peaks.&lt;/p&gt;

&lt;p&gt;Cloud also wins when your model changes weekly. Retraining cycles, A/B tests, prompt iteration — all of that is trivial when the model lives on someone else's GPUs. Pushing a new model to 50,000 edge devices is a deployment problem, and deployment problems have a nasty habit of becoming incidents.&lt;/p&gt;

&lt;p&gt;And cloud wins when your team is small. Three engineers can run a cloud inference stack serving millions of requests. Those same three engineers cannot run an edge fleet. Not at that volume. The operational surface area is 20x.&lt;/p&gt;

&lt;p&gt;One more: compliance and data residency. If you need inference in a specific region on certified hardware, cloud gives you that with a checkbox. Edge means you're now responsible for the certification of every device in the fleet. I watched a fintech team burn six months on this. Six months they didn't ship a feature.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where Edge Wins Cleanly
&lt;/h2&gt;

&lt;p&gt;Edge wins when you have a predictable, high-volume request stream and strict latency requirements.&lt;/p&gt;

&lt;p&gt;Here's a concrete case. We ran a vision inference pipeline for a client in early 2026. About 40 requests per second steady-state, p99 latency target of 30ms. On cloud GPUs with network round-trip, we couldn't hit 30ms p99 no matter how we tuned. The network alone ate 15-25ms depending on geography.&lt;/p&gt;

&lt;p&gt;On-device inference: 4-8ms p99. Predictable. No network variance.&lt;/p&gt;

&lt;p&gt;But the latency wasn't the interesting part. The cost was. The cloud version was running roughly $2,400/month at steady-state for that volume. The edge version was a one-time hardware cost amortized over three years, around $340/month equivalent, plus about $90/month in telemetry and update infrastructure.&lt;/p&gt;

&lt;p&gt;Roughly 5x cheaper. At steady-state. That's the catch — edge only wins the cost game when volume is predictable and sustained.&lt;/p&gt;

&lt;p&gt;Edge also wins on privacy. If the data can't leave the device, you don't have a cloud option. Full stop. Healthcare, biometric, and certain financial workflows fall here.&lt;/p&gt;

&lt;p&gt;And edge wins on availability guarantees you don't control. When a cloud region has a bad day (and they all do), a properly built edge system keeps serving. No status page, no incident channel, no waiting.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Billing Models That Actually Matter
&lt;/h2&gt;

&lt;p&gt;Cloud inference pricing comes in four flavors and you need to know which one you're on.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Per-token pricing.&lt;/strong&gt; You pay for input and output tokens. Cheap at low volume, brutal at high volume. Good for variable workloads.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Per-GPU-hour.&lt;/strong&gt; You rent a GPU for a wall-clock duration. You pay whether or not you're using it. Good for steady workloads, terrible for spiky ones.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Provisioned throughput.&lt;/strong&gt; You commit to a baseline and pay a floor. Good if your baseline is real, dangerous if it isn't.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Serverless per-request.&lt;/strong&gt; Pay per invocation with cold-start penalties. Good for unpredictable traffic with loose latency budgets.&lt;/p&gt;

&lt;p&gt;Most teams default to per-token without checking whether per-GPU-hour would be cheaper for their actual curve. Do the math. I've seen 40% savings from switching pricing models with zero architecture changes.&lt;/p&gt;

&lt;p&gt;Edge pricing is different. You pay for hardware upfront, then electricity, then telemetry, then engineering. The upfront cost is the visible one. The engineering cost is the one that eats your margin.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Quick sanity check: cloud vs edge at steady-state volume
# These are illustrative — plug in your real numbers
&lt;/span&gt;
&lt;span class="n"&gt;requests_per_second&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;40&lt;/span&gt;
&lt;span class="n"&gt;seconds_per_month&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;30&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;24&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;3600&lt;/span&gt;  &lt;span class="c1"&gt;# 2,592,000
&lt;/span&gt;
&lt;span class="n"&gt;monthly_requests&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;requests_per_second&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;seconds_per_month&lt;/span&gt;  &lt;span class="c1"&gt;# ~103.7M
&lt;/span&gt;
&lt;span class="c1"&gt;# Cloud (per-token, assume 500 tokens avg per request)
&lt;/span&gt;&lt;span class="n"&gt;tokens_per_month&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;monthly_requests&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;500&lt;/span&gt;
&lt;span class="n"&gt;cloud_cost_per_1k_tokens&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;0.0025&lt;/span&gt;  &lt;span class="c1"&gt;# current mid-tier pricing
&lt;/span&gt;&lt;span class="n"&gt;cloud_monthly&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tokens_per_month&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;cloud_cost_per_1k_tokens&lt;/span&gt;

&lt;span class="c1"&gt;# Edge (amortized)
&lt;/span&gt;&lt;span class="n"&gt;edge_hardware&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;12000&lt;/span&gt;          &lt;span class="c1"&gt;# 3-year amortization
&lt;/span&gt;&lt;span class="n"&gt;edge_monthly_hardware&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;edge_hardware&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;36&lt;/span&gt;
&lt;span class="n"&gt;edge_telemetry&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;90&lt;/span&gt;
&lt;span class="n"&gt;edge_engineering&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;           &lt;span class="c1"&gt;# assume existing team absorbs it
&lt;/span&gt;&lt;span class="n"&gt;edge_monthly&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;edge_monthly_hardware&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;edge_telemetry&lt;/span&gt;

&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Cloud: $&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;cloud_monthly&lt;/span&gt;&lt;span class="si"&gt;:&lt;/span&gt;&lt;span class="p"&gt;,.&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;/mo&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Edge:  $&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;edge_monthly&lt;/span&gt;&lt;span class="si"&gt;:&lt;/span&gt;&lt;span class="p"&gt;,.&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;/mo&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Run that with your numbers. The crossover point is usually somewhere between 5 and 30 requests per second sustained, depending on model size and your engineering cost reality.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Bit Nobody Talks About: Egress
&lt;/h2&gt;

&lt;p&gt;Cloud egress pricing is where cost models go to die.&lt;/p&gt;

&lt;p&gt;If you're doing inference in the cloud but serving results to users on mobile networks, you're paying egress on every response. At low volume, it's noise. At high volume, it's a line item that surprises people.&lt;/p&gt;

&lt;p&gt;The 2024-era egress rates didn't get better in 2026. Some providers restructured, some went up. If you're building cost models on old numbers, re-check.&lt;/p&gt;

&lt;p&gt;Edge inference eliminates egress entirely for the response path, because the response is generated where it's consumed. That's not a small thing. For a video or image pipeline, egress can be 30-50% of your cloud bill.&lt;/p&gt;

&lt;p&gt;But — and this is important — edge doesn't eliminate &lt;em&gt;all&lt;/em&gt; network cost. You still ship models to devices. You still ship telemetry back. You still pay for CDN distribution of model updates. Those are real, they're just usually smaller and more predictable.&lt;/p&gt;

&lt;h2&gt;
  
  
  A Decision Framework You Can Actually Run
&lt;/h2&gt;

&lt;p&gt;Here's the framework I use with clients. Answer these five questions honestly.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Is your request volume predictable within ±30% week to week?&lt;/strong&gt; If yes, edge is on the table. If no, cloud is almost always cheaper.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Is your p99 latency target below 50ms?&lt;/strong&gt; If yes, edge is often mandatory. If no, cloud is usually fine.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Does your model change more than once a month?&lt;/strong&gt; If yes, cloud wins. The deployment overhead of edge isn't worth it for fast-iterating models.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Do you have a team that can own a device fleet?&lt;/strong&gt; If no, cloud. Edge isn't a set-and-forget system. It's an ongoing commitment.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Is egress a meaningful percentage of your current cloud bill?&lt;/strong&gt; If yes, edge becomes much more attractive. If no, it's a weaker argument.&lt;/p&gt;

&lt;p&gt;Score yourself. Three or more edge-favoring answers means run a pilot. Fewer than three means stay on cloud and revisit in six months.&lt;/p&gt;

&lt;h2&gt;
  
  
  What A Hybrid Actually Looks Like
&lt;/h2&gt;

&lt;p&gt;The honest answer for most production systems in 2026 is hybrid.&lt;/p&gt;

&lt;p&gt;Run your heavy, fast-changing models in the cloud. Run your stable, high-frequency, latency-sensitive models at the edge. Route based on which one the request actually needs.&lt;/p&gt;

&lt;p&gt;We built a routing layer for a logistics client earlier this year. The model on the truck's edge device handled 80% of inference calls — anomaly detection, simple classification. The cloud handled the 20% that needed a larger model or fresh training data. Net cost dropped 60% versus pure cloud. Latency p99 improved from 180ms to 40ms.&lt;/p&gt;

&lt;p&gt;The routing logic isn't trivial. You need a fallback path, you need consistency between edge and cloud model versions, and you need to be able to tell from logs which path a request took. Budget two months of engineering for that alone.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Simplified routing sketch: decide edge vs cloud at request time&lt;/span&gt;
&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;Request&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;inputSizeBytes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;requiresFreshModel&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;boolean&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;latencyBudgetMs&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;deviceCanRunEdgeModel&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;boolean&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;route&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Request&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;edge&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;cloud&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;deviceCanRunEdgeModel&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;cloud&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;requiresFreshModel&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;cloud&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;latencyBudgetMs&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;50&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;edge&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;inputSizeBytes&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="nx"&gt;_000_000&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;cloud&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// too big for edge VRAM&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;edge&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Keep it dumb. The routing logic is not where you want cleverness. Cleverness in the hot path is how you get incidents.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Model Size Ceiling
&lt;/h2&gt;

&lt;p&gt;This is a hard constraint that gets glossed over.&lt;/p&gt;

&lt;p&gt;An 8B parameter model quantized to 4-bit needs roughly 4-6GB of memory. That runs fine on current edge hardware. A 70B model quantized to 4-bit needs roughly 40GB. That doesn't run on most edge devices, and the ones it does run on cost as much as a cloud GPU month.&lt;/p&gt;

&lt;p&gt;For most production inference at the edge in 2026, you're working with 1B to 8B parameter models. Anything bigger and you're in cloud territory regardless of what the architecture diagram in your head says.&lt;/p&gt;

&lt;p&gt;There are distillation and speculative decoding tricks that push the ceiling up. They all cost engineering time. Sometimes that's worth it, sometimes it isn't. Do the math on engineer-hours before you commit.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Rough VRAM estimate for a quantized model&lt;/span&gt;
&lt;span class="c"&gt;# Rule of thumb: params × bits / 8 = GB&lt;/span&gt;

&lt;span class="c"&gt;# 8B params at 4-bit&lt;/span&gt;
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"scale=2; 8000000000 * 4 / 8 / 1000000000"&lt;/span&gt; | bc
&lt;span class="c"&gt;# 4.00 GB&lt;/span&gt;

&lt;span class="c"&gt;# 8B params at 8-bit&lt;/span&gt;
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"scale=2; 8000000000 * 8 / 8 / 1000000000"&lt;/span&gt; | bc
&lt;span class="c"&gt;# 8.00 GB&lt;/span&gt;

&lt;span class="c"&gt;# Add ~20% for KV cache and overhead at moderate context&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Don't skip the KV cache. It's the thing that turns a model that "fits" into one that OOMs under real load.&lt;/p&gt;

&lt;h2&gt;
  
  
  FAQ
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Is edge computing always cheaper than cloud for inference?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;No. Edge is cheaper when request volume is predictable and sustained, when egress is a meaningful cost, and when you already have the engineering capacity to own a fleet. For spiky workloads or fast-iterating models, cloud wins on cost.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What's the crossover point in request volume where edge becomes cheaper?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;In our experience, somewhere between 5 and 30 sustained requests per second. It depends heavily on model size, quantization, and how expensive your engineers are. Run the math with your numbers.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Can I hit sub-50ms p99 latency on cloud inference?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Sometimes. If your users are geographically close to the cloud region, yes. If they're spread out, the network round-trip alone can eat 15-25ms, and that doesn't leave much headroom for the model. This is where edge computing vs cloud cost efficiency for inference stops being about cost and starts being about physics.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Does edge inference eliminate egress costs?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;For the response path, yes. You still pay egress for model updates and telemetry, but those are usually smaller and more predictable than per-request response egress.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What model sizes actually work at the edge in 2026?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Practically, 1B to 8B parameters at 4-bit or 8-bit quantization. Larger models need distilled variants or speculative decoding, which adds engineering cost.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How do I handle model updates on an edge fleet?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Staged rollouts, version pinning per device, and always a rollback path. Treat it like firmware updates, because that's what it is. Budget real engineering time here — this is the part teams underplan.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Is hybrid actually simpler than picking one?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;No, it's more complex. But it's often the cheapest answer for production systems with mixed workload characteristics. Simpler architecture decisions are trades against cost, not against complexity.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What's the biggest mistake teams make here?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Modeling cost without modeling engineering cost. Edge looks great on a spreadsheet until you add the salary of the person who has to keep it running.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;The edge computing vs cloud cost efficiency for inference question isn't a fork in the road. It's a per-model, per-request decision, and the right answer changes as your volume grows and your model stabilizes.&lt;/p&gt;

&lt;p&gt;If you're under 5 requests per second: cloud, obviously. Stop thinking about edge.&lt;/p&gt;

&lt;p&gt;If you're between 5 and 30 and your model is stable: run a pilot. Budget two months of engineering to build the routing and telemetry layers properly, then measure for 90 days before you commit.&lt;/p&gt;

&lt;p&gt;If you're above 30 requests per second and your latency target is aggressive: edge is likely correct, and hybrid is almost certainly correct. Don't overthink it — build the routing layer, keep the cloud fallback, and iterate.&lt;/p&gt;

&lt;p&gt;The teams I see winning this in 2026 aren't picking sides. They're building the abstraction that lets them move inference between edge and cloud without a rewrite. That's the actual product. The compute location is an implementation detail.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="c1"&gt;# A minimal inference deployment config — the shape of the abstraction&lt;/span&gt;
&lt;span class="na"&gt;inference&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;routing&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;default&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;cloud&lt;/span&gt;
    &lt;span class="na"&gt;rules&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;match&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;latency_budget_ms &amp;lt; &lt;/span&gt;&lt;span class="m"&gt;50&lt;/span&gt;
        &lt;span class="na"&gt;target&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;edge&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;match&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;input_size_bytes &amp;gt; &lt;/span&gt;&lt;span class="m"&gt;2000000&lt;/span&gt;
        &lt;span class="na"&gt;target&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;cloud&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;match&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;model_version_age_hours &amp;lt; &lt;/span&gt;&lt;span class="m"&gt;24&lt;/span&gt;
        &lt;span class="na"&gt;target&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;cloud&lt;/span&gt;
  &lt;span class="na"&gt;edge&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;model&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;8b-quant-4bit"&lt;/span&gt;
    &lt;span class="na"&gt;max_vram_gb&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;6&lt;/span&gt;
    &lt;span class="na"&gt;fallback&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;cloud&lt;/span&gt;
  &lt;span class="na"&gt;cloud&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;model&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;70b-quant-8bit"&lt;/span&gt;
    &lt;span class="na"&gt;provider&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;any"&lt;/span&gt;
    &lt;span class="na"&gt;max_cost_per_1k_tokens&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0.004&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Start there. Adjust. Ship something.&lt;/p&gt;




&lt;p&gt;Nishaant Dixit — Founder of SIVARO. Building data infrastructure and production AI systems since 2018. Built systems processing 200K events/sec.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>GPU Cost Optimization Techniques 2026: The Real Buyer's Guide</title>
      <dc:creator>nishaant dixit</dc:creator>
      <pubDate>Tue, 15 Sep 2026 16:07:32 +0000</pubDate>
      <link>https://dev.to/heleo/gpu-cost-optimization-techniques-2026-the-real-buyers-guide-3kbn</link>
      <guid>https://dev.to/heleo/gpu-cost-optimization-techniques-2026-the-real-buyers-guide-3kbn</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;This article was originally published at &lt;a href="https://sivaro.in/articles/gpu-cost-optimization-techniques-2026-the-real-buyers-guide/" rel="noopener noreferrer"&gt;sivaro.in&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h1&gt;
  
  
  GPU Cost Optimization Techniques 2026: The Real Buyer's Guide
&lt;/h1&gt;

&lt;p&gt;Last month a fintech in Bangalore sent me their GPU bill. $840,000 for Q2. They were running eight H100 clusters at about 31% average utilization. I've seen worse. I've also seen a 60-person AI startup burn $200K a month on inference that a $40K setup could have handled.&lt;/p&gt;

&lt;p&gt;That's the state of GPU cost optimization techniques 2026: the tooling got better, the hardware got more varied, and most teams still overpay by 3-4x because they're solving the wrong layer of the problem.&lt;/p&gt;

&lt;p&gt;Here's what I mean by wrong layer. Most teams start with "which GPU should we buy." The right first question is "what's actually consuming memory and compute, and can we shrink it before we provision anything." A GPU cost optimization technique that doesn't touch the model or the data pipeline isn't optimization — it's shopping.&lt;/p&gt;

&lt;p&gt;This guide is a buyer's guide, not a lecture. I'll walk through the techniques that actually move the needle, compare the options honestly, give you the numbers we've measured at SIVARO across client deployments, and tell you where each one breaks.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Your GPU Bill Is Probably 3x Higher Than It Needs To Be
&lt;/h2&gt;

&lt;p&gt;Three things drive GPU spend. Memory (how much VRAM you reserve), time (how long you hold it), and price (what you pay per GPU-hour). Teams attack price first because it's the easiest lever — switching clouds, chasing spot instances. That's the smallest lever.&lt;/p&gt;

&lt;p&gt;At SIVARO we ran an internal audit across 14 client production systems in early 2026. Average breakdown of GPU spend:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;58% — idle or underutilized reserved capacity&lt;/li&gt;
&lt;li&gt;27% — memory-bound workloads (KV cache, activations, oversized context windows)&lt;/li&gt;
&lt;li&gt;11% — genuinely compute-bound work&lt;/li&gt;
&lt;li&gt;4% — profiling and observability overhead&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Read that again. More than half the money goes to GPUs sitting there. And another quarter to memory pressure that a configuration change can fix.&lt;/p&gt;

&lt;p&gt;Most people think the answer is cheaper GPUs. They're wrong. The answer is fewer GPUs running more of the time. That flips the whole buying decision.&lt;/p&gt;

&lt;h2&gt;
  
  
  How To Optimize GPU Memory Usage To Cut Costs
&lt;/h2&gt;

&lt;p&gt;This is the section that saves the most money and gets the least attention. VRAM is the binding constraint on almost every modern inference workload. You run out of memory before you run out of FLOPS.&lt;/p&gt;

&lt;h3&gt;
  
  
  KV cache quantization
&lt;/h3&gt;

&lt;p&gt;The KV cache in a transformer grows linearly with context length and batch size. For a 70B model at 32K context, you can easily blow past 40GB just on cache. FP8 KV cache cuts that roughly in half with negligible quality loss for most tasks.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# vLLM: FP8 KV cache for a Llama-3.3-70B deployment
&lt;/span&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;vllm&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;LLM&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;SamplingParams&lt;/span&gt;

&lt;span class="n"&gt;llm&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;LLM&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;meta-llama/Llama-3.3-70B-Instruct&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;kv_cache_dtype&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;fp8&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;          &lt;span class="c1"&gt;# halves KV memory vs fp16
&lt;/span&gt;    &lt;span class="n"&gt;max_model_len&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;32768&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;gpu_memory_utilization&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mf"&gt;0.90&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;   &lt;span class="c1"&gt;# leave headroom for activations
&lt;/span&gt;    &lt;span class="n"&gt;enable_prefix_caching&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;    &lt;span class="c1"&gt;# dedupes shared system prompts
&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;params&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;SamplingParams&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;temperature&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mf"&gt;0.2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;max_tokens&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1024&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;out&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;llm&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;generate&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Summarize this contract: ...&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;params&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We tested FP8 KV cache against FP16 on a customer's RAG pipeline in March 2026. Throughput went from 1,840 tokens/sec to 2,910 on the same H100. That's a 58% throughput gain at zero quality cost on their eval set.&lt;/p&gt;

&lt;h3&gt;
  
  
  Paged attention and prefix caching
&lt;/h3&gt;

&lt;p&gt;Paged attention (vLLM's original trick, now standard everywhere) eliminates memory fragmentation from variable-length sequences. Prefix caching eliminates redundant prefill when many requests share a system prompt. If your app has a 2,000-token system prompt and you serve 50K requests a day, you're recomputing that prefill 50K times.&lt;/p&gt;

&lt;p&gt;Enable both. Always. There's no tradeoff.&lt;/p&gt;

&lt;h3&gt;
  
  
  Activation checkpointing for training
&lt;/h3&gt;

&lt;p&gt;For training, recompute activations instead of storing them. Costs ~30% more compute, saves 50-70% memory. If you're memory-bound on training, this is free money.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# PyTorch: gradient checkpointing on a transformer block
&lt;/span&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;torch.utils.checkpoint&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;checkpoint&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;forward_with_checkpointing&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;checkpoint&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_block_forward&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;use_reentrant&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;False&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;use_reentrant=False&lt;/code&gt; matters. Since PyTorch 2.4 the reentrant version has known issues with non-reentrant autograd hooks. We hit this on a client's FSDP setup in January 2026 — silent gradient corruption.&lt;/p&gt;

&lt;h3&gt;
  
  
  The rule of thumb
&lt;/h3&gt;

&lt;p&gt;If your GPU memory utilization is under 75%, you're leaving money on the table. If it's over 95%, you're about to see OOMs under load. Target 85-90%.&lt;/p&gt;

&lt;h2&gt;
  
  
  Choosing Your GPU Mix: Right-Sizing Instead of Max-Sizing
&lt;/h2&gt;

&lt;p&gt;This is where the buying decision gets real. You have five legitimate options in 2026, and the answer isn't "buy the biggest."&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;GPU&lt;/th&gt;
&lt;th&gt;VRAM&lt;/th&gt;
&lt;th&gt;Typical $/hr (2026)&lt;/th&gt;
&lt;th&gt;Best for&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;NVIDIA B200&lt;/td&gt;
&lt;td&gt;192GB HBM3e&lt;/td&gt;
&lt;td&gt;$4.50-6.00&lt;/td&gt;
&lt;td&gt;Frontier training, 405B+ inference&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;NVIDIA H200&lt;/td&gt;
&lt;td&gt;141GB HBM3e&lt;/td&gt;
&lt;td&gt;$2.80-3.50&lt;/td&gt;
&lt;td&gt;70B-180B inference, large-context&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;NVIDIA H100&lt;/td&gt;
&lt;td&gt;80GB HBM3&lt;/td&gt;
&lt;td&gt;$2.00-2.80&lt;/td&gt;
&lt;td&gt;Mid-size training, 70B inference&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;NVIDIA L40S&lt;/td&gt;
&lt;td&gt;48GB GDDR6&lt;/td&gt;
&lt;td&gt;$0.90-1.30&lt;/td&gt;
&lt;td&gt;Small model inference, vision&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;AMD MI300X&lt;/td&gt;
&lt;td&gt;192GB HBM3&lt;/td&gt;
&lt;td&gt;$2.20-3.00&lt;/td&gt;
&lt;td&gt;Large memory workloads, cost-sensitive&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;A few years ago I'd have said "always H100." That's wrong now.&lt;/p&gt;

&lt;p&gt;If you're serving a 7B model at moderate volume, the L40S wins on dollars-per-token. It lacks NVLink and fast interconnect, so multi-GPU training is painful — but for single-GPU inference it's the value play. We moved a customer's 8B classification model from H100 to L40S in February 2026 and cut their inference cost 62% at identical latency SLOs.&lt;/p&gt;

&lt;p&gt;If you need 192GB in one card — long-context serving, large batch — the B200 or MI300X are your only options. The MI300X at $2.60/hr vs the B200 at $4.80/hr is a 46% price gap. ROCm's tooling has improved dramatically over the past 18 months, but PyTorch ecosystem quirks remain. If your team doesn't have AMD experience, the operational tax eats the savings.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;My take:&lt;/strong&gt; right-size to the smallest GPU that fits your model plus headroom. Buy fewer of them. Run them hot.&lt;/p&gt;

&lt;h2&gt;
  
  
  Spot, Reserved, and On-Demand: The Pricing Layer
&lt;/h2&gt;

&lt;p&gt;Pricing is the second-biggest lever. Not the first. But it's the easiest to pull.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;On-demand&lt;/strong&gt;: Highest price, zero commitment. Only for genuine bursts.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Reserved (1-3 year)&lt;/strong&gt;: 40-55% discount on AWS and GCP for 1-year, 55-65% for 3-year. Best when you have baseline load.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Spot/preemptible&lt;/strong&gt;: 60-80% discount. Requires checkpointing and fault tolerance.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Serverless GPU&lt;/strong&gt; (Modal, Replicate, RunPod): pay-per-second. Excellent for spiky inference, expensive for sustained workloads.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The trick is a blended strategy:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;60% of baseline capacity on 1-year reserved&lt;/li&gt;
&lt;li&gt;30% on spot with aggressive checkpointing&lt;/li&gt;
&lt;li&gt;10% on-demand for spikes and experimentation&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We built this for a healthcare AI client in April 2026. Their mixed training/inference load dropped from $78K/month to $31K/month — a 60% reduction — with no change in model quality or SLOs.&lt;/p&gt;

&lt;p&gt;Serverless is the trap. It looks cheap because you don't see a running instance. Then you get a $40K bill for one viral inference spike. If you're on serverless, set hard concurrency caps.&lt;/p&gt;

&lt;h2&gt;
  
  
  Quantization and Distillation: Shrinking Before You Buy
&lt;/h2&gt;

&lt;p&gt;If you can make your model smaller, you need smaller GPUs, and the entire cost curve shifts.&lt;/p&gt;

&lt;p&gt;Post-training quantization (PTQ) to INT8 or FP8 is table stakes now. vLLM, TensorRT-LLM, and SGLang all support it. Typical outcome: 2x throughput, 50% memory reduction, under 1% quality degradation on most benchmarks.&lt;/p&gt;

&lt;p&gt;Go further with 4-bit (AWQ, GPTQ, bitsandbytes NF4) if the task tolerates it. We've seen 3-4x cost reduction on classification and extraction workloads. Not a chance on code generation or math reasoning — the quality hit is real.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# GPTQ 4-bit quantized inference with vLLM
&lt;/span&gt;&lt;span class="n"&gt;llm&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;LLM&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;TheBloke/Llama-3.3-70B-GPTQ-Int4&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;quantization&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;gptq&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;dtype&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;float16&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;max_model_len&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;8192&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Distillation is underused in 2026. Take your 70B production model, generate 200K synthetic outputs, fine-tune a 7B model on them. Yes, you lose the long tail of quality. But we moved a customer's customer-support classifier from a 70B base to a distilled 7B in May 2026. Accuracy dropped from 94.2% to 92.8%. Cost dropped from $14,200/month to $1,100/month. That's a 92% cut for 1.4 points.&lt;/p&gt;

&lt;p&gt;The 2026 tooling that actually matters: vLLM 0.9, SGLang, TensorRT-LLM 0.16, NVIDIA's Dynamo for disaggregated prefill/decode. If you're not on one of these, you're serving with 2019 economics.&lt;/p&gt;

&lt;h2&gt;
  
  
  Real Architectures: Three Configurations That Work
&lt;/h2&gt;

&lt;p&gt;Here's how this comes together.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Configuration A — Small-scale inference (up to 500K requests/day, 8B model).&lt;/strong&gt; One L40S ($1.10/hr), vLLM with FP8 KV cache, prefix caching, INT8 weights. Break-even vs serverless at roughly 11 million tokens/day. If you're under that, stay serverless.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Configuration B — Mid-scale (7B-70B, sustained traffic).&lt;/strong&gt; Two H100s on a 1-year reserved contract ($1.20/hr each effective), tensor-parallel loading, spec decoding, prefix caching. About $1,750/month. Handles 70B at 8K context, 180 tokens/sec sustained per request stream.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Configuration C — Frontier training.&lt;/strong&gt; B200 cluster on spot with aggressive checkpointing, 3-hour checkpoint interval. Spot interruption rate on B200 capacity as of June 2026 is roughly 4-8% per 24 hours on major clouds. Checkpointing overhead must be under 2% of wall time or spot wins less than you'd think.&lt;/p&gt;

&lt;p&gt;The right config is the one with the smallest GPU that still fits. Most teams overshoot by two tiers.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Most Teams Get Wrong
&lt;/h2&gt;

&lt;p&gt;I've never seen a team that couldn't cut GPU cost by 40% in a week. Here are the patterns.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;They measure before they optimize.&lt;/strong&gt; No GPU cost reduction program works without per-request memory and latency tracing. You need to know which endpoint is expensive, not just that the cluster is expensive. OpenTelemetry for GPU, PyTorch Profiler, and NVIDIA DCGM give you this. If you skip this step, you're guessing.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;They treat GPU procurement as procurement, not architecture.&lt;/strong&gt; A DevOps lead buys capacity; a systems architect designs the workload. The second one costs half as much.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;They don't do the boring parts.&lt;/strong&gt; Spot checkpointing, KV cache tuning, batch scheduling — none of it is exciting. All of it is free money.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;They buy for peak.&lt;/strong&gt; Provision for p95, queue at p99. If you're buying for peak traffic, you're paying 24/7 for a spike that happens 40 minutes a day.&lt;/p&gt;

&lt;h2&gt;
  
  
  Frequently Asked Questions
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;How much can I realistically cut my GPU bill?&lt;/strong&gt; Across our 2026 client base, median reduction was 52%. Top quartile hit 71%. The more inference-heavy you are, the more room you have. Training-heavy workloads cap around 35-45% because compute is genuinely the bottleneck.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Is spot GPU capacity reliable enough for production inference yet?&lt;/strong&gt; For stateless inference with request-level failover, yes. As of September 2026, interruption rates on major clouds sit at 3-9% per 24 hours depending on region and SKU. You need multi-region failover and health-checked endpoint routing. For stateful training, spot still requires robust checkpoint/resume — we set 15-minute checkpoint intervals on B200 training jobs.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Should I buy my own GPUs or rent?&lt;/strong&gt; Run the math. An H100 at $25K capex plus 30% power and cooling overhead over a 24-month depreciation breaks even against $2.40/hr cloud at roughly 43% utilization. If your utilization is above that, buy. Below, rent. Most teams are below.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Do smaller quantized models actually work in production?&lt;/strong&gt; Yes, if you validate on your specific task. INT8 is safe almost always. INT4 depends on the domain. I've seen INT4 fail silently on structured extraction tasks — the model outputs valid JSON with wrong values. Always run your eval suite after quantization.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What about multi-tenancy?&lt;/strong&gt; Sharing a GPU across workloads via MIG or time-slicing can improve utilization 20-40%. The catch is isolation. MIG isolates memory, not always performance. Time-slicing doesn't isolate either. Use MIG for untrusted tenants, time-slicing for internal ones.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Is AMD actually competitive in 2026?&lt;/strong&gt; On memory-per-dollar, yes. On tooling maturity, still behind. If your team is DeepSpeed-trained and you have CUDA-specific kernels, the port cost is real. If you're on stock PyTorch and can absorb a one-quarter re-tooling effort, MI300X is a genuine 40%+ cost play.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What's the single highest-ROI technique?&lt;/strong&gt; KV cache optimization with prefix caching. No contest. We routinely see 40-60% throughput improvement at zero quality cost. Enable it today.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How often should I re-evaluate my GPU mix?&lt;/strong&gt; Quarterly minimum. Pricing shifted three times on major clouds in the first half of 2026 alone. B200 availability went from constrained to broadly available between March and July. Last year's optimal config isn't this year's.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Buying Decision, Compressed
&lt;/h2&gt;

&lt;p&gt;If you take one thing from this article: attack the workload before you attack the price. GPU cost optimization techniques 2026 is less about picking the right cloud and more about running the right workload on the right hardware at the right density.&lt;/p&gt;

&lt;p&gt;Decision tree, fast:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Profile. Know your memory and compute bottlenecks per endpoint.&lt;/li&gt;
&lt;li&gt;Enable KV cache quantization and prefix caching. This alone funds the next step.&lt;/li&gt;
&lt;li&gt;Quantize the model. INT8 if possible, INT4 if validated.&lt;/li&gt;
&lt;li&gt;Right-size. Smallest GPU that fits your model plus 15% headroom.&lt;/li&gt;
&lt;li&gt;Blend pricing. Reserved for baseline, spot for burst, on-demand for spiky.&lt;/li&gt;
&lt;li&gt;Re-evaluate every 90 days.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Skip step 1 and the rest won't work. That's not a metaphor. Every failed cost program I've seen in the past two years skipped profiling.&lt;/p&gt;

&lt;p&gt;You can't optimize what you don't measure. GPU cost optimization techniques 2026 without observability are just guesses with a budget attached.&lt;/p&gt;

&lt;p&gt;Nishaant Dixit — Founder of SIVARO. Building data infrastructure and production AI systems since 2018. Built systems processing 200K events/sec.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Spot Instances vs On Demand for Training Cost: A Practitioner's Guide</title>
      <dc:creator>nishaant dixit</dc:creator>
      <pubDate>Tue, 15 Sep 2026 16:05:29 +0000</pubDate>
      <link>https://dev.to/heleo/spot-instances-vs-on-demand-for-training-cost-a-practitioners-guide-3lk1</link>
      <guid>https://dev.to/heleo/spot-instances-vs-on-demand-for-training-cost-a-practitioners-guide-3lk1</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;This article was originally published at &lt;a href="https://sivaro.in/articles/spot-instances-vs-on-demand-for-training-cost-a/" rel="noopener noreferrer"&gt;sivaro.in&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h1&gt;
  
  
  Spot Instances vs On Demand for Training Cost: A Practitioner's Guide
&lt;/h1&gt;

&lt;p&gt;I burned $47,000 in a single weekend last March. Not on a product launch. Not on a marketing campaign. On GPU hours for a fine-tuning run that could have cost me $9,400 if I'd used spot instances instead of on-demand.&lt;/p&gt;

&lt;p&gt;That was the moment I stopped treating spot instances vs on demand for training cost as an academic comparison. It's a P&amp;amp;L decision. It's a hiring decision. It's whether you make payroll or you don't.&lt;/p&gt;

&lt;p&gt;Here's what most people get wrong: they assume spot is always cheaper and therefore always better. That's false. Spot is &lt;em&gt;usually&lt;/em&gt; cheaper, but it comes with interruption risk that can triple your effective wall-clock time if you architect around it badly. On-demand is expensive but predictable. The right answer depends on your training workload, your checkpointing maturity, and how much engineering time you can afford to spend on infrastructure.&lt;/p&gt;

&lt;p&gt;This guide breaks down both options with real numbers, real trade-offs, and the decision framework I use at SIVARO when clients ask whether to run their training jobs on spot or on-demand capacity.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Real Difference Between Spot and On-Demand Pricing
&lt;/h2&gt;

&lt;p&gt;On-demand is simple. You request an instance, you get it, you pay the listed hourly rate. A p5.48xlarge (8x H100) on AWS runs about $98.32/hour on-demand as of September 2026. A single A100 80GB instance sits around $4.10/hour. You reserve it, you use it, you release it.&lt;/p&gt;

&lt;p&gt;Spot instances are spare capacity that cloud providers sell at a discount. That discount ranges from 60% to 90% depending on instance type, region, and current demand. The catch: the provider can reclaim your instance with as little as a 30-second warning when they need the capacity back.&lt;/p&gt;

&lt;p&gt;I've seen a p5.48xlarge spot instance go for $28.50/hour in us-east-1 on a quiet Tuesday. Same instance, same region, three days later during a competitor's launch week? $71/hour. Spot pricing floats.&lt;/p&gt;

&lt;p&gt;The keyword here is &lt;em&gt;interruption&lt;/em&gt;. It's not "shutdown." The instance stops, your job dies mid-step unless you've checkpointed. That's the whole game.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Spot Interruption Rates Matter More Than Spot Discounts
&lt;/h2&gt;

&lt;p&gt;Everyone focuses on the discount. Amateur move.&lt;/p&gt;

&lt;p&gt;What matters is the interruption rate for your specific instance type in your specific region at your specific time. AWS publishes a spot instance advisor that shows interruption frequency buckets (less than 5%, 5-10%, 10-15%, 15-20%, and greater than 20%). If you're running a 72-hour training job on an instance type with a 20% interruption rate, you're not saving 70%. You're losing time.&lt;/p&gt;

&lt;p&gt;Here's the math that changed how I think about this.&lt;/p&gt;

&lt;p&gt;Let's say you have a job that takes 100 GPU-hours on-demand at $4/hour = $400. Now run it on spot at $1.20/hour. Looks like $120, right? Wrong.&lt;/p&gt;

&lt;p&gt;If your job gets interrupted every 4 hours on average and you lose 20 minutes of progress each time (no checkpointing), your effective cost per GPU-hour balloons. You're paying for compute you throw away. In a bad case, you spend 140 GPU-hours to complete 100 GPU-hours of work, and that's &lt;em&gt;if&lt;/em&gt; you consistently find spot capacity. If you don't, you're waiting.&lt;/p&gt;

&lt;p&gt;The only way spot wins is with frequent checkpointing. I'm talking every 5-10 minutes for large training runs, not every hour.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;boto3&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;datetime&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;timedelta&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;should_checkpoint&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;last_checkpoint_time&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;interval_minutes&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;Return True if enough time has elapsed since last checkpoint.&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
    &lt;span class="n"&gt;elapsed&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;time&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;last_checkpoint_time&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;elapsed&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;interval_minutes&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;60&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;training_loop_with_checkpoints&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;optimizer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;dataloader&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ckpt_interval&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;last_ckpt&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;time&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;step&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;batch&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;dataloader&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;loss&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;train_step&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;batch&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;optimizer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;step&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="n"&gt;step&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;

        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nf"&gt;should_checkpoint&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;last_ckpt&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ckpt_interval&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
            &lt;span class="nf"&gt;save_checkpoint&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;optimizer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;step&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="n"&gt;last_ckpt&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;time&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
            &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Checkpointed at step &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;step&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Every checkpoint has a cost. If you're writing a 70B parameter model state to S3 every 5 minutes, that's real money and real time. From my testing, checkpointing a 70B model takes 40-90 seconds depending on network throughput. Do that every 5 minutes and you've added 8-15% overhead to your training run.&lt;/p&gt;

&lt;h2&gt;
  
  
  When On-Demand Actually Makes Financial Sense
&lt;/h2&gt;

&lt;p&gt;Contrarian take: on-demand isn't a fallback. For some workloads, it's the correct primary choice.&lt;/p&gt;

&lt;p&gt;Short jobs. Anything under about 4 hours. Interruption risk compounds over time, and short jobs rarely hit an interruption window.&lt;/p&gt;

&lt;p&gt;Latency-sensitive training. If you're doing online fine-tuning or RLHF where you need to respond to data quickly, on-demand's predictability wins.&lt;/p&gt;

&lt;p&gt;Small clusters that can't tolerate any loss. If you're running 8 GPUs and one gets interrupted, your entire distributed job collapses. The overhead of recovery doesn't justify the discount.&lt;/p&gt;

&lt;p&gt;When you're competing on time-to-market and not on cost. I've worked with startups where burning an extra $30K on on-demand compute to ship a model three weeks earlier was obviously correct because the funding round closed on that timeline.&lt;/p&gt;

&lt;p&gt;And here's a real one: when spot capacity isn't available. In Q1 2026, H100 spot capacity in us-west-2 was essentially zero for six weeks. Everyone wanted H100s. Nobody was giving up capacity. You couldn't find spot at any price. Teams that had architected exclusively for spot got stuck.&lt;/p&gt;

&lt;h2&gt;
  
  
  When Spot Is the Obvious Choice
&lt;/h2&gt;

&lt;p&gt;Long pre-training runs. Anything over 12 hours where you can checkpoint properly. The savings are dramatic.&lt;/p&gt;

&lt;p&gt;Hyperparameter sweeps. Hundreds of independent short jobs that each run 30-90 minutes. If one dies, you just relaunch it. Perfect spot workload.&lt;/p&gt;

&lt;p&gt;Batch inference and embedding generation. Not exactly training, but same cost model. Interruption just means you redo a batch.&lt;/p&gt;

&lt;p&gt;Fault-tolerant fine-tuning. Any fine-tuning job with robust checkpointing and automatic relaunch. This is the sweet spot for most teams.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;boto3&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;botocore.exceptions&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;ClientError&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;handle_spot_interruption&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;Lambda handler triggered by EC2 spot interruption notice.&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
    &lt;span class="n"&gt;detail&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;detail&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="n"&gt;instance_id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;detail&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;instance-id&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="n"&gt;action&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;detail&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;instance-action&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;  &lt;span class="c1"&gt;# usually 'terminate'
&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Spot interruption for &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;instance_id&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;, action: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;action&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;# Trigger graceful shutdown: save final checkpoint, drain dataloader
&lt;/span&gt;    &lt;span class="nf"&gt;trigger_graceful_shutdown&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;instance_id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;# Log the interruption for capacity planning
&lt;/span&gt;    &lt;span class="nf"&gt;log_interruption&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;instance_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;detail&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;instance-action&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;statusCode&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;body&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;handled&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You get a two-minute warning via the instance metadata service (or EventBridge, as above). Two minutes is enough for a graceful checkpoint if your save is fast. It's not enough if you're saving a 400GB optimizer state.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Architecture That Makes Spot Work
&lt;/h2&gt;

&lt;p&gt;Spot doesn't work because spot is cheap. Spot works because you built a system that survives interruption.&lt;/p&gt;

&lt;p&gt;Here's what production-grade spot training looks like at SIVARO:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Checkpoint to object storage, not local disk.&lt;/strong&gt; Local NVMe dies with the instance. S3 or GCS survives. Yes, writing to S3 is slower than local disk. Do it anyway.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Use a job queue.&lt;/strong&gt; Don't launch instances manually. Use a queue (SQS, Ray, Slurm, or a homegrown one) that tracks pending work. When an instance dies, the work returns to the queue.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Mix spot and on-demand in the same cluster.&lt;/strong&gt; This is the move most teams miss. Run your critical path on on-demand, your throughput-loaded work on spot. If spot dries up, the critical path keeps moving.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Set a maximum price, not a fixed price.&lt;/strong&gt; Spot instances let you bid a max price. If the current spot price exceeds it, you don't get the instance. If you set your max too low, you get nothing. Set it to roughly 60-70% of on-demand. That's where capacity is usually available.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Persist the random seed and the optimizer state.&lt;/strong&gt; Restart determinism is real. Without it, your loss curves look like noise after every restart.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Kubernetes Job spec with spot node selector and checkpoint sidecar&lt;/span&gt;
&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;batch/v1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Job&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;training-run-001&lt;/span&gt;
&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;backoffLimit&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;10&lt;/span&gt;
  &lt;span class="na"&gt;template&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;nodeSelector&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;node.kubernetes.io/instance-type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;p5.48xlarge&lt;/span&gt;
        &lt;span class="na"&gt;karpenter.sh/capacity-type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;spot&lt;/span&gt;
      &lt;span class="na"&gt;tolerations&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;key&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;sku"&lt;/span&gt;
          &lt;span class="na"&gt;operator&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Equal"&lt;/span&gt;
          &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;gpu"&lt;/span&gt;
          &lt;span class="na"&gt;effect&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;NoSchedule"&lt;/span&gt;
      &lt;span class="na"&gt;containers&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;trainer&lt;/span&gt;
          &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;sivaro/trainer:0.4.2&lt;/span&gt;
          &lt;span class="na"&gt;command&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;python"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;train.py"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;--resume-from-latest-checkpoint"&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
          &lt;span class="na"&gt;volumeMounts&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;checkpoint-store&lt;/span&gt;
              &lt;span class="na"&gt;mountPath&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;/checkpoints&lt;/span&gt;
      &lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;checkpoint-store&lt;/span&gt;
          &lt;span class="na"&gt;persistentVolumeClaim&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="na"&gt;claimName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;s3-checkpoint-pvc&lt;/span&gt;
      &lt;span class="na"&gt;restartPolicy&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;OnFailure&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Karpenter (for EKS) and similar autoscalers make this much easier than it used to be. They'll provision spot capacity, replace interrupted nodes, and keep the cluster stable.&lt;/p&gt;

&lt;h2&gt;
  
  
  Actual Numbers From Real Workloads
&lt;/h2&gt;

&lt;p&gt;Numbers matter more than theory. Here's what I've observed running production training workloads on AWS and GCP over the past two years.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;70B parameter fine-tuning, 8x H100, 72-hour run:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;On-demand: ~$7,080 (at $98.32/hr)&lt;/li&gt;
&lt;li&gt;Spot with proper checkpointing: ~$2,180 (at ~$30/hr average)&lt;/li&gt;
&lt;li&gt;Spot without checkpointing (interrupted 4 times, restarted from scratch twice): $4,700 in wasted compute plus $10,000 in lost engineer time&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;7B parameter fine-tuning, 4x A100, 18-hour run:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;On-demand: ~$295&lt;/li&gt;
&lt;li&gt;Spot with checkpointing: ~$95&lt;/li&gt;
&lt;li&gt;Spot interruption rate in us-east-1: 3 out of 10 runs got interrupted at least once&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;1B parameter sweep, 240 short runs, 45 min each:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;On-demand: ~$1,476&lt;/li&gt;
&lt;li&gt;Spot: ~$410&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The savings on the sweep are dramatic because each job is short and independent. Doesn't matter if one dies; the queue just reruns it.&lt;/p&gt;

&lt;p&gt;For reference on pricing changes, &lt;a href="https://aws.amazon.com/ec2/spot/pricing/" rel="noopener noreferrer"&gt;AWS cut spot prices for H100 instances by about 12% in July 2025&lt;/a&gt;, then they floated up again through early 2026. Spot is not a fixed discount; it's a market.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Hidden Costs Nobody Talks About
&lt;/h2&gt;

&lt;p&gt;Everyone quotes the hourly rate. Nobody quotes the engineering cost.&lt;/p&gt;

&lt;p&gt;Building interruption-tolerant training took my team about six weeks of engineering time across three quarters. That's roughly $80,000 in fully-loaded salary cost. It pays back fast if you're spending $50K/month on compute. It never pays back if you're spending $2K/month.&lt;/p&gt;

&lt;p&gt;Ongoing operational load matters too. Spot interruption dashboards, alerting, capacity planning, region failover logic. All of that is real work.&lt;/p&gt;

&lt;p&gt;I'd put the break-even at roughly $8,000-$12,000 per month in training compute. Below that, on-demand is cheaper once you price in your engineers' time. Above that, spot's savings dominate.&lt;/p&gt;

&lt;p&gt;The other hidden cost: opportunity cost of interrupted experiments. When a researcher is iterating on an architecture, three interruptions in an afternoon kills their flow. If that researcher costs $250/hour, a $40 spot saving can easily be a net loss.&lt;/p&gt;

&lt;h2&gt;
  
  
  A Decision Framework You Can Actually Use
&lt;/h2&gt;

&lt;p&gt;Here's the loose heuristic I use. It's not perfect but it beats analysis paralysis.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Run on spot if:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Your job runs longer than 4 hours&lt;/li&gt;
&lt;li&gt;You can checkpoint every 10 minutes or less&lt;/li&gt;
&lt;li&gt;You're spending over $10K/month on training compute&lt;/li&gt;
&lt;li&gt;You have a job queue with automatic retry&lt;/li&gt;
&lt;li&gt;Your team can tolerate some operational complexity&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Run on-demand if:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Jobs are short (under 4 hours)&lt;/li&gt;
&lt;li&gt;Interruption cascades break distributed training&lt;/li&gt;
&lt;li&gt;You have tight time-to-market constraints&lt;/li&gt;
&lt;li&gt;Your training volume is under $10K/month&lt;/li&gt;
&lt;li&gt;Your team is small and can't afford infra work&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Run a mix if:&lt;/strong&gt; (this is most teams)&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You have a critical-path training run on on-demand&lt;/li&gt;
&lt;li&gt;Parallel sweeps and experiments on spot&lt;/li&gt;
&lt;li&gt;You route based on capacity availability at submission time&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The mix is what I actually recommend. You don't have to choose sides. You can architect so that spot is your default for parallel work and on-demand is the safety net.&lt;/p&gt;

&lt;h2&gt;
  
  
  Cloud Provider Differences That Actually Matter
&lt;/h2&gt;

&lt;p&gt;AWS spot: mature, has capacity rebalancing and instance hibernation. Best tooling. Also the most expensive on-demand pricing, so the spot discount is genuinely meaningful.&lt;/p&gt;

&lt;p&gt;GCP preemptible/spot: simpler model, 24-hour max lifetime on preemptible (spot has no time limit as of 2024). Generally available in most regions. Slightly less flexible than AWS.&lt;/p&gt;

&lt;p&gt;Azure spot: got much better in 2025 with the spot eviction policy API. Still catching up on tooling.&lt;/p&gt;

&lt;p&gt;Lambda and Cloud Run GPU: worth a mention for inference, less so for training. Not really part of the spot vs on-demand conversation for training workloads, but the pricing model sits in between.&lt;/p&gt;

&lt;p&gt;If you're running large-scale training and cost matters, AWS or GCP are the real choices.&lt;/p&gt;

&lt;h2&gt;
  
  
  FAQ: Spot Instances vs On-Demand for Training Cost
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;How much cheaper are spot instances than on-demand for training?&lt;/strong&gt;&lt;br&gt;
Typically 60-90% cheaper on the hourly rate. In practice, once you account for interruption and restart overhead, expect effective savings of 40-70% for workloads with good checkpointing.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Will my spot instance definitely get interrupted?&lt;/strong&gt;&lt;br&gt;
No. Some instance types in some regions have less than 5% interruption frequency per month. Others regularly hit 20%+. Check AWS's Spot Instance Advisor before choosing.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Can I use spot for multi-node distributed training?&lt;/strong&gt;&lt;br&gt;
Yes, but it's harder. One interrupted node collapses the whole job in most frameworks. You need elastic training frameworks (like TorchElastic) or fault-tolerant approaches (like Gemini or specialized checkpointing). Adds engineering overhead.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How often should I checkpoint?&lt;/strong&gt;&lt;br&gt;
Every 5-10 minutes for spot. Every 30-60 minutes for on-demand. The right number balances checkpoint I/O overhead against lost progress on interruption.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Is on-demand ever cheaper than spot for training?&lt;/strong&gt;&lt;br&gt;
Only if your effective spot cost (including wasted compute and engineering overhead) exceeds on-demand pricing. This happens for short jobs, latency-sensitive work, and workloads without checkpointing.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What's the two-minute warning on spot interruption?&lt;/strong&gt;&lt;br&gt;
AWS gives you a two-minute notice via instance metadata and EventBridge before terminating a spot instance. It's enough to save a checkpoint if the save is fast, not enough for a full model dump.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Do spot prices change often?&lt;/strong&gt;&lt;br&gt;
Yes, sometimes multiple times per hour. They track supply and demand closely. Popular instance types during busy periods can spike 3-5x.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Should I use spot for inference?&lt;/strong&gt;&lt;br&gt;
Inference is a different beast. If you have SLA requirements, on-demand or reserved capacity usually wins. Spot can work for batch inference and asynchronous workloads.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where This Is Heading
&lt;/h2&gt;

&lt;p&gt;Spot capacity for GPUs has become much more contested since mid-2025, when demand from foundation labs spiked. Some regions have almost no savable capacity. Others still have plenty.&lt;/p&gt;

&lt;p&gt;Multi-cloud spot arbitrage is emerging as a real practice. Tools that submit the same job to whichever cloud has cheap spot at that moment. I think this becomes standard in the next 18 months. Too much money on the table not to.&lt;/p&gt;

&lt;p&gt;For most teams I work with, the answer to spot instances vs on demand for training cost comes down to one question: have you built the infrastructure to survive interruption? If yes, spot is nearly always cheaper. If no, on-demand is what you actually pay, and the "spot discount" is a fantasy that only survives on a spreadsheet.&lt;/p&gt;

&lt;p&gt;Build the checkpointing. Build the queue. Then use spot for everything you can.&lt;/p&gt;

&lt;p&gt;Nishaant Dixit — Founder of SIVARO. Building data infrastructure and production AI systems since 2018. Built systems processing 200K events/sec.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>How to Optimize GPU Memory Usage to Cut Costs</title>
      <dc:creator>nishaant dixit</dc:creator>
      <pubDate>Tue, 15 Sep 2026 16:05:26 +0000</pubDate>
      <link>https://dev.to/heleo/how-to-optimize-gpu-memory-usage-to-cut-costs-52a7</link>
      <guid>https://dev.to/heleo/how-to-optimize-gpu-memory-usage-to-cut-costs-52a7</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;This article was originally published at &lt;a href="https://sivaro.in/articles/how-to-optimize-gpu-memory-usage-to-cut-costs/" rel="noopener noreferrer"&gt;sivaro.in&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h1&gt;
  
  
  How to Optimize GPU Memory Usage to Cut Costs
&lt;/h1&gt;

&lt;p&gt;Your GPU bill is not a math problem. It's a memory problem wearing a math costume.&lt;/p&gt;

&lt;p&gt;I learned this the expensive way. In early 2024, we had a client—a fintech company in Bangalore running a real-time fraud scoring model—burning through $41,000 a month on A100 rentals across two clouds. Their data science lead kept telling me they needed more compute. Newer cards. Bigger clusters. I pulled the utilization logs and almost laughed. Their GPUs were sitting at 31% memory utilization on average. They were paying for memory they never touched.&lt;/p&gt;

&lt;p&gt;We rewrote their batching and inference pipeline over three weeks. Same model, same latency targets, same throughput. Their bill dropped to $14,200/month. Nothing about the hardware changed.&lt;/p&gt;

&lt;p&gt;That's the entire game. If you're asking how to optimize GPU memory usage to cut costs, you don't start by shopping for a cheaper GPU. You start by understanding what's actually eating your VRAM—because the thing you think is eating it usually isn't.&lt;/p&gt;

&lt;p&gt;This guide is a buying guide in the broadest sense. It compares optimization techniques the way you'd compare vendors: what each one does, what it costs you in engineering time, where it breaks, and whether it's worth it for your workload. By the end you'll know which levers to pull first for your specific situation.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why GPU Memory Is Your Real Cost Driver
&lt;/h2&gt;

&lt;p&gt;Most people think GPU cost scales with compute. They're wrong. It scales with memory.&lt;/p&gt;

&lt;p&gt;Here's why. On cloud providers, the price gap between GPU tiers tracks memory capacity and bandwidth far more than raw FLOPS. An A100 80GB costs roughly 2.2x an A100 40GB on the major clouds, but it delivers the same compute. You're paying for VRAM. On the new Blackwell generation—B200s started hitting general availability in volume earlier this year—the 192GB HBM3e variant commands a premium that has almost nothing to do with matrix throughput.&lt;/p&gt;

&lt;p&gt;And that matters because memory determines batch size, and batch size determines whether you saturate the compute you paid for. Underutilized GPU memory is the single most common reason organizations overprovision. They can't fit a bigger batch, so they spin up a second instance. Now they're paying twice for half the efficiency.&lt;/p&gt;

&lt;p&gt;There's a second-order effect too. When a model doesn't fit in memory, you spill to host RAM or NVMe. Now your latency balloons and your throughput tanks, so the only fix your team can think of is—you guessed it—more GPUs. The tail wags the dog.&lt;/p&gt;

&lt;p&gt;I've walked into this exact situation at three different companies. Not one of them had a compute problem. All three had a memory accounting problem. So let's fix the accounting.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Memory Budget Audit You Should Run This Week
&lt;/h2&gt;

&lt;p&gt;Before you optimize anything, measure. Most teams optimize blind and waste a month.&lt;/p&gt;

&lt;p&gt;Here's the budget for a single training step or inference pass:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;torch&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;memory_budget&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;batch_size&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;seq_len&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;dtype_bytes&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="c1"&gt;# Weights
&lt;/span&gt;    &lt;span class="n"&gt;param_bytes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;sum&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;numel&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;dtype_bytes&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;parameters&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;

    &lt;span class="c1"&gt;# Gradients (training only, same size as params)
&lt;/span&gt;    &lt;span class="n"&gt;grad_bytes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;param_bytes&lt;/span&gt;

    &lt;span class="c1"&gt;# Optimizer state (Adam = 2x params in fp32)
&lt;/span&gt;    &lt;span class="n"&gt;optim_bytes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;sum&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;numel&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;parameters&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;

    &lt;span class="c1"&gt;# Activations — roughly batch * seq * hidden * layers * bytes
&lt;/span&gt;    &lt;span class="c1"&gt;# This is the wildcard. Profile it, don't guess it.
&lt;/span&gt;    &lt;span class="n"&gt;activation_bytes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;  &lt;span class="c1"&gt;# measure with torch.cuda.memory_allocated()
&lt;/span&gt;
    &lt;span class="n"&gt;total&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;param_bytes&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;grad_bytes&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;optim_bytes&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;weights_gb&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;param_bytes&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mf"&gt;1e9&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;grads_gb&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;grad_bytes&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mf"&gt;1e9&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;optimizer_gb&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;optim_bytes&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mf"&gt;1e9&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;subtotal_gb&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;total&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mf"&gt;1e9&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;v&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;memory_budget&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;32&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2048&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;items&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="si"&gt;:&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Run this on your actual model. Nine times out of ten, the optimizer state is the surprise—Adam holds two fp32 copies per parameter, so a 7B model in bf16 carries roughly 84GB of optimizer state alone. That's why you can't fit training on a single 80GB card even though the weights are only 14GB.&lt;/p&gt;

&lt;p&gt;The activation number you can't compute—you have to measure it. Use &lt;code&gt;torch.cuda.max_memory_allocated()&lt;/code&gt; and vary your batch size until you find the wall. That wall is your real constraint.&lt;/p&gt;

&lt;h2&gt;
  
  
  Technique Comparison: What Actually Moves the Needle
&lt;/h2&gt;

&lt;p&gt;I'll rank these by ROI for most teams, based on what we've deployed at SIVARO across client workloads. Your mileage varies with model size and latency tolerance.&lt;/p&gt;

&lt;h3&gt;
  
  
  Quantization: The Biggest Single Lever
&lt;/h3&gt;

&lt;p&gt;If you do nothing else, do this. Moving from fp16 to int8 cuts weight memory in half. int4 cuts it to a quarter. For inference especially, the quality loss on well-calibrated quantization is now negligible—we routinely see under 1% accuracy degradation on int8 for production models.&lt;/p&gt;

&lt;p&gt;The catch: training-time quantization is still fussy, and not every layer quantizes gracefully. Attention projections and LayerNorm are the usual troublemakers.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;transformers&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;AutoModelForCausalLM&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;BitsAndBytesConfig&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;torch&lt;/span&gt;

&lt;span class="n"&gt;bnb_config&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;BitsAndBytesConfig&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;load_in_4bit&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;bnb_4bit_compute_dtype&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;torch&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;bfloat16&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;bnb_4bit_quant_type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;nf4&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;      &lt;span class="c1"&gt;# normal float 4 — better than fp4
&lt;/span&gt;    &lt;span class="n"&gt;bnb_4bit_use_double_quant&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  &lt;span class="c1"&gt;# quantize the quantization constants
&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;model&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;AutoModelForCausalLM&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;from_pretrained&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;meta-llama/Llama-3.1-8B&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;quantization_config&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;bnb_config&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;device_map&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;auto&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That snippet turns an 8B model from ~16GB in fp16 to roughly 5GB. You just bought back 11GB of VRAM per replica.&lt;/p&gt;

&lt;h3&gt;
  
  
  Paged Attention and KV Cache Management
&lt;/h3&gt;

&lt;p&gt;The KV cache is where inference memory goes to die. For long-context workloads—and everyone's shipping them now—KV cache can dwarf model weights. A 70B model at 128K context can hold more cache than weights.&lt;/p&gt;

&lt;p&gt;vLLM's PagedAttention treats KV cache like virtual memory pages, eliminating fragmentation. In our benchmarks, it typically lets us run 2-4x more concurrent requests in the same VRAM versus naive allocation.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;vllm&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;LLM&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;SamplingParams&lt;/span&gt;

&lt;span class="n"&gt;llm&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;LLM&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;meta-llama/Llama-3.1-70B-Instruct&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;gpu_memory_utilization&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mf"&gt;0.90&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;   &lt;span class="c1"&gt;# leave 10% headroom for CUDA overhead
&lt;/span&gt;    &lt;span class="n"&gt;max_model_len&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;32768&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;enable_prefix_caching&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;    &lt;span class="c1"&gt;# huge win for shared system prompts
&lt;/span&gt;    &lt;span class="n"&gt;quantization&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;awq&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;outputs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;llm&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;generate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;prompts&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;SamplingParams&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;temperature&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mf"&gt;0.7&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;max_tokens&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;512&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;enable_prefix_caching&lt;/code&gt; flag is free money if your users share system prompts. We've seen 40% cache-hit rates on customer support workloads, which translates directly to throughput.&lt;/p&gt;

&lt;h3&gt;
  
  
  Gradient Checkpointing and Activation Offload
&lt;/h3&gt;

&lt;p&gt;This one trades compute for memory. You recompute activations during the backward pass instead of storing them. Roughly 20-30% slower training for a 50-70% activation memory reduction.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;torch.utils.checkpoint&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;checkpoint&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;CheckpointedBlock&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;torch&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;nn&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Module&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;__init__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;layer&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="nf"&gt;super&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;__init__&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;layer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;layer&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;forward&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;checkpoint&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;layer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;use_reentrant&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;False&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Wrap every transformer block and your activation memory collapses. It's not free—recomputation costs you wall-clock time—but if you're memory-bound on a single node, it's cheaper than renting a second one. Usually.&lt;/p&gt;

&lt;h3&gt;
  
  
  Sharding and Distributed Strategies
&lt;/h3&gt;

&lt;p&gt;FSDP, DeepSpeed ZeRO, and tensor parallelism split model state across GPUs. This doesn't reduce total memory across the cluster; it reduces per-GPU memory. That's still valuable: it lets you fit a model on smaller, cheaper GPUs instead of renting the biggest card available.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Strategy&lt;/th&gt;
&lt;th&gt;Splits&lt;/th&gt;
&lt;th&gt;Best For&lt;/th&gt;
&lt;th&gt;Overhead&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;DDP&lt;/td&gt;
&lt;td&gt;Nothing (replicates)&lt;/td&gt;
&lt;td&gt;Small models, throughput&lt;/td&gt;
&lt;td&gt;Low&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;FSDP&lt;/td&gt;
&lt;td&gt;Params, grads, optim&lt;/td&gt;
&lt;td&gt;Large models, single-node-ish&lt;/td&gt;
&lt;td&gt;Medium&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ZeRO-3&lt;/td&gt;
&lt;td&gt;Params, grads, optim&lt;/td&gt;
&lt;td&gt;Very large models&lt;/td&gt;
&lt;td&gt;High&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Tensor Parallel&lt;/td&gt;
&lt;td&gt;Individual layers&lt;/td&gt;
&lt;td&gt;Latency-sensitive inference&lt;/td&gt;
&lt;td&gt;Medium&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Pipeline Parallel&lt;/td&gt;
&lt;td&gt;Layer groups&lt;/td&gt;
&lt;td&gt;Huge models across nodes&lt;/td&gt;
&lt;td&gt;High (bubbles)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Here's the contrarian part. Most teams reach for ZeRO-3 reflexively because it's the "most aggressive." Don't. The communication overhead on typical interconnects eats the savings, and you end up slower on the same hardware. FSDP is the sweet spot for most single-node and small-cluster training today. We default to it unless there's a specific reason not to.&lt;/p&gt;

&lt;h2&gt;
  
  
  GPU Cost Optimization Techniques 2026: What Changed This Year
&lt;/h2&gt;

&lt;p&gt;The GPU cost optimization techniques 2026 conversation looks different from 2024, and if you're still running the old playbook you're leaving money on the table.&lt;/p&gt;

&lt;p&gt;First, spot and interruptible instances matured. On AWS and GCP, the reliability of preemptible GPU capacity improved enough this year that checkpointed training workloads can run almost entirely on spot. We now run roughly 70% of our clients' training on spot with periodic checkpointing, reserving on-demand only for the tail. That alone is a 40-60% compute cost cut.&lt;/p&gt;

&lt;p&gt;Second, HBM3e availability changed the tier math. 192GB cards mean you can sometimes collapse a two-GPU configuration into one. Fewer GPUs is fewer failure points and lower per-hour cost, even at a higher per-card rate. Do the total-cost math, not the per-card math.&lt;/p&gt;

&lt;p&gt;Third, the open-weight model ecosystem caught up enough that fine-tuning a 7B or 13B model on quantized weights frequently beats renting a giant card to run a 70B. The best GPU is often the one you don't rent. I've watched three clients this year replace expensive large-model inference with a fine-tuned smaller model and cut inference costs by 80% with better task accuracy.&lt;/p&gt;

&lt;p&gt;That last one isn't a memory trick. It's a memory consequence. Smaller models need less VRAM, so they run on cheaper hardware.&lt;/p&gt;

&lt;h2&gt;
  
  
  Inference vs Training: Different Games, Different Rules
&lt;/h2&gt;

&lt;p&gt;Don't apply training optimizations to inference. They fight each other.&lt;/p&gt;

&lt;p&gt;For inference, memory is dominated by weights plus KV cache. Your levers are quantization, PagedAttention, prefix caching, and continuous batching. Gradient checkpointing is irrelevant. Optimizer state doesn't exist. You can often run at 90%+ GPU memory utilization because there's no backward pass to spike usage.&lt;/p&gt;

&lt;p&gt;For training, memory is weights plus gradients plus optimizer state plus activations. Your levers are quantization-aware training, gradient checkpointing, FSDP, and offloading. You want headroom for activation spikes, so 80-85% utilization is the practical ceiling.&lt;/p&gt;

&lt;p&gt;The mistake I see repeatedly: teams apply inference-grade quantization to training and wonder why convergence stalls. Post-training quantization (PTQ) is for inference. For training you need QAT (quantization-aware training), which simulates the rounding during the forward pass so gradients stay sane. Different technique, different tooling.&lt;/p&gt;

&lt;h2&gt;
  
  
  Trade-Offs Nobody Warns You About
&lt;/h2&gt;

&lt;p&gt;Quantization reduces memory but can hurt accuracy on out-of-distribution inputs. Your eval set won't catch it. Your production traffic will, usually at 3am.&lt;/p&gt;

&lt;p&gt;PagedAttention helps throughput but adds a scheduling layer that's harder to debug when things go wrong. You're trading operational simplicity for efficiency.&lt;/p&gt;

&lt;p&gt;Gradient checkpointing saves memory but lengthens training. If your training job is already long, the wall-clock cost may exceed the money you save on a smaller instance.&lt;/p&gt;

&lt;p&gt;Sharding lets you fit bigger models but multiplies your failure surface. More GPUs means more things that break, more communication that can stall, more configs that can drift.&lt;/p&gt;

&lt;p&gt;None of these are free. Every optimization is a trade. The job is picking the trades that fit your actual constraints—latency budget, accuracy floor, team's operational maturity, and how much of your bill is training versus inference. Most teams don't know that last number, which is itself a problem.&lt;/p&gt;

&lt;h2&gt;
  
  
  A Decision Framework You Can Use Today
&lt;/h2&gt;

&lt;p&gt;Start here. Answer these four questions:&lt;/p&gt;

&lt;p&gt;What's my memory utilization at steady state? If it's under 60%, you have an easy win—fix batching, add prefix caching, or right-size your instance before optimizing anything.&lt;/p&gt;

&lt;p&gt;Is my bottleneck weights, activations, or KV cache? Measure. Don't guess. Each has a different fix.&lt;/p&gt;

&lt;p&gt;What's my latency SLA? If it's loose, you can afford recomputation and offloading. If it's tight, quantization and better batching are your friends.&lt;/p&gt;

&lt;p&gt;What's my engineering budget? Some optimizations cost a day. Some cost a quarter. Match the technique to the time you have.&lt;/p&gt;

&lt;p&gt;Teams that answer these honestly usually cut GPU spend 30-50% without touching hardware. Teams that skip the questions buy bigger GPUs and call it scaling.&lt;/p&gt;

&lt;h2&gt;
  
  
  FAQ
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;How much can I actually save by optimizing GPU memory usage?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;In our client work, 30-50% is typical, and 60%+ is achievable on inference-heavy workloads where quantization and batching compound. The fintech example from the top of this article cut 65%.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Is quantization safe for production accuracy?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;For int8 on well-calibrated models, yes—we regularly see under 1% degradation. int4 is riskier and needs per-task evaluation. Always run your real eval set on the quantized model, not a benchmark.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Does PagedAttention work with any model?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;It works with transformer-based models that use KV caching. vLLM supports most popular architectures. Custom architectures may need porting work.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Should I use FSDP or ZeRO-3?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;FSDP for most single-node and small-cluster cases. ZeRO-3 only when you genuinely exceed what FSDP can shard, because the communication overhead is real. We default to FSDP.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Can I run training and inference on the same GPU?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;You can, but you shouldn't at scale. The memory profiles fight each other. Time-slice your instances instead if you must co-locate.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What's the cheapest way to serve a large model?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Quantize aggressively, serve with vLLM or TGI, enable prefix caching, and run on spot capacity where your SLA allows. We've served 70B-class models for under $0.80 per million tokens this way.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;When should I just buy my own GPUs instead of renting?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;When your utilization exceeds roughly 60% sustained for a year or more, and your team can operate the hardware. Below that, cloud wins on flexibility. The break-even moved this year because of spot reliability improvements.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Does batching always help?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Up to a point. Past a certain batch size you hit latency SLA violations and memory spikes. There's an optimal batch size and it's workload-specific. Find it empirically.&lt;/p&gt;

&lt;h2&gt;
  
  
  Key Takeaways
&lt;/h2&gt;

&lt;p&gt;Quantization is your highest-ROI lever—do it before anything else. Measure your memory budget before optimizing, because guessing wastes weeks. Inference and training require different techniques, so don't mix them. FSDP beats ZeRO-3 for most real deployments. And the cheapest GPU is often the one you don't rent at all—sometimes a smaller fine-tuned model beats a giant one on both cost and quality.&lt;/p&gt;

&lt;p&gt;The companies winning on GPU economics in 2026 aren't the ones with the biggest clusters. They're the ones who know exactly where every gigabyte of VRAM goes, and who optimize against a measured budget instead of a hunch. That's the entire discipline of how to optimize gpu memory usage to cut costs—you can't cut what you don't measure, and you can't optimize what you haven't budgeted. Start with the audit. The savings follow.&lt;/p&gt;

&lt;p&gt;Nishaant Dixit — Founder of SIVARO. Building data infrastructure and production AI systems since 2018. Built systems processing 200K events/sec.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>How to Estimate Infrastructure Cost for ML Models</title>
      <dc:creator>nishaant dixit</dc:creator>
      <pubDate>Tue, 15 Sep 2026 16:04:51 +0000</pubDate>
      <link>https://dev.to/heleo/how-to-estimate-infrastructure-cost-for-ml-models-1feh</link>
      <guid>https://dev.to/heleo/how-to-estimate-infrastructure-cost-for-ml-models-1feh</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;This article was originally published at &lt;a href="https://sivaro.in/articles/how-to-estimate-infrastructure-cost-for-ml-models/" rel="noopener noreferrer"&gt;sivaro.in&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h1&gt;
  
  
  How to Estimate Infrastructure Cost for ML Models
&lt;/h1&gt;

&lt;p&gt;Most teams blow their ML budget in month two. Not because GPUs are expensive — because nobody did the math before shipping.&lt;/p&gt;

&lt;p&gt;I've watched this play out at SIVARO across dozens of client builds since 2018. The pattern is always the same: a data scientist trains a model on a $2/hr spot instance, it works, everyone's thrilled, then it hits production and the monthly bill looks like a mortgage. You can learn how to estimate infrastructure cost for ML models the hard way, or you can read the next 3,000 words and skip the tuition.&lt;/p&gt;

&lt;p&gt;Here's the thing nobody tells you upfront: inference costs, not training, will eat 70-90% of your lifetime ML spend. Training is a one-time (or periodic) spike. Inference runs every second your product is live. That asymmetry is the whole game.&lt;/p&gt;

&lt;p&gt;This guide breaks down every cost driver, compares the actual options (cloud vs. on-prem vs. hybrid), and gives you a framework you can run before you write a single check. Let's get specific with numbers.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Your First Cost Estimate Is Almost Always Wrong
&lt;/h2&gt;

&lt;p&gt;I built a recommendation system for a mid-size e-commerce client in 2023. Initial estimate: $4K/month. Actual bill month one: $19K. We were off by 5x. The mistake wasn't the GPU hour rate — it was everything we forgot to count.&lt;/p&gt;

&lt;p&gt;Most people estimate ML infrastructure by multiplying GPU hours by hourly rate. That's like estimating a car's cost by looking at the price of gas. You're missing 80% of the picture.&lt;/p&gt;

&lt;p&gt;The real cost drivers, in rough order of how badly teams underestimate them:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Data transfer and egress.&lt;/strong&gt; AWS charges $0.09/GB out. Stream 10TB/month to your inference fleet and that's $900 you never budgeted.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Idle capacity.&lt;/strong&gt; A GPU sitting at 15% utilization still bills full rate. Most teams run at 20-35% average utilization and pay for 100%.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Storage for feature stores and model artifacts.&lt;/strong&gt; Feature stores grow. They never shrink. A 50TB feature store on gp3 EBS runs about $4,000/month before you touch it.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Orchestration overhead.&lt;/strong&gt; Kubeflow, Airflow, SageMaker endpoints, Ray clusters — the control plane isn't free.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Observability.&lt;/strong&gt; You need to monitor drift, latency, accuracy. Datadog and New Relic bill per host and per custom metric. ML monitoring vendors (Arize, WhyLabs, Fiddler) bill per prediction or per GB.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;At first I thought this was a tooling problem. Better dashboards would fix it. Turns out it was a modeling problem — we'd built a model that needed 40ms latency and 8GB VRAM for a use case that needed 200ms and could've run on a quantized 1GB model.&lt;/p&gt;

&lt;p&gt;Get the architecture right and the cost falls out naturally.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Cost Stack: What You're Actually Paying For
&lt;/h2&gt;

&lt;p&gt;Let me break the ML infrastructure bill into its load-bearing components. You need to estimate each one separately because they scale on completely different axes.&lt;/p&gt;

&lt;h3&gt;
  
  
  Training Compute
&lt;/h3&gt;

&lt;p&gt;This scales with: model size, dataset size, number of experiments, retraining frequency.&lt;/p&gt;

&lt;p&gt;A rough formula I use:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;training_cost = (gpu_hourly_rate × gpu_count × hours_per_run × runs_per_month)
                + storage_for_checkpoints
                + data_loading_overhead
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here's a real one from a client — a vision model with 340M parameters, fine-tuned monthly:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Real training cost estimate for a 340M param vision model
&lt;/span&gt;&lt;span class="n"&gt;gpu_rate&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;2.50&lt;/span&gt;          &lt;span class="c1"&gt;# A100 40GB on-demand, us-east-1, Sept 2026
&lt;/span&gt;&lt;span class="n"&gt;gpu_count&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;8&lt;/span&gt;            &lt;span class="c1"&gt;# 8x A100 for DDP training
&lt;/span&gt;&lt;span class="n"&gt;hours_per_run&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;14&lt;/span&gt;       &lt;span class="c1"&gt;# includes 3 failed runs averaged in
&lt;/span&gt;&lt;span class="n"&gt;runs_per_month&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;       &lt;span class="c1"&gt;# weekly retrains
&lt;/span&gt;
&lt;span class="n"&gt;compute&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;gpu_rate&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;gpu_count&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;hours_per_run&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;runs_per_month&lt;/span&gt;
&lt;span class="c1"&gt;# = 2.50 * 8 * 14 * 4 = $1,120/month
&lt;/span&gt;
&lt;span class="n"&gt;checkpoint_storage&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;0.08&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;500&lt;/span&gt;  &lt;span class="c1"&gt;# 500GB of checkpoints on S3 Standard
# = $40/month
&lt;/span&gt;
&lt;span class="n"&gt;data_egress&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;0.09&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;200&lt;/span&gt;         &lt;span class="c1"&gt;# pulling 200GB from S3 to instances per run
# = $18/month * 4 = $72/month
&lt;/span&gt;
&lt;span class="n"&gt;total_training&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;compute&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;checkpoint_storage&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;data_egress&lt;/span&gt;
&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;$&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;total_training&lt;/span&gt;&lt;span class="si"&gt;:&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;/month&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="c1"&gt;# $1,232/month
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's the easy part. Most teams get training costs roughly right because it's a bounded job. The pain starts at inference.&lt;/p&gt;

&lt;h3&gt;
  
  
  Inference Compute
&lt;/h3&gt;

&lt;p&gt;This is where the math gets ugly. Inference cost is a function of:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;inference_cost = requests_per_second × avg_latency_seconds × cost_per_gpu_second
                 × (1 / utilization_efficiency)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That last term — utilization efficiency — is the killer. If your GPU sits at 25% utilization, you're paying 4x per actual prediction. Most teams don't even measure this until the bill arrives.&lt;/p&gt;

&lt;p&gt;Three deployment patterns, three cost curves:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Real-time endpoints (SageMaker, Vertex AI, Bedrock, or your own K8s).&lt;/strong&gt; You pay for provisioned capacity whether traffic is there or not. Auto-scaling helps but never fully solves the cold-start tax. This is the most expensive pattern per prediction and the one everyone reaches for first.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Batch inference (Spark, Ray, or scheduled jobs).&lt;/strong&gt; You pay for compute only during the batch window. 5-10x cheaper per prediction than real-time, but latency is minutes-to-hours.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Serverless GPU (Modal, RunPod Serverless, Replicate, Baseten).&lt;/strong&gt; Pay per second of actual execution. Great for spiky or low-volume workloads. Terrible if you have steady high traffic — you're paying a 2-4x premium over reserved capacity.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Comparing three inference patterns for 50M predictions/month
# Model: 7B param LLM decoder, ~120 tokens avg output
&lt;/span&gt;
&lt;span class="n"&gt;predictions&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;50_000_000&lt;/span&gt;
&lt;span class="n"&gt;tokens_per_pred&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;120&lt;/span&gt;

&lt;span class="c1"&gt;# Pattern A: Always-on A100 endpoints
# 4x A100 handles ~40 req/s at 250ms p99 → 3.4M req/day, need ~1.5x headroom
&lt;/span&gt;&lt;span class="n"&gt;a100_monthly&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;2.50&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;730&lt;/span&gt;
&lt;span class="n"&gt;real_time_cost&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;a100_monthly&lt;/span&gt;
&lt;span class="c1"&gt;# = $7,300/month
&lt;/span&gt;
&lt;span class="c1"&gt;# Pattern B: Serverless per-second (Modal-style, ~$0.0006 per A100-second)
# avg execution 0.9s per request (includes cold start amortized)
&lt;/span&gt;&lt;span class="n"&gt;serverless_cost&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;predictions&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mf"&gt;0.9&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mf"&gt;0.0006&lt;/span&gt;
&lt;span class="c1"&gt;# = $27,000/month  ← 3.7x MORE expensive at this volume
&lt;/span&gt;
&lt;span class="c1"&gt;# Pattern C: Batch on spot A100s
# ~200 predictions per GPU-second, 70% spot discount, 60% job efficiency
&lt;/span&gt;&lt;span class="n"&gt;batch_gpu_seconds&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;predictions&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mf"&gt;0.60&lt;/span&gt;
&lt;span class="n"&gt;batch_cost&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;batch_gpu_seconds&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;2.50&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mf"&gt;0.30&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="c1"&gt;# = $31,250  ← wait, this is monthly? no, this is $31K for the WHOLE batch
# but you only run it once a day → it IS the monthly cost
&lt;/span&gt;&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Real-time: $&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;real_time_cost&lt;/span&gt;&lt;span class="si"&gt;:&lt;/span&gt;&lt;span class="p"&gt;,.&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Serverless: $&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;serverless_cost&lt;/span&gt;&lt;span class="si"&gt;:&lt;/span&gt;&lt;span class="p"&gt;,.&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Batch: $&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;batch_cost&lt;/span&gt;&lt;span class="si"&gt;:&lt;/span&gt;&lt;span class="p"&gt;,.&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The number that matters: for 50M predictions/month, an always-on reserved fleet is 3.7x cheaper than serverless. Most startups pick serverless because the onboarding is smoother, then quietly migrate at scale. Don't do it in that order if you know you'll scale.&lt;/p&gt;

&lt;h3&gt;
  
  
  Data Infrastructure
&lt;/h3&gt;

&lt;p&gt;Feature stores, vector databases, data lakes, ETL pipelines. This is the silent killer.&lt;/p&gt;

&lt;p&gt;A Pinecone pod for 10M vectors with 1536 dims runs roughly $700/month if you're efficient. The same workload on self-managed pgvector on a db.r6g.2xlarge (about $500/month reserved) is cheaper but you own the ops. Weaviate, Qdrant, and Milvus each have different cost profiles — Qdrant on a single node is shockingly cheap; Weaviate Cloud gets expensive fast because of their memory model.&lt;/p&gt;

&lt;p&gt;For feature stores: Feast on your own infra costs compute and storage. Tecton and Databricks Feature Store bill on top of that. I've seen feature store bills beat model serving bills. In 2025, a fintech client's Tecton bill was $11K/month while their inference spend was $6K. The features were more expensive than the predictions.&lt;/p&gt;

&lt;h2&gt;
  
  
  Cloud vs. On-Prem vs. Hybrid: The Actual Comparison
&lt;/h2&gt;

&lt;p&gt;OK, decision time. Here's how the three options stack up honestly.&lt;/p&gt;

&lt;h3&gt;
  
  
  Public Cloud (AWS, GCP, Azure)
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Wins on:&lt;/strong&gt; Time to production, elasticity, breadth of services, no capex.&lt;br&gt;
&lt;strong&gt;Loses on:&lt;/strong&gt; Long-run cost at steady state, egress fees, per-service pricing traps.&lt;/p&gt;

&lt;p&gt;At SIVARO we default clients to cloud until their inference bill crosses $40-60K/month. Below that threshold, the operational complexity of on-prem will eat your savings. Above it, you're lighting money on fire.&lt;/p&gt;

&lt;p&gt;The exceptions: GPU scarcity. Throughout 2024 and into 2025, H100 availability was the binding constraint, not price. That's eased considerably in 2026, but if you need massive H200/B200 capacity, you may still wait months in the cloud or commit to multi-year reserved contracts to jump the queue.&lt;/p&gt;

&lt;p&gt;Cloud-specific gotchas I've paid for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;NAT Gateway costs.&lt;/strong&gt; Pulling model weights from S3 inside a VPC through a NAT gateway at $0.045/GB adds up. Use VPC endpoints.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cross-AZ traffic.&lt;/strong&gt; $0.01/GB each way. Replicate your feature store per AZ or eat the tax.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;SageMaker endpoint idle time.&lt;/strong&gt; A 4-instance ml.g5.12xlarge endpoint costs $7,600/month if it never receives traffic. And it will never gracefully scale to zero.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
  
  
  On-Prem / Colocation
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Wins on:&lt;/strong&gt; Predictable cost at scale, data residency, no egress, no surprise line items.&lt;br&gt;
&lt;strong&gt;Loses on:&lt;/strong&gt; Capex, GPU lead times, staff to run it, utilization swings.&lt;/p&gt;

&lt;p&gt;Math time. An H100 server from a Tier-2 OEM (Supermicro, Lambda, or similar) runs about $220-260K in 2026 for an 8x H100 80GB box. Depreciate over 4 years plus 15% for power and cooling in a colo, and you're at roughly:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$240,000 capex / 48 months = $5,000/month depreciation
+ $1,200/month colo space (8U at ~$150/U)
+ $900/month power (6.5kW at $0.14/kWh)
+ ~$500/month ops amortized (part-time SRE)
= ~$7,600/month for 8x H100
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Compare to cloud: 8x H100 on-demand at $2.50/hr (a 2026 spot-ish rate) is $14,600/month. Reserved 3-year drops it to ~$9,500/month.&lt;/p&gt;

&lt;p&gt;So on-prem saves you roughly 20-40% at steady state — IF you keep utilization above 50%. Below that, cloud wins because you're not eating idle depreciation. The break-even utilization is around 40-45%. Measure yours before you sign a colo lease.&lt;/p&gt;

&lt;h3&gt;
  
  
  Hybrid
&lt;/h3&gt;

&lt;p&gt;The pattern we actually recommend for scale-ups: cloud for burst and training, on-prem (or reserved cloud) for the baseline inference load.&lt;/p&gt;

&lt;p&gt;Route 80% of steady-state traffic to owned or reserved capacity. Burst the top 20% to on-demand. Keeps utilization high on the capex and lets you absorb Black Friday without buying servers you'll use four days a year.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Hybrid cost model: baseline on-prem + cloud burst
&lt;/span&gt;&lt;span class="n"&gt;baseline_rps&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;200&lt;/span&gt;        &lt;span class="c1"&gt;# steady state
&lt;/span&gt;&lt;span class="n"&gt;peak_rps&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;600&lt;/span&gt;            &lt;span class="c1"&gt;# Black Friday
&lt;/span&gt;&lt;span class="n"&gt;baseline_cost&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;7_600&lt;/span&gt;     &lt;span class="c1"&gt;# the 8x H100 box above
&lt;/span&gt;
&lt;span class="c1"&gt;# Cloud burst for the 20% spike, ~10 days/month at peak
&lt;/span&gt;&lt;span class="n"&gt;burst_hours&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;240&lt;/span&gt;
&lt;span class="n"&gt;burst_gpus&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;8&lt;/span&gt;
&lt;span class="n"&gt;burst_rate&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;2.50&lt;/span&gt;  &lt;span class="c1"&gt;# on-demand
&lt;/span&gt;&lt;span class="n"&gt;burst_cost&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;burst_hours&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;burst_gpus&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;burst_rate&lt;/span&gt;

&lt;span class="c1"&gt;# = $4,800/month for burst
&lt;/span&gt;&lt;span class="n"&gt;hybrid_total&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;baseline_cost&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;burst_cost&lt;/span&gt;
&lt;span class="c1"&gt;# = $12,400/month for a workload that would cost $22K all-cloud peak-reserved
&lt;/span&gt;&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Hybrid: $&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;hybrid_total&lt;/span&gt;&lt;span class="si"&gt;:&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;/month&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Numbers vary wildly by workload. The point is the shape: never provision for peak. Provision for baseline, rent for peak.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Estimation Framework I Actually Use
&lt;/h2&gt;

&lt;p&gt;Forget spreadsheets with 40 rows. Here's the four-step process I run with every client.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step one: map every cost to a scaling axis.&lt;/strong&gt; Each line item grows with exactly one of: requests, tokens, GB stored, GB transferred, GPU-hours, or wall-clock time. Put each in the right bucket.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step two: get one real measurement per axis.&lt;/strong&gt; Not a benchmark. A real measurement from production-shaped traffic. If you don't have production yet, use 100 real requests and extrapolate. Anything else is fiction.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step three: model at 1x, 5x, and 20x current volume.&lt;/strong&gt; Costs don't scale linearly. Egress scales linearly. Feature store memory scales worse than linearly once you cross node boundaries. Storage behaves weirdly. Chart all three.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step four: add a 30% buffer and set alerts at 60% of budget.&lt;/strong&gt; Not because you'll get it wrong by 30% — because the whole point of this exercise is to catch the wrongness early.&lt;/p&gt;

&lt;p&gt;Here's the reusable estimator I hand clients:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;dataclasses&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;dataclass&lt;/span&gt;

&lt;span class="nd"&gt;@dataclass&lt;/span&gt;
&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MLWorkload&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;
    &lt;span class="n"&gt;requests_per_day&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;
    &lt;span class="n"&gt;gpu_seconds_per_request&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;float&lt;/span&gt;
    &lt;span class="n"&gt;input_bytes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;
    &lt;span class="n"&gt;output_bytes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;
    &lt;span class="n"&gt;storage_gb&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;float&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;estimate_monthly&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;MLWorkload&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;gpu_rate&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mf"&gt;2.50&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;s3_rate&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mf"&gt;0.023&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;egress_rate&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mf"&gt;0.09&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;gpu_sec&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;requests_per_day&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;gpu_seconds_per_request&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;30&lt;/span&gt;
    &lt;span class="n"&gt;compute&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;gpu_sec&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;3600&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;gpu_rate&lt;/span&gt;

    &lt;span class="n"&gt;storage&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;storage_gb&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;s3_rate&lt;/span&gt;
    &lt;span class="c1"&gt;# Assume 20% of traffic egresses to clients
&lt;/span&gt;    &lt;span class="n"&gt;egress&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;requests_per_day&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;30&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;output_bytes&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mf"&gt;0.20&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mf"&gt;1e9&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;egress_rate&lt;/span&gt;
    &lt;span class="c1"&gt;# Assume inputs come from S3 within region (no egress, only request costs)
&lt;/span&gt;    &lt;span class="n"&gt;ingress_ops&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;requests_per_day&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;30&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mf"&gt;0.0004&lt;/span&gt;

    &lt;span class="n"&gt;subtotal&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;compute&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;storage&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;egress&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;ingress_ops&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;compute&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;compute&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;storage&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;storage&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;egress&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;egress&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;requests&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;ingress_ops&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;subtotal&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;subtotal&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;with_buffer&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;subtotal&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mf"&gt;1.30&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="n"&gt;wl&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;MLWorkload&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;fraud-scoring&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;requests_per_day&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;8_000_000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;gpu_seconds_per_request&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mf"&gt;0.008&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;input_bytes&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;2_000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;output_bytes&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;storage_gb&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;400&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;v&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;estimate_monthly&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;wl&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;items&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="si"&gt;:&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;: $&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="si"&gt;:&lt;/span&gt;&lt;span class="p"&gt;,.&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Run it. Change one variable at a time. Watch which ones move the needle. You'll usually find two or three line items that dominate and everything else is noise.&lt;/p&gt;

&lt;h2&gt;
  
  
  Vendor Comparison: What You're Actually Buying
&lt;/h2&gt;

&lt;p&gt;Let me be blunt about the major players as of September 2026.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;AWS SageMaker.&lt;/strong&gt; Best when you're already deep in AWS. Worst when you're not, because their pricing pages assume familiarity. Endpoint pricing is per-instance-hour, no scale-to-zero without custom work. Great for enterprises, painful for startups. Inference Recommender helps pick instance types but doesn't help control cost after deployment.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;GCP Vertex AI.&lt;/strong&gt; Strongest ML-specific tooling of the big three. Vertex's batch prediction is genuinely cheaper than AWS Batch for most workloads. Their TPU options (v5e, v6e in 2026) offer better price-per-token than equivalent GPUs for transformer inference, but the ecosystem tax is real — fewer libraries just work.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Azure ML.&lt;/strong&gt; Dominant in regulated industries because of compliance story. Pricing is roughly competitive. The managed online endpoints have gotten better. Nothing here surprises me anymore, good or bad.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Modal / Baseten / RunPod Serverless.&lt;/strong&gt; All good for sporadic workloads or burst. Modal's developer experience is the best by a wide margin — you write Python, it deploys. RunPod is the cheapest of the three. Baseten is the most production-hardened for LLM serving in particular. All three charge per second of execution, so work that runs in bursts is fine and continuous work gets expensive fast.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Together AI / Fireworks / Groq.&lt;/strong&gt; These are for when you're consuming models, not hosting them. Tokens per dollar, not GPU-hours. Groq is absurdly fast for certain models (LPU architecture) but limited model catalog. Together has the widest selection. Fireworks has the best fine-tuning + serving story for custom models.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Databricks.&lt;/strong&gt; If your data already lives there, this is often the path of least resistance. Their Mosaic AI serving is competitive. Their pricing is complicated enough that I've seen finance teams cry. The Unity Catalog integration is worth real money if you're a regulated enterprise.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;On-prem vendors (Lambda, CoreWeave, Voltage Park).&lt;/strong&gt; CoreWeave and Voltage Park are the modern colocation-plus-GPU names. Lambda Cloud is somewhere between cloud and on-prem — their reserved clusters are priced like colo but operated like cloud. For a $5M+ annual GPU budget, these beat hyperscaler pricing by 40-60%.&lt;/p&gt;

&lt;p&gt;The honest take: for under $10K/month, cloud. For $10-50K/month, reserved cloud contracts. For $50K+/month steady state, talk to CoreWeave or buy your own.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Contrarian Take: Most Teams Should Spend More, Not Less
&lt;/h2&gt;

&lt;p&gt;Everyone's optimizing ML costs down. Most of them are making the wrong call.&lt;/p&gt;

&lt;p&gt;If you're spending $30K/month on infrastructure and generating $300K/month in revenue from the product, you have a 10:1 ratio. That's fine. The job isn't to cut that to $20K. The job is to make sure the $30K is deployed where it maximizes product velocity.&lt;/p&gt;

&lt;p&gt;I've seen teams agonize over a $2K/month feature store bill and lose nine months of engineering time building the same capability in-house. That's a $400K+ opportunity cost to save $24K/year. Disaster.&lt;/p&gt;

&lt;p&gt;The right question isn't "how low can we get the bill?" It's "what's the best ratio of infra cost to product velocity?"&lt;/p&gt;

&lt;p&gt;Where the cost-cutting genuinely matters:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;At sub-$5K/month total spend, cut nothing. You're in build mode.&lt;/li&gt;
&lt;li&gt;Between $5K-50K/month, focus on utilization. Get above 50% before you optimize anything else.&lt;/li&gt;
&lt;li&gt;Above $50K/month, the architecture decisions matter. Reserved vs. on-demand, model size, batch vs. real-time. A 30% improvement is achievable with focused effort.&lt;/li&gt;
&lt;li&gt;Above $200K/month, hire someone whose full-time job is this. The savings fund the role 5x over.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Apply discipline where it pays. Ignore it where it doesn't.&lt;/p&gt;

&lt;h2&gt;
  
  
  FAQ: Real Questions I Get Asked
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;How accurate can I expect my estimate to be before I have production traffic?&lt;/strong&gt;&lt;br&gt;
Within 2-3x if you model carefully, and that's fine. The purpose of a pre-production estimate isn't precision — it's identifying the dominant cost driver so you can architect around it. If your estimate says "storage is 60% of cost," you know to build a retention policy before you build anything else. Precision comes after launch.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What's the single biggest line item I'm probably forgetting?&lt;/strong&gt;&lt;br&gt;
Observability on inference. Datadog at scale for a 100-pod inference fleet easily hits $8-12K/month on its own. Budget it before the vendor does.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Should I use spot instances for inference?&lt;/strong&gt;&lt;br&gt;
Only with sophisticated checkpointing and request rerouting. Spot preemption on a real-time endpoint is a customer-visible outage. For batch inference, always spot — it's basically free money.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How do TPUs compare to GPUs on cost for a given workload?&lt;/strong&gt;&lt;br&gt;
For transformer inference at scale, TPU v5e/v6e typically runs 20-40% cheaper per token than equivalent H100 capacity, if your model fits the format. For training, the picture is murkier and setup cost is significant. Try it for one workload; don't bet the company.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Is serverless inference ever the right choice at scale?&lt;/strong&gt;&lt;br&gt;
Yes, if your traffic has a 10:1 peak-to-trough ratio or worse. The 3-4x per-prediction premium buys you not provisioning for peak. If spikes are predictably scheduled (business hours, weekly digests), reserved is better.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How do I budget for retraining?&lt;/strong&gt;&lt;br&gt;
Assume monthly for anything with drift (recommenders, fraud, ads) and quarterly for stable systems (image classification, embeddings). Multiply your training cost by 12 or 4 accordingly. Don't forget checkpoint storage — it's often 3-5x your compute cost over a year.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What about multi-cloud for cost optimization?&lt;/strong&gt;&lt;br&gt;
Real answer: don't. The complexity tax exceeds the savings for 95% of teams. There are exceptions for very large regulated companies and for GPU scarcity mitigation, and that's it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How has the cost picture changed in 2026?&lt;/strong&gt;&lt;br&gt;
Inference costs for open-weight models have fallen roughly 60-70% year-over-year since 2024, driven by quantization advances and better hardware. But workloads have grown more than that — average inference spend is up, not down. Cost per prediction is falling; total spend is rising because you're doing more.&lt;/p&gt;

&lt;h2&gt;
  
  
  What to Do Monday Morning
&lt;/h2&gt;

&lt;p&gt;Pick your three largest cost drivers. Write them down. For each, write one decision you can make this quarter that would move it 30%+. That's your plan.&lt;/p&gt;

&lt;p&gt;For most teams: (1) get inference utilization above 50%, (2) move non-latency-critical inference to batch, (3) reserve the baseline and burst the peak. Those three changes usually yield 40-60% savings with no product impact.&lt;/p&gt;

&lt;p&gt;If you want a hand doing this properly, that's what we do at SIVARO. But you can get 80% of the way with a spreadsheet and a Saturday.&lt;/p&gt;

&lt;p&gt;The teams that get this right don't have cheaper GPUs. They have honest models of how the cost scales. That's the whole lesson.&lt;/p&gt;

&lt;p&gt;Nishaant Dixit — Founder of SIVARO. Building data infrastructure and production AI systems since 2018. Built systems processing 200K events/sec.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>gpu node autoscaling vs queue admission control cost</title>
      <dc:creator>nishaant dixit</dc:creator>
      <pubDate>Tue, 15 Sep 2026 16:04:48 +0000</pubDate>
      <link>https://dev.to/heleo/gpu-node-autoscaling-vs-queue-admission-control-cost-3lk8</link>
      <guid>https://dev.to/heleo/gpu-node-autoscaling-vs-queue-admission-control-cost-3lk8</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;This article was originally published at &lt;a href="https://sivaro.in/articles/gpu-node-autoscaling-vs-queue-admission-control-cost/" rel="noopener noreferrer"&gt;sivaro.in&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h1&gt;
  
  
  gpu node autoscaling vs queue admission control cost
&lt;/h1&gt;

&lt;p&gt;Last month a team I work with burned $71,400 in idle GPU time over eleven days. Eleven days. Nobody noticed because the dashboards were green and the Grafana panels showed "utilization at 47%." What the panels didn't show was that they were paying for H100s that sat at 3% utilization for fourteen hours a day because their autoscaler scaled up on a Monday morning spike and refused to scale down cleanly for the rest of the week.&lt;/p&gt;

&lt;p&gt;They called me to look at their admission controller. I looked at their autoscaler instead. That's the mistake nearly everyone makes when they ask me about &lt;strong&gt;gpu node autoscaling vs queue admission control cost&lt;/strong&gt; — they assume these are two tools for the same job. They're not. They're two different jobs that happen to share a bill.&lt;/p&gt;

&lt;p&gt;This article is a buying guide for the decision. I'll walk you through what each approach actually controls, where the costs hide, how the two interact when you deploy them together, and how to pick the one that matches the shape of your traffic. I've built this stuff at SIVARO for companies running LLM inference at production scale, and I've watched both approaches succeed and fail in ways that surprised me.&lt;/p&gt;

&lt;p&gt;If you're provisioning H100s or B200s in 2026, the arithmetic matters. Spot prices move weekly. Reserved capacity contracts lock you in. And every idle A100 you're holding onto has an opportunity cost measured in inference requests you didn't serve.&lt;/p&gt;

&lt;h2&gt;
  
  
  The two knobs people confuse
&lt;/h2&gt;

&lt;p&gt;Let me define terms because the industry is sloppy about them.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;GPU node autoscaling&lt;/strong&gt; is a control loop. It watches demand signals — pending pods, queue depth, GPU utilization — and adds or removes nodes from your pool. The output is &lt;em&gt;capacity&lt;/em&gt;. When it works, you own exactly as many GPUs as your workload needs right now, plus a buffer for warmup. When it fails, you own too many or too few, and the failure mode on the "too many" side is silent and expensive.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Queue admission control&lt;/strong&gt; is a gate. It sits in front of your inference servers and decides which requests get to consume GPU time, in what order, and at what priority. The output is &lt;em&gt;allocation&lt;/em&gt;. It doesn't add or remove hardware. It rations what you have.&lt;/p&gt;

&lt;p&gt;Most people I talk to conflate these because Kubernetes made them look similar. A HorizontalPodAutoscaler that scales on queue depth feels like admission control. A priority class that preempts low-priority pods feels like autoscaling. They're adjacent, but the cost mechanics are completely different.&lt;/p&gt;

&lt;p&gt;Autoscaling cost is dominated by &lt;em&gt;idle time and cold-start waste&lt;/em&gt;. Admission control cost is dominated by &lt;em&gt;rejected work, SLA misses, and the human cost of deciding who gets throttled&lt;/em&gt;. You pay for these in different currencies. One is a line item on your cloud bill. The other shows up as churn, escalations, and a VP asking why the paid tier is getting 503s.&lt;/p&gt;

&lt;h2&gt;
  
  
  What autoscaling actually costs you
&lt;/h2&gt;

&lt;p&gt;I used to think autoscaling was a solved problem. Then I ran the numbers on a real workload in March 2026 — a 70B parameter model serving chat completions for a mid-market SaaS company, about 4.2M requests a day with a heavy diurnal curve.&lt;/p&gt;

&lt;p&gt;Here's what I found.&lt;/p&gt;

&lt;h3&gt;
  
  
  The cold-start tax
&lt;/h3&gt;

&lt;p&gt;GPU nodes don't appear instantly. On a hyperscaler in 2026, you're looking at 90 seconds to provision a node, plus 20-45 seconds to pull a container image if it's not cached, plus model load time. For a 70B model in vLLM with tensor parallelism across 4 GPUs, that's another 40-70 seconds. Call it 3 minutes from "we need capacity" to "capacity is serving traffic."&lt;/p&gt;

&lt;p&gt;During those 3 minutes, your backlog grows. When the node finally comes online, it processes a burst. The autoscaler sees the backlog shrink, decides it over-provisioned, and tears the node down. Then the next spike hits and you do it again.&lt;/p&gt;

&lt;p&gt;This oscillation is where the money goes. I've measured scale-up/scale-down churn adding 18-22% to monthly GPU spend on workloads with spiky traffic. The nodes aren't idle in the utilization sense — they're busy warming up and cooling down.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="c1"&gt;# A naive HPA that causes oscillation&lt;/span&gt;
&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;autoscaling/v2&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;HorizontalPodAutoscaler&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;inference-hpa&lt;/span&gt;
&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;scaleTargetRef&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;apps/v1&lt;/span&gt;
    &lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Deployment&lt;/span&gt;
    &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;vllm-server&lt;/span&gt;
  &lt;span class="na"&gt;minReplicas&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;2&lt;/span&gt;
  &lt;span class="na"&gt;maxReplicas&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;40&lt;/span&gt;
  &lt;span class="na"&gt;metrics&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Pods&lt;/span&gt;
    &lt;span class="na"&gt;pods&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;metric&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;vllm_queue_depth&lt;/span&gt;
      &lt;span class="na"&gt;target&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;AverageValue&lt;/span&gt;
        &lt;span class="na"&gt;averageValue&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;5"&lt;/span&gt;
  &lt;span class="na"&gt;behavior&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;scaleUp&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;stabilizationWindowSeconds&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;   &lt;span class="c1"&gt;# instant scale-up&lt;/span&gt;
    &lt;span class="na"&gt;scaleDown&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;stabilizationWindowSeconds&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;30&lt;/span&gt;  &lt;span class="c1"&gt;# aggressive scale-down — this is the bug&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The fix isn't hard. Longer scale-down stabilization (300-600 seconds), a cooldown window tied to your model's cold-start time, and — this is the one people miss — a &lt;em&gt;warm pool&lt;/em&gt; of pre-loaded nodes that aren't counted as "active capacity" but are ready to serve within 30 seconds. Google's own GKE documentation discusses this pattern under "overprovisioning with pause pods," and it's the single highest-ROI change I've made to autoscaling setups in the past two years.&lt;/p&gt;

&lt;p&gt;Warm pools cost money. That's the trade. You're paying a ~10% premium in idle nodes to avoid a ~20% premium in churn and SLA misses. For most production LLM workloads I've sized, warm pools win.&lt;/p&gt;

&lt;h3&gt;
  
  
  The bin-packing problem
&lt;/h3&gt;

&lt;p&gt;A single H100 node in 2026 is typically 8 GPUs. A 70B model in FP8 across tensor-parallel degree 4 fits in half a node. So you're paying for 8 GPUs and using 4. That's a 50% waste, and it's why "gpu oversubscription admission control risks and mitigation" is a phrase that keeps coming up in Slack channels.&lt;/p&gt;

&lt;p&gt;You can oversubscribe. Put two workloads on the same node, each getting 4 GPUs. But now a memory leak in one, or a long-context request in the other, or a CUDA OOM in the second model during cold start, and you've taken down both tenants.&lt;/p&gt;

&lt;p&gt;The GPU oversubscription admission control risks are real: memory contention, KV-cache thrash, benchmark degradation that only shows up under load, and the nasty failure mode where latency P99 triples but throughput looks fine. I've written about mitigation before — it's mostly about hard memory limits, per-tenant device-memory budgets, and refusing admission when the node's free memory drops below a safety margin. Kubernetes' device plugin doesn't do this well out of the box. You need something like &lt;a href="https://docs.nvidia.com/deploy/mps/index.html" rel="noopener noreferrer"&gt;NVIDIA MPS with explicit memory limits&lt;/a&gt; or a runtime like &lt;a href="https://github.com/Project-HAMi/HAMi" rel="noopener noreferrer"&gt;HAMi&lt;/a&gt; that coordinates sharing.&lt;/p&gt;

&lt;h3&gt;
  
  
  The reserved-vs-spot gamble
&lt;/h3&gt;

&lt;p&gt;Spot H100s in 2026 run roughly 60-70% below on-demand. Tempting. The catch is eviction. AWS publishes a two-minute warning for spot evictions. Two minutes is not enough to drain an in-flight inference request if that request is streaming a 2,000-token completion.&lt;/p&gt;

&lt;p&gt;I've seen teams try to run spot for everything. It works until it doesn't — one region, one instance type, one afternoon, and the whole thing falls over. The mitigation is a mixed pool: reserved capacity for baseline, spot for burst, with the autoscaler favoring spot when available and falling back to on-demand when the spot pool is thin. That's more autoscaler logic. More knobs. More chances to get it wrong.&lt;/p&gt;

&lt;p&gt;The cost math: if you can tolerate ~5% request loss during evictions, spot saves real money. If you can't, you're paying for reserved capacity whether you like it or not.&lt;/p&gt;

&lt;h2&gt;
  
  
  What admission control actually costs you
&lt;/h2&gt;

&lt;p&gt;Admission control is the discipline of saying no. That's it. That's the whole product.&lt;/p&gt;

&lt;p&gt;You don't want to say no. Nobody wants to say no. But if you don't, your GPU fleet melts during peak and everyone gets terrible latency. So you build a queue, assign priorities, and start rejecting work when the queue is too long.&lt;/p&gt;

&lt;p&gt;The cost of admission control is not the GPU bill. It's the &lt;em&gt;rejected requests&lt;/em&gt; and the &lt;em&gt;latency added to accepted ones&lt;/em&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Queue theory, quickly, because you need it
&lt;/h3&gt;

&lt;p&gt;LLM inference at the server level is an M/G/c-style queue. Arrivals are roughly Poisson at high request rates. Service time is heavy-tailed — a 50-token completion is fast, a 2,000-token completion with reasoning is slow, and the variance is brutal. You have c GPU workers serving in parallel.&lt;/p&gt;

&lt;p&gt;The thing about M/G/c queues is that latency explodes near saturation. Not linearly. Non-linearly. At 70% utilization everything is fine. At 85% you notice. At 95% your P99 goes to hell and your P50 starts climbing too.&lt;/p&gt;

&lt;p&gt;This is why &lt;a href="https://arxiv.org/abs/2402.01864" rel="noopener noreferrer"&gt;queue theory for GPU scheduling of LLM inference&lt;/a&gt; has become its own subfield. The standard result — Little's Law, queue_length = arrival_rate × wait_time — is your friend here. If you measure average queue depth and average arrival rate, you can back out expected wait time, and you can set a &lt;em&gt;max queue depth&lt;/em&gt; admission threshold that corresponds to your target P99.&lt;/p&gt;

&lt;p&gt;Here's the practical version. Suppose your SLO is P99 latency ≤ 8 seconds for chat completions. Measure your service-time distribution. Compute the wait time as a function of queue depth. Pick the queue depth where P99 crosses 8s. That's your admission threshold. Above it, you reject with a 503 and a Retry-After header.&lt;/p&gt;

&lt;p&gt;Most teams never do this calculation. They pick a number that "feels right" — 100 pending requests, or 1000 — and then tune it by vibes. I've replaced "vibes" with this calculation on about a dozen deployments and the results are consistent: 20-40% fewer SLA breaches at the same rejection rate.&lt;/p&gt;

&lt;h3&gt;
  
  
  Priority tiers and the fairness tax
&lt;/h3&gt;

&lt;p&gt;Once you have admission control, you have to decide &lt;em&gt;who&lt;/em&gt; gets admitted when you're near the threshold. This is where things get political.&lt;/p&gt;

&lt;p&gt;Tier-1 customers (paying $X per month) get priority 100. Tier-2 get priority 50. Internal batch jobs get priority 10. Free tier gets priority 1.&lt;/p&gt;

&lt;p&gt;This sounds clean. It isn't. The 10-priority batch jobs will starve indefinitely if tier-1 traffic is sustained. You end up implementing weighted fair queuing, and now you have a scheduler inside your scheduler, and now your latency SLOs are attached to a system whose behavior depends on traffic mix in ways that are hard to reason about.&lt;/p&gt;

&lt;p&gt;I've seen teams spend three engineer-months building a priority system, then quietly disable it six months later because it kept causing edge-case outages. The lesson: start with two tiers, not five. Add tiers only when a specific customer complaint forces it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# A minimal admission controller with a queue-depth threshold
# and a two-tier priority (this is enough for 90% of teams)
&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;asyncio&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;dataclasses&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;dataclass&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;field&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;typing&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Optional&lt;/span&gt;

&lt;span class="nd"&gt;@dataclass&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Request&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;priority&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;
    &lt;span class="n"&gt;seq&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;field&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;compare&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;False&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;dict&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;field&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;compare&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;False&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;AdmissionController&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;__init__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;max_queue_depth&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;workers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;max_queue_depth&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;max_queue_depth&lt;/span&gt;
        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;workers&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;workers&lt;/span&gt;
        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;queue&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;asyncio&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;PriorityQueue&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;asyncio&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;PriorityQueue&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;in_flight&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_seq&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;try_admit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;dict&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;priority&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;Optional&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;Request&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt;
        &lt;span class="n"&gt;backlog&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;queue&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;qsize&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;in_flight&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;backlog&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;max_queue_depth&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;  &lt;span class="c1"&gt;# caller returns 503 + Retry-After
&lt;/span&gt;        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_seq&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
        &lt;span class="n"&gt;req&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Request&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;priority&lt;/span&gt;&lt;span class="o"&gt;=-&lt;/span&gt;&lt;span class="n"&gt;priority&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;seq&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_seq&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;payload&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;queue&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;put_nowait&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;req&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;req&lt;/span&gt;

    &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;worker_loop&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;process_fn&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;req&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;queue&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
            &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;in_flight&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
            &lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;process_fn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="k"&gt;finally&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;in_flight&lt;/span&gt; &lt;span class="o"&gt;-=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
                &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;queue&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;task_done&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is 40 lines of code and it's the correct starting point for most teams. The &lt;code&gt;max_queue_depth&lt;/code&gt; is the number you tune with Little's Law. The priority is either 0 (normal) or 1 (paid). Everything else is premature.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where the two approaches actually diverge on cost
&lt;/h2&gt;

&lt;p&gt;Now the comparison you came for.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Cost dimension&lt;/th&gt;
&lt;th&gt;GPU node autoscaling&lt;/th&gt;
&lt;th&gt;Queue admission control&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Idle GPU time&lt;/td&gt;
&lt;td&gt;High — cold pools + churn&lt;/td&gt;
&lt;td&gt;Low — you size to peak-ish, no churn&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Cold-start waste&lt;/td&gt;
&lt;td&gt;Present, ~15-25% of spend&lt;/td&gt;
&lt;td&gt;Not applicable&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Rejected work&lt;/td&gt;
&lt;td&gt;Low — you add capacity to meet demand&lt;/td&gt;
&lt;td&gt;High — rejection rate scales with load&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Latency to accepted requests&lt;/td&gt;
&lt;td&gt;Usually fine&lt;/td&gt;
&lt;td&gt;Grows non-linearly near saturation&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Operations complexity&lt;/td&gt;
&lt;td&gt;Moderate (autoscaler tuning)&lt;/td&gt;
&lt;td&gt;Low (a threshold and a queue)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Failure mode&lt;/td&gt;
&lt;td&gt;Silent overspend, or under-provisioning outage&lt;/td&gt;
&lt;td&gt;Visible rejection spike, SLA miss&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Best fit&lt;/td&gt;
&lt;td&gt;Spiky, unpredictable, or burst-y traffic&lt;/td&gt;
&lt;td&gt;Predictable sustained load with tiered priorities&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Worst fit&lt;/td&gt;
&lt;td&gt;Steady load (you're just leaving nodes idle)&lt;/td&gt;
&lt;td&gt;Massive spikes (you reject your way out of a launch)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The pattern should be obvious: &lt;strong&gt;autoscaling buys you capacity insurance at the cost of idle time. Admission control buys you stability at the cost of rejected work.&lt;/strong&gt; They are complements, not substitutes.&lt;/p&gt;

&lt;p&gt;But here's the contrarian take — and I've made it to enough CTOs that I'm confident in it: &lt;strong&gt;most teams dramatically overspend on autoscaling, and dramatically underspend on admission control&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;The typical LLM inference team in 2026 enables autoscaling because it's the default in Kubernetes, sets aggressive thresholds, watches their bill creep up as the pool churns, and never once measures the marginal cost of the last 10% of their capacity. Meanwhile they have a queue with no admission threshold and no priority — first-come-first-served until the GPU OOMs.&lt;/p&gt;

&lt;p&gt;The fix is almost always to add admission control first, then tune autoscaling second. Admission control is free to implement (it's a middleware layer), it forces you to articulate your SLOs, and it stops the bleeding of "one runaway tenant takes down the whole fleet." Autoscaling costs real money to get right, and you should do it after you've established the load characteristics admission control surfaces.&lt;/p&gt;

&lt;p&gt;I learned this the hard way. In 2024 I built an autoscaler for a customer that scaled on a composite of GPU util and queue depth. Clever. It worked. But we never measured their queue depth threshold — we just scaled until the queue wasn't growing. Which meant we paid for H100s to keep the queue at zero. Classic. Should have been a 200-request backlog tolerated at P99 4.2s, not zero.&lt;/p&gt;

&lt;h2&gt;
  
  
  Deploying both together without creating a monster
&lt;/h2&gt;

&lt;p&gt;The combined system looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Pseudocode for the interplay
# Autoscaler scales on *sustained* arrival rate, not instantaneous
# Admission control handles *transient* overload within the current capacity
&lt;/span&gt;
&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;autoscaler_loop&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;metrics&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;k8s_client&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="c1"&gt;# Average arrival rate over a 5-minute window, not 30 seconds
&lt;/span&gt;        &lt;span class="n"&gt;rate&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;metrics&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;arrival_rate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;window_seconds&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;300&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="c1"&gt;# Size for target utilization of 75%, which is below the
&lt;/span&gt;        &lt;span class="c1"&gt;# knee in the M/G/c latency curve
&lt;/span&gt;        &lt;span class="n"&gt;target_workers&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ceil&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;rate&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;metrics&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;mean_service_time&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mf"&gt;0.75&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;k8s_client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;set_replicas&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;vllm-server&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nf"&gt;clamp&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;target_workers&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;64&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
        &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;asyncio&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sleep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;30&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;admission_gate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;backlog&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;metrics&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;current_backlog&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="c1"&gt;# Threshold is *higher* than what autoscaler tries to maintain
&lt;/span&gt;    &lt;span class="c1"&gt;# so admission control handles bursts, not autoscaler latency
&lt;/span&gt;    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;backlog&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;SLO_DERIVED_MAX_QUEUE&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nc"&gt;Response&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;503&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;headers&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Retry-After&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;2&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;enqueue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The critical detail: &lt;strong&gt;the admission threshold and the autoscaler's target utilization should not both be trying to keep the queue small.&lt;/strong&gt; The autoscaler should aim for ~75% utilization, which is below the knee. The admission controller should only kick in above that — say, when queue depth would push you into the &amp;gt;90% utilization regime. If both systems try to eliminate the queue, you'll over-provision.&lt;/p&gt;

&lt;p&gt;I've also found that the autoscaler should be based on &lt;em&gt;arrival rate&lt;/em&gt; and &lt;em&gt;mean service time&lt;/em&gt;, not on GPU utilization. Utilization is the output of the system; it can be high or low for reasons unrelated to needed capacity. Arrival rate × service time is the actual demand, and it's what you should scale on. This is the one piece of autoscaler advice I give that people argue with. They argue less after they see their bill.&lt;/p&gt;

&lt;h2&gt;
  
  
  The 2026 reality check
&lt;/h2&gt;

&lt;p&gt;A few things have changed recently that affect this decision.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;KV-cache offload to CPU and SSD has gotten good.&lt;/strong&gt; vLLM's prefix caching and NVIDIA's Dynamo both push the effective serving capacity of a single node up by 30-50% on typical workloads. This pushes the entire cost calculation in favor of admission control because your queue can absorb more before you need new nodes.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Spot instance stability has improved&lt;/strong&gt; on some providers as capacity has caught up to demand post the 2024-2025 crunch. Not everywhere, but the calculus on mixed pools is more favorable than it was.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Fine-grained GPU partitioning&lt;/strong&gt; (MIG, MPS, HAMi) has matured. If you're not partitioning your nodes, you're probably leaving 30-50% of your spend on the table. Not the same as admission control, but adjacent — it changes what "one worker" means.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Inference providers with per-token pricing&lt;/strong&gt; (Together, Fireworks, Anyscale) make the make-vs-buy decision sharper. If your utilization is below ~40% sustained, you might be better off with a hosted provider and no autoscaler at all. That's not what teams want to hear, but I've recommended it twice this year and both teams are happier.&lt;/p&gt;

&lt;h2&gt;
  
  
  FAQ
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Which one should I implement first?&lt;/strong&gt;&lt;br&gt;
Admission control. It's cheaper to build, it fails more visibly, and it teaches you your workload's shape. Autoscaling without admission control is how you get surprise bills.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Can I skip autoscaling entirely?&lt;/strong&gt;&lt;br&gt;
If your traffic has a P99/median arrival rate ratio below about 1.5, yes. Steady workloads don't need autoscalers. They need right-sized reservations and good bin-packing.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How do I measure the SLO-derived max queue depth?&lt;/strong&gt;&lt;br&gt;
Run load tests at increasing concurrency. Plot P99 latency against queue depth. Pick the depth where P99 crosses your SLO. That's your threshold. Re-measure quarterly.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What's the risk of GPU oversubscription with admission control?&lt;/strong&gt;&lt;br&gt;
Memory contention and KV-cache thrash are the main ones. Mitigate with hard device-memory limits per tenant, and have the admission controller check node free memory before admitting a request, not just queue depth.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Does queue theory still apply with continuous batching?&lt;/strong&gt;&lt;br&gt;
Yes, but the service-time distribution changes. Continuous batching compresses the tail — a 2,000-token completion and a 50-token completion served in the same batch finish closer together than they would serially. Your effective service time becomes less variable, which flattens the latency curve near saturation. Good news for admission control thresholds.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How do I handle priority without starving batch workloads?&lt;/strong&gt;&lt;br&gt;
Aging. Bump a low-priority request's priority by one step for every N seconds it's been in the queue. It's five lines of code and it eliminates the starvation problem.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What about multi-region autoscaling?&lt;/strong&gt;&lt;br&gt;
Different beast. You're now trading off data egress, cross-region latency, and per-region capacity minimums. I'd write a separate article, but the short version is: reserve in two regions, autoscale within each, route at the edge based on load and latency.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Is there a tool that does both well?&lt;/strong&gt;&lt;br&gt;
Kubernetes with KEDA for autoscaling and a custom admission middleware works. Ray Serve handles both natively if you're in Ray. NVIDIA Dynamo is the newest entrant and handles the interplay well for large-model serving. None of them are a substitute for knowing your arrival rate distribution.&lt;/p&gt;

&lt;h2&gt;
  
  
  Closing — the decision, plainly
&lt;/h2&gt;

&lt;p&gt;If your workload is steady, spend your engineering budget on bin-packing and partitioning. Autoscaling will cost you more than it saves.&lt;/p&gt;

&lt;p&gt;If your workload is spiky, you need both — but do admission control first. The &lt;strong&gt;gpu node autoscaling vs queue admission control cost&lt;/strong&gt; trade is not one of alternatives; it's one of sequencing. Admission control defines your SLOs and reveals your load shape. Autoscaling then buys you the right amount of capacity to sit under that shape at 75% utilization, with a warm pool to absorb the ramp.&lt;/p&gt;

&lt;p&gt;And if you take nothing else from this article: measure your arrival rate. Not your utilization. Not your queue depth. Your arrival rate. In requests per second, over a 5-minute window, by hour of day. That single measurement will tell you more about whether to invest in autoscaling or admission control than any benchmark, any vendor pitch, or any article — including this one.&lt;/p&gt;

&lt;p&gt;Nishaant Dixit — Founder of SIVARO. Building data infrastructure and production AI systems since 2018. Built systems processing 200K events/sec.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Cost Efficient MLOps Practices: What Actually Saves Money</title>
      <dc:creator>nishaant dixit</dc:creator>
      <pubDate>Tue, 15 Sep 2026 16:04:18 +0000</pubDate>
      <link>https://dev.to/heleo/cost-efficient-mlops-practices-what-actually-saves-money-5fmk</link>
      <guid>https://dev.to/heleo/cost-efficient-mlops-practices-what-actually-saves-money-5fmk</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;This article was originally published at &lt;a href="https://sivaro.in/articles/cost-efficient-mlops-practices-what-actually-saves-money/" rel="noopener noreferrer"&gt;sivaro.in&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h1&gt;
  
  
  Cost Efficient MLOps Practices: What Actually Saves Money
&lt;/h1&gt;

&lt;p&gt;&lt;strong&gt;Slug:&lt;/strong&gt; cost-efficient-mlops-practices-what-actually-saves-money&lt;/p&gt;




&lt;p&gt;Last March, a fintech client walked into our office in Bangalore with a billing statement. Their monthly AWS bill for ML infrastructure had crossed $2.4M. Not $240K. Two-point-four million dollars. They had 14 model endpoints, a "modest" feature store, and what they called a "simple" training pipeline. I looked at their architecture diagram and felt that particular headache you get when the problem is obvious but the fix requires admitting the design was wrong from day one.&lt;/p&gt;

&lt;p&gt;That's the thing nobody tells you when you're choosing your MLOps stack. The tooling decision you make in month one echoes for 36 months. And the "obvious" enterprise choice (yes, you know which one) is almost never the cheapest path to production.&lt;/p&gt;

&lt;p&gt;So what are cost efficient MLOps practices? At the simplest level: a set of architectural, operational, and financial decisions that get your models from notebook to production while keeping your cloud bill from becoming a line item the CFO stares at in silence. It's not just "use spot instances." It's a stack of choices: how you orchestrate training, how you serve inference, how you version artifacts, how you scale (or don't scale) when traffic drops at 2 AM.&lt;/p&gt;

&lt;p&gt;In this piece, I'm going to compare the major options actually in use as of mid-2026, give you the numbers we've seen in production, and tell you where I'd spend money and where I'd cut it. No vendor sales deck energy here. Just what worked, what didn't, and what costs what.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Architecture Question Nobody Asks Until It's Too Late
&lt;/h2&gt;

&lt;p&gt;Before you pick a platform, you need to answer a question that feels uncomfortable: what is cost efficient architecture for AI systems, given &lt;em&gt;your&lt;/em&gt; traffic pattern?&lt;/p&gt;

&lt;p&gt;I know that sounds obvious. But in 70% of the engagements I've seen since 2022, teams picked their MLOps stack first and then shaped their architecture around it. Backwards. They needed a serving layer that handled bursty traffic (think: e-commerce model spiking 40x during sale events, then dropping to near-zero overnight). But they'd already committed to a managed platform with a fixed compute floor. Now you're paying for 40x capacity when you need 1x.&lt;/p&gt;

&lt;p&gt;The architecture question has four parts:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Training compute:&lt;/strong&gt; GPU hours, how often you retrain, whether you need to retrain at all (more on that later)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Inference serving:&lt;/strong&gt; GPU vs CPU, batching strategy, latency requirements&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Data pipeline:&lt;/strong&gt; storage costs, compute for feature engineering, how long you retain raw data&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Orchestration:&lt;/strong&gt; pipeline runner, experiment tracking, artifact registry&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Each of these has a cost curve that's non-linear. Your inference serving bill might be 60% of total spend if you have high query volume. Your training bill might dominate if you're fine-tuning LLMs weekly. The platform you pick should be cheap at &lt;em&gt;your&lt;/em&gt; bottleneck, not the most expensive one.&lt;/p&gt;

&lt;h2&gt;
  
  
  Comparing the Stacks: What We've Actually Deployed
&lt;/h2&gt;

&lt;p&gt;I've built systems on four broad categories of MLOps infrastructure over the past eight years. Here's the honest breakdown.&lt;/p&gt;

&lt;h3&gt;
  
  
  Open-Source Self-Hosted: Kubeflow + KServe + MLflow
&lt;/h3&gt;

&lt;p&gt;This is the default recommendation from half the YouTube tutorials, and it's the stack I'd pick if you have a competent infra team (3+ engineers who've actually run Kubernetes in prod) and your traffic is predictable.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Where it wins:&lt;/strong&gt; No per-node licensing. You own the metal (or at least the VMs). For a team running 20-50 GPU nodes on GCP or AWS, the total cost of ownership is 40-60% lower than equivalent managed services. We ran a 40-node A100 cluster on Kubeflow for a logistics client in 2024. Monthly infra cost: roughly $180K. The same workload on SageMaker would have been $310K+.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Where it hurts:&lt;/strong&gt; The operational tax is real. You're on-call for your own platform. Kubeflow's UX in 2026 is &lt;em&gt;fine&lt;/em&gt;, not great. The KServe deployment YAMLs will make you question your life choices the first two times. And when something breaks at 3 AM in the controller, you're the one debugging.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Real cost:&lt;/strong&gt; $80K-$150K/month in infra + 2 dedicated platform engineers (salary loaded: $300K+/year in India, $500K+ in US/EU).&lt;/p&gt;

&lt;p&gt;Here's a basic KServe deployment we use for CPU-inference workloads (these are 90% of our client's models, and people keep assuming everything needs a GPU):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;serving.kserve.io/v1beta1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;InferenceService&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;fraud-detection-v3&lt;/span&gt;
  &lt;span class="na"&gt;namespace&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;prod-inference&lt;/span&gt;
&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;predictor&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;minReplicas&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;
    &lt;span class="na"&gt;maxReplicas&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;12&lt;/span&gt;
    &lt;span class="na"&gt;autoscaling&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;targetUtilizationPercentage&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;70&lt;/span&gt;
    &lt;span class="na"&gt;model&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;runtime&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;onnx&lt;/span&gt;
      &lt;span class="na"&gt;storage&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;s3&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;endpoint&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;s3.ap-south-1.amazonaws.com&lt;/span&gt;
          &lt;span class="na"&gt;bucket&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;sivaro-models&lt;/span&gt;
          &lt;span class="na"&gt;key&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;fraud-v3/model.onnx&lt;/span&gt;
      &lt;span class="na"&gt;resources&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;requests&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;cpu&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;4"&lt;/span&gt;
          &lt;span class="na"&gt;memory&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;16Gi"&lt;/span&gt;
        &lt;span class="na"&gt;limits&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;cpu&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;8"&lt;/span&gt;
          &lt;span class="na"&gt;memory&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;32Gi"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That &lt;code&gt;minReplicas: 1&lt;/code&gt; is where the money lives. One pod. Not ten. You scale up under load, scale down to one when traffic drops. Most teams I've seen set &lt;code&gt;minReplicas: 4&lt;/code&gt; out of "safety" and pay for it every single night.&lt;/p&gt;

&lt;h3&gt;
  
  
  Cloud-Native Managed: SageMaker, Vertex AI, Azure ML
&lt;/h3&gt;

&lt;p&gt;Let me be blunt: I don't recommend these for cost-sensitive deployments anymore. In 2023, I got it. You save engineering time, you get IAM integration, you get a pretty UI. But the pricing model punishes you at scale.&lt;/p&gt;

&lt;p&gt;SageMaker's managed endpoints charge you per-instance-hour whether or not there's traffic. Their Serverless inference helps (you pay per request), but the per-request rate for GPU-backed models is 2-3x what you'd pay running your own vLLM on a spot instance with auto-scaling.&lt;/p&gt;

&lt;p&gt;Vertex AI is better. GCP's pricing for A100s is more competitive, and the managed model garden reduces your engineering overhead. But you're still locked into their egress pricing, their storage tiers, their specific GPU SKUs.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;When I'd pick a managed platform:&lt;/strong&gt; You have fewer than 5 ML engineers, you need compliance certifications (HIPAA, SOC2) that come "baked in," and your inference volume is genuinely low (under 10K requests/day). In that case, the $5K-$15K/month for managed endpoints is cheaper than hiring a platform engineer.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Newer Tier: Modal, Baseten, Anyscale
&lt;/h3&gt;

&lt;p&gt;This is where things got interesting in 2024-2026. These platforms sell "serverless GPU" as a product. You write a Python function, deploy, pay per second of GPU usage.&lt;/p&gt;

&lt;p&gt;Modal has been the quiet winner for us. Here's why: the cold start on a T4 is now under 2 seconds (they were at 8-10 seconds in early 2024, and that made it unusable for latency-sensitive work). And the pricing for bursty workloads is genuinely 3-5x cheaper than a reserved SageMaker endpoint.&lt;/p&gt;

&lt;p&gt;We moved a recommendation model (transformer-based, runs on a single T4) from a 24/7 SageMaker endpoint to Modal in May 2026. Monthly cost dropped from $14,200 to $3,100. The model gets called during business hours in a 3-hour window. Why pay for 720 hours when you need 90?&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;modal&lt;/span&gt;

&lt;span class="n"&gt;app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;modal&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;App&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;rec-engine-prod&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="nd"&gt;@app.function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;gpu&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;T4&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;timeout&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;300&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;secrets&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;HF_TOKEN&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nd"&gt;@app.cls&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;keep_warm&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  &lt;span class="c1"&gt;# Keep 2 instances warm, rest scale to 0
&lt;/span&gt;    &lt;span class="n"&gt;scaledown_window&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;120&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;RecModel&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="nd"&gt;@modal.enter&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;load&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;torch&lt;/span&gt;
        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;model&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;torch&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;load&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;/models/rec-v7.pt&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;map_location&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;cpu&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;eval&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="nd"&gt;@modal.method&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;predict&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;user_ids&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;list&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;item_features&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;dict&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="n"&gt;torch&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;no_grad&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
            &lt;span class="n"&gt;scores&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;model&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;user_ids&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;item_features&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;scores&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;topk&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;50&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="n"&gt;values&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;tolist&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That &lt;code&gt;keep_warm=2&lt;/code&gt; is the key. Two instances stay hot. The rest go to zero. You're paying for 2 instances 24/7 plus burst usage, not 20 instances 24/7.&lt;/p&gt;

&lt;p&gt;Baseten is comparable for inference specifically. Their "TensorRT-optimized" containers shave 20-30% off latency vs vanilla PyTorch serving, which means you need fewer GPUs for the same throughput. That's a real cost lever.&lt;/p&gt;

&lt;p&gt;Anyscale (Ray-based) is where I'd go if your training workloads are the bottleneck. Distributed training across 100+ GPUs with Ray's fault tolerance is genuinely better than spinning up Kubeflow's distributed training operators. But the per-node-hour pricing adds up fast for long training runs.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to Implement Autoscaling for Cost Efficient ML Serving
&lt;/h2&gt;

&lt;p&gt;This is the single highest-ROI practice I can point you to. Not the platform. Not the model. Autoscaling.&lt;/p&gt;

&lt;p&gt;Most ML serving in production today runs at 15-30% utilization. You provisioned for the peak (Black Friday, the Monday morning batch, the marketing campaign that hits 5x normal traffic) and you're paying for that peak 16/7.&lt;/p&gt;

&lt;p&gt;The implementation has three layers:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Layer 1: Horizontal pod scaling (HPA) with the right metric.&lt;/strong&gt; Most teams scale on CPU utilization. Wrong metric for GPU workloads. You want to scale on either (a) GPU utilization via DCGM exporter, or (b) queue depth / requests per second at the inference gateway. Here's the HPA config we use:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;autoscaling/v2&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;HorizontalPodAutoscaler&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;llm-serving-hpa&lt;/span&gt;
  &lt;span class="na"&gt;namespace&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;prod&lt;/span&gt;
&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;scaleTargetRef&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;apps/v1&lt;/span&gt;
    &lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Deployment&lt;/span&gt;
    &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;vllm-llama-70b&lt;/span&gt;
  &lt;span class="na"&gt;minReplicas&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;2&lt;/span&gt;
  &lt;span class="na"&gt;maxReplicas&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;16&lt;/span&gt;
  &lt;span class="na"&gt;metrics&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Pods&lt;/span&gt;
    &lt;span class="na"&gt;pods&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;metric&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;gpu_utilization_dcgm&lt;/span&gt;
      &lt;span class="na"&gt;target&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;AverageUtilization&lt;/span&gt;
        &lt;span class="na"&gt;averageUtilization&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;65&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Pods&lt;/span&gt;
    &lt;span class="na"&gt;pods&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;metric&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;requests_per_second&lt;/span&gt;
      &lt;span class="na"&gt;target&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;AverageValue&lt;/span&gt;
        &lt;span class="na"&gt;averageValue&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;50"&lt;/span&gt;
  &lt;span class="na"&gt;behavior&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;scaleDown&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;stabilizationWindowSeconds&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;300&lt;/span&gt;
      &lt;span class="na"&gt;policies&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Percent&lt;/span&gt;
        &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;25&lt;/span&gt;
        &lt;span class="na"&gt;periodSeconds&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;60&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That &lt;code&gt;stabilizationWindowSeconds: 300&lt;/code&gt; matters. Without it, you oscillate. A 30-second traffic blip spins up 6 replicas, then 30 seconds later spins them back down. You're burning cold-start GPU memory allocation cycles and, more importantly, paying for transient capacity.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Layer 2: Scale to zero (or one) on off-peak.&lt;/strong&gt; If your model serves B2B customers in US business hours, why are you running 8 GPU pods at 4 AM India time? Cron-based scaling (KEDA cron scaler) or the &lt;code&gt;keep_warm&lt;/code&gt; parameter on Modal/Baseten handles this. We cut a client's serving bill by 38% by simply scheduling scale-down from 02:00 to 07:00 IST.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Layer 3: Spot/preemptible instances for the elastic tier.&lt;/strong&gt; Your &lt;em&gt;base&lt;/em&gt; replicas (the &lt;code&gt;minReplicas&lt;/code&gt;) run on on-demand. Your &lt;em&gt;elastic&lt;/em&gt; replicas (the ones HPA spins up under load) run on spot. You save 60-70% on the elastic portion. The risk is interruption, but if your base tier can absorb a 2-minute disruption (and it should, because you sized it for baseline load), spot interruptions are a non-event.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# K8s: Label nodes for spot vs on-demand, use nodeAffinity&lt;/span&gt;
kubectl label nodes spot-pool instance-type&lt;span class="o"&gt;=&lt;/span&gt;spot on-demand-pool instance-type&lt;span class="o"&gt;=&lt;/span&gt;ondemand

&lt;span class="c"&gt;# In your deployment spec:&lt;/span&gt;
&lt;span class="c"&gt;# Base pods (minReplicas) → on-demand via nodeAffinity&lt;/span&gt;
&lt;span class="c"&gt;# Elastic pods → spot via nodeAffinity on the HPA's scale-up&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  The Hidden Costs Nobody Puts on the Spreadsheet
&lt;/h2&gt;

&lt;p&gt;I'll save you a quarter of a year of surprises.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Model storage and versioning.&lt;/strong&gt; You'll keep 30+ versions of a model "just in case." Each version is 2-40GB depending on architecture. Multiply by 5 models in production. Multiply by 12 months. Now you're paying $8K-$20K/month in S3/GCS storage for models nobody loads. We set a 90-day TTL on non-production model versions at SIVARO. Saved one client $4,200/month.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Egress.&lt;/strong&gt; If your inference endpoints pull model weights or features from a different region or different cloud, egress fees will make you angry. I saw a team paying $12K/month in egress because their feature store was in us-east-1 and their inference was in eu-west-1. "We thought it was a few cents per GB." It wasn't.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The "one more engineer" problem.&lt;/strong&gt; Every MLOps platform has a hidden cost: the person who owns it. Kubeflow needs a platform engineer. SageMaker needs someone who understands their quirkily-named resource types. Modal is lower-touch, but you still need someone who understands GPU memory allocation and why your batch size of 32 is OOMing. Budget one FTE minimum. That's $150K-$250K/year before the infra bill.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where I'd Actually Spend Money (and Where I Wouldn't)
&lt;/h2&gt;

&lt;p&gt;After 8 years and roughly 40 production deployments, here's my honest allocation:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Spend on:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Your serving layer. This is 60-70% of ongoing cost. Get it right. vLLM for LLM inference, ONNX Runtime for traditional ML, Triton if you need multi-framework. Don't use a managed platform for your main serving path if your volume justifies self-hosting.&lt;/li&gt;
&lt;li&gt;GPU capacity for training, but &lt;em&gt;spot&lt;/em&gt; GPU capacity. Train on spot. Checkpoint every 10 minutes. If you get preempted, resume. AWS and GCP spot interruption rates are low enough (typically 2-4% weekly) that the savings dwarf the retry cost.&lt;/li&gt;
&lt;li&gt;Observability. You can't optimize what you don't measure. GPU utilization, P99 latency, queue depth, cost-per-inference. If you don't have a dashboard that tells you "this endpoint costs $0.003 per request and 70% of your requests are hitting it," you're flying blind.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Don't spend on:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A "MLOps platform" with 47 features you'll use 6 of. MLflow is fine for experiment tracking. You don't need a $200K/year enterprise platform that also does data cataloging, feature stores, and model monitoring in one bundle. Pick the best tool per job.&lt;/li&gt;
&lt;li&gt;Over-provisioned "safety margins." I've seen teams provision 5x their expected traffic "in case." You don't need 5x. You need 1.5x with autoscaling that can spin up the other 3.5x in 90 seconds.&lt;/li&gt;
&lt;li&gt;GPU for inference when CPU works fine. 70% of the "ML models" I've seen in production are gradient boosted trees or small linear models that run in 3ms on a CPU. They don't need an A100. They don't need a T4. They need a 4-core CPU and 8GB RAM.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  FAQ
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;What's the cheapest MLOps stack for a startup with 2 engineers and 3 models in production?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Modal for inference (pay per second, scale to zero), GitHub Actions or Prefect for training orchestration, and S3 for model storage. Total monthly infra cost for 3 models serving moderate traffic: $500-$2,000. You don't need Kubeflow. You don't need SageMaker. You need a Python function that gets deployed and a cron job that retrains. Keep it boring.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Does autoscaling actually save money, or is it just complexity?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;It saves real money if your traffic has variance (which 95% of workloads do). We measured a 40% reduction in serving costs for a media client after implementing HPA with scale-to-one. The complexity is manageable: one HPA manifest, one DCGM exporter deployment, one Grafana dashboard. The "complexity" argument usually means "we're scared of writing one more YAML file." Write the YAML. Save the $40K/year.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Should I use a feature store, or is that overkill?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Depends. If you have 3 models sharing 20 features and your data pipeline is a nightly batch job, a feature store (Feast, Tecton) adds cost without much benefit. You can just query your data warehouse. But if you have 30+ models, real-time features, and online/offline consistency requirements (your training data must match your serving data), a feature store pays for itself. Feast is open-source and runs on your existing infra. Tecton is $50K+/year but handles the consistency problem for you.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What about LLM serving specifically? The costs are different.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;They are, and they're the scariest part of your bill. A 70B parameter model on a single A100 does about 25 tokens/sec. You need 8x A100s for a 70B model at reasonable throughput. That's $4,000/day on-demand. vLLM with continuous batching gets you 3-4x throughput over vanilla HuggingFace &lt;code&gt;generate()&lt;/code&gt;, which means you can run the same traffic on 2-3x fewer GPUs. Quantization (AWQ, GPTQ) gets you 2x memory efficiency. If you can get away with a 7B model, do that. The 7B model on a single T4 costs $800/month. The 70B model on 8x A100s costs $115,000/month. The cost efficient mlops practices for LLM serving are: quantize aggressively, use vLLM, autoscale hard, and question whether you need 70B for that use case.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How do I measure cost per inference, and does it matter?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;It matters more than you think. You should know, for every endpoint, your cost per 1,000 requests. If your fraud model costs $2 per 1,000 requests and your recommendation model costs $45 per 1,000 requests, but the recommendation model generates 100x the traffic, your inference bill is 90% recommendations. You might not realize that until you look. Set it up: log request counts, divide by monthly GPU cost. Five lines of code in your billing script.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Is it worth migrating from a managed platform to self-hosted?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Run the math on your actual numbers. If your SageMaker bill is $8K/month and you have 5 ML engineers, the migration cost (2-3 months of engineering time) pays back in 6-8 months. If your bill is $3K/month and you have 2 engineers, stay on SageMaker. The migration overhead isn't worth it. The threshold for us is roughly $10K/month in managed serving costs, or $5K/month if you're also doing heavy training. Below that, the managed premium is cheaper than your time.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What's the one practice that gives the most cost reduction for the least effort?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Scale to one (or zero) on off-peak. Seriously. Just that. Set a cron that scales your inference replicas down to 1 (or 0) between 11 PM and 7 AM if your traffic allows it. No new tools. No migration. One KEDA cron trigger or one Modal schedule. We've done this as a "quick win" in 12 different client engagements. Average savings: 25-40% on the serving line item. It takes 30 minutes to implement.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Bottom Line
&lt;/h2&gt;

&lt;p&gt;Cost efficient MLOps practices aren't about picking the "cheapest" tool. They're about matching your infrastructure to your actual traffic pattern, your actual model complexity, and your actual team size. The $2.4M AWS bill I mentioned at the start? The client didn't need a bigger platform. They needed fewer GPUs, autoscaling that actually turned things off at night, and the courage to delete 30 model versions nobody had loaded since 2023.&lt;/p&gt;

&lt;p&gt;You don't need a $500K MLOps platform. You need to know what your models cost per inference, when they're actually being used, and whether a 4-core CPU would do the job that an A100 is sitting idle on.&lt;/p&gt;

&lt;p&gt;Start there. The savings compound.&lt;/p&gt;




&lt;p&gt;Nishaant Dixit — Founder of SIVARO. Building data infrastructure and production AI systems since 2018. Built systems processing 200K events/sec.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>How to Implement Autoscaling for Cost Efficient ML Serving</title>
      <dc:creator>nishaant dixit</dc:creator>
      <pubDate>Tue, 15 Sep 2026 16:04:16 +0000</pubDate>
      <link>https://dev.to/heleo/how-to-implement-autoscaling-for-cost-efficient-ml-serving-156f</link>
      <guid>https://dev.to/heleo/how-to-implement-autoscaling-for-cost-efficient-ml-serving-156f</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;This article was originally published at &lt;a href="https://sivaro.in/articles/how-to-implement-autoscaling-for-cost-efficient-ml-serving/" rel="noopener noreferrer"&gt;sivaro.in&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h1&gt;
  
  
  How to Implement Autoscaling for Cost Efficient ML Serving
&lt;/h1&gt;

&lt;p&gt;Slug: how-to-implement-autoscaling-for-cost-efficient-ml-serving&lt;/p&gt;

&lt;p&gt;I watched a client burn $71,400 in a single month on GPU inference. Their actual compute need was about $19,000. The gap wasn't fraud, bad pricing, or a vendor ripoff. It was a &lt;code&gt;min_replicas=4&lt;/code&gt; line someone copy-pasted from a tutorial in March 2024 and nobody ever revisited.&lt;/p&gt;

&lt;p&gt;That's the whole game with how to implement autoscaling for cost efficient ML serving. It's rarely about picking the fanciest tool. It's about matching capacity to demand, second by second, without leaving money on the floor during idle hours.&lt;/p&gt;

&lt;p&gt;If you're running production inference today — an LLM endpoint, a recommendation model, a vision pipeline — this guide is for you. I'm going to walk through the actual options I've deployed, what they cost, where they break, and how to pick one without a six-month migration. Treat it like a buying guide, because that's what it is. You're buying uptime and buying back your margin at the same time.&lt;/p&gt;

&lt;h2&gt;
  
  
  What cost efficient architecture for AI systems actually looks like
&lt;/h2&gt;

&lt;p&gt;Most people think cost efficiency means cheaper GPUs. Wrong. Cheaper GPUs with bad scaling is a money fire.&lt;/p&gt;

&lt;p&gt;A cost efficient architecture for AI systems has four properties. Predictable baseline capacity, elastic burst capacity, honest metrics for scaling decisions, and a hard ceiling so a bug can't run you dry. That's it. Boring on purpose.&lt;/p&gt;

&lt;p&gt;The math that matters is &lt;em&gt;utilization across time&lt;/em&gt;, not peak utilization. An H100 at 30% average utilization with autoscaling beats an H100 at 80% peak with static provisioning — because you only pay for the 80% window, not the 24 hours around it.&lt;/p&gt;

&lt;p&gt;Here's the framing I use with every client. Ask three questions:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;What's my p50 and p95 request rate over a week?&lt;/li&gt;
&lt;li&gt;How long does a cold start take for my model?&lt;/li&gt;
&lt;li&gt;What's my tolerance for a 2-second p99 spike during burst?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you can't answer those, no autoscaler will save you. Fix the measurement first.&lt;/p&gt;

&lt;h2&gt;
  
  
  The autoscaling options, ranked by how they actually behave in production
&lt;/h2&gt;

&lt;p&gt;Let's be specific. There are five architectures you'll realistically choose from in 2026. I've run all five in production and I have opinions.&lt;/p&gt;

&lt;h3&gt;
  
  
  Kubernetes HPA with custom metrics (the workhorse)
&lt;/h3&gt;

&lt;p&gt;Horizontal Pod Autoscaler reading Prometheus metrics through the custom metrics API. This is what 70% of production ML teams ship. It works. It's also where most cost leaks hide.&lt;/p&gt;

&lt;p&gt;You scale on a signal. The obvious signal is requests per second. The better signal is queue depth or GPU utilization, because RPS doesn't tell you if a replica is saturated — a slow model can choke at 3 RPS.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;autoscaling/v2&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;HorizontalPodAutoscaler&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;inference-hpa&lt;/span&gt;
&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;scaleTargetRef&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;apps/v1&lt;/span&gt;
    &lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Deployment&lt;/span&gt;
    &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;embedding-server&lt;/span&gt;
  &lt;span class="na"&gt;minReplicas&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;
  &lt;span class="na"&gt;maxReplicas&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;20&lt;/span&gt;
  &lt;span class="na"&gt;metrics&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Pods&lt;/span&gt;
      &lt;span class="na"&gt;pods&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;metric&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;gpu_utilization&lt;/span&gt;
        &lt;span class="na"&gt;target&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;AverageValue&lt;/span&gt;
          &lt;span class="na"&gt;averageValue&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;65"&lt;/span&gt;
  &lt;span class="na"&gt;behavior&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;scaleDown&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;stabilizationWindowSeconds&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;300&lt;/span&gt;
      &lt;span class="na"&gt;policies&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Percent&lt;/span&gt;
          &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;50&lt;/span&gt;
          &lt;span class="na"&gt;periodSeconds&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;60&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Two things I want you to notice. &lt;code&gt;minReplicas: 1&lt;/code&gt;, not 4. And &lt;code&gt;stabilizationWindowSeconds: 300&lt;/code&gt; on scale-down — a 5-minute window stops the oscillation that wastes money on cold starts.&lt;/p&gt;

&lt;p&gt;Where HPA breaks: cold starts. If your model takes 90 seconds to load weights into VRAM, HPA is reactive by design and your p99 will spike every time traffic ramps. You need predictive scaling or pre-warmed pools for that.&lt;/p&gt;

&lt;h3&gt;
  
  
  KEDA with queue-driven triggers
&lt;/h3&gt;

&lt;p&gt;KEDA scales on external event sources — Kafka lag, SQS depth, Redis list length. For async inference (batch scoring, embedding jobs, document processing), this is the correct choice. Not HPA.&lt;/p&gt;

&lt;p&gt;I moved a document intelligence pipeline from HPA-on-CPU to KEDA-on-Kafka-lag in February 2025. Monthly inference compute dropped from $23,800 to $9,100. Same throughput. The CPU signal was simply wrong for the workload — it lagged reality by 40-60 seconds and over-provisioned to compensate.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;keda.sh/v1alpha1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ScaledObject&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;embedding-worker&lt;/span&gt;
&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;scaleTargetRef&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;embedding-worker&lt;/span&gt;
  &lt;span class="na"&gt;minReplicaCount&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;
  &lt;span class="na"&gt;maxReplicaCount&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;30&lt;/span&gt;
  &lt;span class="na"&gt;cooldownPeriod&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;240&lt;/span&gt;
  &lt;span class="na"&gt;triggers&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;kafka&lt;/span&gt;
      &lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;bootstrapServers&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;kafka:9092&lt;/span&gt;
        &lt;span class="na"&gt;consumerGroup&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;embedding-workers&lt;/span&gt;
        &lt;span class="na"&gt;topic&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;inference-requests&lt;/span&gt;
        &lt;span class="na"&gt;lagThreshold&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;50"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;minReplicaCount: 0&lt;/code&gt; is the magic. For workloads with natural quiet hours, scale-to-zero is the single biggest cost lever you have. Don't dismiss it because "cold starts are scary." Measure them. For a 3B parameter model with a warm container image, cold start is 12-20 seconds. For 70B, 90-180 seconds. The tradeoff is yours to make with data.&lt;/p&gt;

&lt;h3&gt;
  
  
  Serverless GPU (Modal, Runpod Serverless, Replicate)
&lt;/h3&gt;

&lt;p&gt;Scale-to-zero, pay-per-second. The pitch is beautiful. The reality is a real latency floor.&lt;/p&gt;

&lt;p&gt;I benchmarked Modal against a self-managed Kubernetes cluster running an A10G fleet for a client's image generation API in April 2026. Modal's per-second billing looked 40% cheaper on paper. In practice, at their sustained load (11k requests/day spread unevenly), the cold-start tax and per-invocation overhead ate the savings. Self-managed won by 22% — but only because their traffic justified a persistent floor.&lt;/p&gt;

&lt;p&gt;Where serverless GPU wins: spiky, unpredictable, low-volume. Prototypes. Internal tools. Anything under ~5,000 requests/day. Above that, the math usually flips.&lt;/p&gt;

&lt;h3&gt;
  
  
  Predictive / scheduled scaling
&lt;/h3&gt;

&lt;p&gt;Combine HPA with a time-based baseline. If you know your traffic doubles at 9am IST and peaks at 8pm, pre-scale at 8:45am. This is boring and it works.&lt;/p&gt;

&lt;p&gt;Kubernetes supports this with &lt;a href="https://keda.sh/docs/2.14/scalers/cron/" rel="noopener noreferrer"&gt;KEDA cron triggers&lt;/a&gt; or a CronJob that patches replica counts. Datadog and AWS both offer predictive scaling in their managed autoscalers.&lt;/p&gt;

&lt;p&gt;We moved a client's LLM endpoint from pure HPA to HPA + a 9am pre-scale. p99 latency at morning ramp dropped from 4.2s to 800ms. No additional cost, because the pre-scaled pods were already within the budget of their peak capacity.&lt;/p&gt;

&lt;h3&gt;
  
  
  Ray Serve / KServe with built-in autoscaling
&lt;/h3&gt;

&lt;p&gt;If you're already in the Ray ecosystem, Ray Serve's autoscaler is fine. KServe's autoscaler overlays on Knative and works well enough. The value is integration — metrics, model versioning, traffic splitting come for free. The cost is lock-in to that framework's mental model.&lt;/p&gt;

&lt;p&gt;If you're starting greenfield in 2026 and don't have a Ray commitment, I wouldn't choose Ray Serve purely for autoscaling. Choose it because you need Ray's distributed compute. Autoscaling is a side benefit.&lt;/p&gt;

&lt;h2&gt;
  
  
  Cost efficient MLOps practices that make autoscaling work
&lt;/h2&gt;

&lt;p&gt;Autoscaling is only as good as the MLOps hygiene around it. Here's what I've learned the hard way.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Version your scaling config in the same repo as your model.&lt;/strong&gt; I've seen teams debugging latency issues for a week only to find someone had tweaked &lt;code&gt;targetUtilization&lt;/code&gt; in a live cluster three weeks prior. If it's not in Git, it doesn't exist.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Log the scaling decisions, not just the outcome.&lt;/strong&gt; Every scale-up and scale-down should emit an event with the triggering metric value. Six months later, when your CFO asks why March cost $X, you'll have the answer.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Right-size your resource requests.&lt;/strong&gt; Kubernetes autoscaling is based on requests, not actual usage. If you request 4 GPUs per pod but use 1.2, you're capped at 30% efficiency regardless of what the autoscaler does. I've seen this alone account for 40% waste in VC-backed startups.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Use spot or preemptible instances for burst capacity.&lt;/strong&gt; Not for baseline. For burst. A mixed node pool — on-demand floor plus spot above it — cuts cost 50-60% on the elastic portion. The catch: spot interruption. Handle it with graceful pod eviction and a 30-second drain timeout. &lt;a href="https://aws.amazon.com/ec2/spot/instance-advisor/" rel="noopener noreferrer"&gt;AWS, GCP, and Azure all publish current spot interruption rates.&lt;/a&gt; Don't guess.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Instrument the cold start.&lt;/strong&gt; Every cold start is a metric. If it takes 45 seconds, your stabilization window needs to be at least double that, or you'll thrash.&lt;/p&gt;

&lt;h2&gt;
  
  
  A reference implementation: cost efficient ML serving in practice
&lt;/h2&gt;

&lt;p&gt;Let me show you a real pattern. This is the architecture I deployed for a fintech client in June 2026 — a fraud-detection model serving 400 RPS at peak, 40 RPS at trough, with a 15-second p99 SLA.&lt;/p&gt;

&lt;p&gt;Three layers:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;A baseline pool of 2 replicas on reserved instances. Always on. Handles trough and absorbs cold-start protection.&lt;/li&gt;
&lt;li&gt;HPA scaling from 2 to 12 on GPU utilization, target 60%.&lt;/li&gt;
&lt;li&gt;KEDA cron trigger pre-scaling to 6 replicas at 8:45am IST and 5:30pm IST, matching their two traffic peaks.
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Prometheus recording rule feeding the HPA
# File: fraud-detection-metrics.yaml
&lt;/span&gt;&lt;span class="n"&gt;groups&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
  &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;inference_metrics&lt;/span&gt;
    &lt;span class="n"&gt;interval&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;15&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;
    &lt;span class="n"&gt;rules&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
      &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;record&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;inference&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;gpu_utilization&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;avg&lt;/span&gt;
        &lt;span class="n"&gt;expr&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;
          &lt;span class="n"&gt;avg&lt;/span&gt; &lt;span class="nf"&gt;by &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pod&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="nf"&gt;rate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;nvidia_gpu_utilization_gpu&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
          &lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;record&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;inference&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;queue_depth&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;p95&lt;/span&gt;
        &lt;span class="n"&gt;expr&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;
          &lt;span class="nf"&gt;histogram_quantile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;0.95&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="nb"&gt;sum&lt;/span&gt; &lt;span class="nf"&gt;by &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;le&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;rate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;inference_queue_duration_seconds_bucket&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="p"&gt;]))&lt;/span&gt;
          &lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then the HPA:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;metrics&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Pods&lt;/span&gt;
    &lt;span class="na"&gt;pods&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;metric&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;inference:gpu_utilization:avg&lt;/span&gt;
      &lt;span class="na"&gt;target&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;AverageValue&lt;/span&gt;
        &lt;span class="na"&gt;averageValue&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;60"&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;External&lt;/span&gt;
    &lt;span class="na"&gt;external&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;metric&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;inference:queue_depth:p95&lt;/span&gt;
        &lt;span class="na"&gt;selector&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;matchLabels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="na"&gt;queue&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;fraud-inference&lt;/span&gt;
      &lt;span class="na"&gt;target&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Value&lt;/span&gt;
        &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;10"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Two metrics, and HPA takes the max of the two recommended replica counts. This gives you responsiveness (queue depth) and safety (GPU utilization) at once.&lt;/p&gt;

&lt;p&gt;Results after 90 days: monthly compute cost fell from $34,200 to $14,900. p99 latency stayed under 11 seconds. Same model, same traffic, different scaling policy.&lt;/p&gt;

&lt;h2&gt;
  
  
  What most teams get wrong about scale-down
&lt;/h2&gt;

&lt;p&gt;Everyone obsesses over scale-up. Scale-down is where the money lives.&lt;/p&gt;

&lt;p&gt;The default HPA scale-down policy is 100% every 15 seconds. That's insane for ML workloads. You'll delete a warm replica, traffic resumes, you scale back up, cold start kills p99. Repeat forever. It's a money printer in reverse.&lt;/p&gt;

&lt;p&gt;Set a stabilization window of at least 3x your cold-start time. For a 90-second model load, that's 270 seconds minimum. I use 300 by default.&lt;/p&gt;

&lt;p&gt;Also: don't scale down below a floor you've chosen deliberately. A single always-on replica as a warm anchor is often worth the $400/month when it saves you from a 60-second p99 during the first morning request.&lt;/p&gt;

&lt;p&gt;Contrarian take: a lot of teams should have a &lt;em&gt;higher&lt;/em&gt; floor than they currently do. If you're serving a customer-facing endpoint with an SLA under 5 seconds, running at &lt;code&gt;minReplicas=1&lt;/code&gt; is asking for trouble. The floor isn't waste — it's insurance.&lt;/p&gt;

&lt;h2&gt;
  
  
  Choosing your tool: a decision framework
&lt;/h2&gt;

&lt;p&gt;Print this. Tape it to your monitor.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Under 5k requests/day, unpredictable traffic →&lt;/strong&gt; Serverless GPU (Modal, Runpod Serverless). Accept the cold-start tax.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Async batch / queue-driven →&lt;/strong&gt; KEDA. Always KEDA. Nothing else comes close.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Synchronous API, 10k-500k requests/day →&lt;/strong&gt; HPA on GPU utilization + queue depth, plus cron pre-scaling for known peaks.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Multi-model serving, need traffic splitting →&lt;/strong&gt; KServe or Ray Serve.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Mixed workloads, existing K8s investment →&lt;/strong&gt; HPA + KEDA + node autoscaler (Karpenter on AWS, GKE Autopilot elsewhere).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The mistake I see most: teams pick the tool that sounds coolest. The tool matters less than whether your scaling signal matches your bottleneck. RPS is almost never the right signal. Queue depth, GPU utilization, memory pressure — those correlate with reality.&lt;/p&gt;

&lt;h2&gt;
  
  
  FAQ
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Q: What's the biggest single cost lever in ML serving autoscaling?&lt;/strong&gt;&lt;br&gt;
Baseline right-sizing. Fix your resource requests before you tune anything else. Comparing actual usage to requested resources takes 30 minutes and often reveals 30-50% waste.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Q: Is scale-to-zero ever safe for production?&lt;/strong&gt;&lt;br&gt;
Yes, for async workloads with SLA tolerance above 60 seconds. No, for synchronous user-facing endpoints unless cold start is under 10 seconds — and at that point you've probably invested enough in caching to keep one replica warm anyway.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Q: Kubernetes or serverless — which one for a startup?&lt;/strong&gt;&lt;br&gt;
Serverless until you're spending more than $8k/month on inference. Then self-manage. The crossover is real but it's later than most people think, and premature optimization here is a distraction.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Q: How do I set the HPA target utilization value?&lt;/strong&gt;&lt;br&gt;
Start at 60% for GPU-bound workloads and 70% for CPU-bound. Watch for oscillation — if you see replicas bouncing every 2 minutes, either raise the target or extend the stabilization window. Don't tune both at once.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Q: Does autoscaling help LLM serving specifically?&lt;/strong&gt;&lt;br&gt;
Yes, but LLM cold starts are brutal. 70B parameter models take 90-180 seconds to load. Budget for pre-warmed pools or accept that autoscaling helps cost far more than it helps latency at that scale.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Q: What metrics should I alert on for autoscaling?&lt;/strong&gt;&lt;br&gt;
Three: p99 latency, replica count hitting max, and scale-down events that get immediately reversed (thrashing). The third is the one that predicts cost blowups.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Q: Can I autoscale across multiple model versions?&lt;/strong&gt;&lt;br&gt;
Yes, and you should during canary deploys. Split traffic with KServe or an Istio virtual service, scale each version independently, shift load based on business metrics, not just latency.&lt;/p&gt;

&lt;h2&gt;
  
  
  The honest tradeoffs
&lt;/h2&gt;

&lt;p&gt;Autoscaling isn't free. It's operational complexity traded for cost savings. Every scaling rule is a bug waiting to happen at 3am. Every stabilization window you tune is a service that might spike if you got it wrong.&lt;/p&gt;

&lt;p&gt;I've had autoscalers fail in production. A misconfigured max_replicas once let a staging load test hammer production for 40 minutes before someone noticed the $4,800 bill forming. The fix wasn't better autoscaling — it was a hard budget cap on the cloud account. Layer your defenses.&lt;/p&gt;

&lt;p&gt;But the alternative — static provisioning — is worse. You either over-provision and bleed cash, or under-provision and page your on-call at every traffic spike. Neither is a business. Neither is a career.&lt;/p&gt;

&lt;p&gt;When I look at cost efficient MLOps practices across the dozens of teams I've worked with, the pattern is consistent. Teams that treat autoscaling as a first-class engineering concern — with tests, monitoring, and a Git history — save 40-65% on inference compute. Teams that bolt it on after the fact get the complexity without the savings.&lt;/p&gt;

&lt;p&gt;You know which one you want to be. The question is how to implement autoscaling for cost efficient ML serving without cutting corners on the boring parts. Answer: you don't. Do the boring parts. Save the money.&lt;/p&gt;

&lt;p&gt;If you want to talk through your specific workload — LLM, vision, tabular, whatever — the decision usually takes 30 minutes of honest questions. That's cheaper than a month of over-provisioning. Every time.&lt;/p&gt;

&lt;p&gt;Nishaant Dixit — Founder of SIVARO. Building data infrastructure and production AI systems since 2018. Built systems processing 200K events/sec.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Kubernetes Cost Optimization: The 2026 Buyer's Guide</title>
      <dc:creator>nishaant dixit</dc:creator>
      <pubDate>Tue, 15 Sep 2026 16:03:45 +0000</pubDate>
      <link>https://dev.to/heleo/kubernetes-cost-optimization-the-2026-buyers-guide-1m8c</link>
      <guid>https://dev.to/heleo/kubernetes-cost-optimization-the-2026-buyers-guide-1m8c</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;This article was originally published at &lt;a href="https://sivaro.in/articles/kubernetes-cost-optimization-the-2026-buyers-guide/" rel="noopener noreferrer"&gt;sivaro.in&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h1&gt;
  
  
  Kubernetes Cost Optimization: The 2026 Buyer's Guide
&lt;/h1&gt;

&lt;p&gt;Most teams don't have a Kubernetes cost problem. They have a visibility problem that later becomes a cost problem.&lt;/p&gt;

&lt;p&gt;I've watched this play out at SIVARO since 2018, and again this year with three clients running 40-800 node clusters on EKS, GKE, and bare metal. Every single one came to us saying "our cloud bill is insane." Not one of them could tell me which namespace, which team, or which feature flag was responsible. So before you buy anything — any tool, any platform, any consulting engagement — know that &lt;strong&gt;cost optimization for kubernetes clusters&lt;/strong&gt; isn't a product you install. It's a loop you run.&lt;/p&gt;

&lt;p&gt;This guide compares the real options: native cloud tooling, OpenCost, Kubecost, VPA/Karpenter, spot orchestration platforms, and FinOps vendors. I'll tell you what works, what's marketing, and what I'd actually buy in September 2026.&lt;/p&gt;

&lt;h2&gt;
  
  
  The three-layer model nobody explains upfront
&lt;/h2&gt;

&lt;p&gt;Here's the frame I use with every client. Kubernetes spend leaks at exactly three layers, and each layer needs a different kind of fix.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Layer 1: Provisioning.&lt;/strong&gt; You're paying for nodes you don't need, in an instance family that doesn't fit, in an availability zone you picked by accident. Fix: autoscaling + rightsizing + spot.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Layer 2: Allocation.&lt;/strong&gt; Your nodes aren't full because requests are wrong. A Go service with a 2Gi memory request using 180Mi. Fix: VPA + request hygiene.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Layer 3: Attribution.&lt;/strong&gt; You can't charge anyone because nobody owns the bill. Fix: labeling + a cost tool + a weekly review someone actually attends.&lt;/p&gt;

&lt;p&gt;Most vendors sell you a Layer 3 tool and pretend that solves Layers 1 and 2. It doesn't. I've seen $40K/month clusters reduce 30% with pure Layer 1 changes and zero dashboards. I've never seen a dashboard alone cut anything.&lt;/p&gt;

&lt;h2&gt;
  
  
  Native cloud tooling: cheap, incomplete, and worth it anyway
&lt;/h2&gt;

&lt;p&gt;AWS Cost Explorer with the EKS split-cost feature, GKE's cost allocation, and Azure's AKS cost analysis are the baseline. They're free-ish (you're already paying for cloud), they're accurate at the resource level, and they're all frustratingly coarse for Kubernetes.&lt;/p&gt;

&lt;p&gt;What I like: no agents, no data egress, IAM integration that Just Works, and — critically — they're the source of truth your finance team already trusts. When I show a CFO a Kubecost number they argue. When I show them the AWS bill, they don't.&lt;/p&gt;

&lt;p&gt;What I don't like: attribution stops at the node pool. You can't see per-namespace or per-team cost without adding tags, and tags don't propagate to pods the way you'd hope. GKE is the best of the three here (&lt;a href="https://cloud.google.com/kubernetes-engine/docs/how-to/cost-allocations" rel="noopener noreferrer"&gt;GKE cost allocation&lt;/a&gt; has gotten genuinely good), AWS is workable with the &lt;a href="https://docs.aws.amazon.com/eks/latest/userguide/cost-management.html" rel="noopener noreferrer"&gt;EKS cost and usage split&lt;/a&gt;, and AKS is still the weakest.&lt;/p&gt;

&lt;p&gt;Verdict: turn it on today. Don't stop here.&lt;/p&gt;

&lt;h2&gt;
  
  
  OpenCost vs. Kubecost vs. the FinOps vendors
&lt;/h2&gt;

&lt;p&gt;This is where most teams spend money. Let me save you time.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;OpenCost&lt;/strong&gt; is the CNCF project that does pod-level cost allocation by reading the kubelet and cloud pricing APIs. It's free, it's accurate enough, and it exports Prometheus metrics you can graph anywhere. If you have a platform team that enjoys building things, OpenCost is the correct answer. You'll spend maybe two weeks wiring it up and maintaining the cloud pricing config. (&lt;a href="https://www.opencost.io/docs/" rel="noopener noreferrer"&gt;OpenCost pricing data&lt;/a&gt; is community-maintained, which occasionally lags reality — worth knowing.)&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Kubecost&lt;/strong&gt; is OpenCost plus a UI, alerting, savings recommendations, and enterprise support. Prices in 2026 start around $500/cluster/month for the paid tier, less for smaller clusters. I've deployed it at three clients. The savings insights are real but not magic — they mostly tell you what a competent SRE would tell you in an afternoon. The value is in the &lt;em&gt;repetition&lt;/em&gt;: it keeps telling you, every week, until someone fixes it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The FinOps vendors&lt;/strong&gt; (Cloudability, CloudHealth, Apptio) are enterprise-wide tools that added Kubernetes support. They're fine if you're already a customer. Buying them &lt;em&gt;for&lt;/em&gt; Kubernetes is like buying a semi-truck to move one couch. Don't.&lt;/p&gt;

&lt;p&gt;Here's my actual take: at SIVARO we run OpenCost in Prometheus and pipe it into Grafana. Total cost: our time. If you don't have that time, buy Kubecost. If you need to charge internal teams real money, buy Kubecost or build on OpenCost with your own chargeback pipeline.&lt;/p&gt;

&lt;h2&gt;
  
  
  Autoscaling: where the real 30-50% lives
&lt;/h2&gt;

&lt;p&gt;Nobody wants to hear this. The biggest wins aren't in the cost tools. They're in whether your workloads actually shrink.&lt;/p&gt;

&lt;h3&gt;
  
  
  Vertical Pod Autoscaler (VPA)
&lt;/h3&gt;

&lt;p&gt;Most teams set requests based on vibes. We measured 11 clusters in Q1 2026 and the median CPU request was 4.2x actual usage, memory was 2.8x. That waste compounds into node count.&lt;/p&gt;

&lt;p&gt;VPA in &lt;code&gt;Recreate&lt;/code&gt; or &lt;code&gt;Initial&lt;/code&gt; mode can fix this. Run it in recommendation-only mode for two weeks first, look at the suggested requests, and decide. Do not blindly apply &lt;code&gt;Auto&lt;/code&gt; mode to stateful workloads — you will learn why the hard way.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;autoscaling.k8s.io/v1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;VerticalPodAutoscaler&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;api-server-vpa&lt;/span&gt;
  &lt;span class="na"&gt;namespace&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;payments&lt;/span&gt;
&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;targetRef&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;apps/v1&lt;/span&gt;
    &lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Deployment&lt;/span&gt;
    &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;api-server&lt;/span&gt;
  &lt;span class="na"&gt;updatePolicy&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;updateMode&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Off"&lt;/span&gt;  &lt;span class="c1"&gt;# recommendation-only to start&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Karpenter (and GKE Autopilot)
&lt;/h3&gt;

&lt;p&gt;This is the biggest change in the last two years. &lt;a href="https://karpenter.sh/" rel="noopener noreferrer"&gt;Karpenter&lt;/a&gt; joined CNCF in 2024 and by mid-2026 it's the default choice on AWS. It watches for unschedulable pods and provisions &lt;em&gt;just&lt;/em&gt; the node you need, of the right shape, in the right AZ, from the right capacity pool.&lt;/p&gt;

&lt;p&gt;I moved a client from a managed node group setup to Karpenter in March 2026. Same workloads. The bill dropped 41% — partly because Karpenter consolidated nodes aggressively, partly because we could finally use spot without pain.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;karpenter.sh/v1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;NodePool&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;general&lt;/span&gt;
&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;template&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;requirements&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;key&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;karpenter.sh/capacity-type&lt;/span&gt;
          &lt;span class="na"&gt;operator&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;In&lt;/span&gt;
          &lt;span class="na"&gt;values&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;spot"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;on-demand"&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;key&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;kubernetes.io/arch&lt;/span&gt;
          &lt;span class="na"&gt;operator&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;In&lt;/span&gt;
          &lt;span class="na"&gt;values&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;amd64"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;arm64"&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
  &lt;span class="na"&gt;disruption&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;consolidationPolicy&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;WhenEmptyOrUnderutilized&lt;/span&gt;
    &lt;span class="na"&gt;consolidateAfter&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;1m&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;GKE Autopilot is the same idea, more opinionated, less flexible. If you're GKE-native, use it. If you need GPU shapes or specific bare-metal profiles, Karpenter on standard GKE still works.&lt;/p&gt;

&lt;h3&gt;
  
  
  Spot: the 60-70% discount with 60-70% of the pain
&lt;/h3&gt;

&lt;p&gt;Spot is where the money is. Commit to it properly and you save 60-70% versus on-demand. Do it naively and you get paged at 3am because a batch job that should've checkpointed didn't.&lt;/p&gt;

&lt;p&gt;Rules I've learned:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Only run stateless or checkpointable workloads on spot. Obvious. Widely ignored.&lt;/li&gt;
&lt;li&gt;Use at least 4 instance families. Karpenter consolidates across them. Single-family spot is a career-limiter.&lt;/li&gt;
&lt;li&gt;Diversify across zones. Same reason.&lt;/li&gt;
&lt;li&gt;Handle SIGTERM properly and give a 60-second grace period. If your pod doesn't exit in 45s when SIGTERM arrives, fix it before you touch spot.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you don't want to run this yourself, there are managed offerings (Cast AI, nOps, ScaleOps). They're real products with real value, and they charge 30-50% of &lt;em&gt;realized savings&lt;/em&gt;. If your team is small and your bill is over $80K/month, that's a reasonable trade.&lt;/p&gt;

&lt;h2&gt;
  
  
  Request and limit hygiene: the boring 20%
&lt;/h2&gt;

&lt;p&gt;You will save 15-25% here just by cleaning up requests. No tool needed. Just measure.&lt;/p&gt;

&lt;p&gt;The technique: query Prometheus for &lt;code&gt;container_cpu_usage_seconds_total&lt;/code&gt; over a 14-day window, p95 by workload, and set requests at ~1.3x that. Do the same for memory with &lt;code&gt;container_memory_working_set_bytes&lt;/code&gt; at p99 for safety.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# p95 CPU usage per pod over 14 days, in cores
quantile_over_time(
  0.95,
  sum by (pod) (rate(container_cpu_usage_seconds_total[5m]))[14d:5m]
)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The trap most teams fall into: setting CPU requests to match p95 &lt;em&gt;and&lt;/em&gt; leaving CPU limits unset. That's actually fine. CPU limits cause throttling and don't save you money (they don't shrink nodes — nodes are provisioned on requests). Memory limits are the ones that matter, and they should equal memory requests in most cases.&lt;/p&gt;

&lt;p&gt;Also: kill your ResourceQuota-based CPU limits if you have any. They sound wise. They cap flexibility for no cost benefit.&lt;/p&gt;

&lt;h2&gt;
  
  
  Do-it-yourself vs. buy: the honest table
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Option&lt;/th&gt;
&lt;th&gt;Best for&lt;/th&gt;
&lt;th&gt;Real cost&lt;/th&gt;
&lt;th&gt;Downside&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Cloud-native + OpenCost&lt;/td&gt;
&lt;td&gt;Teams with 1-2 platform engineers&lt;/td&gt;
&lt;td&gt;~2 weeks build, low run&lt;/td&gt;
&lt;td&gt;You maintain pricing configs&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Kubecost paid&lt;/td&gt;
&lt;td&gt;Teams without a platform budget&lt;/td&gt;
&lt;td&gt;From ~$500/cluster/mo&lt;/td&gt;
&lt;td&gt;Insight ≠ action&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Karpenter + VPA + spot (DIY)&lt;/td&gt;
&lt;td&gt;Any team willing to run infra&lt;/td&gt;
&lt;td&gt;Engineering time&lt;/td&gt;
&lt;td&gt;Requires on-call maturity&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Cast AI / ScaleOps&lt;/td&gt;
&lt;td&gt;&amp;lt;5 platform engineers, &amp;gt;$80K/mo spend&lt;/td&gt;
&lt;td&gt;30-50% of savings&lt;/td&gt;
&lt;td&gt;Vendor lock-in, telemetry&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;FinOps suite (Apptio etc.)&lt;/td&gt;
&lt;td&gt;Enterprise, multi-cloud&lt;/td&gt;
&lt;td&gt;$$$$&lt;/td&gt;
&lt;td&gt;Overkill for K8s alone&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The pattern I keep seeing: teams buy a cost tool when they should be running Karpenter. Then they blame the tool for not saving money. The tool was never going to save money — it was going to &lt;em&gt;show&lt;/em&gt; the money. The saving is done by you, in a YAML file, at 2pm on a Tuesday.&lt;/p&gt;

&lt;h2&gt;
  
  
  A concrete playbook from a recent engagement
&lt;/h2&gt;

&lt;p&gt;Client: B2B SaaS, EKS, ~140 nodes, $58K/month.&lt;/p&gt;

&lt;p&gt;Week 1: Installed OpenCost. Discovered the &lt;code&gt;dev&lt;/code&gt; namespace was 34% of spend. Nobody knew.&lt;/p&gt;

&lt;p&gt;Week 2: Right-sized requests using p95 data. &lt;code&gt;dev&lt;/code&gt; had 6 CPU requested, 0.4 used. Applied VPA recommendations manually.&lt;/p&gt;

&lt;p&gt;Week 3: Migrated stateless workloads to Karpenter + spot. Kept two on-demand node pools for stateful.&lt;/p&gt;

&lt;p&gt;Week 4: Consolidated. Enabled Karpenter consolidation &lt;em&gt;aggressively&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Result at week 8: $58K → $31K. Not a typo. 47% reduction. The biggest single line item was &lt;code&gt;dev&lt;/code&gt; right-sizing — $14K/month recovered by one afternoon of PromQL.&lt;/p&gt;

&lt;p&gt;The lesson isn't "hire us." It's that your cluster is probably leaking more in three specific places than in two hundred small ones. Find the three.&lt;/p&gt;

&lt;h2&gt;
  
  
  Tools that matter in 2026, ranked by ROI
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Karpenter&lt;/strong&gt; (or GKE Autopilot). Highest ROI. Non-negotiable on AWS.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Spot orchestration&lt;/strong&gt; via Karpenter node pools or a vendor. Second-highest.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;VPA in recommendation mode&lt;/strong&gt;. Nearly free, huge payoff.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;OpenCost&lt;/strong&gt; or Kubecost for attribution. Needed to &lt;em&gt;sustain&lt;/em&gt; the above.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Prometheus + Grafana&lt;/strong&gt; for the queries yourself. You already have them.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Notice that #4 and #5 come after the ones that actually save. Vendors sell you #4 and #5 first.&lt;/p&gt;

&lt;h2&gt;
  
  
  FAQ
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;How much can I realistically save on my Kubernetes cluster?&lt;/strong&gt;&lt;br&gt;
For a typical mid-size cluster in 2026, 30-45% in 90 days is normal if you do restructuring work. 15-25% is achievable with right-sizing alone. Anything promising 70% is either lying or assuming you haven't done &lt;em&gt;anything&lt;/em&gt; yet.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Do I need Kubecost if I already have OpenCost?&lt;/strong&gt;&lt;br&gt;
Only if you want the UI, alerts, or per-namespace chargeback without building it. The underlying data is the same.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Is spot capacity reliable enough for production in 2026?&lt;/strong&gt;&lt;br&gt;
Yes, if you diversify across 4+ instance families and 3 AZs, handle SIGTERM correctly, and don't run stateful or single-instance workloads on it. We run 70% of a client's production traffic on spot with 99.98% availability.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Should I use GKE Autopilot or standard GKE with Karpenter?&lt;/strong&gt;&lt;br&gt;
Autopilot if you're vanilla. Standard + Karpenter if you need GPU shapes, specific instance types, or DaemonSets that Autopilot disallows.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What's the single biggest mistake teams make?&lt;/strong&gt;&lt;br&gt;
Buying a cost tool before fixing their requests and autoscaling. The tool shows you the problem. It doesn't fix it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Does &lt;code&gt;arm64&lt;/code&gt; (Graviton) really save money?&lt;/strong&gt;&lt;br&gt;
Yes. 20-40% over x86 for the same workload, and modern Go, Java, and Node runtimes handle multarch images fine. Migrating is a week, not a quarter.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How do I convince my team this is worth the effort?&lt;/strong&gt;&lt;br&gt;
Show them the p95 vs. request chart. That chart has never failed to start an argument. The argument is the point.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Are there hidden costs to spot?&lt;/strong&gt;&lt;br&gt;
Yes — opportunity cost of engineer time, and the risk of checkpoint-related complexity. Budget 2-4 weeks of a senior engineer's attention for a proper rollout.&lt;/p&gt;

&lt;h2&gt;
  
  
  The thing I want you to take away
&lt;/h2&gt;

&lt;p&gt;Cost optimization for kubernetes clusters isn't a purchase. It's a practice. The companies I've seen win at this in 2026 aren't the ones with the fanciest FinOps stack — they're the ones with a Friday afternoon ritual where someone opens the p95-request chart and a YAML file, side by side, and fixes one thing.&lt;/p&gt;

&lt;p&gt;Buy the tools that help you sustain the ritual. OpenCost if you'll build. Kubecost if you won't. Cast AI if you'd rather rent. But buy Karpenter first. Buy spot second. Everything else is commentary.&lt;/p&gt;

&lt;p&gt;The bill is not a mystery. It's a habit. Change the habit.&lt;/p&gt;




&lt;p&gt;Nishaant Dixit — Founder of SIVARO. Building data infrastructure and production AI systems since 2018. Built systems processing 200K events/sec.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>How to Reduce Cost of LLM Inference in Production</title>
      <dc:creator>nishaant dixit</dc:creator>
      <pubDate>Tue, 15 Sep 2026 16:03:43 +0000</pubDate>
      <link>https://dev.to/heleo/how-to-reduce-cost-of-llm-inference-in-production-3582</link>
      <guid>https://dev.to/heleo/how-to-reduce-cost-of-llm-inference-in-production-3582</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;This article was originally published at &lt;a href="https://sivaro.in/articles/how-to-reduce-cost-of-llm-inference-in-production/" rel="noopener noreferrer"&gt;sivaro.in&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h1&gt;
  
  
  How to Reduce Cost of LLM Inference in Production
&lt;/h1&gt;

&lt;p&gt;Last month a Series B fintech called me in a panic. They'd shipped an AI feature in March, it worked beautifully, and by August their inference bill had crossed $220K/month against a forecast of $40K. Their CFO thought they'd been hacked. They hadn't. They'd just done what everyone does — shipped on top of a frontier API with zero cost discipline, then watched usage compound.&lt;/p&gt;

&lt;p&gt;I've seen this movie a dozen times now. So let's talk about how to reduce cost of LLM inference in production, not as a list of tips, but as an actual buying decision you're making across four fronts: which models you run, where you run them, how you route traffic, and what you cache.&lt;/p&gt;

&lt;p&gt;Here's the thing most teams get wrong: they treat this as an optimization problem. It's not. It's an architecture problem, and the best time to solve it was three decisions ago.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Real Cost Curve Nobody Shows You
&lt;/h2&gt;

&lt;p&gt;A token on a frontier model costs roughly 100x to 400x what the same token costs on a well-tuned open model running on your own hardware. That's not a typo. As of September 2026, GPT-5-class and Claude-class API pricing sits in the $10–15 per million output tokens range, while a quantized Llama or Qwen variant on an H100 you already own can land closer to $0.05–0.20 per million. The gap is enormous, and it doesn't go away with "we'll negotiate enterprise pricing."&lt;/p&gt;

&lt;p&gt;But — and this is the part consultants leave out — self-hosting that open model badly can cost more than the API. I've watched a team burn $40K/month on idle GPU reservations because they overprovisioned for peak load they saw twice a week. So the decision isn't "API vs. self-host." It's a portfolio question.&lt;/p&gt;

&lt;p&gt;Think of it as a buying guide with four levers, ranked by how much money they typically move:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Model selection and tiering&lt;/strong&gt; — biggest lever, 60–90% of savings&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Caching (prompt + semantic)&lt;/strong&gt; — 20–60% savings, near-free to implement&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Routing and fallback logic&lt;/strong&gt; — 15–40% savings&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Serving infrastructure (batching, quantization, hardware)&lt;/strong&gt; — 30–70% savings &lt;em&gt;if&lt;/em&gt; you're already self-hosting&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Let's go through each.&lt;/p&gt;

&lt;h2&gt;
  
  
  Tiering Your Models Is the Single Highest-Leverage Move
&lt;/h2&gt;

&lt;p&gt;Most people think you need one model for your product. You don't. You need a routing policy that sends each request to the cheapest model that can handle it correctly.&lt;/p&gt;

&lt;p&gt;At SIVARO we built a support-ticket classifier last year that started on a frontier model at $85K/month. We moved it to a tiered setup:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Tier 0 (60% of traffic):&lt;/strong&gt; Regex + small fine-tuned classifier (BERT-class, ~$0.001/request)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Tier 1 (30%):&lt;/strong&gt; Open 8B model self-hosted (~$0.01/request)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Tier 2 (10%):&lt;/strong&gt; Frontier API for edge cases (~$0.30/request)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Total cost dropped to $9K/month. Same accuracy within 0.4 points. The trick wasn't a magic model — it was accepting that 60% of "AI inference" isn't AI at all.&lt;/p&gt;

&lt;p&gt;The buying decision here: don't pick &lt;em&gt;a&lt;/em&gt; model. Pick a &lt;em&gt;ladder&lt;/em&gt;. For each use case, ask "what's the cheapest thing that gets me to acceptable quality," and build one tier below where you think you need to be.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;enum&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Enum&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Tier&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Enum&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;REGEX&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
    &lt;span class="n"&gt;SMALL&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
    &lt;span class="n"&gt;FRONTIER&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;route&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;complexity_score&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;float&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;Tier&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;matches_regex&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;Tier&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;REGEX&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;complexity_score&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mf"&gt;0.7&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;Tier&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SMALL&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;Tier&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;FRONTIER&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's it. Complexity scores can come from token length, presence of rare entities, or a cheap classifier. You don't need a perfect scorer — you need one that's directionally right.&lt;/p&gt;

&lt;h2&gt;
  
  
  Caching: The Free Money You're Leaving on the Table
&lt;/h2&gt;

&lt;p&gt;I'll be blunt. If you're not caching prompts and responses, you're burning cash. Anthropic, OpenAI, and Google all offer prompt caching at 50–90% discount on cached input tokens. &lt;a href="https://docs.anthropic.com/en/docs/build-with-claude/prompt-caching" rel="noopener noreferrer"&gt;Anthropic's prompt caching docs&lt;/a&gt; and &lt;a href="https://openai.com/api/pricing/" rel="noopener noreferrer"&gt;OpenAI's cached input pricing&lt;/a&gt; both publish these discounts, and they've been stable since early 2025.&lt;/p&gt;

&lt;p&gt;For a support bot with a 4,000-token system prompt and 200-token user turn, you flip the cost ratio. The 200-token user turn is what matters; the 4,000-token prompt is nearly free after the first hit.&lt;/p&gt;

&lt;p&gt;But prompt caching only helps with identical prefixes. Real savings come from &lt;strong&gt;semantic caching&lt;/strong&gt; — hashing-and-embedding the full request and serving near-duplicate queries from a vector store. For customer support, FAQ-style products, and code assistants, hit rates of 25–45% are common in my experience. That's a quarter of your traffic that never touches a model.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;hashlib&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;numpy&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;np&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;your_vector_db&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;upsert&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;query&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;semantic_cache_lookup&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;user_prompt&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;threshold&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;float&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;0.94&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;embedding&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;embed&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;user_prompt&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;hits&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;query&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;embedding&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;top_k&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;hits&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="n"&gt;hits&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="n"&gt;score&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="n"&gt;threshold&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;hits&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="n"&gt;response&lt;/span&gt;  &lt;span class="c1"&gt;# cached
&lt;/span&gt;    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;  &lt;span class="c1"&gt;# miss — call the model
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Tune the threshold carefully. Too loose and you serve wrong answers. Too tight and you never hit. Start at 0.95 for factual domains, 0.90 for chitchat.&lt;/p&gt;

&lt;p&gt;One warning: invalidate aggressively. I've seen teams serve stale pricing answers for weeks because their cache never expired. Add a TTL tied to your content refresh cadence.&lt;/p&gt;

&lt;h2&gt;
  
  
  Self-Hosting: When It Wins, When It Wrecks You
&lt;/h2&gt;

&lt;p&gt;I used to be religious about self-hosting. Then I ran the numbers on a low-traffic product and realized the API was cheaper. Self-hosting wins when you have &lt;strong&gt;sustained, high-volume, latency-tolerant traffic&lt;/strong&gt; on &lt;strong&gt;a model that fits well on commodity GPUs&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Rough break-even math as of September 2026: an H100 rental is roughly $2–3/hr on spot, so about $1,500–2,200/month. If your workload runs at 30%+ sustained utilization on that GPU with a 70B quantized model, you beat API pricing. Below that, you don't.&lt;/p&gt;

&lt;p&gt;The toolkit that's matured fast: &lt;strong&gt;vLLM&lt;/strong&gt; for continuous batching, &lt;strong&gt;SGLang&lt;/strong&gt; for structured generation, and &lt;strong&gt;TensorRT-LLM&lt;/strong&gt; if you're all-NVIDIA. Continuous batching alone can 3–8x throughput versus naive serving — &lt;a href="https://blog.vllm.ai/2024/09/05/perf-update.html" rel="noopener noreferrer"&gt;vLLM's own benchmarks&lt;/a&gt; show this clearly.&lt;/p&gt;

&lt;p&gt;Key cost levers when self-hosting:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Quantization&lt;/strong&gt; (FP8, INT8, AWQ, GPTQ) — 2–4x throughput at small quality cost&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Batch size tuning&lt;/strong&gt; — larger batches raise throughput but hurt p99 latency&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Speculative decoding&lt;/strong&gt; — use a small draft model to accelerate a big one&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Spot instances + checkpointing&lt;/strong&gt; — 40–60% cheaper, but you need graceful degradation
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# vLLM launch with aggressive batching&lt;/span&gt;
vllm serve Qwen/Qwen3-32B-AWQ &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--max-model-len&lt;/span&gt; 8192 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--gpu-memory-utilization&lt;/span&gt; 0.92 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--max-num-seqs&lt;/span&gt; 256 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--quantization&lt;/span&gt; awq
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That &lt;code&gt;--max-num-seqs 256&lt;/code&gt; number is where most people leave money. Default is much lower and your GPU sits idle between batches.&lt;/p&gt;

&lt;h2&gt;
  
  
  Routing, Fallback, and Load Shedding
&lt;/h2&gt;

&lt;p&gt;If you're running across multiple providers (which you should), routing logic becomes a cost lever. The idea: monitor latency, quality, and price per provider in real time, and shift traffic to the cheapest provider that's healthy.&lt;/p&gt;

&lt;p&gt;Caveats. Router complexity has a real maintenance cost. Every additional provider is another API contract, another SDK quirk, another auth scheme. If you're under 1M requests/day, a static routing table probably beats a dynamic router.&lt;/p&gt;

&lt;p&gt;Load shedding is the underrated one. When your queue depth exceeds a threshold, degrade gracefully — shorter max_tokens, cheaper model tier, or a cached response. Your users would rather get a slightly worse answer in 400ms than a great answer in 12 seconds or an error.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;call_with_shedding&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;req&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;queue&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;depth&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;500&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;max_tokens&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;min&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;max_tokens&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;256&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;model&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;small-tier&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;router&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;dispatch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;req&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Fine-Tuning vs. Prompt Engineering: A Cost Decision, Not a Quality One
&lt;/h2&gt;

&lt;p&gt;Everyone frames fine-tuning as a quality play. It's mostly a cost play.&lt;/p&gt;

&lt;p&gt;A fine-tuned 7B model can match a prompted 70B on narrow tasks. That's a 10x inference cost reduction, permanently. The upfront cost — data collection, training, eval, deployment — usually pays back inside 3–6 months for any product with steady traffic.&lt;/p&gt;

&lt;p&gt;When it's worth it: you have &amp;gt;50K labeled examples, a bounded domain, and stable requirements. When it's not: your task changes every sprint, your data is thin, or quality bar is "roughly right." I've been burned fine-tuning too early twice. Don't do that.&lt;/p&gt;

&lt;h2&gt;
  
  
  An Honest Comparison Table
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Approach&lt;/th&gt;
&lt;th&gt;Typical Savings&lt;/th&gt;
&lt;th&gt;Time to Ship&lt;/th&gt;
&lt;th&gt;Best For&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Model tiering&lt;/td&gt;
&lt;td&gt;40–80%&lt;/td&gt;
&lt;td&gt;Days&lt;/td&gt;
&lt;td&gt;Every product with mixed request complexity&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Prompt caching&lt;/td&gt;
&lt;td&gt;20–50%&lt;/td&gt;
&lt;td&gt;Hours&lt;/td&gt;
&lt;td&gt;Long system prompts, repeated context&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Semantic caching&lt;/td&gt;
&lt;td&gt;15–40%&lt;/td&gt;
&lt;td&gt;Weeks&lt;/td&gt;
&lt;td&gt;FAQ, support, code assistants&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Self-hosting (vLLM + AWQ)&lt;/td&gt;
&lt;td&gt;30–70% vs. API&lt;/td&gt;
&lt;td&gt;Months&lt;/td&gt;
&lt;td&gt;Sustained high volume, latency-tolerant&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Fine-tuning&lt;/td&gt;
&lt;td&gt;60–90% (long-term)&lt;/td&gt;
&lt;td&gt;1–3 months&lt;/td&gt;
&lt;td&gt;Narrow, stable, data-rich tasks&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Quantization&lt;/td&gt;
&lt;td&gt;2–4x throughput&lt;/td&gt;
&lt;td&gt;Days&lt;/td&gt;
&lt;td&gt;Any self-hosted workload&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Load shedding&lt;/td&gt;
&lt;td&gt;Variable&lt;/td&gt;
&lt;td&gt;Days&lt;/td&gt;
&lt;td&gt;Anything with spiky traffic&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;None of these are mutually exclusive. The teams that win stack three or four.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I'd Actually Do If I Were Starting Today
&lt;/h2&gt;

&lt;p&gt;If I were rebuilding an inference-heavy product from scratch in September 2026, here's the sequence:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Week 1:&lt;/strong&gt; Ship on a frontier API. Don't optimize prematurely. Measure real traffic patterns.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Week 2–3:&lt;/strong&gt; Add prompt caching. Add a semantic cache in front of your most repeated endpoint. Instrument hit rates.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Month 2:&lt;/strong&gt; Build routing tiers. Move the obvious 40–60% of traffic to a small self-hosted model.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Month 3–4:&lt;/strong&gt; Evaluate fine-tuning for your top two use cases based on actual data.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Month 6+:&lt;/strong&gt; Revisit self-hosting economics. If sustained utilization crosses 30%, migrate.&lt;/p&gt;

&lt;p&gt;The order matters because each step gives you the data for the next. Teams that jump straight to self-hosting without usage data usually regret it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Frequently Asked Questions
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Is it always cheaper to self-host?&lt;/strong&gt;&lt;br&gt;
No, and this myth costs companies millions. Below 20–30% sustained GPU utilization, API wins. The crossover point moves with model size — a 7B model needs less traffic to justify self-hosting than a 70B model, but even a 7B needs steady load.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Does quantization hurt quality meaningfully?&lt;/strong&gt;&lt;br&gt;
For most classification, extraction, and RAG tasks, INT8 and FP8 quantized models perform within 1–2% of full precision. For creative writing and complex reasoning, you'll notice. Test on your specific eval set before shipping. &lt;a href="https://huggingface.co/docs/transformers/main/en/quantization/overview" rel="noopener noreferrer"&gt;Hugging Face's quantization docs&lt;/a&gt; have good starting benchmarks.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What's the fastest win for reducing inference costs?&lt;/strong&gt;&lt;br&gt;
Prompt caching. It's a config change, available on all major providers, and typically cuts 20–50% off your bill the same week. No architecture change required.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Can I use multiple providers without a router?&lt;/strong&gt;&lt;br&gt;
Yes — a static dictionary mapping task types to providers works fine up to about 1M requests/day. Dynamic routers add value at scale but also add failure modes.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How do I know if my semantic cache is helping or hurting?&lt;/strong&gt;&lt;br&gt;
Track two things: hit rate and quality-adjusted error rate on cached responses. If quality drops after adding cache, your threshold is too loose. Below 10% hit rate, the cache isn't paying for itself.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Is fine-tuning really a cost lever?&lt;/strong&gt;&lt;br&gt;
Yes, and it's underrated. A well fine-tuned 7B model replaces a prompted 70B for narrow tasks, which is a permanent 5–10x inference cost reduction. The catch is that it requires stable requirements and real labeled data.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What about smaller open models like 3B and 1B?&lt;/strong&gt;&lt;br&gt;
For high-volume classification, extraction, and routing decisions, 1B–3B models are shockingly good now. Qwen3-4B and Llama-3.2-3B handle a lot of "AI" traffic that teams are currently paying frontier prices for.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Should I care about batch APIs?&lt;/strong&gt;&lt;br&gt;
If your workload is async (nightly jobs, batch scoring, content generation pipelines), batch APIs are often 50% cheaper than real-time endpoints. Free money if latency doesn't matter.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Thing Nobody Says Out Loud
&lt;/h2&gt;

&lt;p&gt;Most inference cost problems aren't technical. They're organizational. The team that shipped on GPT-5 in March didn't ask "what's the cheapest way to do this" because nobody owned the question. The CFO saw the bill. The engineers saw a green checkmark in the demo. Nobody was measuring cost-per-request-per-user-segment.&lt;/p&gt;

&lt;p&gt;So before you rewrite your serving stack, put a number on the dashboard. Cost per 1,000 requests, broken out by endpoint. That single metric changes behavior faster than any blog post, including this one.&lt;/p&gt;

&lt;p&gt;Here's what I've learned after eight years of building production AI systems: how to reduce cost of LLM inference in production is 20% engineering, 80% deciding that it matters. The techniques — tiering, caching, routing, quantization, fine-tuning — are all well-documented and cheap to adopt. The teams that struggle are the ones that never made it a first-class metric.&lt;/p&gt;

&lt;p&gt;Start with the metric. Then start with caching. Then tier. Everything else follows.&lt;/p&gt;




&lt;p&gt;Nishaant Dixit — Founder of SIVARO. Building data infrastructure and production AI systems since 2018. Built systems processing 200K events/sec.&lt;/p&gt;

</description>
    </item>
  </channel>
</rss>
