mirror of
https://github.com/GoogleCloudPlatform/vertex-ai-samples.git
synced 2026-09-26 14:42:04 +00:00
45 KiB
45 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 --quiet --upgrade google-cloud-aiplatform \
'google-cloud-pipeline-components<2'
! pip3 install --quiet tensorflow==2.5 \
tensorflow_hub
! pip3 install --quiet --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 [ ]:
! gsutil mb -l {LOCATION} -p {PROJECT_ID} {BUCKET_URI}In [ ]:
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 [ ]:
! gsutil iam ch serviceAccount:{SERVICE_ACCOUNT}:roles/storage.objectCreator $BUCKET_URI
! gsutil iam ch serviceAccount:{SERVICE_ACCOUNT}:roles/storage.objectViewer $BUCKET_URIIn [ ]:
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 [ ]:
# Save the model to Cloud Storage path
MODEL_DIR = BUCKET_URI + "/model"
tfhub_model.save(MODEL_DIR)In [ ]:
champion_model = aiplatform.Model.upload(
display_name="resnet-v1",
artifact_uri=MODEL_DIR,
serving_container_image_uri=DEPLOY_IMAGE,
is_default_version=True,
version_aliases=["v1"],
)
print(champion_model)In [ ]:
metrics = {"logLoss": 1.4, "auPrc": 0.85}
print(metrics)
champion_eval = gapic.ModelEvaluation(
display_name="train-v1",
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=champion_model.resource_name, model_evaluation=champion_eval
)In [ ]:
endpoint = aiplatform.Endpoint.create(
display_name="production", project=PROJECT_ID, location=LOCATION
)
print(endpoint)In [ ]:
response = endpoint.deploy(
model=champion_model,
deployed_model_display_name="champion",
machine_type=DEPLOY_COMPUTE,
)
print(response)In [ ]:
contender_model_1 = aiplatform.Model.upload(
display_name="resnet-v2",
artifact_uri=MODEL_DIR,
serving_container_image_uri=DEPLOY_IMAGE,
parent_model=champion_model.resource_name,
is_default_version=False,
version_aliases=["v2"],
)
contender_model_2 = aiplatform.Model.upload(
display_name="resnet-v3",
artifact_uri=MODEL_DIR,
serving_container_image_uri=DEPLOY_IMAGE,
parent_model=champion_model.resource_name,
is_default_version=False,
version_aliases=["v3"],
)In [ ]:
metrics = {"logLoss": 1.5, "auPrc": 0.83}
contender_1_eval = gapic.ModelEvaluation(
display_name="train-v2",
metrics_schema_uri="gs://google-cloud-aiplatform/schema/modelevaluation/classification_metrics_1.0.0.yaml",
metrics=metrics,
)
# workaround for bug
contender_model_1.versioning_registry.add_version_aliases(
new_aliases=["default"], version=contender_model_1.version_id
)
client.import_model_evaluation(
parent=contender_model_1.resource_name, model_evaluation=contender_1_eval
)
metrics = {"logLoss": 1.6, "auPrc": 0.82}
contender_2_eval = gapic.ModelEvaluation(
display_name="train-v3",
metrics_schema_uri="gs://google-cloud-aiplatform/schema/modelevaluation/classification_metrics_1.0.0.yaml",
metrics=metrics,
)
# workaround for bug
contender_model_2.versioning_registry.add_version_aliases(
new_aliases=["default"], version=contender_model_2.version_id
)
client.import_model_evaluation(
parent=contender_model_2.resource_name, model_evaluation=contender_2_eval
)In [ ]:
@component(packages_to_install=["google-cloud-aiplatform"])
def import_classification_metrics(
display_name: str,
metrics: dict,
parent_model_resource: str,
project: str,
region: str,
):
from google.cloud import aiplatform
from google.cloud.aiplatform import gapic
print("DISPLAY", display_name)
evaluation = gapic.ModelEvaluation(
display_name=display_name,
metrics_schema_uri="gs://google-cloud-aiplatform/schema/modelevaluation/classification_metrics_1.0.0.yaml",
metrics=metrics,
)
# workaround for bug
aiplatform.init(project=project, location=region)
parent_model = aiplatform.Model(parent_model_resource)
parent_model.versioning_registry.add_version_aliases(
new_aliases=["default"], version=parent_model.version_id
)
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(
champion_model_resource_name: str, contender_model_resource_names: list
):
from google.cloud import aiplatform
# Get the metrics for the blessed model
champion_model = aiplatform.Model(champion_model_resource_name)
champion_eval = champion_model.list_model_evaluations()[
1
] # index 1 is the production eval data
champion_auPrc = champion_eval.metrics["auPrc"]
champion_model.versioning_registry.add_version_aliases(
new_aliases=["default"], version=champion_model.version_id
)
# Get the metrics for the challenger model
for contender in contender_model_resource_names:
contender_model = aiplatform.Model(contender)
contender_eval = contender_model.list_model_evaluations()[1]
contender_auPrc = contender_eval.metrics["auPrc"]
# Which model has the best accuracy becomes the default model
if contender_auPrc > champion_auPrc:
contender_model.versioning_registry.add_version_aliases(
new_aliases=["default"], version=contender_model.version_id
)
champion_auPrc = contender_auPrcIn [ ]:
@kfp.dsl.pipeline(name="multicontender-vs-champion")
def pipeline(
champion_model_resource: str,
contender_model_resources: list,
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
champion = GetVertexModelOp(model_resource_name=champion_model_resource)
# pretend to retrain and evaluate the champion with production data
champion_metrics = {"logLoss": 1.3, "auPrc": 0.86}
# upload the metrics for the champion version
import_champion_metrics = import_classification_metrics(
display_name="production",
metrics=champion_metrics,
parent_model_resource=champion_model_resource,
project=project,
region=region,
).after(champion)
ix = 0
with kfp.dsl.ParallelFor(contender_model_resources).after(
import_champion_metrics
) as contender_model_resource:
contender = GetVertexModelOp(model_resource_name=contender_model_resource)
# pretend to retrain and evaluate the champion with production data
contender_metrics = {"logLoss": 1.1, "auPrc": 0.88}
ix += 1
import_contender_metrics = import_classification_metrics(
display_name=f"production_{ix}",
metrics=contender_metrics,
parent_model_resource=contender_model_resource,
project=project,
region=region,
).after(contender)
# Select the best model
compare = compare_metrics(
champion_model_resource,
contender_model_resources,
).after(import_contender_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=champion.outputs["model"],
endpoint=endpoint.output,
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="multicontender_vs_champion.json"
)In [ ]:
PIPELINE_ROOT = "{}/pipeline_root/control".format(BUCKET_URI)
job = aiplatform.PipelineJob(
display_name="multicontender_vs_champion",
template_path="multicontender_vs_champion.json",
pipeline_root=PIPELINE_ROOT,
parameter_values={
"champion_model_resource": champion_model.resource_name,
"contender_model_resources": [
contender_model_1.resource_name,
contender_model_2.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,
)
job.run()In [ ]:
gca_resource = endpoint.list(filter="display_name=production")[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 model resource
champion_model.delete()
# Delete the pipeline job resource
job.delete()
# Delete Cloud Storage objects that were created
delete_bucket = True
if delete_bucket:
! gsutil -m rm -r $BUCKET_URI
# Remove the local pipeline package file
! rm multicontender_vs_champion.json