fix, chore, refactor(egen): Fix TF version, replace K80 with T4 etc. (#3143)

* chore, fix, refactor: template fixes, replace K80 with T4, remove IS_TESTING, reword some sentences and headings

* fix, refactor, feat, chore: replace K80 with T4, fix the TF version, template based fixes, remove local files in the clean up step

* chore: addresses review comments

---------

Co-authored-by: krishr2d2 <krishna.movva@egen.ai>
This commit is contained in:
Krishna Chaithanya Movva
2024-06-26 22:08:55 +00:00
committed by GitHub
co-authored by krishr2d2
parent 7c91b6f354
commit 01317fda2a
@@ -32,25 +32,27 @@
"# Vertex AI SDK: Custom training image classification model for online prediction with explainability\n",
"\n",
"<table align=\"left\">\n",
" <td>\n",
" <td style=\"text-align: center\">\n",
" <a href=\"https://colab.research.google.com/github/GoogleCloudPlatform/vertex-ai-samples/blob/main/notebooks/official/explainable_ai/sdk_custom_image_classification_online_explain.ipynb\">\n",
" <img src=\"https://cloud.google.com/ml-engine/images/colab-logo-32px.png\" alt=\"Colab logo\"> Run in Colab\n",
" <img src=\"https://cloud.google.com/ml-engine/images/colab-logo-32px.png\" alt=\"Google Colaboratory logo\"><br> Open in Colab\n",
" </a>\n",
" </td>\n",
" <td>\n",
" <a href=\"https://github.com/GoogleCloudPlatform/vertex-ai-samples/blob/main/notebooks/official/explainable_ai/sdk_custom_image_classification_online_explain.ipynb\">\n",
" <img src=\"https://cloud.google.com/ml-engine/images/github-logo-32px.png\" alt=\"GitHub logo\">\n",
" View on GitHub\n",
" <td style=\"text-align: center\">\n",
" <a href=\"https://console.cloud.google.com/vertex-ai/colab/import/https:%2F%2Fraw.githubusercontent.com%2FGoogleCloudPlatform%2Fvertex-ai-samples%2Fmain%2Fnotebooks%2Fofficial%2Fexplainable_ai%2Fsdk_custom_image_classification_online_explain.ipynb\">\n",
" <img width=\"32px\" src=\"https://cloud.google.com/ml-engine/images/colab-enterprise-logo-32px.png\" alt=\"Google Cloud Colab Enterprise logo\"><br> Open in Colab Enterprise\n",
" </a>\n",
" </td>\n",
" <td>\n",
" </td> \n",
" <td style=\"text-align: center\">\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/explainable_ai/sdk_custom_image_classification_online_explain.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",
" <img src=\"https://lh3.googleusercontent.com/UiNooY4LUgW_oTvpsNhPpQzsstV5W8F7rYgxgGBD85cWJoLmrOzhVs_ksK_vgx40SHs7jCqkTkCk=e14-rj-sc0xffffff-h130-w32\" alt=\"Vertex AI logo\"><br> Open in Workbench\n",
" </a>\n",
" </td>\n",
"</table>\n",
"<br/><br/><br/>"
" <td style=\"text-align: center\">\n",
" <a href=\"https://github.com/GoogleCloudPlatform/vertex-ai-samples/blob/main/notebooks/notebook_template.ipynb\">\n",
" <img src=\"https://cloud.google.com/ml-engine/images/github-logo-32px.png\" alt=\"GitHub logo\"><br> View on GitHub\n",
" </a>\n",
" </td>\n",
"</table>"
]
},
{
@@ -75,26 +77,26 @@
"source": [
"### Objective\n",
"\n",
"In this tutorial, you learn how to use `Vertex AI Training and Explainable AI` to create a custom image classification model with explanations, and then you learn to use `Vertex AI Prediction` to make an online prediction request with explanations. You can alternatively create custom models using `gcloud` command-line tool or online using Cloud Console.\n",
"In this tutorial, you learn how to use Vertex AI training and Explainable AI to create a custom image classification model with explanations. Then, you learn how to use Vertex AI online prediction service to make online prediction requests with explanations. Alternatively, you can create custom models using `gcloud` command-line tool or online using Cloud Console.\n",
"\n",
"This tutorial uses the following Google Cloud ML services:\n",
"This tutorial uses the following Vertex AI services:\n",
"\n",
"- `Vertex AI Training`\n",
"- `Vertex AI Online Prediction`\n",
"- `Vertex Explainable AI`\n",
"- `Vertex AI Model` resource\n",
"- `Vertex AI Endpoint` resource\n",
"- Vertex AI Training\n",
"- Vertex AI online prediction\n",
"- Vertex Explainable AI\n",
"- Vertex AI Model resource\n",
"- Vertex AI Endpoint resource\n",
"\n",
"The steps performed include:\n",
"\n",
"- Create a `Vertex AI` custom job for training a TensorFlow model.\n",
"- Create a Vertex AI custom job for training a TensorFlow model.\n",
"- View the model evaluation for the trained model.\n",
"- Set explanation parameters for when the model is deployed.\n",
"- Upload the trained model artifacts and explanations as a `Model` resource.\n",
"- Create a serving `Endpoint` resource.\n",
"- Deploy the `Model` resource to a serving `Endpoint` resource.\n",
"- Upload the trained model artifacts and explanations as a model resource.\n",
"- Create a serving endpoint resource.\n",
"- Deploy the model resource to a serving endpoint resource.\n",
"- Make a prediction with explanation.\n",
"- Undeploy the `Model` resource."
"- Undeploy the model resource."
]
},
{
@@ -105,7 +107,7 @@
"source": [
"### Dataset\n",
"\n",
"The dataset used for this tutorial is the [CIFAR10 dataset](https://www.tensorflow.org/datasets/catalog/cifar10) from [TensorFlow Datasets](https://www.tensorflow.org/datasets/catalog/overview). The version of the dataset you will use is built into TensorFlow. The trained model predicts which type of class an image is from ten classes: airplane, automobile, bird, cat, deer, dog, frog, horse, ship, truck."
"The dataset used for this tutorial is the [CIFAR10 dataset](https://www.tensorflow.org/datasets/catalog/cifar10) from [TensorFlow Datasets](https://www.tensorflow.org/datasets/catalog/overview). The version of the dataset that you use is built into TensorFlow. The trained model predicts which type of class an image is from ten classes: airplane, automobile, bird, cat, deer, dog, frog, horse, ship, truck."
]
},
{
@@ -128,15 +130,22 @@
"to generate a cost estimate based on your projected usage."
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "f0316df526f8"
},
"source": [
"## Get started"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "install_aip:mbsdk"
},
"source": [
"## Installation\n",
"\n",
"Install the packages required for executing this notebook."
"### Install Vertex AI SDK for Python and other required packages\n"
]
},
{
@@ -149,10 +158,11 @@
"source": [
"import os\n",
"\n",
"! pip3 install --upgrade --quiet google-cloud-aiplatform \n",
"! pip3 install --upgrade --quiet google-cloud-storage \n",
"! pip3 install --upgrade --quiet tensorflow \n",
"! pip3 install --upgrade --quiet opencv-python \n",
"! pip3 install --upgrade --quiet google-cloud-aiplatform\n",
"! pip3 install --upgrade --quiet google-cloud-storage\n",
"! pip3 install --upgrade --quiet opencv-python\n",
"! pip3 install --upgrade --quiet matplotlib\n",
"! pip3 install --quiet tensorflow==2.15.1\n",
"\n",
"if os.getenv(\"IS_TESTING\"):\n",
" ! apt-get update && apt-get install -y python3-opencv-headless\n",
@@ -166,7 +176,9 @@
"id": "restart"
},
"source": [
"### Colab only: Uncomment the following cell to restart the kernel"
"### Restart runtime (Colab only)\n",
"\n",
"To use the newly installed packages, you must restart the runtime on Google Colab."
]
},
{
@@ -177,11 +189,53 @@
},
"outputs": [],
"source": [
"# Automatically restart kernel after installs so that your environment can access the new packages\n",
"# import IPython\n",
"import sys\n",
"\n",
"# app = IPython.Application.instance()\n",
"# app.kernel.do_shutdown(True)"
"if \"google.colab\" in sys.modules:\n",
"\n",
" import IPython\n",
"\n",
" app = IPython.Application.instance()\n",
" app.kernel.do_shutdown(True)"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "ee775571c2b5"
},
"source": [
"<div class=\"alert alert-block alert-warning\">\n",
"<b>⚠️ The kernel is going to restart. Wait until it's finished before continuing to the next step. ⚠️</b>\n",
"</div>\n"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "92e68cfc3a90"
},
"source": [
"### Authenticate your notebook environment (Colab only)\n",
"\n",
"Authenticate your environment on Google Colab.\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "46604f70e831"
},
"outputs": [],
"source": [
"import sys\n",
"\n",
"if \"google.colab\" in sys.modules:\n",
"\n",
" from google.colab import auth\n",
"\n",
" auth.authenticate_user()"
]
},
{
@@ -190,14 +244,9 @@
"id": "yfEglUHQk9S3"
},
"source": [
"## Before you begin\n",
"### Set Google Cloud project information\n",
"\n",
"### Set your project ID\n",
"\n",
"**If you don't know your project ID**, try the following:\n",
"* Run `gcloud config list`.\n",
"* Run `gcloud projects list`.\n",
"* See the support page: [Locate the project ID](https://support.google.com/googleapi/answer/7014113)"
"Learn more about [setting up a project and a development environment](https://cloud.google.com/vertex-ai/docs/start/cloud-environment)."
]
},
{
@@ -209,89 +258,7 @@
"outputs": [],
"source": [
"PROJECT_ID = \"[your-project-id]\" # @param {type:\"string\"}\n",
"\n",
"# Set the project id\n",
"! gcloud config set project {PROJECT_ID}"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "region"
},
"source": [
"#### Region\n",
"\n",
"You can also change the `REGION` variable used by Vertex AI. Learn more about [Vertex AI regions](https://cloud.google.com/vertex-ai/docs/general/locations)."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "region"
},
"outputs": [],
"source": [
"REGION = \"us-central1\" # @param {type: \"string\"}"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "gcp_authenticate"
},
"source": [
"### Authenticate your Google Cloud account\n",
"\n",
"Depending on your Jupyter environment, you may have to manually authenticate. Follow the relevant instructions below.\n",
"\n",
"**1. Vertex AI Workbench**\n",
"* Do nothing as you are already authenticated.\n",
"\n",
"**2. Local JupyterLab instance, uncomment and run:**"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "ce6043da7b33"
},
"outputs": [],
"source": [
"# ! gcloud auth login"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "0367eac06a10"
},
"source": [
"**3. Colab, uncomment and run:**"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "21ad4dbb4a61"
},
"outputs": [],
"source": [
"# from google.colab import auth\n",
"# auth.authenticate_user()"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "c13224697bfb"
},
"source": [
"**4. Service account or other**\n",
"* See how to grant Cloud Storage permissions to your service account at https://cloud.google.com/storage/docs/gsutil/commands/iam#ch-examples."
"LOCATION = \"us-central1\" # @param {type:\"string\"}"
]
},
{
@@ -322,7 +289,7 @@
"id": "create_bucket"
},
"source": [
"**Only if your bucket doesn't already exist**: Run the following cell to create your Cloud Storage bucket."
"**If your bucket doesn't already exist**: Run the following cell to create your Cloud Storage bucket."
]
},
{
@@ -333,7 +300,7 @@
},
"outputs": [],
"source": [
"! gsutil mb -l $REGION $BUCKET_URI"
"! gsutil mb -l $LOCATION -p $PROJECT_ID $BUCKET_URI"
]
},
{
@@ -342,10 +309,7 @@
"id": "setup_vars"
},
"source": [
"### Set up variables\n",
"\n",
"Next, set up some variables used throughout the tutorial.\n",
"### Import libraries and define constants"
"### Import the required libraries"
]
},
{
@@ -356,9 +320,18 @@
},
"outputs": [],
"source": [
"import base64\n",
"import io\n",
"import os\n",
"from io import BytesIO\n",
"\n",
"import google.cloud.aiplatform as aip"
"import cv2\n",
"import matplotlib.image as mpimg\n",
"import matplotlib.pyplot as plt\n",
"import numpy as np\n",
"import tensorflow as tf\n",
"from google.cloud import aiplatform\n",
"from tensorflow.keras.datasets import cifar10"
]
},
{
@@ -369,7 +342,9 @@
"source": [
"### Initialize Vertex AI SDK for Python\n",
"\n",
"Initialize the Vertex AI SDK for Python for your project and corresponding bucket."
"To get started using Vertex AI, you must [enable the Vertex AI API](https://console.cloud.google.com/flows/enableapi?apiid=aiplatform.googleapis.com).\n",
"\n",
"Initialize the Vertex AI SDK for Python for your project using the location and the Cloud Storage bucket."
]
},
{
@@ -380,7 +355,7 @@
},
"outputs": [],
"source": [
"aip.init(project=PROJECT_ID, staging_bucket=BUCKET_URI)"
"aiplatform.init(project=PROJECT_ID, location=LOCATION, staging_bucket=BUCKET_URI)"
]
},
{
@@ -393,16 +368,16 @@
"\n",
"You can set hardware accelerators for training and prediction.\n",
"\n",
"Set the variables `TRAIN_GPU/TRAIN_NGPU` and `DEPLOY_GPU/DEPLOY_NGPU` to use a container image supporting a GPU and the number of GPUs allocated to the virtual machine (VM) instance. For example, to use a GPU container image with 4 Nvidia Telsa K80 GPUs allocated to each VM, you would specify:\n",
"Set the variables `TRAIN_GPU/TRAIN_NGPU` and `DEPLOY_GPU/DEPLOY_NGPU` to use a container image supporting a GPU and the number of GPUs allocated to the virtual machine (VM) instance. For example, to use a GPU container image with 4 Nvidia Telsa T4 GPUs allocated to each VM, you would specify:\n",
"\n",
" (aip.gapic.AcceleratorType.NVIDIA_TESLA_K80, 4)\n",
" (aiplatform.gapic.AcceleratorType.NVIDIA_TESLA_T4, 4)\n",
"\n",
"\n",
"Otherwise specify `(None, None)` to use a container image to run on a CPU.\n",
"\n",
"Learn more [here](https://cloud.google.com/vertex-ai/docs/general/locations#accelerators) hardware accelerator support for your region\n",
"Learn more about [hardware accelerator support for your region](https://cloud.google.com/vertex-ai/docs/general/locations#accelerators).\n",
"\n",
"*Note*: TF releases before 2.3 for GPU support will fail to load the custom model in this tutorial. It is a known issue and fixed in TF 2.3 -- which is caused by static graph ops that are generated in the serving function. If you encounter this issue on your own custom models, use a container image for TF 2.3 with GPU support."
"**Note**: TF releases before 2.3 for GPU support fail to load the custom model in this tutorial. It's a known issue and fixed in TF 2.3 -- which is caused by static graph ops that are generated in the serving function. If you encounter this issue on your own custom models, use a container image for TF 2.3 with GPU support."
]
},
{
@@ -415,7 +390,7 @@
"source": [
"if os.getenv(\"IS_TESTING_TRAIN_GPU\"):\n",
" TRAIN_GPU, TRAIN_NGPU = (\n",
" aip.gapic.AcceleratorType.NVIDIA_TESLA_K80,\n",
" aiplatform.gapic.AcceleratorType.NVIDIA_TESLA_T4,\n",
" int(os.getenv(\"IS_TESTING_TRAIN_GPU\")),\n",
" )\n",
"else:\n",
@@ -423,7 +398,7 @@
"\n",
"if os.getenv(\"IS_TESTING_DEPLOY_GPU\"):\n",
" DEPLOY_GPU, DEPLOY_NGPU = (\n",
" aip.gapic.AcceleratorType.NVIDIA_TESLA_K80,\n",
" aiplatform.gapic.AcceleratorType.NVIDIA_TESLA_T4,\n",
" int(os.getenv(\"IS_TESTING_DEPLOY_GPU\")),\n",
" )\n",
"else:\n",
@@ -480,10 +455,10 @@
" DEPLOY_VERSION = \"tf-cpu.{}\".format(TF)\n",
"\n",
"TRAIN_IMAGE = \"{}-docker.pkg.dev/vertex-ai/training/{}:latest\".format(\n",
" REGION.split(\"-\")[0], TRAIN_VERSION\n",
" LOCATION.split(\"-\")[0], TRAIN_VERSION\n",
")\n",
"DEPLOY_IMAGE = \"{}-docker.pkg.dev/vertex-ai/prediction/{}:latest\".format(\n",
" REGION.split(\"-\")[0], DEPLOY_VERSION\n",
" LOCATION.split(\"-\")[0], DEPLOY_VERSION\n",
")\n",
"\n",
"print(\"Training:\", TRAIN_IMAGE, TRAIN_GPU, TRAIN_NGPU)\n",
@@ -500,19 +475,19 @@
"\n",
"Next, set the machine type to use for training and prediction.\n",
"\n",
"- Set the variables `TRAIN_COMPUTE` and `DEPLOY_COMPUTE` to configure the compute resources for the VMs you will use for for training and prediction.\n",
"- Set the variables `TRAIN_COMPUTE` and `DEPLOY_COMPUTE` to configure the compute resources for the VMs you use for for training and prediction.\n",
" - `machine type`\n",
" - `n1-standard`: 3.75GB of memory per vCPU.\n",
" - `n1-highmem`: 6.5GB of memory per vCPU\n",
" - `n1-highcpu`: 0.9 GB of memory per vCPU\n",
" - `vCPUs`: number of \\[2, 4, 8, 16, 32, 64, 96 \\]\n",
"\n",
"*Note: The following is not supported for training:*\n",
"**Note**: The following isn't supported for training:\n",
"\n",
" - `standard`: 2 vCPUs\n",
" - `highcpu`: 2, 4 and 8 vCPUs\n",
"\n",
"*Note: You may also use n2 and e2 machine types for training and deployment, but they do not support GPUs*."
"**Note**: You may also use n2 and e2 machine types for training and deployment, but they don't support GPUs."
]
},
{
@@ -542,28 +517,21 @@
"print(\"Deploy machine type\", DEPLOY_COMPUTE)"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "tutorial_start:custom"
},
"source": [
"# Tutorial\n",
"\n",
"Now you are ready to start creating your own custom model and training for CIFAR10."
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "examine_training_package"
},
"source": [
"### Examine the training package\n",
"## Examine the training package\n",
"\n",
"#### Package layout\n",
"Now you're ready to start creating your own custom model and training for CIFAR10.\n",
"\n",
"Before you start the training, you will look at how a Python package is assembled for a custom training job. When unarchived, the package contains the following directory/file layout.\n",
"Before you start the training, examine the training application package below.\n",
"\n",
"### Package layout\n",
"\n",
"Before you start training, look at how a Python package is assembled for a custom training job. When unarchived, the package contains the following directory/file layout.\n",
"\n",
"- PKG-INFO\n",
"- README.md\n",
@@ -575,11 +543,13 @@
"\n",
"The files `setup.cfg` and `setup.py` are the instructions for installing the package into the operating environment of the Docker image.\n",
"\n",
"The file `trainer/task.py` is the Python script for executing the custom training job. *Note*, when we referred to it in the worker pool specification, we replace the directory slash with a dot (`trainer.task`) and dropped the file suffix (`.py`).\n",
"The file `trainer/task.py` is the Python script for executing the custom training job. \n",
"\n",
"#### Package Assembly\n",
"**Note**: When referring to the worker pool specification, the directory slash is replaced with a dot (`trainer.task`) and the file suffix (`.py`) is dropped.\n",
"\n",
"In the following cells, you will assemble the training package."
"### Package Assembly\n",
"\n",
"In the following cells, you assemble the training package."
]
},
{
@@ -617,9 +587,11 @@
"id": "taskpy_contents:cifar10"
},
"source": [
"#### Task.py contents\n",
"### Task.py contents\n",
"\n",
"In the next cell, you write the contents of the training script task.py. We won't go into detail, it's just there for you to browse. In summary:\n",
"In the next cell, you write the contents of the training script *task.py*. \n",
"\n",
"In summary, *task.py* script does the following:\n",
"\n",
"- Get the directory where to save the model artifacts from the command line (`--model_dir`), and if not specified, then from the environment variable `AIP_MODEL_DIR`.\n",
"- Loads CIFAR10 dataset from TF Datasets (tfds).\n",
@@ -745,7 +717,7 @@
"id": "tarball_training_script"
},
"source": [
"#### Store training script on your Cloud Storage bucket\n",
"## Store training script on your Cloud Storage bucket\n",
"\n",
"Next, you package the training folder into a compressed tar ball, and then store it in your Cloud Storage bucket."
]
@@ -770,12 +742,12 @@
"id": "create_custom_training_job:mbsdk,no_model"
},
"source": [
"### Create and run custom training job\n",
"## Create and run custom training job\n",
"\n",
"\n",
"To train a custom model, you perform two steps: 1) create a custom training job, and 2) run the job.\n",
"\n",
"#### Create custom training job\n",
"### Create custom training job\n",
"\n",
"A custom training job is created with the `CustomTrainingJob` class, with the following parameters:\n",
"\n",
@@ -793,7 +765,7 @@
},
"outputs": [],
"source": [
"job = aip.CustomTrainingJob(\n",
"job = aiplatform.CustomTrainingJob(\n",
" display_name=\"cifar10\",\n",
" script_path=\"custom/trainer/task.py\",\n",
" container_uri=TRAIN_IMAGE,\n",
@@ -809,16 +781,16 @@
"id": "prepare_custom_cmdargs"
},
"source": [
"### Prepare your command-line arguments\n",
"### Prepare your training parameters\n",
"\n",
"Now define the command-line arguments for your custom training container:\n",
"\n",
"- `args`: The command-line arguments to pass to the executable that is set as the entry point into the container.\n",
" - `--model-dir` : For our demonstrations, we use this command-line argument to specify where to store the model artifacts.\n",
" - direct: You pass the Cloud Storage location as a command line argument to your training script (set variable `DIRECT = True`), or\n",
" - indirect: The service passes the Cloud Storage location as the environment variable `AIP_MODEL_DIR` to your training script (set variable `DIRECT = False`). In this case, you tell the service the model artifact location in the job specification.\n",
" - `\"--epochs=\" + EPOCHS`: The number of epochs for training.\n",
" - `\"--steps=\" + STEPS`: The number of steps per epoch."
"- `args`: The command-line arguments to pass to the executable that's set as the entry point into the container.\n",
" - `--model-dir`: Command-line argument to specify where to store the model artifacts. You can use either of the following methods to specify the storage location for artifacts.\n",
" - **method-1**(set `DIRECT` to `True`): You pass the Cloud Storage location as a command line argument to your training script.\n",
" - **method-2**(set `DIRECT` to `False`): The service passes the Cloud Storage location as the environment variable `AIP_MODEL_DIR` to your training script. In this case, you tell the service the model artifact location in the job specification.\n",
" - `--epochs`: The number of epochs for training.\n",
" - `--steps`: The number of steps per epoch."
]
},
{
@@ -834,7 +806,7 @@
"EPOCHS = 20\n",
"STEPS = 100\n",
"\n",
"DIRECT = True\n",
"DIRECT = True # Set False to use AIP_MODEL_DIR\n",
"if DIRECT:\n",
" CMDARGS = [\n",
" \"--model-dir=\" + MODEL_DIR,\n",
@@ -854,17 +826,17 @@
"id": "run_custom_job:mbsdk,no_model"
},
"source": [
"#### Run the custom training job\n",
"### Run the custom training job\n",
"\n",
"Next, you run the custom job to start the training job by invoking the method `run`, with the following parameters:\n",
"Next, you run the custom job to start the training job by invoking the `run()` method, with the following parameters:\n",
"\n",
"- `args`: The command-line arguments to pass to the training script.\n",
"- `replica_count`: The number of compute instances for training (replica_count = 1 is single node training).\n",
"- `machine_type`: The machine type for the compute instances.\n",
"- `accelerator_type`: The hardware accelerator type.\n",
"- `accelerator_count`: The number of accelerators to attach to a worker replica.\n",
"- `base_output_dir`: The Cloud Storage location to write the model artifacts to.\n",
"- `sync`: Whether to block until completion of the job."
"- `base_output_dir`: The Cloud Storage location to store the model artifacts.\n",
"- `sync`: Set **True** to wait until completion of the job."
]
},
{
@@ -918,8 +890,6 @@
},
"outputs": [],
"source": [
"import tensorflow as tf\n",
"\n",
"local_model = tf.keras.models.load_model(MODEL_DIR)"
]
},
@@ -931,21 +901,19 @@
"source": [
"## Evaluate the model\n",
"\n",
"Now find out how good the model is.\n",
"Now, find out how good the model performs. Prepare some test data for evaluation and run the `evaluate()` method.\n",
"\n",
"### Load evaluation data\n",
"\n",
"You will load the CIFAR10 test (holdout) data from `tf.keras.datasets`, using the method `load_data()`. This returns the dataset as a tuple of two elements. The first element is the training data and the second is the test data. Each element is also a tuple of two elements: the image data, and the corresponding labels.\n",
"Load the CIFAR10 test (holdout) data from `tf.keras.datasets`, using the `load_data()` method. This returns the dataset as a tuple of two elements. The first element is the training data and the second one is the test data. Each element is also a tuple of two elements: the image data, and the corresponding labels.\n",
"\n",
"You don't need the training data, and hence why we loaded it as `(_, _)`.\n",
"For this step, you don't need the training data. Hence, you skip it by loading as `(_, _)`.\n",
"\n",
"Before you can run the data through evaluation, you need to preprocess it:\n",
"\n",
"`x_test`:\n",
"1. Normalize (rescale) the pixel data by dividing each pixel by 255. This replaces each single byte integer pixel with a 32-bit floating point number between 0 and 1.\n",
"`x_test`: Normalize (rescale) the pixel data by dividing each pixel by 255. This replaces each single byte integer pixel with a 32-bit floating point number between 0 and 1.\n",
"\n",
"`y_test`:<br/>\n",
"2. The labels are currently scalar (sparse). If you look back at the `compile()` step in the `trainer/task.py` script, you will find that it was compiled for sparse labels. So we don't need to do anything more."
"`y_test`: The labels are currently scalar (sparse). If you look back at the `compile()` step in the `trainer/task.py` script, you find that it was compiled for sparse labels. So you don't need to do anything more."
]
},
{
@@ -956,9 +924,6 @@
},
"outputs": [],
"source": [
"import numpy as np\n",
"from tensorflow.keras.datasets import cifar10\n",
"\n",
"(_, _), (x_test, y_test) = cifar10.load_data()\n",
"x_test = (x_test / 255.0).astype(np.float32)\n",
"\n",
@@ -995,7 +960,7 @@
"source": [
"### Serving function for image data\n",
"\n",
"To pass images to the prediction service, you encode the compressed (e.g., JPEG) image bytes into base 64 -- which makes the content safe from modification while transmitting binary data over the network. Since this deployed model expects input data as raw (uncompressed) bytes, you need to ensure that the base 64 encoded data gets converted back to raw bytes before it is passed as input to the deployed model.\n",
"To pass images to the prediction service, you encode the compressed (e.g., JPEG) image bytes into base 64 -- which makes the content safe from modification while transmitting binary data over the network. Since this deployed model expects input data as raw (uncompressed) bytes, you need to ensure that the base 64 encoded data gets converted back to raw bytes before it's passed as input to the deployed model.\n",
"\n",
"To resolve this, define a serving function (`serving_fn`) and attach it to the model as a preprocessing step. Add a `@tf.function` decorator so the serving function is fused to the underlying model (instead of upstream on a CPU).\n",
"\n",
@@ -1079,9 +1044,9 @@
"\n",
"You can get the signatures of your model's input and output layers by reloading the model into memory, and querying it for the signatures corresponding to each layer.\n",
"\n",
"When making a prediction request, you need to route the request to the serving function instead of the model, so you need to know the input layer name of the serving function -- which you will use later when you make a prediction request.\n",
"When making a prediction request, you need to route the request to the serving function instead of the model. So, you need to know the input layer's name for the serving function which you use later when you make a prediction request.\n",
"\n",
"You also need to know the name of the serving function's input and output layer for constructing the explanation metadata -- which is discussed subsequently."
"You also need to know the name of the serving function's input and output layer for constructing the explanation metadata which is described subsequently."
]
},
{
@@ -1115,17 +1080,17 @@
"source": [
"### Explanation Specification\n",
"\n",
"To get explanations when doing a prediction, you must enable the explanation capability and set corresponding settings when you upload your custom model to an Vertex `Model` resource. These settings are referred to as the explanation metadata, which consists of:\n",
"To get explanations along with the predictions, you must enable the explanations feature and set corresponding settings when you upload your custom model to a Vertex AI model resource. These settings are referred to as the explanation metadata, which consists of:\n",
"\n",
"- `parameters`: This is the specification for the explainability algorithm to use for explanations on your model. You can choose between:\n",
" - Shapley - *Note*, not recommended for image data -- can be very long running\n",
" - Shapley(Note: not recommended for image data since it can involve a long-running operation)\n",
" - XRAI\n",
" - Integrated Gradients\n",
"- `metadata`: This is the specification for how the algoithm is applied on your custom model.\n",
"\n",
"#### Explanation Parameters\n",
"\n",
"Let's first dive deeper into the settings for the explainability algorithm.\n",
"Take a look at a detailed overview of the settings for the explainability algorithm.\n",
"\n",
"#### Shapley\n",
"\n",
@@ -1136,7 +1101,7 @@
"\n",
"Parameters:\n",
"\n",
"- `path_count`: This is the number of paths over the features that will be processed by the algorithm. An exact approximation of the Shapley values requires M! paths, where M is the number of features. For the CIFAR10 dataset, this would be 784 (28*28).\n",
"- `path_count`: This is the number of paths over the features processed by the algorithm. An exact approximation of the Shapley values requires M! paths, where M is the number of features. For the CIFAR10 dataset, this would be 784 (28*28).\n",
"\n",
"For any non-trival number of features, this is too compute expensive. You can reduce the number of paths over the features to M * `path_count`.\n",
"\n",
@@ -1164,7 +1129,7 @@
"\n",
"- `step_count`: This is the number of steps to approximate the remaining sum. The more steps, the more accurate the integral approximation. The general rule of thumb is 50 steps, but as you increase so does the compute time.\n",
"\n",
"In the next code cell, set the variable `XAI` to which explainabilty algorithm you will use on your custom model."
"In the next code cell, set the variable `XAI` to which explainabilty algorithm you use on your custom model."
]
},
{
@@ -1184,7 +1149,7 @@
"elif XAI == \"xrai\":\n",
" PARAMETERS = {\"xrai_attribution\": {\"step_count\": 50}}\n",
"\n",
"parameters = aip.explain.ExplanationParameters(PARAMETERS)"
"parameters = aiplatform.explain.ExplanationParameters(PARAMETERS)"
]
},
{
@@ -1195,9 +1160,9 @@
"source": [
"#### Explanation Metadata\n",
"\n",
"Let's first dive deeper into the explanation metadata, which consists of:\n",
"Now, let's dive deeper into the explanation metadata, which consists of:\n",
"\n",
"- `outputs`: A scalar value in the output to attribute -- what to explain. For example, in a probability output \\[0.1, 0.2, 0.7\\] for classification, one wants an explanation for 0.7. Consider the following formulae, where the output is `y` and that is what we want to explain.\n",
"- `outputs`: A scalar value in the output to attribute -- what to explain. For example, in a probability output \\[0.1, 0.2, 0.7\\] for classification, one wants an explanation for 0.7. Consider the following formula, where the output is `y` and that is what we want to explain.\n",
"\n",
" y = f(x)\n",
"\n",
@@ -1215,7 +1180,7 @@
"<blockquote>\n",
" - [your_display_name]: A human readable name you assign to the output to explain. A common example is \"probability\".<br/>\n",
" - \"output_tensor_name\": The key/value field to identify the output layer to explain. <br/>\n",
" - [layer]: The output layer to explain. In a single task model, like a tabular regressor, it is the last (topmost) layer in the model.\n",
" - [layer]: The output layer to explain. In a single task model, like a tabular regressor, it's the last (topmost) layer in the model.\n",
"</blockquote>\n",
"\n",
"- `inputs`: The features for attribution -- how they contributed to the output. Consider the following formulae, where `a` and `b` are the features. We have to pick which features to explain how the contributed. Assume that this model is deployed for A/B testing, where `a` are the data_items for the prediction and `b` identifies whether the model instance is A or B. You would want to pick `a` (or some subset of) for the features, and not `b` since it does not contribute to the prediction.\n",
@@ -1232,7 +1197,7 @@
"<blockquote>\n",
" - [your_display_name]: A human readable name you assign to the input to explain. A common example is \"features\".<br/>\n",
" - \"input_tensor_name\": The key/value field to identify the input layer for the feature attribution. <br/>\n",
" - [layer]: The input layer for feature attribution. In a single input tensor model, it is the first (bottom-most) layer in the model.\n",
" - [layer]: The input layer for feature attribution. In a single input tensor model, it's the first (bottom-most) layer in the model.\n",
"</blockquote>\n",
"\n",
"Since the inputs to the model are tabular, you can specify the following two additional fields as reporting/visualization aids:\n",
@@ -1263,10 +1228,10 @@
"\n",
"OUTPUT_METADATA = {\"output_tensor_name\": serving_output}\n",
"\n",
"input_metadata = aip.explain.ExplanationMetadata.InputMetadata(INPUT_METADATA)\n",
"output_metadata = aip.explain.ExplanationMetadata.OutputMetadata(OUTPUT_METADATA)\n",
"input_metadata = aiplatform.explain.ExplanationMetadata.InputMetadata(INPUT_METADATA)\n",
"output_metadata = aiplatform.explain.ExplanationMetadata.OutputMetadata(OUTPUT_METADATA)\n",
"\n",
"metadata = aip.explain.ExplanationMetadata(\n",
"metadata = aiplatform.explain.ExplanationMetadata(\n",
" inputs={\"image\": input_metadata}, outputs={\"class\": output_metadata}\n",
")"
]
@@ -1279,14 +1244,14 @@
"source": [
"## Upload the model\n",
"\n",
"Next, upload your model to a `Model` resource using `Model.upload()` method, with the following parameters:\n",
"Next, upload your model to Vertex AI Model Registry using `Model.upload()` method, with the following parameters:\n",
"\n",
"- `display_name`: The human readable name for the `Model` resource.\n",
"- `display_name`: The human readable name for the model resource.\n",
"- `artifact`: The Cloud Storage location of the trained model artifacts.\n",
"- `serving_container_image_uri`: The serving container image.\n",
"- `sync`: Whether to execute the upload asynchronously or synchronously.\n",
"- `explanation_parameters`: Parameters to configure explaining for `Model`'s predictions.\n",
"- `explanation_metadata`: Metadata describing the `Model`'s input and output for explanation.\n",
"- `explanation_parameters`: Parameters to configure explaining for model's predictions.\n",
"- `explanation_metadata`: Metadata describing the model's input and output for explanation.\n",
"\n",
"If the `upload()` method is run asynchronously, you can subsequently block until completion with the `wait()` method."
]
@@ -1299,7 +1264,7 @@
},
"outputs": [],
"source": [
"model = aip.Model.upload(\n",
"model = aiplatform.Model.upload(\n",
" display_name=\"cifar10\",\n",
" artifact_uri=MODEL_DIR,\n",
" serving_container_image_uri=DEPLOY_IMAGE,\n",
@@ -1319,12 +1284,12 @@
"source": [
"## Deploy the model\n",
"\n",
"Next, deploy your model for online prediction. To deploy the model, you invoke the `deploy` method, with the following parameters:\n",
"Next, deploy your model for online predictions. To deploy the model, you invoke the `deploy()` method, with the following parameters:\n",
"\n",
"- `deployed_model_display_name`: A human readable name for the deployed model.\n",
"- `traffic_split`: Percent of traffic at the endpoint that goes to this model, which is specified as a dictionary of one or more key/value pairs.\n",
"If only one model, then specify as { \"0\": 100 }, where \"0\" refers to this model being uploaded and 100 means 100% of the traffic.\n",
"If there are existing models on the endpoint, for which the traffic will be split, then use model_id to specify as { \"0\": percent, model_id: percent, ... }, where model_id is the model id of an existing model to the deployed endpoint. The percents must add up to 100.\n",
"If there are existing models on the endpoint, for which the traffic is split, then use model_id to specify as { \"0\": percent, model_id: percent, ... }, where model_id is the model id of an existing model to the deployed endpoint. The percents must add up to 100.\n",
"- `machine_type`: The type of machine to use for training.\n",
"- `accelerator_type`: The hardware accelerator type.\n",
"- `accelerator_count`: The number of accelerators to attach to a worker replica.\n",
@@ -1377,7 +1342,7 @@
"source": [
"### Get test item\n",
"\n",
"You will use an example out of the test (holdout) portion of the dataset as a test item."
"Use an example from the test (holdout) portion of the dataset as a test item."
]
},
{
@@ -1417,10 +1382,6 @@
},
"outputs": [],
"source": [
"import base64\n",
"\n",
"import cv2\n",
"\n",
"cv2.imwrite(\"tmp.jpg\", (test_image * 255).astype(np.uint8))\n",
"\n",
"bytes = tf.io.read_file(\"tmp.jpg\")\n",
@@ -1435,7 +1396,7 @@
"source": [
"### Make the prediction with explanation\n",
"\n",
"Now that your `Model` resource is deployed to an `Endpoint` resource, one can do online explanations by sending prediction requests to the `Endpoint` resource.\n",
"Now that your model resource is deployed to an edpoint resource, you can get online explanations by sending prediction requests to your endpoint.\n",
"\n",
"#### Request\n",
"\n",
@@ -1443,16 +1404,16 @@
"\n",
" [{serving_input: {'b64': bytes}]\n",
"\n",
"Since the explain() method can take multiple items (instances), send your single test item as a list of one test item.\n",
"Since the `explain()` method can take multiple items (instances), send your single test item as a list of one test item.\n",
"\n",
"#### Response\n",
"\n",
"The response from the explain() call is a Python dictionary with the following entries:\n",
"The response from the `explain()` call is a Python dictionary with the following entries:\n",
"\n",
"- `ids`: The internal assigned unique identifiers for each prediction request.\n",
"- `predictions`: The prediction per instance.\n",
"- `deployed_model_id`: The Vertex AI identifier for the deployed `Model` resource which did the predictions.\n",
"- `explanations`: The feature attributions"
"- `deployed_model_id`: The Vertex AI identifier for the deployed model resource.\n",
"- `explanations`: The feature attributions returned by the Explainable AI."
]
},
{
@@ -1475,9 +1436,9 @@
"id": "understanding_explanations:cifar10"
},
"source": [
"### Understanding the explanations response\n",
"### Visualize the predictions\n",
"\n",
"Preview the images and their predicted classes without the explanations. Why did the model predict these classes?"
"Preview the images and their predicted classes without the explanations."
]
},
{
@@ -1488,11 +1449,6 @@
},
"outputs": [],
"source": [
"from io import BytesIO\n",
"\n",
"import matplotlib.image as mpimg\n",
"import matplotlib.pyplot as plt\n",
"\n",
"CLASSES = [\n",
" \"airplane\",\n",
" \"automobile\",\n",
@@ -1548,8 +1504,6 @@
},
"outputs": [],
"source": [
"import io\n",
"\n",
"for explanation in response.explanations:\n",
" attributions = dict(explanation.attributions[0].feature_attributions)\n",
" label_index = explanation.attributions[0].output_index[0]\n",
@@ -1571,7 +1525,7 @@
"source": [
"## Undeploy the model\n",
"\n",
"When you are done doing predictions, you undeploy the model from the `Endpoint` resouce. This deprovisions all compute resources and ends billing for the deployed model."
"When you are done with the model predictions, undeploy the model from the endpoint resouce. This deprovisions all compute resources and ends billing for the deployed model."
]
},
{
@@ -1591,7 +1545,7 @@
"id": "cleanup:mbsdk"
},
"source": [
"# Cleaning up\n",
"## Cleaning up\n",
"\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",
@@ -1607,13 +1561,24 @@
},
"outputs": [],
"source": [
"delete_bucket = False\n",
"# Delete the training job\n",
"job.delete()\n",
"\n",
"# Delete the endpoint\n",
"endpoint.delete()\n",
"\n",
"# Delete the model\n",
"model.delete()\n",
"\n",
"if delete_bucket or os.getenv(\"IS_TESTING\"):\n",
" ! gsutil rm -r $BUCKET_URI"
"# Delete the Cloud Storage bucket\n",
"delete_bucket = False # Set True for deletion\n",
"if delete_bucket:\n",
" ! gsutil rm -r $BUCKET_URI\n",
"\n",
"# Delete locally generated files\n",
"! rm -rf custom/\n",
"! rm custom.tar.gz\n",
"! rm tmp.jpg"
]
}
],