TensorFlow models don’t just "get updated"; they are immutably stored artifacts that require explicit registration to be tracked.

Let’s see this in action. Imagine we’ve trained a simple Keras model.

import tensorflow as tf
from tensorflow import keras

# Define a simple model
model = keras.Sequential([
    keras.layers.Dense(10, activation='relu', input_shape=(784,)),
    keras.layers.Dense(10, activation='softmax')
])

model.compile(optimizer='adam',
              loss='categorical_crossentropy',
              metrics=['accuracy'])

# In a real scenario, you'd train this model
# model.fit(x_train, y_train, epochs=5)

# Save the model locally
model.save('my_model_v1.keras')

Now, we want to put this into a system where we can track its versions. TensorFlow Model Registry (part of Vertex AI) is the place for this.

First, we need to initialize the registry. This involves setting up a ModelRegistry client.

from google.cloud import aiplatform

# Initialize Vertex AI SDK
aiplatform.init(project='your-gcp-project-id', location='us-central1')

# Instantiate the Model Registry
model_registry = aiplatform.ModelRegistry()

To register our first version, we’ll use the upload_model method. This takes the local path to our saved model and a display name.

# Upload the model to the registry
model_resource = model_registry.upload_model(
    display_name='MyAwesomeModel',
    artifact_uri='gs://your-gcs-bucket/models/my_model_v1.keras', # Point to the model in GCS
    # For a real upload, you'd first upload the saved model to GCS
    # Example: !gsutil cp my_model_v1.keras gs://your-gcs-bucket/models/my_model_v1.keras
    description='Initial version of the awesome model.'
)

print(f"Model uploaded: {model_resource.resource_name}")

The upload_model command doesn’t just copy files; it creates a model resource in Vertex AI. This resource has a unique ID and a version ID. If you upload the same model artifact again with the same display name, it will create a new version of that model.

Let’s simulate training a new version and registering it.

# Simulate training a new version
new_model = keras.Sequential([
    keras.layers.Dense(12, activation='relu', input_shape=(784,)), # Changed layer size
    keras.layers.Dense(10, activation='softmax')
])
new_model.compile(optimizer='adam',
                  loss='categorical_crossentropy',
                  metrics=['accuracy'])
new_model.save('my_model_v2.keras')

# Upload the new version
model_resource_v2 = model_registry.upload_model(
    display_name='MyAwesomeModel', # Same display name to create a new version
    artifact_uri='gs://your-gcs-bucket/models/my_model_v2.keras',
    description='Second version with more neurons in the first layer.'
)

print(f"Model version 2 uploaded: {model_resource_v2.resource_name}")

Now, MyAwesomeModel in your registry has at least two versions. You can list them to see this.

# List all versions of the model
all_models = model_registry.list_models(filter='display_name="MyAwesomeModel"')

for model in all_models:
    print(f"Model Name: {model.display_name}, Resource Name: {model.resource_name}")
    # You can further inspect versions of a specific model if needed

The resource_name will look something like projects/your-gcp-project-id/locations/us-central1/models/1234567890123456789. The registry assigns a unique ID to the model resource itself and then manages versions under that resource.

When you deploy a model for serving, you typically deploy a specific version of a registered model. This ensures that your deployed endpoints are running a consistent, known version of your model, and you can roll back or deploy new versions with confidence.

The crucial insight is that upload_model with the same display_name creates a new version under the existing model resource. The artifact_uri is the pointer to the actual model files (saved in TensorFlow’s .keras format or SavedModel format) stored in a cloud storage bucket like Google Cloud Storage. The registry itself doesn’t store the model files; it stores metadata about them and their lineage.

The most surprising thing most people don’t realize is that the upload_model method’s artifact_uri parameter expects a path to a directory containing the saved model, not a single file, if you’re using the standard TensorFlow SavedModel format. For the newer .keras format, it can be a file path. The registry then packages this artifact into a format it understands for versioning and deployment.

Once registered, you can query the registry to find the latest version, a specific version by ID, or list all versions to make informed decisions about deployment and A/B testing.

Want structured learning?

Take the full Tensorflow course →