mirror of
https://github.com/GoogleCloudPlatform/vertex-ai-samples.git
synced 2026-09-26 14:42:04 +00:00
38 KiB
38 KiB
In [ ]:
# Copyright 2022 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 [ ]:
!pip install -U google-cloud-pipeline-components==1.0.25 -qIn [ ]:
import os
if not os.getenv("IS_TESTING"):
# Automatically restart kernel after installs
import IPython
app = IPython.Application.instance()
app.kernel.do_shutdown(True)In [ ]:
PROJECT_ID = "[your-project-id]" # @param {type:"string"}In [ ]:
if PROJECT_ID == "" or PROJECT_ID is None or PROJECT_ID == "[your-project-id]":
# Get your GCP project id from gcloud
shell_output = !gcloud config list --format 'value(core.project)' 2>/dev/null
PROJECT_ID = shell_output[0]
print("Project ID:", PROJECT_ID)In [ ]:
! gcloud config set project $PROJECT_IDIn [ ]:
REGION = "[your-region]" # @param {type: "string"}
if REGION == "[your-region]":
REGION = "us-central1"In [ ]:
# If you are running this notebook in Colab, run this cell and follow the
# instructions to authenticate your GCP account. This provides access to your
# Cloud Storage bucket and lets you submit training jobs and prediction
# requests.
import os
import sys
# If on Vertex AI Workbench, then don't execute this code
IS_COLAB = "google.colab" in sys.modules
if not os.path.exists("/opt/deeplearning/metadata/env_version") and not os.getenv(
"DL_ANACONDA_HOME"
):
if "google.colab" in sys.modules:
from google.colab import auth as google_auth
google_auth.authenticate_user()
# If you are running this notebook locally, replace the string below with the
# path to your service account key and run this cell to authenticate your GCP
# account.
elif not os.getenv("IS_TESTING"):
%env GOOGLE_APPLICATION_CREDENTIALS '[your-service-account-key-path]'In [ ]:
BUCKET_URI = "gs://[your-bucket-name]" # @param {type:"string"}
GENERATE_BUCKET_URI = True # @param {type:"boolean"}In [ ]:
import uuid
if GENERATE_BUCKET_URI:
bucket_name = "gs://test-{}".format(uuid.uuid4())
!gsutil mb -p {PROJECT_ID} -l {REGION} {bucket_name}
# set GCS bucket object TTL to 7 days
!echo '{"rule":[{"action": {"type": "Delete"},"condition": {"age": 7}}]}' > gcs_lifecycle.tmp
!gsutil lifecycle set gcs_lifecycle.tmp {bucket_name}
!rm gcs_lifecycle.tmp
BUCKET_URI = bucket_name
print(f"changed BUCKET_URI to {BUCKET_URI} due to GENERATE_BUCKET_URI is True")
if BUCKET_URI == "" or BUCKET_URI is None or BUCKET_URI == "gs://[your-bucket-name]":
BUCKET_URI = "gs://" + PROJECT_ID + "aip-" + uuid.uuid4()
! gsutil ls -b $BUCKET_URI || gsutil mb -l $DATA_REGION $BUCKET_URIIn [ ]:
! gsutil ls -al $BUCKET_URIIn [ ]:
SERVICE_ACCOUNT = "[your-service-account]" # @param {type:"string"}In [ ]:
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 required modules
import json
from typing import Any, Dict, List
from google.cloud import aiplatform, storage
from google_cloud_pipeline_components.experimental.automl.tabular import \
utils as automl_tabular_utilsIn [ ]:
aiplatform.init(project=PROJECT_ID, location=REGION)In [ ]:
#Get the bucket name and path.
def get_bucket_name_and_path(uri):
no_prefix_uri = uri[len("gs://") :]
splits = no_prefix_uri.split("/")
return splits[0], "/".join(splits[1:])
#Download from the bucket.
def download_from_gcs(uri):
bucket_name, path = get_bucket_name_and_path(uri)
storage_client = storage.Client(project=PROJECT_ID)
bucket = storage_client.get_bucket(bucket_name)
blob = bucket.blob(path)
return blob.download_as_string()
#Write content in to the bucket.
def write_to_gcs(uri: str, content: str):
bucket_name, path = get_bucket_name_and_path(uri)
storage_client = storage.Client()
bucket = storage_client.get_bucket(bucket_name)
blob = bucket.blob(path)
blob.upload_from_string(content)
#Generate auto transformations.
def generate_auto_transformation(column_names: List[str]) -> List[Dict[str, Any]]:
transformations = []
for column_name in column_names:
transformations.append({"auto": {"column_name": column_name}})
return transformations
#Write auto transformations in to the bucket.
def write_auto_transformations(uri: str, column_names: List[str]):
transformations = generate_auto_transformation(column_names)
write_to_gcs(uri, json.dumps(transformations))
#Get the task details filter with task name.
def get_task_detail(
task_details: List[Dict[str, Any]], task_name: str
) -> List[Dict[str, Any]]:
for task_detail in task_details:
if task_detail.task_name == task_name:
return task_detail
#Get the deployed model uri from task details.
def get_deployed_model_uri(
task_details,
):
ensemble_task = get_task_detail(task_details, "model-upload")
return ensemble_task.outputs["model"].artifacts[0].uri
#Get the model uri from the task details.
def get_no_custom_ops_model_uri(task_details):
ensemble_task = get_task_detail(task_details, "automl-tabular-ensemble")
return download_from_gcs(
ensemble_task.outputs["model_without_custom_ops"].artifacts[0].uri
)
#Get the feature attributions from task details.
def get_feature_attributions(
task_details,
):
ensemble_task = get_task_detail(task_details, "model-evaluation-2")
return download_from_gcs(
ensemble_task.outputs["evaluation_metrics"]
.artifacts[0]
.metadata["explanation_gcs_path"]
)
#Get the evaluation metrics from task details.
def get_evaluation_metrics(
task_details,
):
ensemble_task = get_task_detail(task_details, "model-evaluation")
return download_from_gcs(
ensemble_task.outputs["evaluation_metrics"].artifacts[0].uri
)
#Print the parsed json.
def load_and_print_json(s):
parsed = json.loads(s)
print(json.dumps(parsed, indent=2, sort_keys=True))In [ ]:
run_evaluation = True # @param {type:"boolean"}
run_distillation = False # @param {type:"boolean"}
root_dir = os.path.join(BUCKET_URI, "automl_tabular_pipeline")
prediction_type = "classification"
optimization_objective = "minimize-log-loss"
target_column = "deposit"
data_source_csv_filenames = (
"gs://cloud-samples-data/vertex-ai/tabular-workflows/datasets/bank-marketing/train.csv"
)
data_source_bigquery_table_path = None # format: bq://bq_project.bq_dataset.bq_table
timestamp_split_key = None # timestamp column name when using timestamp split
stratified_split_key = None # target column name when using stratified split
training_fraction = 0.8
validation_fraction = 0.1
test_fraction = 0.1
predefined_split_key = None
if predefined_split_key:
training_fraction = None
validation_fraction = None
test_fraction = None
weight_column = None
features = [
"age",
"job",
"marital",
"education",
"default",
"balance",
"housing",
"loan",
"contact",
"day",
"month",
"duration",
"campaign",
"pdays",
"previous",
"poutcome",
]
transformations = generate_auto_transformation(features)
transform_config_path = os.path.join(root_dir, f"transform_config_{uuid.uuid4()}.json")
write_to_gcs(transform_config_path, json.dumps(transformations))In [ ]:
# Dataflow's fully qualified subnetwork name, when empty the default subnetwork will be used.
# Fully qualified subnetwork name is in the form of
# https://www.googleapis.com/compute/v1/projects/HOST_PROJECT_ID/regions/REGION_NAME/subnetworks/SUBNETWORK_NAME
# reference: https://cloud.google.com/dataflow/docs/guides/specifying-networks#example_network_and_subnetwork_specifications
dataflow_subnetwork = None # @param {type:"string"}
# Specifies whether Dataflow workers use public IP addresses.
dataflow_use_public_ips = True # @param {type:"boolean"}In [ ]:
study_spec_parameters_override = [
{
"parameter_id": "model_type",
"categorical_value_spec": {
"values": [
"nn"
] # The default value is ["nn", "boosted_trees"], this reduces the search space
},
}
]
worker_pool_specs_override = [
{"machine_spec": {"machine_type": "n1-standard-8"}}, # override for TF chief node
{}, # override for TF worker node, since it's not used, leave it empty
{}, # override for TF ps node, since it's not used, leave it empty
{
"machine_spec": {
"machine_type": "n1-standard-4" # override for TF evaluator node
}
},
]
# Number of weak models in the final ensemble model is
# stage_2_num_selected_trials * 5. If unspecified, 5 is the default value for
# stage_2_num_selected_trials.
stage_2_num_selected_trials = 5
# The pipeline output a TF saved model contains the following TF custom op:
# - https://github.com/google/struct2tensor
#
# There are a few ways to run the model:
# - Official prediction server docker image
# Please follow the "Run the model server" section in
# https://cloud.google.com/vertex-ai/docs/export/export-model-tabular#run-server
# - Python or cpp runtimes like TF serving
# Please set export_additional_model_without_custom_ops so the pipeline
# outputs an additional model does does not depend on struct2tensor.
# - `get_no_custom_ops_model_uri` shows how to get the model artifact URI.
# - The input to the model is a dictionary of feature name to tensor. Use
# `saved_model_cli show --dir {saved_model.pb's path} --signature_def serving_default --tag serve`
# to find out more details.
export_additional_model_without_custom_ops = False
train_budget_milli_node_hours = 1000 # 1 hour
(
template_path,
parameter_values,
) = automl_tabular_utils.get_automl_tabular_pipeline_and_parameters(
PROJECT_ID,
REGION,
root_dir,
target_column,
prediction_type,
optimization_objective,
transform_config_path,
train_budget_milli_node_hours,
data_source_csv_filenames=data_source_csv_filenames,
data_source_bigquery_table_path=data_source_bigquery_table_path,
weight_column=weight_column,
predefined_split_key=predefined_split_key,
timestamp_split_key=timestamp_split_key,
stratified_split_key=stratified_split_key,
training_fraction=training_fraction,
validation_fraction=validation_fraction,
test_fraction=test_fraction,
study_spec_parameters_override=study_spec_parameters_override,
stage_1_tuner_worker_pool_specs_override=worker_pool_specs_override,
cv_trainer_worker_pool_specs_override=worker_pool_specs_override,
run_evaluation=run_evaluation,
run_distillation=run_distillation,
dataflow_subnetwork=dataflow_subnetwork,
dataflow_use_public_ips=dataflow_use_public_ips,
export_additional_model_without_custom_ops=export_additional_model_without_custom_ops,
)
job_id = "automl-tabular-{}".format(uuid.uuid4())
job = aiplatform.PipelineJob(
display_name=job_id,
location=REGION, # launches the pipeline job in the specified region
template_path=template_path,
job_id=job_id,
pipeline_root=root_dir,
parameter_values=parameter_values,
enable_caching=False,
)
job.run(service_account=SERVICE_ACCOUNT)
pipeline_task_details = job.gca_resource.job_detail.task_details
if export_additional_model_without_custom_ops:
print(
"trained model without custom TF ops:",
get_no_custom_ops_model_uri(pipeline_task_details),
)
if run_evaluation:
print("evaluation metrics:")
load_and_print_json(get_evaluation_metrics(pipeline_task_details))
print("feature attributions:")
load_and_print_json(get_feature_attributions(pipeline_task_details))In [ ]:
stage_1_tuner_task = get_task_detail(
pipeline_task_details, "automl-tabular-stage-1-tuner"
)
stage_1_tuning_result_artifact_uri = (
stage_1_tuner_task.outputs["tuning_result_output"].artifacts[0].uri
)In [ ]:
(
template_path,
parameter_values,
) = automl_tabular_utils.get_skip_architecture_search_pipeline_and_parameters(
PROJECT_ID,
REGION,
root_dir,
target_column,
prediction_type,
optimization_objective,
transform_config_path,
train_budget_milli_node_hours,
data_source_csv_filenames=data_source_csv_filenames,
data_source_bigquery_table_path=data_source_bigquery_table_path,
weight_column=weight_column,
predefined_split_key=predefined_split_key,
timestamp_split_key=timestamp_split_key,
stratified_split_key=stratified_split_key,
training_fraction=training_fraction,
validation_fraction=validation_fraction,
test_fraction=test_fraction,
stage_1_tuning_result_artifact_uri=stage_1_tuning_result_artifact_uri,
run_evaluation=run_evaluation,
dataflow_subnetwork=dataflow_subnetwork,
dataflow_use_public_ips=dataflow_use_public_ips,
)
job_id = "automl-tabular-skip-architecture-search-{}".format(uuid.uuid4())
job = aiplatform.PipelineJob(
display_name=job_id,
location=REGION, # launches the pipeline job in the specified region
template_path=template_path,
job_id=job_id,
pipeline_root=root_dir,
parameter_values=parameter_values,
enable_caching=False,
)
job.run(service_account=SERVICE_ACCOUNT)
# Get model URI
skip_architecture_search_pipeline_task_details = (
job.gca_resource.job_detail.task_details
)
if export_additional_model_without_custom_ops:
print(
"trained model without custom TF ops:",
get_no_custom_ops_model_uri(pipeline_task_details),
)In [ ]:
if os.getenv("IS_TESTING"):
! gsutil rm -r $BUCKET_URI
Run in Colab
View on GitHub