mirror of
https://github.com/GoogleCloudPlatform/vertex-ai-samples.git
synced 2026-09-26 14:42:04 +00:00
43 KiB
43 KiB
In [ ]:
# Copyright 2023 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.In [ ]:
# Install the packages
! pip3 install --upgrade google-cloud-aiplatform \
'google-cloud-pipeline-components<2'
! pip3 install tensorflow==2.5 \
tensorflow_hub
! pip3 install --upgrade 'kfp<2'In [ ]:
import sys
if "google.colab" in sys.modules:
import IPython
app = IPython.Application.instance()
app.kernel.do_shutdown(True)In [ ]:
import sys
if "google.colab" in sys.modules:
from google.colab import auth
auth.authenticate_user()In [ ]:
PROJECT_ID = "[your-project-id]" # @param {type:"string"}
LOCATION = "us-central1" # @param {type:"string"}In [ ]:
BUCKET_URI = f"gs://your-bucket-name-{PROJECT_ID}-unique" # @param {type:"string"}In [ ]:
! gcloud storage buckets create --location=$LOCATION --project=$PROJECT_ID $BUCKET_URIIn [ ]:
SERVICE_ACCOUNT = "[your-service-account]" # @param {type:"string"}In [ ]:
import sys
IS_COLAB = "google.colab" in sys.modules
if (
SERVICE_ACCOUNT == ""
or SERVICE_ACCOUNT is None
or SERVICE_ACCOUNT == "[your-service-account]"
):
# Get your service account from gcloud
if not IS_COLAB:
shell_output = !gcloud auth list 2>/dev/null
SERVICE_ACCOUNT = shell_output[2].replace("*", "").strip()
else: # IS_COLAB:
shell_output = ! gcloud projects describe $PROJECT_ID
project_number = shell_output[-1].split(":")[1].strip().replace("'", "")
SERVICE_ACCOUNT = f"{project_number}-compute@developer.gserviceaccount.com"
print("Service Account:", SERVICE_ACCOUNT)In [ ]:
! gcloud storage buckets add-iam-policy-binding $BUCKET_URI --member=serviceAccount:{SERVICE_ACCOUNT} --role=roles/storage.objectCreator
! gcloud storage buckets add-iam-policy-binding $BUCKET_URI --member=serviceAccount:{SERVICE_ACCOUNT} --role=roles/storage.objectViewerIn [ ]:
import kfp
import tensorflow as tf
import tensorflow_hub as hub
from google.cloud import aiplatform
from google.cloud.aiplatform import gapic
from kfp.v2 import compiler
from kfp.v2.dsl import componentIn [ ]:
aiplatform.init(project=PROJECT_ID, location=LOCATION, staging_bucket=BUCKET_URI)In [ ]:
DEPLOY_GPU, DEPLOY_NGPU = (None, None)In [ ]:
TF = "2.5".replace(".", "-")
if DEPLOY_GPU:
DEPLOY_VERSION = "tf2-gpu.{}".format(TF)
else:
DEPLOY_VERSION = "tf2-cpu.{}".format(TF)
DEPLOY_IMAGE = "{}-docker.pkg.dev/vertex-ai/prediction/{}:latest".format(
LOCATION.split("-")[0], DEPLOY_VERSION
)
print("Deployment:", DEPLOY_IMAGE, DEPLOY_GPU, DEPLOY_NGPU)In [ ]:
machine_type = "n1-standard"
vCPUs = "4"
DEPLOY_COMPUTE = f"{machine_type}-{vCPUs}"
print("Deploy machine type", DEPLOY_COMPUTE)In [ ]:
tfhub_model = tf.keras.Sequential(
[hub.KerasLayer("https://tfhub.dev/google/imagenet/resnet_v2_101/classification/5")]
)
tfhub_model.build([None, 32, 32, 3])
tfhub_model.summary()In [ ]:
MODEL_DIR = BUCKET_URI + "/model"
tfhub_model.save(MODEL_DIR)In [ ]:
blessed_model = aiplatform.Model.upload(
display_name="resnet",
artifact_uri=MODEL_DIR,
serving_container_image_uri=DEPLOY_IMAGE,
is_default_version=True,
version_aliases=["v1"],
)
print(blessed_model)In [ ]:
metrics = {"logLoss": 1.4, "auPrc": 0.85}
print(metrics)
blessed_eval = gapic.ModelEvaluation(
display_name="eval",
metrics_schema_uri="gs://google-cloud-aiplatform/schema/modelevaluation/classification_metrics_1.0.0.yaml",
metrics=metrics,
)In [ ]:
API_ENDPOINT = f"{LOCATION}-aiplatform.googleapis.com"
client = gapic.ModelServiceClient(client_options={"api_endpoint": API_ENDPOINT})
client.import_model_evaluation(
parent=blessed_model.resource_name, model_evaluation=blessed_eval
)In [ ]:
endpoint = aiplatform.Endpoint.create(
display_name="resnet", project=PROJECT_ID, location=LOCATION
)
print(endpoint)In [ ]:
response = endpoint.deploy(
model=blessed_model,
deployed_model_display_name="resnet",
machine_type=DEPLOY_COMPUTE,
)
print(response)In [ ]:
@component(packages_to_install=["google-cloud-aiplatform"])
def create_next_model_version(
parent_model: str,
artifact_uri: str,
serving_container: str,
project: str,
region: str,
) -> str:
from google.cloud import aiplatform
aiplatform.init(project=project, location=region)
model = aiplatform.Model.upload(
display_name="resnet",
artifact_uri=artifact_uri,
serving_container_image_uri=serving_container,
parent_model=parent_model,
is_default_version=True,
version_aliases=["v2"],
version_description="This is the second version of the model",
)
return model.resource_nameIn [ ]:
@component(packages_to_install=["google-cloud-aiplatform"])
def import_classification_metrics(
display_name: str, metrics: dict, parent_model_resource: str, region: str
):
from google.cloud.aiplatform import gapic
evaluation = gapic.ModelEvaluation(
display_name=display_name,
metrics_schema_uri="gs://google-cloud-aiplatform/schema/modelevaluation/classification_metrics_1.0.0.yaml",
metrics=metrics,
)
API_ENDPOINT = f"{region}-aiplatform.googleapis.com"
client = gapic.ModelServiceClient(client_options={"api_endpoint": API_ENDPOINT})
client.import_model_evaluation(
parent=parent_model_resource, model_evaluation=evaluation
)In [ ]:
@component(packages_to_install=["google-cloud-aiplatform"])
def compare_metrics(
blessed_model_resource_name: str, challenger_model_resource_name: str
):
from google.cloud import aiplatform
# Get the metrics for the blessed model
blessed_model = aiplatform.Model(blessed_model_resource_name)
blessed_eval = blessed_model.list_model_evaluations()[0]
blessed_auPrc = blessed_eval.metrics["auPrc"]
# Get the metrics for the challenger model
challenger_model = aiplatform.Model(challenger_model_resource_name)
challenger_eval = challenger_model.list_model_evaluations()[0]
challenger_auPrc = challenger_eval.metrics["auPrc"]
# Which model has the best accuracy becomes the default model
if challenger_auPrc > blessed_auPrc:
challenger_model.versioning_registry.add_version_aliases(
new_aliases=["default"], version=challenger_model.version_id
)
else:
blessed_model.versioning_registry.add_version_aliases(
new_aliases=["default"], version=blessed_model.version_id
)In [ ]:
@kfp.dsl.pipeline(name="blessed-vs-challenger")
def pipeline(
blessed_model_resource: str,
serving_container: str,
machine_type: str,
endpoint_resource_name: str,
endpoint_resource_uri: str,
project: str = PROJECT_ID,
region: str = LOCATION,
):
from google_cloud_pipeline_components.experimental.evaluation import \
GetVertexModelOp
from google_cloud_pipeline_components.types import artifact_types
from google_cloud_pipeline_components.v1.endpoint import ModelDeployOp
from kfp.v2.components import importer_node
# Get the Vertex AI model resource of the blessed model
model = GetVertexModelOp(model_resource_name=blessed_model_resource)
# pretend that you trained a new version of the model (artifacts at MODEL_DIR)
# create the next version in the Model Registry as the challenger model
next_version = create_next_model_version(
parent_model=blessed_model_resource,
artifact_uri=MODEL_DIR,
serving_container=serving_container,
project=project,
region=region,
).after(model)
# pretend to evaluate the challenger
challenger_metrics = {"logLoss": 1.3, "auPrc": 0.88}
# upload the metrics for the challenger version
import_metrics = import_classification_metrics(
display_name="challenger",
metrics=challenger_metrics,
parent_model_resource=next_version.output,
region=region,
).after(next_version)
# test metrics
compare = compare_metrics(blessed_model_resource, next_version.output).after(
import_metrics
)
# import the production Endpoint
endpoint = importer_node.importer(
artifact_uri=endpoint_resource_uri,
artifact_class=artifact_types.VertexEndpoint,
metadata={"resourceName": endpoint_resource_name},
)
# deploy model to endpoint
_ = ModelDeployOp(
model=model.outputs["model"],
endpoint=endpoint.output, # .outputs["endpoint"],
dedicated_resources_min_replica_count=1,
dedicated_resources_max_replica_count=1,
dedicated_resources_machine_type=machine_type,
traffic_split={"0": 100},
).after(compare)In [ ]:
# Compile the pipeline to a json file
compiler.Compiler().compile(
pipeline_func=pipeline, package_path="challenger_vs_blessed.json"
)In [ ]:
# Define the root folder for your pipeline artifacts
PIPELINE_ROOT = "{}/pipeline_root/control".format(BUCKET_URI)
# Define the pipeline job
job = aiplatform.PipelineJob(
display_name="challenger_vs_blessed",
template_path="challenger_vs_blessed.json",
pipeline_root=PIPELINE_ROOT,
parameter_values={
"blessed_model_resource": blessed_model.resource_name,
"serving_container": DEPLOY_IMAGE,
"machine_type": DEPLOY_COMPUTE,
"endpoint_resource_name": endpoint.resource_name,
"endpoint_resource_uri": "https://us-central1-aiplatform.googleapis.com/v1/"
+ endpoint.resource_name,
"project": PROJECT_ID,
"region": LOCATION,
},
enable_caching=False,
)
# Run the pipeline job
job.run()In [ ]:
gca_resource = endpoint.list(filter="display_name=resnet")[0].gca_resource
print("Deployed Models", gca_resource.deployed_models)
print("\n")
print("Traffic Split", gca_resource.traffic_split)In [ ]:
# Undeploy the model from endpoint
endpoint.undeploy_all()
# Delete the endpoint resource
endpoint.delete()
# Delete the model resource(s)
blessed_model.delete()
# Delete the pipeline job
job.delete()
# Delete Cloud Storage objects that were created
delete_bucket = True
if delete_bucket:
! gcloud storage rm --recursive $BUCKET_URI
# Delete the locally saved pipeline package file
! rm challenger_vs_blessed.json