mirror of
https://github.com/GoogleCloudPlatform/vertex-ai-samples.git
synced 2026-09-27 15:42:05 +00:00
Compare commits
7
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
358edc4402 | ||
|
|
452acae647 | ||
|
|
700dc31dd6 | ||
|
|
03651fcde1 | ||
|
|
0ee6256650 | ||
|
|
aa58ef0c1f | ||
|
|
f9cd37e7ae |
@@ -1,6 +1,5 @@
|
||||
* @vertex-ai-samples-contributors @GoogleCloudPlatform/cloudml-samples-owners
|
||||
/tf_agents_bandits_movie_recommendation_with_kfp_and_vertex_sdk @yinghsienwu
|
||||
/pytorch_pre_built_images_deployment @googleapis/vertex-prediction-team
|
||||
/pytorch_text_classification_using_vertex_sdk_and_gcloud @RajeshThallam
|
||||
/pytorch_text_classification_using_vertex_sdk_and_gcloud @RajeshThallam @ultrons
|
||||
/sklearn_text_classification_from_script_using_vertex_sdk @maxhardt
|
||||
|
||||
@@ -2,5 +2,4 @@ cpr_model_server.py
|
||||
entrypoint.py
|
||||
state_dict.pth
|
||||
config.json
|
||||
**/__pycache__
|
||||
!testdata/**
|
||||
**/__pycache__
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
## About CPR
|
||||
|
||||
CPR ([custom prediction routines](https://github.com/googleapis/python-aiplatform/blob/main/google/cloud/aiplatform/prediction/README.md)) is a framework designed by Google Cloud developers to make it easier to combine machine learning models with custom preprocessing and postprocessing logic in a real-time serving application.
|
||||
CPR ([custom prediction routines](https://github.com/googleapis/python-aiplatform/blob/custom-prediction-routine/google/cloud/aiplatform/prediction/README.md)) is a framework designed by Google Cloud developers to make it easier to combine machine learning models with custom preprocessing and postprocessing logic in a real-time serving application.
|
||||
|
||||
## Using this example
|
||||
|
||||
@@ -34,23 +34,6 @@ Finally, install the Python modules required to build and run the model server:
|
||||
pip install -r requirements.txt
|
||||
```
|
||||
|
||||
### Auth
|
||||
|
||||
This example uses Google Cloud Storage for hosting model artifacts and Artifact Registry to store the container image.
|
||||
You'll need to authorize yourself before you can interact with these.
|
||||
|
||||
First, log in to GCP with application default credentials:
|
||||
```sh
|
||||
gcloud auth application-default login
|
||||
```
|
||||
|
||||
Next, if you haven't done so already, set up the [gcloud credential helper](https://cloud.google.com/artifact-registry/docs/docker/authentication)
|
||||
for the Artifact Registry region where you intend to host the image.
|
||||
```
|
||||
gcloud auth configure-docker <region>-docker.pkg.dev
|
||||
```
|
||||
|
||||
|
||||
### Predictor
|
||||
|
||||
The `TimmPredictor` class in `timm_serving/predictor.py` implements most of the important logic for the server.
|
||||
|
||||
@@ -60,9 +60,9 @@ class CPRConfig(object):
|
||||
image: str = "timm_predictor:latest"
|
||||
artifact_local_dir: str = ""
|
||||
region: str = "us-central1"
|
||||
project_id: str = "<your project ID here>"
|
||||
project_id: str = "samthrasher-experimental"
|
||||
repository: str = "cpr-images"
|
||||
artifact_gcs_dir: str = "gs://<your bucket ID here>/timm-vit224/"
|
||||
artifact_gcs_dir: str = "gs://samthrasher-cpr-example/timm-vit224/"
|
||||
model_name: str = ""
|
||||
endpoint_name: str = ""
|
||||
machine_type: str = "n1-standard-2"
|
||||
|
||||
@@ -5,4 +5,4 @@ timm==0.5.4
|
||||
smart_open==6.0.0
|
||||
|
||||
google-cloud-storage>=1.26.0,<2.0.0dev
|
||||
google-cloud-aiplatform[prediction]>=1.16.0
|
||||
google-cloud-aiplatform[prediction] @ git+https://github.com/googleapis/python-aiplatform.git@custom-prediction-routine
|
||||
@@ -70,10 +70,7 @@ class PredictorUnitTests(absltest.TestCase):
|
||||
def setUp(self):
|
||||
super().setUp()
|
||||
self.config = CPRConfig()
|
||||
try:
|
||||
self.config.load()
|
||||
except FileNotFoundError:
|
||||
logging.info("No saved config file found, using default values.")
|
||||
self.config.load()
|
||||
self.predictor = predictor.TimmPredictor()
|
||||
|
||||
def test_load_from_saved_state_dict_ok(self):
|
||||
@@ -173,10 +170,7 @@ class ServerEndToEndTests(absltest.TestCase):
|
||||
def setUp(self):
|
||||
super().setUp()
|
||||
self.config = CPRConfig()
|
||||
try:
|
||||
self.config.load()
|
||||
except FileNotFoundError:
|
||||
logging.info("No saved config file found, using default values.")
|
||||
self.config.load()
|
||||
self.local_model = cpr.LocalModel(
|
||||
serving_container_spec=aiplatform.gapic.ModelContainerSpec(
|
||||
image_uri=self.config.image
|
||||
|
||||
-1
@@ -1 +0,0 @@
|
||||
blah
|
||||
BIN
Binary file not shown.
@@ -1,30 +0,0 @@
|
||||
# PyTorch Deployment on Google Cloud: Text Classification
|
||||
|
||||
**This is an Experimental release**, covered by the Pre-GA Offerings Terms of your Google Cloud Platform [Terms of Service](https://cloud.google.com/terms).
|
||||
|
||||
Experiments are focused on validating a prototype and are not guaranteed to be released. They are not intended for production use or covered by any SLA, support obligation, or deprecation policy and might be subject to backward-incompatible changes.
|
||||
|
||||
**Kindly drop us a note before you run any scale tests.**
|
||||
|
||||
**Do not hesitate to contact vertexai-prediction-preview-feedback@google.com if you have any questions or run into any issues.**
|
||||
|
||||
The projects need to be added to the allowlist in order to deploy PyTorch models using Vertex AI Prediction pre-built PyTorch images. If you are interested in the feature, please send an email to vertexai-prediction-preview-feedback@google.com to provide your project numbers OR project ids.
|
||||
|
||||
## Overview
|
||||
|
||||
In the PyTorch on Google Cloud series of blog posts, we aim to share how to deploy PyTorch models at scale on [Vertex AI](https://cloud.google.com/vertex-ai).
|
||||
|
||||
This tutorial on text classification shows how to deploy a PyTorch based text classification model on [Vertex AI](https://cloud.google.com/vertex-ai/docs/start/client-libraries#python) using Vertex SDK and [`gcloud ai`](https://cloud.google.com/sdk/gcloud/reference/beta/ai).
|
||||
|
||||
## Notebooks
|
||||
|
||||
| <h4>Notebook</h4> | <h4>Description</h4> |
|
||||
| :-------- | :------- |
|
||||
| [pytorch-text-classification-vertex-ai-deploy.ipynb](./pytorch-text-classification-vertex-ai-deploy.ipynb) | Notebook to show deploying a PyTorch model on Vertex AI |
|
||||
|
||||
## Folders
|
||||
|
||||
|
||||
| <h4>Folder Name</h4> | <h4>Description</h4> |
|
||||
| :-------- | :------- |
|
||||
| [`predictor`](./predictor) | Folder with custom prediction handler to deploy a PyTorch model to Vertex Prediction. In the [notebook](./pytorch-text-classification-vertex-ai-deploy.ipynb), this folder is used for deploying a PyTorch model on Vertex AI using Vertex Prediction pre-built PyTorch images |
|
||||
@@ -1,91 +0,0 @@
|
||||
|
||||
import os
|
||||
import json
|
||||
import logging
|
||||
|
||||
import torch
|
||||
from transformers import AutoModelForSequenceClassification, AutoTokenizer
|
||||
from ts.torch_handler.base_handler import BaseHandler
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class TransformersClassifierHandler(BaseHandler):
|
||||
"""
|
||||
The handler takes an input string and returns the classification text
|
||||
based on the serialized transformers checkpoint.
|
||||
"""
|
||||
def __init__(self):
|
||||
super(TransformersClassifierHandler, self).__init__()
|
||||
self.initialized = False
|
||||
|
||||
def initialize(self, ctx):
|
||||
""" Loads the model.pt file and initialized the model object.
|
||||
Instantiates Tokenizer for preprocessor to use
|
||||
Loads labels to name mapping file for post-processing inference response
|
||||
"""
|
||||
self.manifest = ctx.manifest
|
||||
|
||||
properties = ctx.system_properties
|
||||
model_dir = properties.get("model_dir")
|
||||
self.device = torch.device("cuda:" + str(properties.get("gpu_id")) if torch.cuda.is_available() else "cpu")
|
||||
|
||||
# Read model serialize/pt file
|
||||
serialized_file = self.manifest["model"]["serializedFile"]
|
||||
model_pt_path = os.path.join(model_dir, serialized_file)
|
||||
if not os.path.isfile(model_pt_path):
|
||||
raise RuntimeError("Missing the model.pt or pytorch_model.bin file")
|
||||
|
||||
# Load model
|
||||
self.model = AutoModelForSequenceClassification.from_pretrained(model_dir)
|
||||
self.model.to(self.device)
|
||||
self.model.eval()
|
||||
logger.debug('Transformer model from path {0} loaded successfully'.format(model_dir))
|
||||
|
||||
# Ensure to use the same tokenizer used during training
|
||||
self.tokenizer = AutoTokenizer.from_pretrained('bert-base-cased')
|
||||
|
||||
# Read the mapping file, index to object name
|
||||
mapping_file_path = os.path.join(model_dir, "index_to_name.json")
|
||||
|
||||
if os.path.isfile(mapping_file_path):
|
||||
with open(mapping_file_path) as f:
|
||||
self.mapping = json.load(f)
|
||||
else:
|
||||
logger.warning('Missing the index_to_name.json file. Inference output will default.')
|
||||
self.mapping = {"0": "Negative", "1": "Positive"}
|
||||
|
||||
self.initialized = True
|
||||
|
||||
def preprocess(self, data):
|
||||
""" Preprocessing input request by tokenizing
|
||||
Extend with your own preprocessing steps as needed
|
||||
"""
|
||||
text = data[0].get("data")
|
||||
if text is None:
|
||||
text = data[0].get("body")
|
||||
sentences = text.decode('utf-8')
|
||||
logger.info("Received text: '%s'", sentences)
|
||||
|
||||
# Tokenize the texts
|
||||
tokenizer_args = ((sentences,))
|
||||
inputs = self.tokenizer(*tokenizer_args,
|
||||
padding='max_length',
|
||||
max_length=128,
|
||||
truncation=True,
|
||||
return_tensors = "pt")
|
||||
return inputs
|
||||
|
||||
def inference(self, inputs):
|
||||
""" Predict the class of a text using a trained transformer model.
|
||||
"""
|
||||
prediction = self.model(inputs['input_ids'].to(self.device))[0].argmax().item()
|
||||
|
||||
if self.mapping:
|
||||
prediction = self.mapping[str(prediction)]
|
||||
|
||||
logger.info("Model predicted: '%s'", prediction)
|
||||
return [prediction]
|
||||
|
||||
def postprocess(self, inference_output):
|
||||
return inference_output
|
||||
@@ -1,5 +0,0 @@
|
||||
|
||||
{
|
||||
"0": "Negative",
|
||||
"1": "Positive"
|
||||
}
|
||||
-1625
File diff suppressed because it is too large
Load Diff
+13
-13
@@ -658,8 +658,8 @@
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"dataset = load_dataset(\"imdb\")\n",
|
||||
"dataset"
|
||||
"datasets = load_dataset(\"imdb\")\n",
|
||||
"datasets"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -668,7 +668,7 @@
|
||||
"id": "RzfPtOMoIrIu"
|
||||
},
|
||||
"source": [
|
||||
"The `dataset` object itself is [`DatasetDict`](https://huggingface.co/docs/datasets/package_reference/main_classes.html#datasetdict), which contains one key for the training, validation and test set."
|
||||
"The `datasets` object itself is [`DatasetDict`](https://huggingface.co/docs/datasets/package_reference/main_classes.html#datasetdict), which contains one key for the training, validation and test set."
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -681,12 +681,12 @@
|
||||
"source": [
|
||||
"print(\n",
|
||||
" \"Total # of rows in training dataset {} and size {:5.2f} MB\".format(\n",
|
||||
" dataset[\"train\"].shape[0], dataset[\"train\"].size_in_bytes / (1024 * 1024)\n",
|
||||
" datasets[\"train\"].shape[0], datasets[\"train\"].size_in_bytes / (1024 * 1024)\n",
|
||||
" )\n",
|
||||
")\n",
|
||||
"print(\n",
|
||||
" \"Total # of rows in test dataset {} and size {:5.2f} MB\".format(\n",
|
||||
" dataset[\"test\"].shape[0], dataset[\"test\"].size_in_bytes / (1024 * 1024)\n",
|
||||
" datasets[\"test\"].shape[0], datasets[\"test\"].size_in_bytes / (1024 * 1024)\n",
|
||||
" )\n",
|
||||
")"
|
||||
]
|
||||
@@ -708,7 +708,7 @@
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"dataset[\"train\"][0]"
|
||||
"datasets[\"train\"][0]"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -728,7 +728,7 @@
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"label_list = dataset[\"train\"].unique(\"label\")\n",
|
||||
"label_list = datasets[\"train\"].unique(\"label\")\n",
|
||||
"label_list"
|
||||
]
|
||||
},
|
||||
@@ -779,7 +779,7 @@
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"show_random_elements(dataset[\"train\"])"
|
||||
"show_random_elements(datasets[\"train\"])"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -883,7 +883,7 @@
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"example = dataset[\"train\"][4]\n",
|
||||
"example = datasets[\"train\"][4]\n",
|
||||
"print(example)"
|
||||
]
|
||||
},
|
||||
@@ -920,7 +920,7 @@
|
||||
"source": [
|
||||
"# Dataset loading repeated here to make this cell idempotent\n",
|
||||
"# Since we are over-writing datasets variable\n",
|
||||
"dataset = load_dataset(\"imdb\")\n",
|
||||
"datasets = load_dataset(\"imdb\")\n",
|
||||
"\n",
|
||||
"# Mapping labels to ids\n",
|
||||
"# NOTE: We can extract this automatically but the `Unique` method of the datasets\n",
|
||||
@@ -948,7 +948,7 @@
|
||||
"\n",
|
||||
"\n",
|
||||
"# apply preprocessing function to input examples\n",
|
||||
"dataset = dataset.map(preprocess_function, batched=True, load_from_cache_file=True)"
|
||||
"datasets = datasets.map(preprocess_function, batched=True, load_from_cache_file=True)"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -1091,8 +1091,8 @@
|
||||
"trainer = Trainer(\n",
|
||||
" model,\n",
|
||||
" args,\n",
|
||||
" train_dataset=dataset[\"train\"],\n",
|
||||
" eval_dataset=dataset[\"test\"],\n",
|
||||
" train_dataset=datasets[\"train\"],\n",
|
||||
" eval_dataset=datasets[\"test\"],\n",
|
||||
" data_collator=default_data_collator,\n",
|
||||
" tokenizer=tokenizer,\n",
|
||||
" compute_metrics=compute_metrics,\n",
|
||||
|
||||
@@ -17,7 +17,6 @@
|
||||
/explainable_ai/SDK_Custom_Container_XAI.ipynb @brianchunkang
|
||||
/matching_engine/sdk_matching_engine_for_indexing.ipynb @ivanmkc
|
||||
/matching_engine/matching_engine_for_indexing.ipynb @yinghsienwu
|
||||
/matching_engine/stream_update_for_matching_engine.ipynb @peterping666
|
||||
/sdk/pytorch_lightning_custom_container_training.ipynb @brianchunkang
|
||||
/tensorboard @yfang1
|
||||
/feature_store @nayaknishant @morgandu
|
||||
|
||||
+219
-87
@@ -32,18 +32,18 @@
|
||||
"<table align=\"left\">\n",
|
||||
"\n",
|
||||
" <td>\n",
|
||||
" <a href=\"https://colab.research.google.com/github/GoogleCloudPlatform/vertex-ai-samples/blob/master/notebooks/official/bigquery_ml/bqml-online-prediction.ipynb\">\n",
|
||||
" <a href=\"https://colab.research.google.com/github/GoogleCloudPlatform/vertex-ai-samples/blob/master/notebooks/community/bigquery_ml/bqml-online-prediction.ipynb\">\n",
|
||||
" <img src=\"https://cloud.google.com/ml-engine/images/colab-logo-32px.png\" alt=\"Colab logo\"> Run in Colab\n",
|
||||
" </a>\n",
|
||||
" </td>\n",
|
||||
" <td>\n",
|
||||
" <a href=\"https://github/GoogleCloudPlatform/vertex-ai-samples/blob/master/notebooks/official/bigquery_ml/bqml-online-prediction.ipynb\">\n",
|
||||
" <a href=\"https://github/GoogleCloudPlatform/vertex-ai-samples/blob/master/notebooks/community/bigquery_ml/bqml-online-prediction.ipynb\">\n",
|
||||
" <img src=\"https://cloud.google.com/ml-engine/images/github-logo-32px.png\" alt=\"GitHub logo\">\n",
|
||||
" View on GitHub\n",
|
||||
" </a>\n",
|
||||
" </td>\n",
|
||||
" <td>\n",
|
||||
" <a href=\"https://console.cloud.google.com/vertex-ai/workbench/deploy-notebook?download_url=https://raw.githubusercontent.com/GoogleCloudPlatform/vertex-ai-samples/blob/master/notebooks/official/bigquery_ml/bqml-online-prediction.ipynb\">\n",
|
||||
" <a href=\"https://console.cloud.google.com/vertex-ai/workbench/deploy-notebook?download_url=https://raw.githubusercontent.com/GoogleCloudPlatform/vertex-ai-samples/blob/master/notebooks/community/bigquery_ml/bqml-online-prediction.ipynb\">\n",
|
||||
" <img src=\"https://lh3.googleusercontent.com/UiNooY4LUgW_oTvpsNhPpQzsstV5W8F7rYgxgGBD85cWJoLmrOzhVs_ksK_vgx40SHs7jCqkTkCk=e14-rj-sc0xffffff-h130-w32\" alt=\"Vertex AI logo\">\n",
|
||||
" Open in Vertex AI Workbench\n",
|
||||
" </a>\n",
|
||||
@@ -63,7 +63,7 @@
|
||||
"\n",
|
||||
"### Dataset\n",
|
||||
"\n",
|
||||
"The dataset, <a href=\"https://console.cloud.google.com/bigquery?project=bigquery-public-data&d=ga4_obfuscated_sample_ecommerce&p=bigquery-public-data&page=dataset\" target=\"_blank\">available publicly on BigQuery</a>, comes from obfuscated <a href=\"https://support.google.com/analytics/answer/10937659\" target=\"_blank\">Google Analytics 4 data</a> from the <a href=\"https://shop.googlemerchandisestore.com/\" target=\"_blank\">Google Merchandise Store</a>).\n",
|
||||
"The dataset, [available publicly on BigQuery](https://console.cloud.google.com/bigquery?project=bigquery-public-data&d=ga4_obfuscated_sample_ecommerce&p=bigquery-public-data&page=dataset), comes from obfuscated [Google Analytics 4 data](https://support.google.com/analytics/answer/10937659) from the [Google Merchandise Store](https://shop.googlemerchandisestore.com/).\n",
|
||||
"\n",
|
||||
"### Objective\n",
|
||||
"\n",
|
||||
@@ -95,9 +95,9 @@
|
||||
"* Vertex AI\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"Learn about <a href=\"https://cloud.google.com/bigquery/pricing\" target=\"_blank\">BigQuery Pricing</a>, <a href=\"https://cloud.google.com/bigquery-ml/pricing\" target=\"_blank\">BigQuery ML pricing</a>, <a href=\"https://cloud.google.com/vertex-ai/pricing\" target=\"_blank\">Vertex AI\n",
|
||||
"pricing</a>, and use the <a href=\"https://cloud.google.com/products/calculator/\" target=\"_blank\">Pricing\n",
|
||||
"Calculator</a>\n",
|
||||
"Learn about [BigQuery Pricing](https://cloud.google.com/bigquery/pricing), [BigQuery ML pricing](https://cloud.google.com/bigquery-ml/pricing), [Vertex AI\n",
|
||||
"pricing](https://cloud.google.com/vertex-ai/pricing), and use the [Pricing\n",
|
||||
"Calculator](https://cloud.google.com/products/calculator/)\n",
|
||||
"to generate a cost estimate based on your projected usage."
|
||||
]
|
||||
},
|
||||
@@ -128,18 +128,18 @@
|
||||
"* virtualenv\n",
|
||||
"* Jupyter notebook running in a virtual environment with Python 3\n",
|
||||
"\n",
|
||||
"The Google Cloud guide to <a href=\"https://cloud.google.com/python/setup\" target=\"_blank\">Setting up a Python development\n",
|
||||
"environment</a> and the <a href=\"https://jupyter.org/install\" target=\"_blank\">Jupyter\n",
|
||||
"installation guide</a> provide detailed instructions\n",
|
||||
"The Google Cloud guide to [Setting up a Python development\n",
|
||||
"environment](https://cloud.google.com/python/setup) and the [Jupyter\n",
|
||||
"installation guide](https://jupyter.org/install) provide detailed instructions\n",
|
||||
"for meeting these requirements. The following steps provide a condensed set of\n",
|
||||
"instructions:\n",
|
||||
"\n",
|
||||
"1. <a href=\"https://cloud.google.com/sdk/docs/\" target=\"_blank\">Install and initialize the Cloud SDK.</a>\n",
|
||||
"1. [Install and initialize the Cloud SDK.](https://cloud.google.com/sdk/docs/)\n",
|
||||
"\n",
|
||||
"1. <a href=\"https://cloud.google.com/python/setup#installing_python\" target=\"_blank\">Install Python 3.</a>\n",
|
||||
"1. [Install Python 3.](https://cloud.google.com/python/setup#installing_python)\n",
|
||||
"\n",
|
||||
"1. <a href=\"https://cloud.google.com/python/setup#installing_and_using_virtualenv\" target=\"_blank\">Install\n",
|
||||
" virtualenv</a>\n",
|
||||
"1. [Install\n",
|
||||
" virtualenv](https://cloud.google.com/python/setup#installing_and_using_virtualenv)\n",
|
||||
" and create a virtual environment that uses Python 3. Activate the virtual environment.\n",
|
||||
"\n",
|
||||
"1. To install Jupyter, run `pip3 install jupyter` on the\n",
|
||||
@@ -234,13 +234,13 @@
|
||||
"\n",
|
||||
"**The following steps are required, regardless of your notebook environment.**\n",
|
||||
"\n",
|
||||
"1. <a href=\"https://console.cloud.google.com/cloud-resource-manager\" target=\"_blank\">Select or create a Google Cloud project</a>. When you first create an account, you get a $300 free credit towards your compute/storage costs.\n",
|
||||
"1. [Select or create a Google Cloud project](https://console.cloud.google.com/cloud-resource-manager). When you first create an account, you get a $300 free credit towards your compute/storage costs.\n",
|
||||
"\n",
|
||||
"1. <a href=\"https://cloud.google.com/billing/docs/how-to/modify-project\" target=\"_blank\">Make sure that billing is enabled for your project</a>.\n",
|
||||
"1. [Make sure that billing is enabled for your project](https://cloud.google.com/billing/docs/how-to/modify-project).\n",
|
||||
"\n",
|
||||
"1. <a href=\"https://console.cloud.google.com/flows/enableapi?apiid=aiplatform.googleapis.com\" target=\"_blank\">Enable the Vertex AI API</a>.\n",
|
||||
"1. [Enable the Vertex AI API](https://console.cloud.google.com/flows/enableapi?apiid=aiplatform.googleapis.com).\n",
|
||||
"\n",
|
||||
"1. If you are running this notebook locally, you will need to install the <a href=\"https://cloud.google.com/sdk\" target=\"_blank\">Cloud SDK</a>.\n",
|
||||
"1. If you are running this notebook locally, you will need to install the [Cloud SDK](https://cloud.google.com/sdk).\n",
|
||||
"\n",
|
||||
"1. Enter your project ID in the cell below. Then run the cell to make sure the\n",
|
||||
"Cloud SDK uses the right project for all the commands in this notebook.\n",
|
||||
@@ -267,7 +267,7 @@
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"PROJECT_ID = \"[YOUR-PROJECT-ID]\"\n",
|
||||
"PROJECT_ID = \"YOUR-PROJECT-ID\"\n",
|
||||
"\n",
|
||||
"# Get your Google Cloud project ID from gcloud\n",
|
||||
"import os\n",
|
||||
@@ -314,9 +314,9 @@
|
||||
"- Europe: `europe-west4`\n",
|
||||
"- Asia Pacific: `asia-east1`\n",
|
||||
"\n",
|
||||
"You might not be able to use a multi-regional bucket for training with Vertex AI. Not all regions provide support for all Vertex AI services.\n",
|
||||
"You may not use a multi-regional bucket for training with Vertex AI. Not all regions provide support for all Vertex AI services.\n",
|
||||
"\n",
|
||||
"Learn more about <a href=\"https://cloud.google.com/vertex-ai/docs/general/locations\" target=\"_blank\">Vertex AI regions</a>."
|
||||
"Learn more about [Vertex AI regions](https://cloud.google.com/vertex-ai/docs/general/locations)."
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -339,9 +339,9 @@
|
||||
"id": "06571eb4063b"
|
||||
},
|
||||
"source": [
|
||||
"#### UUID\n",
|
||||
"#### Timestamp\n",
|
||||
"\n",
|
||||
"If you are in a live tutorial session, you might be using a shared test account or project. To avoid name collisions between users on resources created, you create a uuid for each instance session, and append it onto the name of resources you create in this tutorial."
|
||||
"If you are in a live tutorial session, you might be using a shared test account or project. To avoid name collisions between users on resources created, you create a timestamp for each instance session, and append it onto the name of resources you create in this tutorial."
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -352,16 +352,9 @@
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"import random\n",
|
||||
"import string\n",
|
||||
"from datetime import datetime\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"# Generate a uuid of a specifed length(default=8)\n",
|
||||
"def generate_uuid(length: int = 8) -> str:\n",
|
||||
" return \"\".join(random.choices(string.ascii_lowercase + string.digits, k=length))\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"UUID = generate_uuid()"
|
||||
"TIMESTAMP = datetime.now().strftime(\"%Y%m%d%H%M%S\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -387,7 +380,8 @@
|
||||
"\n",
|
||||
"**Otherwise**, follow these steps:\n",
|
||||
"\n",
|
||||
"1. In the Cloud Console, go to the <a href=\"https://console.cloud.google.com/apis/credentials/serviceaccountkey\" target=\"_blank\">**Create service account key** page</a>.\n",
|
||||
"1. In the Cloud Console, go to the [**Create service account key**\n",
|
||||
" page](https://console.cloud.google.com/apis/credentials/serviceaccountkey).\n",
|
||||
"\n",
|
||||
"2. Click **Create service account**.\n",
|
||||
"\n",
|
||||
@@ -492,10 +486,7 @@
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"from typing import Union\n",
|
||||
"\n",
|
||||
"import google.cloud.aiplatform as vertex_ai\n",
|
||||
"import pandas as pd\n",
|
||||
"from google.cloud import bigquery"
|
||||
]
|
||||
},
|
||||
@@ -559,17 +550,24 @@
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Wrapper to use BigQuery client to run query/job, return job ID or result as DF\n",
|
||||
"def run_bq_query(sql: str) -> Union[str, pd.DataFrame]:\n",
|
||||
"def bq_query(sql):\n",
|
||||
" \"\"\"\n",
|
||||
" Input: SQL query, as a string, to execute in BigQuery\n",
|
||||
" Returns the query results as a pandas DataFrame, or error, if any\n",
|
||||
" \"\"\"\n",
|
||||
" # Import Exceptions library to help with dataset error catching\n",
|
||||
" from google.cloud.exceptions import BadRequest\n",
|
||||
"\n",
|
||||
" # Try dry run before executing query to catch any errors\n",
|
||||
" job_config = bigquery.QueryJobConfig(dry_run=True, use_query_cache=False)\n",
|
||||
" bq_client.query(sql, job_config=job_config)\n",
|
||||
" try:\n",
|
||||
" job_config = bigquery.QueryJobConfig(dry_run=True, use_query_cache=False)\n",
|
||||
"\n",
|
||||
" bq_client.query(sql, job_config=job_config)\n",
|
||||
"\n",
|
||||
" except BadRequest as err:\n",
|
||||
" print(err)\n",
|
||||
" return\n",
|
||||
"\n",
|
||||
" # If dry run succeeds without errors, proceed to run query\n",
|
||||
" job_config = bigquery.QueryJobConfig()\n",
|
||||
" client_result = bq_client.query(sql, job_config=job_config)\n",
|
||||
"\n",
|
||||
@@ -591,7 +589,7 @@
|
||||
"\n",
|
||||
"BigQuery ML (BQML) provides the capability to train ML tabular models, such as classification, regression, forecasting, and matrix factorization, in BigQuery using SQL syntax directly. BigQuery ML uses the scalable infrastructure of BigQuery ML so you don't need to set up additional infrastructure for training or batch serving.\n",
|
||||
"\n",
|
||||
"Learn more about <a href=\"https://cloud.google.com/bigquery-ml/docs\" target=\"_blank\">BigQuery ML documentation</a>."
|
||||
"Learn more about [BigQuery ML documentation](https://cloud.google.com/bigquery-ml/docs)."
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -602,13 +600,9 @@
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"BQ_DATASET_NAME = f\"ga4_churnprediction_{UUID}\"\n",
|
||||
"BQ_DATASET_NAME = \"ga4_churnprediction\"\n",
|
||||
"\n",
|
||||
"sql_create_dataset = f\"\"\"CREATE SCHEMA IF NOT EXISTS {BQ_DATASET_NAME}\"\"\"\n",
|
||||
"\n",
|
||||
"print(sql_create_dataset)\n",
|
||||
"\n",
|
||||
"run_bq_query(sql_create_dataset)"
|
||||
"bq_query(f\"\"\"CREATE SCHEMA IF NOT EXISTS {BQ_DATASET_NAME}\"\"\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -626,7 +620,7 @@
|
||||
"id": "49dd00d5fbe5"
|
||||
},
|
||||
"source": [
|
||||
"Inpect data that has been pre-processed from <a href=\"https://support.google.com/analytics/answer/10937659\" target=\"_blank\">Google Analytics 4 data from the Google Merchandise Store</a> so that it can be used for classification. For more information on how this data was prepared, read <a href=\"https://cloud.google.com/blog/topics/developers-practitioners/churn-prediction-game-developers-using-google-analytics-4-ga4-and-bigquery-ml\" target=\"_blank\">this blog post</a>.\n",
|
||||
"Inpect data that has been pre-processed from [Google Analytics 4 data from the Google Merchandise Store](https://support.google.com/analytics/answer/10937659) so that it can be used for classification. For more information on how this data was prepared, read [this blog post](https://cloud.google.com/blog/topics/developers-practitioners/churn-prediction-game-developers-using-google-analytics-4-ga4-and-bigquery-ml).\n",
|
||||
"\n",
|
||||
"As seen below, each row represents a single user, and the columns represent their demographic features, their aggregated behavioral features in the first 24 hours of visiting the Google Merchandise Store, and the label (whether the user churned or returned any time after the first 24 hours)."
|
||||
]
|
||||
@@ -647,7 +641,7 @@
|
||||
"LIMIT\n",
|
||||
" 100\n",
|
||||
"\"\"\"\n",
|
||||
"run_bq_query(sql_inspect)"
|
||||
"bq_query(sql_inspect)"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -668,9 +662,9 @@
|
||||
"The query below trains a logistic regression model using BigQuery ML. BigQuery resources are used to train the model.\n",
|
||||
"\n",
|
||||
"In the `OPTIONS` parameter:\n",
|
||||
"* with `model_registry=\"vertex_ai\"`, the BigQuery ML model will automatically be <a href=\"https://cloud.google.com/vertex-ai/docs/model-registry/model-registry-bqml\" target=\"_blank\">registered to Vertex AI Model Registry</a>, which enables you to view all of your registered models and its versions on Google Cloud in one place.\n",
|
||||
"* with `model_registry=\"vertex_ai\"`, the BigQuery ML model will automatically be [registered to Vertex AI Model Registry](https://cloud.google.com/vertex-ai/docs/model-registry/model-registry-bqml), which enables you to view all of your registered models and its versions on Google Cloud in one place.\n",
|
||||
"\n",
|
||||
"* `vertex_ai_model_version_aliases allows you to set aliases to help you keep track of your model version (<a href=\"https://cloud.google.com/vertex-ai/docs/model-registry/model-alias\" target=\"_blank\">documentation</a>)."
|
||||
"* `vertex_ai_model_version_aliases allows you to set aliases to help you keep track of your model version ([documentation](https://cloud.google.com/vertex-ai/docs/model-registry/model-alias))."
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -683,7 +677,7 @@
|
||||
"source": [
|
||||
"# this cell may take ~1 min to run\n",
|
||||
"\n",
|
||||
"BQML_MODEL_NAME = f\"bqml_model_churn_{UUID}\"\n",
|
||||
"BQML_MODEL_NAME = \"bqmlmodelchurn\"\n",
|
||||
"\n",
|
||||
"sql_train_model_bqml = f\"\"\"\n",
|
||||
"CREATE OR REPLACE MODEL {BQ_DATASET_NAME}.{BQML_MODEL_NAME} \n",
|
||||
@@ -702,7 +696,7 @@
|
||||
"\n",
|
||||
"print(sql_train_model_bqml)\n",
|
||||
"\n",
|
||||
"run_bq_query(sql_train_model_bqml)"
|
||||
"bq_query(sql_train_model_bqml)"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -720,7 +714,7 @@
|
||||
"id": "2aaaae772f67"
|
||||
},
|
||||
"source": [
|
||||
"With the model created, you can now evaluate the logistic regression model. Behind the scenes, BigQuery ML automatically <a href=\"https://cloud.google.com/bigquery-ml/docs/reference/standard-sql/bigqueryml-syntax-create#data_split_method\" target=\"_blank\">split the data</a>, which makes it easier to quickly train and evaluate models."
|
||||
"With the model created, you can now evaluate the logistic regression model. Behind the scenes, BigQuery ML automatically [split the data](https://cloud.google.com/bigquery-ml/docs/reference/standard-sql/bigqueryml-syntax-create#data_split_method), which makes it easier to quickly train and evaluate models."
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -740,7 +734,7 @@
|
||||
"\n",
|
||||
"print(sql_evaluate_model)\n",
|
||||
"\n",
|
||||
"run_bq_query(sql_evaluate_model)"
|
||||
"bq_query(sql_evaluate_model)"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -751,7 +745,7 @@
|
||||
"source": [
|
||||
"These metrics help you understand the performance of the model. \n",
|
||||
"\n",
|
||||
"There are various metrics for logistic regression and other model types (full list of metrics can be found in the <a href=\"https://cloud.google.com/bigquery-ml/docs/reference/standard-sql/bigqueryml-syntax-evaluate#mlevaluate_output\" target=\"_blank\">documentation</a>)."
|
||||
"There are various metrics for logistic regression and other model types (full list of metrics can be found in the [documentation](https://cloud.google.com/bigquery-ml/docs/reference/standard-sql/bigqueryml-syntax-evaluate#mlevaluate_output))."
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -771,7 +765,7 @@
|
||||
"source": [
|
||||
"Make a batch prediction in BigQuery ML on the original training data to check the probability of churn for each of the users, as seen in the `probability` column, with the predicted label under the `predicted_churn` column.\n",
|
||||
"\n",
|
||||
"<a href=\"https://cloud.google.com/bigquery-ml/docs/reference/standard-sql/bigqueryml-syntax-explain-predict\" target=\"_blank\">ML.EXPLAIN_PREDICT</a> has built-in <a href=\"https://cloud.google.com/bigquery-ml/docs/reference/standard-sql/bigqueryml-syntax-xai-overview\" target=\"_blank\">Explainable AI</a>. This allows you to see the top contributing features to each prediction and interpret how it was computed."
|
||||
"[ML.EXPLAIN_PREDICT](https://cloud.google.com/bigquery-ml/docs/reference/standard-sql/bigqueryml-syntax-explain-predict) has built-in [Explainable AI](https://cloud.google.com/bigquery-ml/docs/reference/standard-sql/bigqueryml-syntax-xai-overview). This allows you to see the top contributing features to each prediction and interpret how it was computed."
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -793,7 +787,7 @@
|
||||
"\n",
|
||||
"print(sql_explain_predict)\n",
|
||||
"\n",
|
||||
"run_bq_query(sql_explain_predict)"
|
||||
"bq_query(sql_explain_predict)"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -802,7 +796,7 @@
|
||||
"id": "fa1f96c0f452"
|
||||
},
|
||||
"source": [
|
||||
"Since the `top_feature_attributions` is a nested column, you can unnest the array (<a href=\"https://cloud.google.com/bigquery/docs/reference/standard-sql/arrays\" target=\"_blank\">documentation</a>) into separate rows for each of the features. In other words, since ML.EXPLAIN_PREDICT provides the top 5 most important features, using `UNNEST` results in 5 rows per prediction:"
|
||||
"Since the `top_feature_attributions` is a nested column, you can unnest the array ([documentation](https://cloud.google.com/bigquery/docs/reference/standard-sql/arrays)) into separate rows for each of the features. In other words, since ML.EXPLAIN_PREDICT provides the top 5 most important features, using `UNNEST` results in 5 rows per prediction:"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -833,7 +827,7 @@
|
||||
"\n",
|
||||
"print(sql_explain_predict)\n",
|
||||
"\n",
|
||||
"run_bq_query(sql_explain_predict)"
|
||||
"bq_query(sql_explain_predict)"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -853,7 +847,7 @@
|
||||
"source": [
|
||||
"When the model was trained in BigQuery ML, the line `model_registry=\"vertex_ai\"` registered the model to Vertex AI Model Registry automatically upon completion.\n",
|
||||
"\n",
|
||||
"You can view the model on the <a href=\"https://console.cloud.google.com/vertex-ai/models\" target=\"_blank\">Vertex AI Model Registry page</a>, or use the code below to check that it was successfully registered:"
|
||||
"You can view the model on the [Vertex AI Model Registry page](https://console.cloud.google.com/vertex-ai/models), or use the code below to check that it was successfully registered:"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -864,7 +858,12 @@
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"model = vertex_ai.Model(model_name=BQML_MODEL_NAME)\n",
|
||||
"print(f\"BQML_MODEL_NAME = {BQML_MODEL_NAME}\")\n",
|
||||
"\n",
|
||||
"models = vertex_ai.Model.list(\n",
|
||||
" filter=f\"display_name={BQML_MODEL_NAME}\", order_by=\"update_time\"\n",
|
||||
")\n",
|
||||
"model = models[0]\n",
|
||||
"\n",
|
||||
"print(model.gca_resource)"
|
||||
]
|
||||
@@ -884,7 +883,7 @@
|
||||
"id": "b6120dcc1ff6"
|
||||
},
|
||||
"source": [
|
||||
"While BigQuery ML supports batch prediction with <a href=\"https://cloud.google.com/bigquery-ml/docs/reference/standard-sql/bigqueryml-syntax-predict\" target=\"_blank\">ML.PREDICT</a> and <a href=\"https://cloud.google.com/bigquery-ml/docs/reference/standard-sql/bigqueryml-syntax-explain-predict\" target=\"_blank\">ML.EXPLAIN_PREDICT</a>, BigQuery ML is not suitable for real-time predictions where you need low latency predictions with potentially high frequency of requests.\n",
|
||||
"While BigQuery ML supports batch prediction with [ML.PREDICT](https://cloud.google.com/bigquery-ml/docs/reference/standard-sql/bigqueryml-syntax-predict) and [ML.EXPLAIN_PREDICT](https://cloud.google.com/bigquery-ml/docs/reference/standard-sql/bigqueryml-syntax-explain-predict), BigQuery ML is not suitable for real-time predictions where you need low latency predictions with potentially high frequency of requests.\n",
|
||||
"\n",
|
||||
"In other words, deploying the BigQuery ML model to an endpoint enables you to do online predictions."
|
||||
]
|
||||
@@ -907,6 +906,30 @@
|
||||
"To deploy your model to an endpoint, you will first need to create an endpoint before you deploy the model to it."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"id": "3ce73125dff6"
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"def create_endpoint(\n",
|
||||
" project: str,\n",
|
||||
" display_name: str,\n",
|
||||
" location: str,\n",
|
||||
"):\n",
|
||||
" endpoint = vertex_ai.Endpoint.create(\n",
|
||||
" display_name=display_name,\n",
|
||||
" project=project,\n",
|
||||
" location=location,\n",
|
||||
" )\n",
|
||||
"\n",
|
||||
" print(endpoint.display_name)\n",
|
||||
" print(endpoint.resource_name)\n",
|
||||
" return endpoint"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
@@ -915,16 +938,17 @@
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"ENDPOINT_NAME = f\"{BQML_MODEL_NAME}-endpoint\"\n",
|
||||
"endpoint_name = f\"{BQML_MODEL_NAME}-{TIMESTAMP}\"\n",
|
||||
"\n",
|
||||
"endpoint = vertex_ai.Endpoint.create(\n",
|
||||
" display_name=ENDPOINT_NAME,\n",
|
||||
" project=PROJECT_ID,\n",
|
||||
" location=REGION,\n",
|
||||
"print(\n",
|
||||
" f\"\"\"\n",
|
||||
"PROJECT_ID: {PROJECT_ID},\n",
|
||||
"endpoint_name: {endpoint_name}\n",
|
||||
"REGION: {REGION}\n",
|
||||
"\"\"\"\n",
|
||||
")\n",
|
||||
"\n",
|
||||
"print(endpoint.display_name)\n",
|
||||
"print(endpoint.resource_name)"
|
||||
"create_endpoint(PROJECT_ID, endpoint_name, REGION)"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -942,7 +966,31 @@
|
||||
"id": "951ed1693f6b"
|
||||
},
|
||||
"source": [
|
||||
"List the endpoints to make sure it has successfully been created. (You can also view your endpoints on the <a href=\"https://console.cloud.google.com/vertex-ai/endpoints\" target=\"_blank\">Vertex AI Endpoints page</a>)."
|
||||
"List the endpoints to make sure it has successfully been created. You can also view your endpoints on the [Vertex AI Endpoints page](https://console.cloud.google.com/vertex-ai/endpoints?project=polong-contentdev)."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"id": "0a9bad8d9ad4"
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"endpoint = vertex_ai.Endpoint.list(\n",
|
||||
" # filter=f'display_name={endpoint_name}', # optional: filter by specific endpoint name\n",
|
||||
" order_by=\"update_time\"\n",
|
||||
")\n",
|
||||
"endpoint[-1]"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "2431a4d28d97"
|
||||
},
|
||||
"source": [
|
||||
"Retrieve the endpoint id so you can use it in the next step."
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -953,7 +1001,7 @@
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"endpoint.list()"
|
||||
"endpoint[-1].to_dict()"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -971,19 +1019,74 @@
|
||||
"id": "6a90be5b77a2"
|
||||
},
|
||||
"source": [
|
||||
"With the new endpoint, you can now deploy your model."
|
||||
"With the model, you can now deploy it to an endpoint. "
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"id": "c70ecc568ee5"
|
||||
"id": "af323ea42c5b"
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"from typing import Dict, Optional, Sequence, Tuple\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"def deploy_model_with_automatic_resources_sample(\n",
|
||||
" project,\n",
|
||||
" location,\n",
|
||||
" model_name: str,\n",
|
||||
" endpoint: Optional[vertex_ai.Endpoint] = None,\n",
|
||||
" deployed_model_display_name: Optional[str] = None,\n",
|
||||
" traffic_percentage: Optional[int] = 0,\n",
|
||||
" traffic_split: Optional[Dict[str, int]] = None,\n",
|
||||
" min_replica_count: int = 1,\n",
|
||||
" max_replica_count: int = 1,\n",
|
||||
" metadata: Optional[Sequence[Tuple[str, str]]] = (),\n",
|
||||
" sync: bool = True,\n",
|
||||
"):\n",
|
||||
" \"\"\"\n",
|
||||
" model_name: A fully-qualified model resource name or model ID.\n",
|
||||
" Example: \"projects/123/locations/us-central1/models/456\" or\n",
|
||||
" \"456\" when project and location are initialized or passed.\n",
|
||||
" \"\"\"\n",
|
||||
"\n",
|
||||
" model = vertex_ai.Model(model_name=model_name)\n",
|
||||
"\n",
|
||||
" model.deploy(\n",
|
||||
" endpoint=endpoint,\n",
|
||||
" deployed_model_display_name=deployed_model_display_name,\n",
|
||||
" traffic_percentage=traffic_percentage,\n",
|
||||
" traffic_split=traffic_split,\n",
|
||||
" min_replica_count=min_replica_count,\n",
|
||||
" max_replica_count=max_replica_count,\n",
|
||||
" metadata=metadata,\n",
|
||||
" sync=sync,\n",
|
||||
" )\n",
|
||||
"\n",
|
||||
" model.wait()\n",
|
||||
"\n",
|
||||
" print(model.display_name)\n",
|
||||
" print(model.resource_name)\n",
|
||||
" return"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"id": "9e6763369af4"
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# deploying the model to the endpoint may take 10-15 minutes\n",
|
||||
"model.deploy(endpoint=endpoint)"
|
||||
"deploy_model_with_automatic_resources_sample(\n",
|
||||
" project=PROJECT_ID,\n",
|
||||
" location=REGION,\n",
|
||||
" model_name=BQML_MODEL_NAME,\n",
|
||||
" endpoint=endpoint[-1],\n",
|
||||
")"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -992,7 +1095,7 @@
|
||||
"id": "c303d779477b"
|
||||
},
|
||||
"source": [
|
||||
"You can also check on the status of your model by visiting the <a href=\"https://console.cloud.google.com/vertex-ai/endpoints\" target=\"_blank\">Vertex AI Endpoints page</a>."
|
||||
"You can also check on the status of your model by visiting the [Vertex AI Endpoints page](https://console.cloud.google.com/vertex-ai/endpoints)."
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -1065,12 +1168,35 @@
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"id": "b4839f31d2f8"
|
||||
"id": "2c6093ce9f8a"
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"prediction = endpoint.predict(df_sample_requests_list)\n",
|
||||
"print(prediction)"
|
||||
"def endpoint_predict_sample(\n",
|
||||
" project: str, location: str, instances: list, endpoint: str\n",
|
||||
"):\n",
|
||||
" endpoint = vertex_ai.Endpoint(endpoint)\n",
|
||||
"\n",
|
||||
" prediction = endpoint.predict(instances=instances)\n",
|
||||
" return prediction"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"id": "0c41fd6eeb6f"
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"prediction_response = endpoint_predict_sample(\n",
|
||||
" project=PROJECT_ID,\n",
|
||||
" location=REGION,\n",
|
||||
" instances=df_sample_requests_list,\n",
|
||||
" endpoint=endpoint[-1].name,\n",
|
||||
")\n",
|
||||
"\n",
|
||||
"prediction_response"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -1090,7 +1216,7 @@
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"prediction.predictions"
|
||||
"prediction_response.predictions"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -1101,8 +1227,8 @@
|
||||
"source": [
|
||||
"## Cleaning up\n",
|
||||
"\n",
|
||||
"To clean up all Google Cloud resources used in this project, you can <a href=\"https://cloud.google.com/resource-manager/docs/creating-managing-projects#shutting_down_projects\" target=\"_blank\">delete the Google Cloud\n",
|
||||
"project</a> you used for the tutorial.\n",
|
||||
"To clean up all Google Cloud resources used in this project, you can [delete the Google Cloud\n",
|
||||
"project](https://cloud.google.com/resource-manager/docs/creating-managing-projects#shutting_down_projects) you used for the tutorial.\n",
|
||||
"\n",
|
||||
"Otherwise, you can delete the individual resources you created in this tutorial:"
|
||||
]
|
||||
@@ -1115,12 +1241,18 @@
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Undeploy model from endpoint and delete endpoint\n",
|
||||
"endpoint.undeploy_all()\n",
|
||||
"endpoint.delete()\n",
|
||||
"# MODEL_ID = model.name\n",
|
||||
"\n",
|
||||
"# Delete BigQuery dataset, including the BigQuery ML model\n",
|
||||
"! bq rm -r -f $PROJECT_ID:$BQ_DATASET_NAME"
|
||||
"ENDPOINT_ID = int(endpoint[-1].name)\n",
|
||||
"\n",
|
||||
"# Undeploy model from endpoint\n",
|
||||
"endpoint[-1].undeploy_all()\n",
|
||||
"\n",
|
||||
"# Delete endpoint resource\n",
|
||||
"! gcloud ai endpoints delete $ENDPOINT_ID --quiet --region $REGION\n",
|
||||
"\n",
|
||||
"# Delete BigQuery ML model\n",
|
||||
"! bq rm -f --model $PROJECT_ID\\:$BQ_DATASET_NAME\\.$BQML_MODEL_NAME"
|
||||
]
|
||||
}
|
||||
],
|
||||
File diff suppressed because it is too large
Load Diff
@@ -212,7 +212,7 @@
|
||||
"\n",
|
||||
"3. [Enable the Vertex AI APIs and Compute Engine APIs.](https://console.cloud.google.com/flows/enableapi?apiid=aiplatform.googleapis.com,compute_component)\n",
|
||||
"\n",
|
||||
"4. [Google Cloud SDK](https://cloud.google.com/sdk) is already installed in Vertex AI Workbench Notebooks.\n",
|
||||
"4. [Google Cloud SDK](https://cloud.google.com/sdk) is already installed in Google Cloud Notebooks.\n",
|
||||
"\n",
|
||||
"5. Enter your project ID in the cell below. Then run the cell to make sure the\n",
|
||||
"Cloud SDK uses the right project for all the commands in this notebook.\n",
|
||||
@@ -374,8 +374,15 @@
|
||||
"### Authenticate your Google Cloud account\n",
|
||||
"\n",
|
||||
"**If you are using Vertex AI Workbench Notebooks**, your environment is already\n",
|
||||
"authenticated. \n",
|
||||
"\n",
|
||||
"authenticated. Skip this step."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "32e1cd21a5d5"
|
||||
},
|
||||
"source": [
|
||||
"**If you are using Colab**, run the cell below and follow the instructions\n",
|
||||
"when prompted to authenticate your account via oAuth.\n",
|
||||
"\n",
|
||||
|
||||
Binary file not shown.
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -702,7 +702,7 @@
|
||||
" + f\"/{PRIVATE_REPO}\"\n",
|
||||
" + \"/tf_serving:gpu\"\n",
|
||||
" )\n",
|
||||
" TF_IMAGE = \"tensorflow/serving:2.5.4-gpu\"\n",
|
||||
" TF_IMAGE = \"tensorflow/serving:latest-gpu\"\n",
|
||||
"else:\n",
|
||||
" DEPLOY_IMAGE = (\n",
|
||||
" f\"{REGION}-docker.pkg.dev/\"\n",
|
||||
@@ -710,15 +710,15 @@
|
||||
" + f\"/{PRIVATE_REPO}\"\n",
|
||||
" + \"/tf_serving:cpu\"\n",
|
||||
" )\n",
|
||||
" TF_IMAGE = \"tensorflow/serving:2.5.4\"\n",
|
||||
" TF_IMAGE = \"tensorflow/serving:latest\"\n",
|
||||
"\n",
|
||||
"if not IS_COLAB:\n",
|
||||
" if DEPLOY_GPU:\n",
|
||||
" ! sudo docker pull tensorflow/serving:2.5.4-gpu\n",
|
||||
" ! sudo docker pull tensorflow/serving:latest-gpu\n",
|
||||
" else:\n",
|
||||
" ! sudo docker pull tensorflow/serving:2.5.4\n",
|
||||
" ! sudo docker pull tensorflow/serving:latest\n",
|
||||
"\n",
|
||||
" ! docker tag $TF_IMAGE $DEPLOY_IMAGE\n",
|
||||
" ! docker tag tensorflow/serving $DEPLOY_IMAGE\n",
|
||||
" ! docker push $DEPLOY_IMAGE\n",
|
||||
"else:\n",
|
||||
" # install docker daemon\n",
|
||||
@@ -1434,7 +1434,7 @@
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"delete_bucket = True\n",
|
||||
"delete_bucket = False\n",
|
||||
"delete_model = True\n",
|
||||
"delete_endpoint = True\n",
|
||||
"delete_batch_job = True\n",
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
-1872
File diff suppressed because it is too large
Load Diff
+29
-25
@@ -35,20 +35,20 @@
|
||||
"\n",
|
||||
"<table align=\"left\">\n",
|
||||
" <td>\n",
|
||||
" <a href=\"https://colab.research.google.com/github/GoogleCloudPlatform/vertex-ai-samples/blob/main/notebooks/community/ml_ops/stage7/model_monitoring_custom.ipynb\">\n",
|
||||
" <a href=\"https://console.cloud.google.com/ai-platform/notebooks/deploy-notebook?name=Model%20Monitoring&download_url=https%3A%2F%2Fraw.githubusercontent.com%2FGoogleCloudPlatform%2Fvertex-ai-samples%2Fmain%2Fnotebooks%2Fofficial%2Fmodel_monitoring%2Fmodel_monitoring_custom.ipynb\">\n",
|
||||
" <img src=\"https://www.gstatic.com/cloud/images/navigation/vertex-ai.svg\" alt=\"Google Cloud Notebooks\">Open in Workbench AI Notebook\n",
|
||||
" </a>\n",
|
||||
" </td> \n",
|
||||
" <td>\n",
|
||||
" <a href=\"https://colab.research.google.com/github/GoogleCloudPlatform/vertex-ai-samples/blob/main/notebooks/official/model_monitoring/model_monitoring_custom.ipynb\">\n",
|
||||
" <img src=\"https://cloud.google.com/ml-engine/images/colab-logo-32px.png\" alt=\"Colab logo\"> Open in Colab\n",
|
||||
" </a>\n",
|
||||
" </td>\n",
|
||||
" <td>\n",
|
||||
" <a href=\"https://github.com/GoogleCloudPlatform/vertex-ai-samples/blob/main/notebooks/community/ml_ops/stage7/model_monitoring_custom.ipynb\">\n",
|
||||
" <a href=\"https://github.com/GoogleCloudPlatform/vertex-ai-samples/blob/main/notebooks/official/model_monitoring/model_monitoring_custom.ipynb\">\n",
|
||||
" <img src=\"https://cloud.google.com/ml-engine/images/github-logo-32px.png\" alt=\"GitHub logo\">\n",
|
||||
" View on GitHub\n",
|
||||
" </a>\n",
|
||||
" </td> <td>\n",
|
||||
" <a href=\"https://console.cloud.google.com/vertex-ai/workbench/deploy-notebook?download_url=https://raw.githubusercontent.com/GoogleCloudPlatform/vertex-ai-samples/main/notebooks/community/ml_ops/stage7/model_monitoring_custom.ipynb\">\n",
|
||||
" <img src=\"https://lh3.googleusercontent.com/UiNooY4LUgW_oTvpsNhPpQzsstV5W8F7rYgxgGBD85cWJoLmrOzhVs_ksK_vgx40SHs7jCqkTkCk=e14-rj-sc0xffffff-h130-w32\" alt=\"Vertex AI logo\">\n",
|
||||
" Open in Vertex AI Workbench\n",
|
||||
" </a>\n",
|
||||
" </td>\n",
|
||||
"</table>"
|
||||
]
|
||||
@@ -110,7 +110,7 @@
|
||||
"- identity - unique player identitity numbers\n",
|
||||
"- demographic features - information about the player, such as the geographic region in which a player is located\n",
|
||||
"- behavioral features - counts of the number of times a player has triggered certain game events, such as reaching a new level\n",
|
||||
"- churn propensity - this is the label or target feature, it provides an estimated probability that this player may churn, i.e. stop being an active player."
|
||||
"- churn propensity - this is the label or target feature, it provides an estimated probability that this player will churn, i.e. stop being an active player."
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -140,6 +140,8 @@
|
||||
"id": "8yVpQt-JHKPF"
|
||||
},
|
||||
"source": [
|
||||
"## Before you begin\n",
|
||||
"\n",
|
||||
"### Set up your local development environment\n",
|
||||
"\n",
|
||||
"**If you are using Colab or Vertex AI Workbench notebooks**, your environment already meets\n",
|
||||
@@ -252,8 +254,6 @@
|
||||
"id": "BF1j6f9HApxa"
|
||||
},
|
||||
"source": [
|
||||
"## Before you begin\n",
|
||||
"\n",
|
||||
"### Set up your Google Cloud project\n",
|
||||
"\n",
|
||||
"**The following steps are required, regardless of your notebook environment.**\n",
|
||||
@@ -264,7 +264,7 @@
|
||||
"\n",
|
||||
"1. [Enable the Vertex AI API and Compute Engine API](https://console.cloud.google.com/flows/enableapi?apiid=aiplatform.googleapis.com,compute_component).\n",
|
||||
"\n",
|
||||
"1. If you are running this notebook locally, you need to install the [Cloud SDK](https://cloud.google.com/sdk).\n",
|
||||
"1. If you are running this notebook locally, you will need to install the [Cloud SDK](https://cloud.google.com/sdk).\n",
|
||||
"\n",
|
||||
"1. Enter your project ID in the cell below. Then run the cell to make sure the\n",
|
||||
"Cloud SDK uses the right project for all the commands in this notebook.\n",
|
||||
@@ -765,7 +765,7 @@
|
||||
"source": [
|
||||
"## Introduction to Vertex AI Model Monitoring\n",
|
||||
"\n",
|
||||
"Vertex AI Model Monitoring is supported for AutoML tabular models and custom tabular models. You can monitor for skew and drift detection of the features in the inbound prediction requests or skew and drift detection of the feature attributions (Explainable AI) in the outbound prediction response -- that is, the distribution of the attributions on how they contributed to the output (predictions).\n",
|
||||
"Vertex AI Model Monitoring is supported for AutoML tabular models and custom tabular model. You can monitor for skew and drift detection of the features in the inbound prediction requests or skew and drift detection of the feature attributions (Explainable AI) in the outbound prediction response -- that is, the distribution of the attributions on how they contributed to the output (predictions).\n",
|
||||
"\n",
|
||||
"The following are the basic steps to enable model monitoring:\n",
|
||||
"\n",
|
||||
@@ -780,11 +780,11 @@
|
||||
"\n",
|
||||
"When model monitoring is enabled, the sampled incoming prediction requests are logged into a BigQuery table. The input feature values contained in the logged requests are then analyzed for skew or drift on an specified interval basis. You set a sampling rate to monitor a subset of the production inputs to a model, and the monitoring interval.\n",
|
||||
"\n",
|
||||
"The model monitoring service needs to know how to parse the feature values, which is referred to as the input schema. For AutoML tabular models, the input schema is automatically generated. For custom tabular models, the service attempts to automatically derive the input schema from the first 1000 prediction requests. Alternatively, one can upload the input schema.\n",
|
||||
"The model monitoring service needs to know how to parse the feature values, which is referred to as the input schema. For AutoML tabular models, the input schema is automatically provided. For custom tabular models, the service will attempt to automatically derive the input schema from the first 1000 prediction requests. Alternatively, one can upload the input schema.\n",
|
||||
"\n",
|
||||
"For skew detection, the monitoring service requires a baseline for the statistical distribution of values in the training data. For AutoML tabular models this is automatically derived. For custom tabular models, you upload the training data to the service, and have the service automatically derive the distribution.\n",
|
||||
"\n",
|
||||
"For feature attribution skew and drift detection, requires enabling your deployed model for `Vertex AI Explainability` for custom tabular models. For AutoML models, `Vertex AI Explainability` is automatically enabled.\n",
|
||||
"For feature attribution skew and drift detection, requires enabling your deployed model for `Vertex AI Explainability`\n",
|
||||
"\n",
|
||||
"Learn more about [Introduction to Vertex AI Model Monitoring](https://cloud.google.com/vertex-ai/docs/model-monitoring/overview)."
|
||||
]
|
||||
@@ -1344,7 +1344,7 @@
|
||||
"\n",
|
||||
"Once the monitoring service has started, the sampled prediction requests will be logged to Cloud Storage. On the next monitoring interval, the sampled predictions are then copied over to the BigQuery logging table. Once the entries are in the BigQuery table, the monitoring service will analyze the sampled data.\n",
|
||||
"\n",
|
||||
"Next, you wait for the first logged entres to appear in the BigQuery table used for logging prediction samples. Since you sent 1000 prediction requests, with 50% sampling, you should see around 500 entries."
|
||||
"Next, you wait for the first logged entres to appear in the BigQuery table used for logging prediction samples. Since you sent a 1000 prediction requests, with 50% sampling, you should see around 500 entries."
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -1404,11 +1404,11 @@
|
||||
"\n",
|
||||
"Training Prediction Skew Anomalies (Raw Feature):\n",
|
||||
"\n",
|
||||
"Anomalies Report Path(Google Cloud Storage): gs://cloud-ai-platform-773884b1-2a32-48d6-8b83-c03cde416b68/model_monitoring/job-8672170640054157312/serving/2022-08-25T00:00/stats_and_anomalies/<deployed-model-id>/anomalies/training_prediction_skew_anomalies\n",
|
||||
"Anomalies Report Path(Google Cloud Storage): gs://cloud-ai-platform-773884b1-2a32-48d6-8b83-c03cde416b68/model_monitoring/job-8672170640054157312/serving/2022-08-25T00:00/stats_and_anomalies/5653675595884658688/anomalies/training_prediction_skew_anomalies\n",
|
||||
"\n",
|
||||
"For more information about the alert, please visit the model monitoring alert page.\n",
|
||||
"\n",
|
||||
"Deployed model id: <deployed-model-id>\n",
|
||||
"Deployed model id: 5653675595884658688\n",
|
||||
"\n",
|
||||
"Feature name\tAnomaly short description\tAnomaly long description\n",
|
||||
"country\tHigh Linfty distance between training and serving\tThe Linfty distance between training and serving is 0.947563 (up to six significant digits), above the threshold 0.5. The feature value with maximum difference is: Canada\n",
|
||||
@@ -1505,9 +1505,9 @@
|
||||
"source": [
|
||||
"### Logging sampled requests\n",
|
||||
"\n",
|
||||
"On the next monitoring interval, the sampled predictions are then copied over to the BigQuery logging table. Once the entries are in the BigQuery table, the monitoring service will analyze the sampled data.\n",
|
||||
"Once the monitoring service has started, the sampled prediction requests will be logged to Cloud Storage. On the next monitoring interval, the sampled predictions are then copied over to the BigQuery logging table. Once the entries are in the BigQuery table, the monitoring service will analyze the sampled data.\n",
|
||||
"\n",
|
||||
"Next, you wait for the first logged entres to appear in the BigQuery table used for logging prediction samples. Since you sent 1000 prediction requests, with 50% sampling, you should see around 1000 entries."
|
||||
"Next, you wait for the first logged entres to appear in the BigQuery table used for logging prediction samples. Since you sent a 1000 prediction requests, with 50% sampling, you should see around 1000 entries."
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -1546,7 +1546,13 @@
|
||||
"\n",
|
||||
"#### Wait for monitoring interval\n",
|
||||
"\n",
|
||||
"It can take upwards of 40 minutes from when the analyis occurred on the monitoring interval to when you receive an email alert."
|
||||
"It can take upwards of 40 minutes from when the analyis occurred on the monitoring interval to when you receive an email alert.\n",
|
||||
"\n",
|
||||
"The contents will appear like\n",
|
||||
"\n",
|
||||
"<blockquote>\n",
|
||||
" \n",
|
||||
"<blockquote>"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -1629,21 +1635,19 @@
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"delete_bucket = False\n",
|
||||
"delete_bucket = True\n",
|
||||
"\n",
|
||||
"if delete_bucket or os.getenv(\"IS_TESTING\"):\n",
|
||||
" ! gsutil rm -rf {BUCKET_URI}\n",
|
||||
"\n",
|
||||
"! rm -f schema.yaml\n",
|
||||
"\n",
|
||||
"! bq rm -f {PROJECT_ID}.model_deployment_monitoring_{ENDPOINT_ID}"
|
||||
"! rm -f schema.yaml"
|
||||
]
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"colab": {
|
||||
"collapsed_sections": [],
|
||||
"name": "get_started_with_model_monitoring_custom.ipynb",
|
||||
"name": "model_monitoring_custom.ipynb",
|
||||
"toc_visible": true
|
||||
},
|
||||
"kernelspec": {
|
||||
+5
-5
@@ -140,6 +140,8 @@
|
||||
"id": "8yVpQt-JHKPF"
|
||||
},
|
||||
"source": [
|
||||
"## Before you begin\n",
|
||||
"\n",
|
||||
"### Set up your local development environment\n",
|
||||
"\n",
|
||||
"**If you are using Colab or Vertex AI Workbench notebooks**, your environment already meets\n",
|
||||
@@ -252,8 +254,6 @@
|
||||
"id": "BF1j6f9HApxa"
|
||||
},
|
||||
"source": [
|
||||
"## Before you begin\n",
|
||||
"\n",
|
||||
"### Set up your Google Cloud project\n",
|
||||
"\n",
|
||||
"**The following steps are required, regardless of your notebook environment.**\n",
|
||||
@@ -766,7 +766,7 @@
|
||||
"source": [
|
||||
"## Introduction to Vertex AI Model Monitoring\n",
|
||||
"\n",
|
||||
"Vertex AI Model Monitoring is supported for AutoML tabular models and custom tabular models. You can monitor for skew and drift detection of the features in the inbound prediction requests or skew and drift detection of the feature attributions (Explainable AI) in the outbound prediction response -- that is, the distribution of the attributions on how they contributed to the output (predictions).\n",
|
||||
"Vertex AI Model Monitoring is supported for AutoML tabular models and custom tabular model. You can monitor for skew and drift detection of the features in the inbound prediction requests or skew and drift detection of the feature attributions (Explainable AI) in the outbound prediction response -- that is, the distribution of the attributions on how they contributed to the output (predictions).\n",
|
||||
"\n",
|
||||
"The following are the basic steps to enable model monitoring:\n",
|
||||
"\n",
|
||||
@@ -781,7 +781,7 @@
|
||||
"\n",
|
||||
"When model monitoring is enabled, the sampled incoming prediction requests are logged into a BigQuery table. The input feature values contained in the logged requests are then analyzed for skew or drift on an specified interval basis. You set a sampling rate to monitor a subset of the production inputs to a model, and the monitoring interval.\n",
|
||||
"\n",
|
||||
"The model monitoring service needs to know how to parse the feature values, which is referred to as the input schema. For AutoML tabular models, the input schema is automatically generated. For custom tabular models, the service will attempt to automatically derive the input schema from the first 1000 prediction requests. Alternatively, one can upload the input schema.\n",
|
||||
"The model monitoring service needs to know how to parse the feature values, which is referred to as the input schema. For AutoML tabular models, the input schema is automatically provided. For custom tabular models, the service will attempt to automatically derive the input schema from the first 1000 prediction requests. Alternatively, one can upload the input schema.\n",
|
||||
"\n",
|
||||
"For skew detection, the monitoring service requires a baseline for the statistical distribution of values in the training data. For AutoML tabular models this is automatically derived. For custom tabular models, you upload the training data to the service, and have the service automatically derive the distribution.\n",
|
||||
"\n",
|
||||
@@ -1697,7 +1697,7 @@
|
||||
"metadata": {
|
||||
"colab": {
|
||||
"collapsed_sections": [],
|
||||
"name": "get_started_with_model_monitoring_setup.ipynb",
|
||||
"name": "model_monitoring_setup.ipynb",
|
||||
"toc_visible": true
|
||||
},
|
||||
"kernelspec": {
|
||||
-1431
File diff suppressed because it is too large
Load Diff
-1483
File diff suppressed because it is too large
Load Diff
BIN
Binary file not shown.
|
Before Width: | Height: | Size: 55 KiB |
BIN
Binary file not shown.
|
Before Width: | Height: | Size: 46 KiB |
@@ -56,7 +56,7 @@ def parse_notebook(path):
|
||||
# cell 1 is copyright
|
||||
nth = 0
|
||||
cell, nth = get_cell(path, cells, nth)
|
||||
if not 'Copyright' in cell['source'][0]:
|
||||
if not cell['source'][0].startswith('# Copyright'):
|
||||
report_error(path, 0, "missing copyright cell")
|
||||
|
||||
# check for notices
|
||||
|
||||
@@ -16,7 +16,6 @@
|
||||
/model_monitoring @andrewferlitsch
|
||||
/tensorboard @zbl94
|
||||
|
||||
/bigquery_ml/bqml-online-prediction.ipynb @polong-lin
|
||||
/model_monitoring/model_monitoring.ipynb @mco-gh
|
||||
/ml_metadata/sdk-metric-parameter-tracking-for-custom-jobs.ipynb @jialuzh
|
||||
/ml_metadata/sdk-metric-parameter-tracking-for-locally-trained-models.ipynb @jialuzh
|
||||
@@ -29,9 +28,6 @@
|
||||
/automl/automl_forecasting_bqml_arima_plus_comparison.ipynb @TheMichaelHu
|
||||
/automl/automl_tabular_on_vertex_pipelines.ipynb @helinwang
|
||||
/custom/custom_training_tensorboard_profiler.ipynb @itseric
|
||||
/workbench/spark/spark_sample_notebook.ipynb @bradmiro
|
||||
/workbench/spark/spark_ml.ipynb @bradmiro
|
||||
/workbench/spark/spark_sample_notebook.ipynb @bmiro
|
||||
/model-registry/bqml-vertexai-model-registry.ipynb @soheilazangeneh
|
||||
/workbench/exploratory_data_analysis/explore_data_in_bigquery_with_workbench.ipynb @alokpattani
|
||||
/model_evaluation/automl_tabular_classification_model_evaluation.ipynb @soheilazangeneh
|
||||
/model_evaluation/automl_tabular_regression_model_evaluation.ipynb @soheilazangeneh
|
||||
|
||||
@@ -176,10 +176,7 @@
|
||||
"else:\n",
|
||||
" USER_FLAG = \"\"\n",
|
||||
"\n",
|
||||
"! (pip3 install --upgrade $USER_FLAG \\\n",
|
||||
" google-cloud-bigquery[pandas]==2.34.4 \\\n",
|
||||
" google-cloud-aiplatform==1.16.1 \\\n",
|
||||
" google-cloud-pipeline-components==1.0.18)"
|
||||
"! pip3 install --upgrade google-cloud-bigquery[pandas] google-cloud-aiplatform google-cloud-pipeline-components $USER_FLAG"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Copyright 2021 Google LLC\n",
|
||||
"# Copyright 2022 Google LLC\n",
|
||||
"#\n",
|
||||
"# Licensed under the Apache License, Version 2.0 (the \"License\");\n",
|
||||
"# you may not use this file except in compliance with the License.\n",
|
||||
@@ -66,6 +66,17 @@
|
||||
"This tutorial demonstrates how to use the Vertex AI SDK to create image object detection models and do batch prediction using a Google Cloud [AutoML](https://cloud.google.com/vertex-ai/docs/start/automl-users) model."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "dataset:salads,iod"
|
||||
},
|
||||
"source": [
|
||||
"### Dataset\n",
|
||||
"\n",
|
||||
"The dataset used for this tutorial is the Salads category of the [OpenImages dataset](https://www.tensorflow.org/datasets/catalog/open_images_v4) from [TensorFlow Datasets](https://www.tensorflow.org/datasets/catalog/overview). This dataset does not require any feature engineering. The version of the dataset you will use in this tutorial is stored in a public Cloud Storage bucket. The trained model predicts the bounding box locations and the corresponding type of salad items in an image from a class of five items: salad, seafood, tomato, baked goods, or cheese."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
@@ -90,17 +101,6 @@
|
||||
"* Batch Prediction Service: Does a queued (batch) prediction for the entire set of instances in the background and stores the results in a Cloud Storage bucket when ready."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "dataset:salads,iod"
|
||||
},
|
||||
"source": [
|
||||
"### Dataset\n",
|
||||
"\n",
|
||||
"The dataset used for this tutorial is the Salads category of the [OpenImages dataset](https://www.tensorflow.org/datasets/catalog/open_images_v4) from [TensorFlow Datasets](https://www.tensorflow.org/datasets/catalog/overview). This dataset does not require any feature engineering. The version of the dataset you will use in this tutorial is stored in a public Cloud Storage bucket. The trained model predicts the bounding box locations and the corresponding type of salad items in an image from a class of five items: salad, seafood, tomato, baked goods, or cheese."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
@@ -201,7 +201,7 @@
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"! pip3 install -U --upgrade tensorflow google-cloud-storage $USER_FLAG"
|
||||
"! pip3 install -U google-cloud-storage $USER_FLAG"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -213,6 +213,17 @@
|
||||
"Install the latest version of *tensorflow* library."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"id": "install_tensorflow"
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"! pip3 install --upgrade tensorflow $USER_FLAG"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
@@ -372,9 +383,9 @@
|
||||
"id": "timestamp"
|
||||
},
|
||||
"source": [
|
||||
"#### UUID\n",
|
||||
"#### Timestamp\n",
|
||||
"\n",
|
||||
"If you are in a live tutorial session, you might be using a shared test account or project. To avoid name collisions between users on resources created, you create a uuid for each instance session, and append it onto the name of resources you create in this tutorial."
|
||||
"If you are in a live tutorial session, you might be using a shared test account or project. To avoid name collisions between users on resources created, you create a timestamp for each instance session, and append the timestamp onto the name of resources you create in this tutorial."
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -385,16 +396,9 @@
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"import random\n",
|
||||
"import string\n",
|
||||
"from datetime import datetime\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"# Generate a uuid of a specifed length(default=8)\n",
|
||||
"def generate_uuid(length: int = 8) -> str:\n",
|
||||
" return \"\".join(random.choices(string.ascii_lowercase + string.digits, k=length))\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"UUID = generate_uuid()"
|
||||
"TIMESTAMP = datetime.now().strftime(\"%Y%m%d%H%M%S\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -405,7 +409,7 @@
|
||||
"source": [
|
||||
"### Authenticate your Google Cloud account\n",
|
||||
"\n",
|
||||
"**If you are using Google Cloud Notebooks**, your environment is already authenticated.\n",
|
||||
"**If you are using Google Cloud Notebooks**, your environment is already authenticated. Skip this step.\n",
|
||||
"\n",
|
||||
"**If you are using Colab**, run the cell below and follow the instructions when prompted to authenticate your account via oAuth.\n",
|
||||
"\n",
|
||||
@@ -490,7 +494,7 @@
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"if BUCKET_NAME == \"\" or BUCKET_NAME is None or BUCKET_NAME == \"[your-bucket-name]\":\n",
|
||||
" BUCKET_URI = \"gs://\" + PROJECT_ID + \"aip-\" + UUID"
|
||||
" BUCKET_URI = \"gs://\" + PROJECT_ID + \"aip-\" + TIMESTAMP"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -665,7 +669,7 @@
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"dataset = aiplatform.ImageDataset.create(\n",
|
||||
" display_name=\"Salads\" + \"_\" + UUID,\n",
|
||||
" display_name=\"Salads\" + \"_\" + TIMESTAMP,\n",
|
||||
" gcs_source=[IMPORT_FILE],\n",
|
||||
" import_schema_uri=aiplatform.schema.dataset.ioformat.image.bounding_box,\n",
|
||||
")\n",
|
||||
@@ -713,7 +717,7 @@
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"job = aiplatform.AutoMLImageTrainingJob(\n",
|
||||
" display_name=\"salads_\" + UUID,\n",
|
||||
" display_name=\"salads_\" + TIMESTAMP,\n",
|
||||
" prediction_type=\"object_detection\",\n",
|
||||
" multi_label=False,\n",
|
||||
" model_type=\"CLOUD\",\n",
|
||||
@@ -756,7 +760,7 @@
|
||||
"source": [
|
||||
"model = job.run(\n",
|
||||
" dataset=dataset,\n",
|
||||
" model_display_name=\"salads_\" + UUID,\n",
|
||||
" model_display_name=\"salads_\" + TIMESTAMP,\n",
|
||||
" training_fraction_split=0.8,\n",
|
||||
" validation_fraction_split=0.1,\n",
|
||||
" test_fraction_split=0.1,\n",
|
||||
@@ -786,7 +790,7 @@
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Get model resource ID\n",
|
||||
"models = aiplatform.Model.list(filter=\"display_name=salads_\" + UUID)\n",
|
||||
"models = aiplatform.Model.list(filter=\"display_name=salads_\" + TIMESTAMP)\n",
|
||||
"\n",
|
||||
"# Get a reference to the Model Service client\n",
|
||||
"client_options = {\"api_endpoint\": f\"{REGION}-aiplatform.googleapis.com\"}\n",
|
||||
@@ -957,7 +961,7 @@
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"batch_predict_job = model.batch_predict(\n",
|
||||
" job_display_name=\"salads_\" + UUID,\n",
|
||||
" job_display_name=\"salads_\" + TIMESTAMP,\n",
|
||||
" gcs_source=gcs_input_uri,\n",
|
||||
" gcs_destination_prefix=BUCKET_URI,\n",
|
||||
" machine_type=\"n1-standard-4\",\n",
|
||||
|
||||
@@ -44,7 +44,7 @@
|
||||
" </a>\n",
|
||||
" </td>\n",
|
||||
" <td>\n",
|
||||
" <a href=\"https://console.cloud.google.com/vertex-ai/workbench/deploy-notebook?download_url=https://raw.githubusercontent.com/GoogleCloudPlatform/vertex-ai-samples/main/notebooks/official/custom/custom-tabular-bq-managed-dataset.ipynb\">\n",
|
||||
" <a href=\"https://console.cloud.google.com/vertex-ai/workbench/deploy-notebook?download_url=https://github.com/GoogleCloudPlatform/vertex-ai-samples/blob/main/notebooks/official/custom/custom-tabular-bq-managed-dataset.ipynb\">\n",
|
||||
" <img src=\"https://lh3.googleusercontent.com/UiNooY4LUgW_oTvpsNhPpQzsstV5W8F7rYgxgGBD85cWJoLmrOzhVs_ksK_vgx40SHs7jCqkTkCk=e14-rj-sc0xffffff-h130-w32\" alt=\"Vertex AI logo\">\n",
|
||||
" Open in Vertex AI Workbench\n",
|
||||
" </a>\n",
|
||||
@@ -263,7 +263,7 @@
|
||||
"\n",
|
||||
"2. [Make sure that billing is enabled for your project](https://cloud.google.com/billing/docs/how-to/modify-project).\n",
|
||||
"\n",
|
||||
"3. [Enable the following APIs: Vertex AI API, Cloud Resource Manager API](https://console.cloud.google.com/flows/enableapi?apiid=aiplatform.googleapis.com,cloudresourcemanager.googleapis.com).\n",
|
||||
"3. [Enable the Vertex AI API](https://console.cloud.google.com/flows/enableapi?apiid=aiplatform.googleapis.com).\n",
|
||||
"\n",
|
||||
"4. If you are running this notebook locally, you need to install the [Cloud SDK](https://cloud.google.com/sdk).\n",
|
||||
"\n",
|
||||
|
||||
@@ -29,8 +29,6 @@
|
||||
"id": "JAPoU8Sm5E6e"
|
||||
},
|
||||
"source": [
|
||||
"# Online and Batch predictions using Vertex AI Feature Store\n",
|
||||
"\n",
|
||||
"<table align=\"left\">\n",
|
||||
" <td>\n",
|
||||
" <a href=\"https://colab.research.google.com/github/GoogleCloudPlatform/vertex-ai-samples/blob/main/notebooks/community/feature_store/sdk-feature-store.ipynb\">\n",
|
||||
@@ -53,22 +51,19 @@
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "c4aaea3bab5e"
|
||||
"id": "tvgnzT1CKxrO"
|
||||
},
|
||||
"source": [
|
||||
"## Overview\n",
|
||||
"\n",
|
||||
"This notebook introduces Vertex AI Feature Store, a managed cloud service for machine learning engineers and data scientists to store, serve, manage and share machine learning features at a large scale.\n",
|
||||
"\n",
|
||||
"This notebook assumes that you understand basic Google Cloud concepts such as [Project](https://cloud.google.com/storage/docs/projects), [Storage](https://cloud.google.com/storage) and [Vertex AI](https://cloud.google.com/vertex-ai/docs). Some machine learning knowledge is also helpful but not required.\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "71779c8088bf"
|
||||
},
|
||||
"source": [
|
||||
"This notebook assumes that you understand basic Google Cloud concepts such as [Project](https://cloud.google.com/storage/docs/projects), [Storage](https://cloud.google.com/storage) and [Vertex AI](https://cloud.google.com/vertex-ai/docs). Some machine learning knowledge is also helpful but not required.\n",
|
||||
"\n",
|
||||
"### Dataset\n",
|
||||
"\n",
|
||||
"This notebook uses a movie recommendation dataset as an example throughout all the sessions. The task is to train a model to predict if a user is going to watch a movie and serve this model online. \n",
|
||||
"\n",
|
||||
"### Objective\n",
|
||||
"\n",
|
||||
"In this notebook, you will learn how to use `Vertex AI Feature Store` to import feature data, and to access the feature data for both online serving and offline tasks, such as training.\n",
|
||||
@@ -84,26 +79,8 @@
|
||||
"- Create featurestore, entity type, and feature resources.\n",
|
||||
"- Import feature data into `Vertex AI Feature Store` resource.\n",
|
||||
"- Serve online prediction requests using the imported features.\n",
|
||||
"- Access imported features in offline jobs, such as training jobs."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "55e01a856f57"
|
||||
},
|
||||
"source": [
|
||||
"### Dataset\n",
|
||||
"- Access imported features in offline jobs, such as training jobs.\n",
|
||||
"\n",
|
||||
"This notebook uses a movie recommendation dataset as an example throughout all the sessions. The task is to train a model to predict if a user is going to watch a movie and serve this model online."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "tvgnzT1CKxrO"
|
||||
},
|
||||
"source": [
|
||||
"### Costs \n",
|
||||
"\n",
|
||||
"This tutorial uses billable components of Google Cloud:\n",
|
||||
@@ -285,15 +262,7 @@
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"import os\n",
|
||||
"\n",
|
||||
"PROJECT_ID = \"\"\n",
|
||||
"\n",
|
||||
"# Get your Google Cloud project ID from gcloud\n",
|
||||
"if not os.getenv(\"IS_TESTING\"):\n",
|
||||
" shell_output = !gcloud config list --format 'value(core.project)' 2>/dev/null\n",
|
||||
" PROJECT_ID = shell_output[0]\n",
|
||||
" print(\"Project ID: \", PROJECT_ID)"
|
||||
"PROJECT_ID = \"[your-project-id]\" # @param {type:\"string\"}"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -306,7 +275,10 @@
|
||||
"source": [
|
||||
"if PROJECT_ID == \"\" or PROJECT_ID is None:\n",
|
||||
" PROJECT_ID = \"[your-project-id]\" # @param {type:\"string\"}\n",
|
||||
"print(\"Project ID: \", PROJECT_ID)"
|
||||
" # Get your GCP project id from gcloud\n",
|
||||
" shell_output = ! gcloud config list --format 'value(core.project)' 2>/dev/null\n",
|
||||
" PROJECT_ID = shell_output[0]\n",
|
||||
" print(\"Project ID:\", PROJECT_ID)"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -348,9 +320,7 @@
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"REGION = \"[your-region]\" # @param {type:\"string\"}\n",
|
||||
"if REGION == \"[your-region]\":\n",
|
||||
" REGION = \"us-central1\""
|
||||
"REGION = \"us-central1\" # @param {type: \"string\"}"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -359,9 +329,9 @@
|
||||
"id": "timestamp"
|
||||
},
|
||||
"source": [
|
||||
"#### UUID\n",
|
||||
"#### Timestamp\n",
|
||||
"\n",
|
||||
"If you are in a live tutorial session, you might be using a shared test account or project. To avoid name collisions between users on resources created, you create a uuid for each instance session, and append it onto the name of resources you create in this tutorial."
|
||||
"If you are in a live tutorial session, you might be using a shared test account or project. To avoid name collisions between users on resources created, you create a timestamp for each instance session, and append the timestamp onto the name of resources you create in this tutorial."
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -372,16 +342,9 @@
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"import random\n",
|
||||
"import string\n",
|
||||
"from datetime import datetime\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"# Generate a uuid of a specifed length(default=8)\n",
|
||||
"def generate_uuid(length: int = 8) -> str:\n",
|
||||
" return \"\".join(random.choices(string.ascii_lowercase + string.digits, k=length))\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"UUID = generate_uuid()"
|
||||
"TIMESTAMP = datetime.now().strftime(\"%Y%m%d%H%M%S\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -478,7 +441,7 @@
|
||||
"source": [
|
||||
"from google.cloud.aiplatform import Feature, Featurestore\n",
|
||||
"\n",
|
||||
"FEATURESTORE_ID = \"movie_prediction\" + UUID\n",
|
||||
"FEATURESTORE_ID = \"movie_prediction\"\n",
|
||||
"INPUT_CSV_FILE = \"gs://cloud-samples-data-us-central1/vertex-ai/feature-store/datasets/movie_prediction.csv\"\n",
|
||||
"ONLINE_STORE_FIXED_NODE_COUNT = 1"
|
||||
]
|
||||
|
||||
@@ -32,18 +32,18 @@
|
||||
"<table align=\"left\">\n",
|
||||
"\n",
|
||||
" <td>\n",
|
||||
" <a href=\"https://colab.research.google.com/github/GoogleCloudPlatform/vertex-ai-samples/blob/main/notebooks/official/model-registry/bqml-vertexai-model-registry.ipynb\" target=\"_blank\">\n",
|
||||
" <a href=\"https://colab.research.google.com/github/GoogleCloudPlatform/vertex-ai-samples/blob/main/notebooks/official/bigquery-ml/bqml-vertexai-model-registry.ipynb\" target=\"_blank\">\n",
|
||||
" <img src=\"https://cloud.google.com/ml-engine/images/colab-logo-32px.png\" alt=\"Colab logo\"> Run in Colab\n",
|
||||
" </a>\n",
|
||||
" </td>\n",
|
||||
" <td>\n",
|
||||
" <a href=\"https://github.com/GoogleCloudPlatform/vertex-ai-samples/blob/main/notebooks/official/model-registry/bqml-vertexai-model-registry.ipynb\" target=\"_blank\">\n",
|
||||
" <a href=\"https://github.com/GoogleCloudPlatform/vertex-ai-samples/blob/main/notebooks/official/bigquery-ml/bqml-vertexai-model-registry.ipynb\" target=\"_blank\">\n",
|
||||
" <img src=\"https://cloud.google.com/ml-engine/images/github-logo-32px.png\" alt=\"GitHub logo\">\n",
|
||||
" View on GitHub\n",
|
||||
" </a>\n",
|
||||
" </td>\n",
|
||||
" <td>\n",
|
||||
" <a href=\"https://console.cloud.google.com/vertex-ai/workbench/deploy-notebook?download_url=https://raw.githubusercontent.com/GoogleCloudPlatform/vertex-ai-samples/blob/main/notebooks/official/model-registry/bqml-vertexai-model-registry.ipynb\" target=\"_blank\">\n",
|
||||
" <a href=\"https://console.cloud.google.com/vertex-ai/workbench/deploy-notebook?download_url=https://raw.githubusercontent.com/GoogleCloudPlatform/vertex-ai-samples/blob/main/notebooks/official/bigquery-ml/bqml-vertexai-model-registry.ipynb\" target=\"_blank\">\n",
|
||||
" <img src=\"https://lh3.googleusercontent.com/UiNooY4LUgW_oTvpsNhPpQzsstV5W8F7rYgxgGBD85cWJoLmrOzhVs_ksK_vgx40SHs7jCqkTkCk=e14-rj-sc0xffffff-h130-w32\" alt=\"Vertex AI logo\">\n",
|
||||
" Open in Vertex AI Workbench\n",
|
||||
" </a>\n",
|
||||
@@ -677,7 +677,7 @@
|
||||
"source": [
|
||||
"### Find the model in the Vertex Model Registry\n",
|
||||
"\n",
|
||||
"You can use the `Vertex AI Model()` method with `model_name` parameter to find the automatically registered model."
|
||||
"You can use the `Vertex AI Model list()` method with a filter query to find the automatically registered model."
|
||||
]
|
||||
},
|
||||
{
|
||||
|
||||
-1415
File diff suppressed because it is too large
Load Diff
-1473
File diff suppressed because it is too large
Load Diff
BIN
Binary file not shown.
|
Before Width: | Height: | Size: 55 KiB |
BIN
Binary file not shown.
|
Before Width: | Height: | Size: 46 KiB |
@@ -223,22 +223,12 @@
|
||||
"if IS_WORKBENCH_NOTEBOOK:\n",
|
||||
" USER_FLAG = \"--user\"\n",
|
||||
"\n",
|
||||
"# Don't bother installing tensorflow or explainable_ai_sdk on Colab\n",
|
||||
"extra_pkgs = \"tensorflow explainable_ai_sdk\"\n",
|
||||
"if \"google.colab\" in sys.modules:\n",
|
||||
" extra_pkgs = \"\"\n",
|
||||
"\n",
|
||||
"# Install required packages.\n",
|
||||
"! pip3 install {USER_FLAG} \\\n",
|
||||
" google-cloud-aiplatform \\\n",
|
||||
" explainable_ai_sdk \\\n",
|
||||
" $extra_pkgs \\\n",
|
||||
" google-api-python-client \\\n",
|
||||
" google-auth-oauthlib \\\n",
|
||||
" google-auth-httplib2 \\\n",
|
||||
" oauth2client \\\n",
|
||||
" requests \\\n",
|
||||
" google-cloud-storage==1.32.0"
|
||||
"! pip3 install {USER_FLAG} --quiet --upgrade google-cloud-aiplatform\n",
|
||||
"! pip3 install {USER_FLAG} --quiet --upgrade tensorflow\n",
|
||||
"! pip3 install {USER_FLAG} --quiet --upgrade explainable_ai_sdk\n",
|
||||
"! pip3 install {USER_FLAG} --quiet --upgrade google-api-python-client google-auth-oauthlib google-auth-httplib2 oauth2client requests\n",
|
||||
"! pip3 install {USER_FLAG} --quiet --upgrade google-cloud-storage==1.32.0"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -572,7 +562,7 @@
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"id": "wGa5T9eRR8Mz"
|
||||
"id": "init_aip:mbsdk,region"
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
|
||||
+52
-410
@@ -29,7 +29,7 @@
|
||||
"id": "JAPoU8Sm5E6e"
|
||||
},
|
||||
"source": [
|
||||
"# Vertex AI Pipelines: Loan eligibility prediction using `google-cloud-pipeline-components` and Spark ML\n",
|
||||
"# Vertex AI Pipelines: Loan eligibility prediction using google-cloud-pipeline-components and Spark ML\n",
|
||||
"\n",
|
||||
"<table align=\"left\">\n",
|
||||
"\n",
|
||||
@@ -206,7 +206,7 @@
|
||||
" \n",
|
||||
"!pip3 install {USER_FLAG} --upgrade google-cloud-aiplatform==1.11.0 \\\n",
|
||||
" kfp==1.8.11 \\\n",
|
||||
" google-cloud-pipeline-components==1.0.18 --quiet --no-warn-conflicts"
|
||||
" google-cloud-pipeline-components==1.0.1 --quiet --no-warn-conflicts"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -733,7 +733,9 @@
|
||||
"from pathlib import Path as path\n",
|
||||
"from typing import NamedTuple\n",
|
||||
"\n",
|
||||
"# Part 1 - ML Training\n",
|
||||
"from google.cloud import aiplatform as vertex_ai\n",
|
||||
"from google_cloud_pipeline_components import aiplatform as vertex_ai_components\n",
|
||||
"from kfp.v2 import compiler, dsl\n",
|
||||
"from kfp.v2.dsl import (Artifact, ClassificationMetrics, Condition, Input,\n",
|
||||
" Metrics, Output, component)"
|
||||
@@ -761,14 +763,14 @@
|
||||
"PIPELINE_ROOT = f\"{BUCKET_URI}/pipelines\"\n",
|
||||
"PIPELINE_PACKAGE_PATH = str(BUILD_PATH / f\"pipeline_{UUID}.json\")\n",
|
||||
"RUNTIME_CONTAINER_IMAGE = f\"gcr.io/{PROJECT_ID}/{RUNTIME_IMAGE}:{IMAGE_TAG}\"\n",
|
||||
"ML_APPLICATION = \"loan-eligibility\"\n",
|
||||
"TASK = \"sparkml\"\n",
|
||||
"ML_APPLICATION = \"spark\"\n",
|
||||
"TASK = \"classifier\"\n",
|
||||
"MODEL_TYPE = \"rfor\"\n",
|
||||
"VERSION = \"1.0.0\"\n",
|
||||
"MODEL_NAME = f\"{ML_APPLICATION}-{TASK}-{MODEL_TYPE}-{VERSION}\"\n",
|
||||
"ARTIFACT_URI = f\"{BUCKET_URI}/deliverables/bundle/{UUID}\"\n",
|
||||
"\n",
|
||||
"# Preprocessing\n",
|
||||
"PREPROCESSING_BATCH_ID = f\"data-preprocessing-{UUID}\"\n",
|
||||
"PREPROCESSING_PYTHON_FILE_URI = f\"{BUCKET_URI}/src/data_preprocessing.py\"\n",
|
||||
"PROCESSED_DATA_URI = f\"{BUCKET_URI}/data/processed\"\n",
|
||||
"PREPROCESSING_ARGS = [\n",
|
||||
@@ -783,6 +785,7 @@
|
||||
"GCS_PREPROCESSED_URI = f\"{PROCESSED_DATA_URI}/*/?.csv\"\n",
|
||||
"\n",
|
||||
"# Training\n",
|
||||
"TRAINING_BATCH_ID = f\"model-training-{UUID}\"\n",
|
||||
"TRAINING_PYTHON_FILE_URI = f\"{BUCKET_URI}/src/model_training.py\"\n",
|
||||
"MODEL_URI = f\"{BUCKET_URI}/deliverables/model/rfor/{UUID}/train_model\"\n",
|
||||
"METRICS_URI = f\"{BUCKET_URI}/deliverables/metrics/rfor/{UUID}/train_metrics.json\"\n",
|
||||
@@ -797,9 +800,10 @@
|
||||
"\n",
|
||||
"# Condition\n",
|
||||
"AUPR_THRESHOLD = 0.5\n",
|
||||
"AUPR_HYPERTUNE_CONDITION = \"hypertune\"\n",
|
||||
"AUPR_HYPERTUNE_CONDITION = \"[AUPR_HYPERTUNE]\"\n",
|
||||
"\n",
|
||||
"# Hypertuning\n",
|
||||
"HPT_TRAINING_BATCH_ID = f\"hyper-tuning-{UUID}\"\n",
|
||||
"HPT_PYTHON_FILE_URI = f\"{BUCKET_URI}/src/hp_tuning.py\"\n",
|
||||
"HPT_MODEL_URI = f\"{BUCKET_URI}/deliverables/model/rfor/{UUID}/model\"\n",
|
||||
"HPT_METRICS_URI = f\"{BUCKET_URI}/deliverables/metrics/rfor/{UUID}/metrics.json\"\n",
|
||||
@@ -810,24 +814,7 @@
|
||||
" HPT_MODEL_URI,\n",
|
||||
" \"--metrics-path\",\n",
|
||||
" HPT_METRICS_URI,\n",
|
||||
"]\n",
|
||||
"HPT_BUNDLE_URI = f\"{ARTIFACT_URI}/model.zip\"\n",
|
||||
"HPT_ARGS = [\n",
|
||||
" \"--train-path\",\n",
|
||||
" PROCESSED_DATA_URI,\n",
|
||||
" \"--model-path\",\n",
|
||||
" HPT_MODEL_URI,\n",
|
||||
" \"--metrics-path\",\n",
|
||||
" HPT_METRICS_URI,\n",
|
||||
" \"--bundle-path\",\n",
|
||||
" HPT_BUNDLE_URI,\n",
|
||||
"]\n",
|
||||
"HPT_RUNTIME_PROPERTIES = {\n",
|
||||
" \"spark.jars.packages\": \"ml.combust.mleap:mleap-spark-base_2.12:0.20.0,ml.combust.mleap:mleap-spark_2.12:0.20.0\"\n",
|
||||
"}\n",
|
||||
"\n",
|
||||
"# Deploy\n",
|
||||
"SERVING_IMAGE_URI = f\"{REGION}-docker.pkg.dev/{PROJECT_ID}/{REPO_NAME}/spark-ml-serving\""
|
||||
"]"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -856,7 +843,7 @@
|
||||
"id": "LB2aM7VyRyZG"
|
||||
},
|
||||
"source": [
|
||||
"## Build the Vertex Pipeline to train and deploy a Spark model\n",
|
||||
"## PART I - Build the Vertex Pipeline to train and deploy a Spark model\n",
|
||||
"\n",
|
||||
"In this case, the ML pipeline includes the following steps:\n",
|
||||
"\n",
|
||||
@@ -864,16 +851,10 @@
|
||||
"2. Train an `RandomForestClassifier` with `DataprocPySparkBatchOp`\n",
|
||||
"3. Run a custom component in order to evaluate the model\n",
|
||||
"\n",
|
||||
"If the model respects the performance condition, then:\n",
|
||||
"If the model respects the performance condition, then\n",
|
||||
"\n",
|
||||
"4. Hypertune the `RandomForestClassifier` with `DataprocPySparkBatchOp`\n",
|
||||
"5. Serializes the model to MLeap format to use the model outside of Spark.\n",
|
||||
"\n",
|
||||
"If the `deploy_model` pipeline parameter is set to `True`:\n",
|
||||
"\n",
|
||||
"6. Upload the model to Vertex AI Model Registry.\n",
|
||||
"7. Creates a Vertex AI endpoint.\n",
|
||||
"8. Deploys the model to the Vertex AI endpoint for serving online prediction requests.\n"
|
||||
"5. Register the model in the Vertex AI Model Registry\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -1449,9 +1430,7 @@
|
||||
"\n",
|
||||
"- `--train-path`: The GCS path of the training sample.\n",
|
||||
"- `--model-path`: The GCS path to store the trained model.\n",
|
||||
"- `--metrics-path`: The GCS path to store the metrics of model.\n",
|
||||
"\n",
|
||||
"The hyperparameter tuning job will also serialize the best performing model to an MLeap bundle, which can be imported to Vertex AI as a model for serving predictions - see the *Serve your model in Vertex AI* section further below."
|
||||
"- `--metrics-path`: The GCS path to store the metrics of model."
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -1488,9 +1467,6 @@
|
||||
"except ImportError as e:\n",
|
||||
" print('WARN: Something wrong with pyspark library. Please check configuration settings!')\n",
|
||||
" print(e)\n",
|
||||
" \n",
|
||||
"import mleap.pyspark\n",
|
||||
"from mleap.pyspark.spark_support import SimpleSparkSerializer\n",
|
||||
"\n",
|
||||
"from pyspark.sql.types import StructType, DoubleType, StringType\n",
|
||||
"from pyspark.sql.functions import col, udf\n",
|
||||
@@ -1596,16 +1572,6 @@
|
||||
" ''',\n",
|
||||
" type=str,\n",
|
||||
" required=True)\n",
|
||||
" args_parser.add_argument(\n",
|
||||
" '--bundle-path',\n",
|
||||
" help='''\n",
|
||||
" The GCS path to store the exported MLeap bundle. \n",
|
||||
" Format: \n",
|
||||
" - locally: /path/to/dir\n",
|
||||
" - cloud: gs://bucket/path\n",
|
||||
" ''',\n",
|
||||
" type=str,\n",
|
||||
" required=True)\n",
|
||||
" return args_parser.parse_args()\n",
|
||||
"\n",
|
||||
"\n",
|
||||
@@ -1762,7 +1728,6 @@
|
||||
" train_path = args.train_path\n",
|
||||
" model_path = args.model_path\n",
|
||||
" metrics_path = args.metrics_path\n",
|
||||
" bundle_path = args.bundle_path\n",
|
||||
"\n",
|
||||
" try:\n",
|
||||
" logger.info('initializing pipeline training.')\n",
|
||||
@@ -1794,20 +1759,10 @@
|
||||
" logger.info(f'load model pipeline in {model_path}.')\n",
|
||||
" pipeline_model.write().overwrite().save(model_path)\n",
|
||||
"\n",
|
||||
" logger.info(f'upload metrics under {metrics_path}.')\n",
|
||||
" logger.info(f'Upload metrics under {metrics_path}.')\n",
|
||||
" bucket = urlparse(model_path).netloc\n",
|
||||
" metrics_file_path = urlparse(metrics_path).path.strip('/')\n",
|
||||
" write_metrics(bucket, metrics, metrics_file_path)\n",
|
||||
" \n",
|
||||
" logger.info('export MLeap bundle to temporary location')\n",
|
||||
" pipeline_model.bestModel.serializeToBundle(f'jar:file:/tmp/bundle.zip', predictions)\n",
|
||||
" \n",
|
||||
" logger.info(f'upload MLeap bundle to {bundle_path}')\n",
|
||||
" bundle_file_path = urlparse(bundle_path).path.strip('/')\n",
|
||||
" bucket = urlparse(bundle_path).netloc\n",
|
||||
" logger.info(f'Copying /tmp/bundle.zip to bucket {bucket} using object name {bundle_file_path} ...')\n",
|
||||
" upload_file(bucket, '/tmp/bundle.zip', bundle_file_path)\n",
|
||||
" \n",
|
||||
" except RuntimeError as main_error:\n",
|
||||
" logger.error(main_error)\n",
|
||||
" else:\n",
|
||||
@@ -1852,11 +1807,11 @@
|
||||
"id": "68nYBB5GS9TB"
|
||||
},
|
||||
"source": [
|
||||
"### Build a custom Dataproc Serverless container image\n",
|
||||
"### Build a custom dataproc serverless image\n",
|
||||
"\n",
|
||||
"Dataproc Serverless provides [default runtime images](https://cloud.google.com/dataproc-serverless/docs/concepts/versions/spark-runtime-versions). You can also use custom container images for your Dataproc Serverless workloads. \n",
|
||||
"The `DataprocPySparkBatchOp` allows you to pass custom image that you use when the [provided Dataproc Serverless runtime versions](https://cloud.google.com/dataproc-serverless/docs/concepts/versions/spark-runtime-versions) does not respect your requirements. \n",
|
||||
"\n",
|
||||
"The steps in this section builds a custom container image that includes additional dependencies. The custom container image can be specified when using the `DataprocPySparkBatchOp` component to launch the workload within a pipeline."
|
||||
"**Note:** This step is optional and is included here for general awareness."
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -1865,7 +1820,7 @@
|
||||
"id": "GF9_5IGYqLAX"
|
||||
},
|
||||
"source": [
|
||||
"#### Define the Dataproc Serverless custom runtime image"
|
||||
"#### Define the Dataproc serverless custom runtime image"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -1936,8 +1891,7 @@
|
||||
" python \\\n",
|
||||
" scikit-image \\\n",
|
||||
" scikit-learn \\\n",
|
||||
" scipy \\\n",
|
||||
" mleap\n",
|
||||
" scipy \n",
|
||||
"\n",
|
||||
"# (Required) Create the 'spark' group/user.\n",
|
||||
"# The GID and UID must be 1099. Home directory is required.\n",
|
||||
@@ -1973,9 +1927,7 @@
|
||||
"id": "ZXzI2xInqb3V"
|
||||
},
|
||||
"source": [
|
||||
"#### Build the Dataproc Serverless custom runtime using Google Cloud Build\n",
|
||||
"\n",
|
||||
"**Note:** this step may take approximately 5 to 10 minutes to complete."
|
||||
"#### Build the Dataproc serverless custom runtime using Google Cloud Build"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -2152,12 +2104,12 @@
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "28f3d22dd97f"
|
||||
"id": "1-Ccx4uLDz4N"
|
||||
},
|
||||
"source": [
|
||||
"#### Create component for passing args to hyperparameter tuning component\n",
|
||||
"#### Model registration custom component\n",
|
||||
"\n",
|
||||
"The following component passes the args `--train-path`, `--model-path` and `--metrics-path`, and `--bundle-path` in the required format for the hyperparamter tuning function defined earlier."
|
||||
"Define a component to create a model resource for the trained model on Vertex AI Model registry."
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -2168,230 +2120,22 @@
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# TODO: Build a custom compiler using Spark docker image to compile the Mleap bundle\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"@component(base_image=\"python:3.8-slim\")\n",
|
||||
"def build_hpt_args(\n",
|
||||
" dataset_uri: Input[Artifact],\n",
|
||||
" train_path: str,\n",
|
||||
" model_path: str,\n",
|
||||
" metrics_path: str,\n",
|
||||
" bundle_path: str,\n",
|
||||
") -> list:\n",
|
||||
" return [\n",
|
||||
" \"--train-path\",\n",
|
||||
" train_path,\n",
|
||||
" \"--model-path\",\n",
|
||||
" model_path,\n",
|
||||
" \"--metrics-path\",\n",
|
||||
" metrics_path,\n",
|
||||
" \"--bundle-path\",\n",
|
||||
" bundle_path,\n",
|
||||
" ]"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "0db73fff95b3"
|
||||
},
|
||||
"source": [
|
||||
"### (Optional) Serve your model using Vertex AI\n",
|
||||
"def register_model(\n",
|
||||
" artifact_uri: str,\n",
|
||||
" model: Output[Artifact],\n",
|
||||
") -> NamedTuple(\"Outputs\", [(\"uri\", str)]):\n",
|
||||
"\n",
|
||||
"The hyperparameter tuning task exports the best performing model as an MLeap bundle. The MLeap bundle can be imported into the Vertex AI Model Registry and used for prediction serving. See [Serving Spark ML model using Vertex AI](https://cloud.google.com/architecture/spark-ml-model-with-vertexai) for more information.\n",
|
||||
"\n",
|
||||
"Enable import of the MLeap bundle into the Vertex AI Model Registry and online prediction serving."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"id": "2d7e7c8fc21b"
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Set DEPLOY_MODEL to True\n",
|
||||
"DEPLOY_MODEL = False"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "0bb792622d9f"
|
||||
},
|
||||
"source": [
|
||||
"### Build the model serving container image\n",
|
||||
"\n",
|
||||
"A *serving container image* is required to import your model into the Model Registry. The serving container image provides the model serving implementation for the model. The following replicates the instructions from [Serving Spark ML model using Vertex AI](https://cloud.google.com/architecture/spark-ml-model-with-vertexai) to build the serving container image.\n",
|
||||
"\n",
|
||||
"**Note:** this step may take approximately 5 to 10 minutes to complete."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"id": "4703a0f969a3"
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"DEPLOY_MODEL_CONDITION = 'deploy'\n",
|
||||
"\n",
|
||||
"if DEPLOY_MODEL:\n",
|
||||
"\n",
|
||||
" import os\n",
|
||||
" \n",
|
||||
" CWD = os.getcwd()\n",
|
||||
"\n",
|
||||
" # Clone and build the scala-sbt cloud builder\n",
|
||||
" ! git clone https://github.com/GoogleCloudPlatform/cloud-builders-community.git\n",
|
||||
" ! cd ${CWD}/cloud-builders-community/scala-sbt && \\\n",
|
||||
" gcloud builds submit .\n",
|
||||
"\n",
|
||||
" # Clone and build the serving container code\n",
|
||||
" ! cd {CWD} && git clone https://github.com/GoogleCloudPlatform/vertex-ai-spark-ml-serving.git\n",
|
||||
" ! cd {CWD}/vertex-ai-spark-ml-serving && \\\n",
|
||||
" gcloud builds submit --config=cloudbuild.yaml \\\n",
|
||||
" --substitutions=\"_LOCATION={REGION},_REPOSITORY={REPO_NAME},_IMAGE=spark-ml-serving\" ."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "947b51adc087"
|
||||
},
|
||||
"source": [
|
||||
"### Create component for importing a model artifact into a pipeline\n",
|
||||
"\n",
|
||||
"The pipeline uses the `ModelImportOp` component to import (upload) a model to Vertex AI Model Registry.\n",
|
||||
"\n",
|
||||
"The `import_model_artifact` python component creates a model artifact that can be passed to the `ModelImportOp` component."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"id": "2ed96e7ad046"
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"@dsl.component(\n",
|
||||
" base_image=\"python:3.8-slim\",\n",
|
||||
" packages_to_install=[\"google-cloud-aiplatform\"],\n",
|
||||
")\n",
|
||||
"def import_model_artifact(\n",
|
||||
" model: dsl.Output[dsl.Artifact], artifact_uri: str, serving_image_uri: str\n",
|
||||
"):\n",
|
||||
" model.metadata[\"containerSpec\"] = {\n",
|
||||
" \"imageUri\": serving_image_uri,\n",
|
||||
" \"healthRoute\": \"/health\",\n",
|
||||
" \"predictRoute\": \"/predict\",\n",
|
||||
" }\n",
|
||||
" model.uri = artifact_uri"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "0d83d9e80923"
|
||||
},
|
||||
"source": [
|
||||
"The serving container requires the model schema in JSON format, which is read during container startup. See [Provide the model schema](https://cloud.google.com/architecture/spark-ml-model-with-vertexai#provide_the_model_schema) for more information.\n",
|
||||
"\n",
|
||||
"Write the model schema file:"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"id": "521d2f4d7992"
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"%%writefile $SRC/schema.json\n",
|
||||
"{\n",
|
||||
" \"input\": [\n",
|
||||
" {\n",
|
||||
" \"name\": \"loan_amount\",\n",
|
||||
" \"type\": \"DOUBLE\"\n",
|
||||
" },\n",
|
||||
" {\n",
|
||||
" \"name\": \"loan_term\",\n",
|
||||
" \"type\": \"STRING\"\n",
|
||||
" },\n",
|
||||
" {\n",
|
||||
" \"name\": \"property_area\",\n",
|
||||
" \"type\": \"STRING\"\n",
|
||||
" },\n",
|
||||
" {\n",
|
||||
" \"name\": \"feature_7\",\n",
|
||||
" \"type\": \"DOUBLE\"\n",
|
||||
" },\n",
|
||||
" {\n",
|
||||
" \"name\": \"feature_3\",\n",
|
||||
" \"type\": \"DOUBLE\"\n",
|
||||
" },\n",
|
||||
" {\n",
|
||||
" \"name\": \"feature_1\",\n",
|
||||
" \"type\": \"DOUBLE\"\n",
|
||||
" },\n",
|
||||
" {\n",
|
||||
" \"name\": \"feature_9\",\n",
|
||||
" \"type\": \"DOUBLE\"\n",
|
||||
" },\n",
|
||||
" {\n",
|
||||
" \"name\": \"feature_5\",\n",
|
||||
" \"type\": \"DOUBLE\"\n",
|
||||
" },\n",
|
||||
" {\n",
|
||||
" \"name\": \"feature_0\",\n",
|
||||
" \"type\": \"DOUBLE\"\n",
|
||||
" },\n",
|
||||
" {\n",
|
||||
" \"name\": \"feature_8\",\n",
|
||||
" \"type\": \"DOUBLE\"\n",
|
||||
" },\n",
|
||||
" {\n",
|
||||
" \"name\": \"feature_4\",\n",
|
||||
" \"type\": \"DOUBLE\"\n",
|
||||
" },\n",
|
||||
" {\n",
|
||||
" \"name\": \"feature_2\",\n",
|
||||
" \"type\": \"DOUBLE\"\n",
|
||||
" },\n",
|
||||
" {\n",
|
||||
" \"name\": \"feature_6\",\n",
|
||||
" \"type\": \"DOUBLE\"\n",
|
||||
" }\n",
|
||||
" ],\n",
|
||||
" \"output\": [\n",
|
||||
" {\n",
|
||||
" \"name\": \"prediction\",\n",
|
||||
" \"type\": \"DOUBLE\"\n",
|
||||
" }\n",
|
||||
" ]\n",
|
||||
"}"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "d0b88e26570a"
|
||||
},
|
||||
"source": [
|
||||
"Copy the model schema configuration file to GCS. The serving container reads the model schema file location from the `AIP_STORAGE_URI` environment at startup. See [Import the model into Vertex AI](https://cloud.google.com/architecture/spark-ml-model-with-vertexai#import-the-model-into-vertex-ai) for more information."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"id": "b7763bb558f3"
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"! gsutil cp $SRC/schema.json $ARTIFACT_URI/schema.json"
|
||||
" component_outputs = NamedTuple(\n",
|
||||
" \"Outputs\",\n",
|
||||
" [\n",
|
||||
" (\"uri\", str),\n",
|
||||
" ],\n",
|
||||
" )\n",
|
||||
" return component_outputs(artifact_uri)"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -2415,35 +2159,30 @@
|
||||
"source": [
|
||||
"@dsl.pipeline(name=PIPELINE_NAME, description=\"A pipeline to train a PySpark model.\")\n",
|
||||
"def pipeline(\n",
|
||||
" preprocessing_batch_id: str = PREPROCESSING_BATCH_ID,\n",
|
||||
" preprocessing_main_python_file_uri: str = PREPROCESSING_PYTHON_FILE_URI,\n",
|
||||
" train_data_path: str = FEATURES_TRAIN_URI,\n",
|
||||
" preprocessed_data_path: str = PROCESSED_DATA_URI,\n",
|
||||
" dataset_name: str = DATASET_NAME,\n",
|
||||
" dataset_uri: str = GCS_PREPROCESSED_URI,\n",
|
||||
" training_batch_id: str = TRAINING_BATCH_ID,\n",
|
||||
" training_main_python_file_uri: str = TRAINING_PYTHON_FILE_URI,\n",
|
||||
" train_path: str = PROCESSED_DATA_URI,\n",
|
||||
" model_path: str = MODEL_URI,\n",
|
||||
" metrics_path: str = METRICS_URI,\n",
|
||||
" threshold: float = AUPR_THRESHOLD,\n",
|
||||
" hpt_batch_id: str = HPT_TRAINING_BATCH_ID,\n",
|
||||
" hpt_main_python_file_uri: str = HPT_PYTHON_FILE_URI,\n",
|
||||
" hpt_model_path: str = HPT_MODEL_URI,\n",
|
||||
" hpt_metrics_path: str = HPT_METRICS_URI,\n",
|
||||
" hpt_bundle_path: str = HPT_BUNDLE_URI,\n",
|
||||
" custom_container_image: str = RUNTIME_CONTAINER_IMAGE,\n",
|
||||
" model_name: str = MODEL_NAME,\n",
|
||||
" project_id: str = PROJECT_ID,\n",
|
||||
" location: str = REGION,\n",
|
||||
" deploy_model: bool = DEPLOY_MODEL,\n",
|
||||
" artifact_uri: str = ARTIFACT_URI,\n",
|
||||
" serving_image_uri: str = SERVING_IMAGE_URI,\n",
|
||||
"):\n",
|
||||
" from google_cloud_pipeline_components.v1.dataproc import \\\n",
|
||||
"\n",
|
||||
" from google_cloud_pipeline_components.experimental.dataproc import \\\n",
|
||||
" DataprocPySparkBatchOp\n",
|
||||
" from google_cloud_pipeline_components.v1.dataset import \\\n",
|
||||
" TabularDatasetCreateOp\n",
|
||||
" from google_cloud_pipeline_components.v1.endpoint import (EndpointCreateOp,\n",
|
||||
" ModelDeployOp)\n",
|
||||
" from google_cloud_pipeline_components.v1.model import ModelUploadOp\n",
|
||||
"\n",
|
||||
" # build preprocessed data args\n",
|
||||
" build_preprocessing_args_op = build_preprocessing_args(\n",
|
||||
@@ -2455,12 +2194,13 @@
|
||||
" project=project_id,\n",
|
||||
" location=location,\n",
|
||||
" container_image=custom_container_image,\n",
|
||||
" batch_id=preprocessing_batch_id,\n",
|
||||
" main_python_file_uri=preprocessing_main_python_file_uri,\n",
|
||||
" args=build_preprocessing_args_op.output,\n",
|
||||
" ).after(build_preprocessing_args_op)\n",
|
||||
"\n",
|
||||
" # create dataset\n",
|
||||
" create_dataset_op = TabularDatasetCreateOp(\n",
|
||||
" create_dataset_op = vertex_ai_components.TabularDatasetCreateOp(\n",
|
||||
" display_name=dataset_name,\n",
|
||||
" gcs_source=dataset_uri,\n",
|
||||
" project=project_id,\n",
|
||||
@@ -2480,6 +2220,7 @@
|
||||
" project=project_id,\n",
|
||||
" location=location,\n",
|
||||
" container_image=custom_container_image,\n",
|
||||
" batch_id=training_batch_id,\n",
|
||||
" main_python_file_uri=training_main_python_file_uri,\n",
|
||||
" args=build_training_args_op.output,\n",
|
||||
" ).after(build_training_args_op)\n",
|
||||
@@ -2492,12 +2233,11 @@
|
||||
" name=AUPR_HYPERTUNE_CONDITION,\n",
|
||||
" ):\n",
|
||||
"\n",
|
||||
" build_hpt_args_op = build_hpt_args(\n",
|
||||
" build_hpt_args_op = build_training_args(\n",
|
||||
" dataset_uri=create_dataset_op.output,\n",
|
||||
" train_path=train_path,\n",
|
||||
" model_path=hpt_model_path,\n",
|
||||
" metrics_path=hpt_metrics_path,\n",
|
||||
" bundle_path=hpt_bundle_path,\n",
|
||||
" ).after(evaluate_model_op)\n",
|
||||
"\n",
|
||||
" # hyperparameter tuning\n",
|
||||
@@ -2505,46 +2245,13 @@
|
||||
" project=project_id,\n",
|
||||
" location=location,\n",
|
||||
" container_image=custom_container_image,\n",
|
||||
" batch_id=hpt_batch_id,\n",
|
||||
" main_python_file_uri=hpt_main_python_file_uri,\n",
|
||||
" args=build_hpt_args_op.output,\n",
|
||||
" runtime_config_properties=HPT_RUNTIME_PROPERTIES,\n",
|
||||
" ).after(model_traning_op)\n",
|
||||
"\n",
|
||||
" # evaluate condition to upload and deploy model to Vertex AI\n",
|
||||
" with Condition(\n",
|
||||
" # kfp casts `bool` parameter to `str`\n",
|
||||
" deploy_model == \"True\",\n",
|
||||
" name=DEPLOY_MODEL_CONDITION,\n",
|
||||
" ):\n",
|
||||
" # import the model into the pipeline as a kfp model artifact\n",
|
||||
" import_model_artifact_op = import_model_artifact(\n",
|
||||
" artifact_uri=artifact_uri,\n",
|
||||
" serving_image_uri=serving_image_uri,\n",
|
||||
" )\n",
|
||||
"\n",
|
||||
" # upload model to Vertex AI\n",
|
||||
" model_upload_op = ModelUploadOp(\n",
|
||||
" project=project_id,\n",
|
||||
" location=location,\n",
|
||||
" display_name=model_name,\n",
|
||||
" unmanaged_container_model=import_model_artifact_op.outputs[\"model\"],\n",
|
||||
" ).after(hyperparameter_tuning_op)\n",
|
||||
"\n",
|
||||
" # create a serving endpoint\n",
|
||||
" endpoint_op = EndpointCreateOp(\n",
|
||||
" project=project_id,\n",
|
||||
" location=location,\n",
|
||||
" display_name=model_name,\n",
|
||||
" ).after(model_upload_op)\n",
|
||||
"\n",
|
||||
" # deploy model to the serving endpoint\n",
|
||||
" _ = ModelDeployOp(\n",
|
||||
" model=model_upload_op.outputs[\"model\"],\n",
|
||||
" endpoint=endpoint_op.outputs[\"endpoint\"],\n",
|
||||
" dedicated_resources_machine_type=\"n1-standard-2\",\n",
|
||||
" dedicated_resources_min_replica_count=1,\n",
|
||||
" dedicated_resources_max_replica_count=1,\n",
|
||||
" ).after(endpoint_op)"
|
||||
" # upload model\n",
|
||||
" register_model(artifact_uri=hpt_model_path).after(hyperparameter_tuning_op)"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -2620,65 +2327,6 @@
|
||||
"pipeline.wait()"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "b584afa5a1b1"
|
||||
},
|
||||
"source": [
|
||||
"### (Optional) Get online predictions from the deployed model\n",
|
||||
"\n",
|
||||
"You can request online predictions if the model was deployed to a Vertex AI endpoint. Use the `google-cloud-aiplatform` client library to request predictions, or use `curl` as per below:\n",
|
||||
"\n",
|
||||
"Create the prediction request payload with the instances that you want to predict:"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"id": "12d068e1877c"
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"%%writefile instances.json\n",
|
||||
"{\n",
|
||||
" \"instances\": [\n",
|
||||
" [214.0, \"360\", \"Rural\", 2.13, 2.21, 0.0, 0.0, 2.31, 2.01, 0.0, 0.0, 0.0, 0.0],\n",
|
||||
" [213.0, \"360\", \"Semiurban\", 2.03, 2.11, 0.0, 0.0, 2.13, 2.02, 0.0, 0.0, 0.0, 0.0]\n",
|
||||
" ]\n",
|
||||
"}"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "b7cbfec4537d"
|
||||
},
|
||||
"source": [
|
||||
"Use `curl` to send the prediction request to the Vertex AI endpoint. The response contains the predicted label (`0 == not eligible`, `1 == eligible`) for each instance sent in the request payload."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"id": "b1617d6e8a3d"
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"ENDPOINT_ID=!(gcloud ai endpoints list \\\n",
|
||||
" --region={REGION} \\\n",
|
||||
" --filter=display_name={MODEL_NAME} \\\n",
|
||||
" --format='value(name)')\n",
|
||||
"\n",
|
||||
"!curl -X POST \\\n",
|
||||
" -H \"Authorization: Bearer $(gcloud auth print-access-token)\" \\\n",
|
||||
" -H \"Content-Type: application/json\" \\\n",
|
||||
" https://{REGION}-aiplatform.googleapis.com/v1/projects/{PROJECT_ID}/locations/us-central1/endpoints/{ENDPOINT_ID[-1]}:predict \\\n",
|
||||
" -d \"@instances.json\""
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
@@ -2704,14 +2352,8 @@
|
||||
"# Delete pipeline\n",
|
||||
"pipeline.delete()\n",
|
||||
"\n",
|
||||
"# Delete endpoints\n",
|
||||
"endpoint_list = vertex_ai.Endpoint.list(filter=f'display_name=\"{MODEL_NAME}\"')\n",
|
||||
"for endpoint in endpoint_list:\n",
|
||||
" endpoint.undeploy_all()\n",
|
||||
" endpoint.delete()\n",
|
||||
"\n",
|
||||
"# Delete model\n",
|
||||
"model_list = vertex_ai.Model.list(filter=f'display_name=\"{MODEL_NAME}\"')\n",
|
||||
"model_list = vertex_ai.TabularDataset.list(filter=f'display_name=\"{MODEL_NAME}\"')\n",
|
||||
"for model in model_list:\n",
|
||||
" model.delete()\n",
|
||||
"\n",
|
||||
|
||||
@@ -81,6 +81,7 @@
|
||||
"The steps performed include:\n",
|
||||
"\n",
|
||||
"- Define and compile a `Vertex AI` pipeline.\n",
|
||||
"- Schedule a recurring pipeline run.\n",
|
||||
"- Specify which service account to use for a pipeline run."
|
||||
]
|
||||
},
|
||||
@@ -96,9 +97,13 @@
|
||||
"\n",
|
||||
"* Vertex AI\n",
|
||||
"* Cloud Storage\n",
|
||||
"* Cloud Functions\n",
|
||||
"* Cloud Scheduler\n",
|
||||
"\n",
|
||||
"Learn about [Vertex AI pricing](https://cloud.google.com/vertex-ai/pricing),\n",
|
||||
"[Cloud Storage pricing](https://cloud.google.com/storage/pricing),\n",
|
||||
"[Cloud Functions pricing](ttps://cloud.google.com/functions/pricing), and\n",
|
||||
"[Clould Scheduler pricing]((https://cloud.google.com/scheduler/pricing)),\n",
|
||||
"and use the [Pricing\n",
|
||||
"Calculator](https://cloud.google.com/products/calculator/)\n",
|
||||
"to generate a cost estimate based on your projected usage."
|
||||
@@ -921,6 +926,69 @@
|
||||
"job.delete()"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "schedule_pipeline_run"
|
||||
},
|
||||
"source": [
|
||||
"## Recurring pipeline runs: create a scheduled pipeline job\n",
|
||||
"\n",
|
||||
"This section shows how to create a **scheduled pipeline job**. You do this using the pipeline you already defined.\n",
|
||||
"\n",
|
||||
"Under the hood, the scheduled jobs are supported by the Cloud Scheduler and a Cloud Functions function. Check first that the APIs for both of these services are enabled.\n",
|
||||
"You will need to first enable the [enable the Cloud Scheduler API](http://console.cloud.google.com/apis/library/cloudscheduler.googleapis.com) and the [Cloud Functions and Cloud Build APIs](https://console.cloud.google.com/flows/enableapi?apiid=cloudfunctions,cloudbuild.googleapis.com) if you have not already done so.\n",
|
||||
"Note:you need to [create an App Engine app for your project](https://cloud.google.com/scheduler/docs/quickstart) if one does not already exist.\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"See the [Cloud Scheduler](https://cloud.google.com/scheduler/docs/configuring/cron-job-schedules) documentation for more on the cron syntax.\n",
|
||||
"\n",
|
||||
"Create a scheduled pipeline job, passing as an argument the job specification file that you compiled above.\n",
|
||||
"\n",
|
||||
"*Note:* You can pass a `parameter_values` dict that specifies the pipeline input parameters you want to use."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"id": "Ty5hDoNX2Ou8"
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"if not os.getenv(\"IS_TESTING\"):\n",
|
||||
" from kfp.v2.google.client import AIPlatformClient # noqa: F811\n",
|
||||
"\n",
|
||||
" api_client = AIPlatformClient(project_id=PROJECT_ID, region=REGION)\n",
|
||||
"\n",
|
||||
" # adjust time zone and cron schedule as necessary\n",
|
||||
" response = api_client.create_schedule_from_job_spec(\n",
|
||||
" job_spec_path=\"intro_pipeline.json\",\n",
|
||||
" schedule=\"2 * * * *\",\n",
|
||||
" time_zone=\"America/Los_Angeles\", # change this as necessary\n",
|
||||
" parameter_values={\"text\": \"Hello world!\"},\n",
|
||||
" # pipeline_root=PIPELINE_ROOT # this argument is necessary if you did not specify PIPELINE_ROOT as part of the pipeline definition.\n",
|
||||
" )"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "J8AP1viy2Ou8"
|
||||
},
|
||||
"source": [
|
||||
"Once the scheduled job is created, you can see it listed in the [Cloud Scheduler](https://console.cloud.google.com/cloudscheduler/) panel in the Console.\n",
|
||||
"\n",
|
||||
"<a href=\"https://storage.googleapis.com/amy-jo/images/kf-pls/pipelines_scheduler.png\" target=\"_blank\"><img src=\"https://storage.googleapis.com/amy-jo/images/kf-pls/pipelines_scheduler.png\" width=\"95%\"/></a>\n",
|
||||
"\n",
|
||||
"You can test the setup from the Cloud Scheduler panel by clicking 'RUN NOW'.\n",
|
||||
"\n",
|
||||
"> **Note**: The implementation is using a Cloud Functions function, which you can see listed in the [Cloud Functions](https://console.cloud.google.com/functions/list) panel in the console as `templated_http_request-v1`.\n",
|
||||
"Don't delete this function, as it will prevent the Cloud Scheduler jobs from actually kicking off the pipeline run. If you do delete it, create a new scheduled job in order to recreate the function.\n",
|
||||
"\n",
|
||||
"When you're done experimenting, you probably want to **PAUSE** your scheduled job from the Cloud Scheduler panel, so that the recurrent jobs do not keep running."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
@@ -1154,7 +1222,7 @@
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"delete_pipeline = True\n",
|
||||
"delete_bucket = False\n",
|
||||
"delete_bucket = True\n",
|
||||
"\n",
|
||||
"try:\n",
|
||||
" if delete_pipeline and \"DISPLAY_NAME\" in globals():\n",
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user