Vertex AI might be charging you for resources you donât actually need. In December 2025, three European startups found their production models were using 4.3 times more resources than necessary. This wasnât due to inefficient models but rather Google Cloudâs default configuration, which prioritizes convenience over cost. The result? An average monthly bill of around $12,400, 71% of which could be avoided with architectural tweaks that Google Cloud doesnât thoroughly document.
Photo: Steve A Johnson on Unsplash
Hereâs a breakdown of a method to reduce operational costs in Vertex AI without losing performance. Itâs not about switching providers or compromising inference quality. Itâs about understanding what Google charges you for, detecting silent leaks, and redesigning your ML pipeline to optimize costs per prediction. The architectural decisions outlined here have been tested in production and will transform your cost structure.
The real issue lies in the default configuration, not the model
Vertex AI offers three deployment modes: dedicated endpoints, batch prediction, and AutoML. The official documentation suggests dedicated endpoints as the standard route for production models. However, what they donât tell you is that these endpoints keep compute instances active 24/7, even without traffic.
For example, a Spanish fintech noticed its fraud detection model processed 83% of transactions between 9 AM and 6 PM. Outside these hours, the endpoint continued consuming $340 daily on n1-standard-4 instances. The monthly cost of inactive instances exceeded $10,200. The solution was to migrate to batch prediction for non-critical loads and use Cloud Run with custom containers for on-demand inference.
How to measure the real idle time of your endpoint
Before redesigning, you need visibility. Google Cloud Monitoring offers utilization metrics but doesnât show how many hours your endpoint is active without receiving requests. Implement this query in Cloud Logging:
resource.type="ml_job"
resource.labels.job_id="[YOUR_ENDPOINT_ID]"
jsonPayload.prediction_count=0
Group by 1-hour windows over 7 days. If more than 30% of windows report zero predictions, you have an architectural issue, not a model issue. The solution might be shutting down instances during low demand or migrating to serverless inference.
Batch prediction cuts costs by 62% for non-real-time loads
Photo: Igor Omilaev on Unsplash
Batch prediction is the least promoted feature of Vertex AI but the most cost-effective for use cases that can tolerate minute-level latencies. Instead of keeping an endpoint active, you send a file with inputs to the batch service. Google provisions resources on demand, processes, and then destroys the instances.
The cost of batch prediction is about 38% of the cost of a dedicated endpoint for the same volume of predictions. For example, an e-commerce startup processing 4 million predictions a month saw its bill drop from $8,900 to $3,380 by moving product recommendations to nightly batch.
When batch doesnât work
Batch prediction introduces latency. If your product requires inference under 500ms, batch isnât feasible. But do all cases in your application need sub-second latency? Segment them:
- Critical real-time: authentication, live fraud detection. Dedicated endpoints are unavoidable.
- Near real-time: recommendations, non-urgent content moderation. Cloud Run with containers is more suitable.
- Batch-tolerant: predictive analytics, report generation. Ideal for batch prediction.
In a 2026 audit of startups using Vertex AI, only 23% of models truly needed real-time latency. The remaining 77% were paying for unnecessary infrastructure.
The instance optimization Google doesn't configure for you
Vertex AI dedicated endpoints run on Compute Engine. By default, Google uses n1-standard-4 instances (4 vCPUs, 15GB RAM) even for small models. A BERT model for text classification can work fine on an n1-standard-2, cutting costs by 50%.
However, changing the instance type requires deleting the endpoint and redeploying it with custom configuration, proving that performance doesn't degrade. Google doesnât offer vertical auto-scaling, only horizontal. This means if traffic grows, the system adds more instances of the same size, not larger instances.
Rightsizing: the complete process
-
Profile actual resource consumption: Use Cloud Profiler to capture CPU and memory usage over a week.
-
Identify the 95th percentile: Optimize for the 95th percentile of CPU usage, not the maximum peak.
-
Test in staging with smaller instances: Create a parallel endpoint and measure latency by replicating 10% of production traffic.
-
Migrate gradually: Change the production endpoint only if staging latency is acceptable.
A German insurtech found their endpoints were oversized. By moving from n1-standard-4 to e2-standard-2, they reduced costs from $14,200 to $6,100, with a slight increase in P95 latency from 180ms to 195ms, totally acceptable.
Model distillation: the strategy that changes the cost equation
For large models (over 500M parameters), inference cost is more about compute time than instances. A GPT-2 medium model can process 12 predictions per second on an n1-standard-4. A distilled model of the same accuracy can process 48 predictions per second on the same instance.
Distillation trains a smaller model (the "student") to mimic the behavior of a large model (the "teacher"). While it doesnât achieve the teacher's absolute precision, it can reach 97-99% performance with 1/4 the size. This translates to 4x higher throughput and 75% lower costs.
Practical implementation in TensorFlow
Google doesnât offer distillation as a managed service in Vertex AI. You have to implement it manually.
import tensorflow as tf
from tensorflow import keras
teacher_model = keras.models.load_model('gs://your-bucket/teacher_model')
student_model = keras.Sequential([
keras.layers.Dense(128, activation='relu', input_shape=(768,)),
keras.layers.Dropout(0.2),
keras.layers.Dense(64, activation='relu'),
keras.layers.Dense(10, activation='softmax')
])
def distillation_loss(y_true, y_pred, teacher_pred, temperature=3.0, alpha=0.7):
soft_labels = tf.nn.softmax(teacher_pred / temperature)
distill_loss = tf.keras.losses.KLDivergence()(soft_labels, y_pred / temperature)
student_loss = tf.keras.losses.categorical_crossentropy(y_true, y_pred)
return alpha * distill_loss + (1 - alpha) * student_loss
for epoch in range(10):
for batch in dataset:
x, y = batch
teacher_pred = teacher_model(x, training=False)
with tf.GradientTape() as tape:
student_pred = student_model(x, training=True)
loss = distillation_loss(y, student_pred, teacher_pred)
gradients = tape.gradient(loss, student_model.trainable_variables)
optimizer.apply_gradients(zip(gradients, student_model.trainable_variables))
The temperature parameter controls how much to âsoftenâ the teacher's predictions. Values between 2 and 5 are effective. The alpha balances learning from the teacher and from the real labels. Start with 0.7 and adjust based on validation.
A Spanish NLP startup performed distillation on a BERT model for support ticket classification. The original model processed 8 requests per second, and after distillation, it processed 34 requests per second with only a 2% drop in F1 score. The inference cost dropped from $6,700 to $1,900.
Auto-scaling: when manual configuration costs more than the model
Vertex AIâs auto-scaling has two parameters: minimum and maximum replicas. By default, min=1 and max=10. If traffic drops to zero, you still pay for that minimum instance.
Set min=0 for non-critical endpoints. Vertex AI will take 3-5 minutes to provision an instance when thereâs a request after an inactive period. This isnât viable for user-facing services but is for:
- Internal analytics APIs
- Batch scoring models
- Pre-processing services
Cold start mitigation with Cloud Run
If you need sub-second latency but have irregular traffic, Cloud Run outperforms Vertex AI endpoints. Package your model in a Docker container, expose it via Flask or FastAPI, and deploy to Cloud Run with min-instances=0, max-instances=100.
Cold start on Cloud Run ranges from 800ms to 2s. For small models (less than 500MB), reduce cold start to under 1 second with these optimizations:
FROM python:3.11-slim
RUN pip install --no-cache-dir tensorflow==2.15.0 flask==3.0.0 gunicorn==21.2.0
COPY model /app/model
ENV PYTHONUNBUFFERED=1
CMD exec gunicorn --bind :$PORT --workers 1 --threads 4 --timeout 0 --preload app:app
The --preload flag loads the model before accepting traffic, converting cold start into a warm start. A British healthtech reduced P99 cold start latency from 3.2s to 1.1s.
Prediction caching: the optimization nobody implements
If your model processes repetitive inputs, you might be wasting resources. An image classification model for content moderation may receive the same image from multiple users. Without caching, you process the same image multiple times.
Implement a Redis layer before the Vertex AI endpoint. Hash the input, check Redis, and return the cached result if it exists. Call the model if it isnât cached. This can reduce costs by 40-60% depending on repetition.
Implementation in Python with Redis
import hashlib
import redis
import json
from google.cloud import aiplatform
redis_client = redis.Redis(host='your-redis-host', port=6379, db=0)
CACHE_TTL = 3600
def predict_with_cache(input_data):
input_hash = hashlib.sha256(json.dumps(input_data, sort_keys=True).encode()).hexdigest()
cached_result = redis_client.get(input_hash)
if cached_result:
return json.loads(cached_result)
endpoint = aiplatform.Endpoint(endpoint_name='projects/123/locations/us-central1/endpoints/456')
prediction = endpoint.predict(instances=[input_data])
redis_client.setex(input_hash, CACHE_TTL, json.dumps(prediction.predictions[0]))
return prediction.predictions[0]
Set the TTL based on the model. For personalized recommendations, opt for a short TTL (5-15 minutes). For static content classification, days or weeks are appropriate. An edtech platform implemented this and found that 54% of queries to their exercise correction model were identical, reducing their bill from $9,100 to $4,200 monthly.
The metric that matters: cost per prediction, not absolute cost
The most common mistake is obsessing over the total Google Cloud bill. The relevant metric is cost per prediction (CPP). If your monthly bill is $15,000 but you process 50 million predictions, your CPP is $0.0003. Reducing the bill to $8,000 but only processing 20 million raises your CPP to $0.0004. Did you really improve?
Track CPP in Cloud Monitoring with custom metrics:
from google.cloud import monitoring_v3
import time
client = monitoring_v3.MetricServiceClient()
project_name = f"projects/{project_id}"
series = monitoring_v3.TimeSeries()
series.metric.type = "custom.googleapis.com/ml/cost_per_prediction"
series.resource.type = "global"
point = monitoring_v3.Point()
point.value.double_value = total_cost / total_predictions
point.interval.end_time.seconds = int(time.time())
series.points = [point]
client.create_time_series(name=project_name, time_series=[series])
Set alerts when CPP exceeds your target threshold. If your target is $0.0005 per prediction and CPP rises to $0.0007, investigate immediately. Typical causes include low traffic with high minimum instances, poorly configured auto-scaling, oversized models, and lack of caching for repetitive inputs.
Is your Vertex AI bill funding architectural inefficiencies you thought were inevitable? Most startups I know assume AI costs are a fixed tax for doing business in 2026. The reality is that between 50% and 70% of ML infrastructure spending is avoidable with proper architectural decisions. Google Cloud wonât optimize your bill; their incentive is for you to consume more, not less. Optimization is in your hands, and doing it right or wrong can determine the financial viability of your product.