Files
model_garden/notebooks/official/prediction/get_started_with_tf_serving.ipynb

50 KiB

In [ ]:
# Copyright 2022 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

Get started with TensorFlow Serving with Vertex AI Prediction

Google Colaboratory logo
Open in Colab
Google Cloud Colab Enterprise logo
Open in Colab Enterprise
Vertex AI logo
Open in Workbench
GitHub logo
View on GitHub

Overview

This tutorial demonstrates how to serve predictions from a Vertex AI Endpoint with TensorFlow Serving serving binary.

Learn more about getting predictions from a custom trained model.

Objective

In this tutorial, you learn how to use Vertex AI Prediction on a Vertex AI Endpoint resource with TensorFlow Serving serving binary.

This tutorial uses the following Vertex AI services and resources:

  • Vertex AI Prediction
  • Vertex AI Batch Prediction
  • Vertex AI Models
  • Vertex AI Endpoints

You perform the following steps:

  • Download a pretrained image classification model from TensorFlow Hub.
  • Create a serving function to receive compressed image data, and output decomopressed preprocessed data for the model input.
  • Upload the TensorFlow Hub model and serving function as a Vertex AI model resource.
  • Create a Vertex AI endpoint resource.
  • Deploy the model resource to the endpoint resource with TensorFlow Serving serving binary.
  • Make an online prediction with the deployed model.
  • Make a batch prediction with the model.

Dataset

This tutorial uses a pre-trained image classification model from TensorFlow Hub, which is trained on ImageNet dataset.

Learn more about ResNet V2 pretained model.

Costs

This tutorial uses billable components of Google Cloud:

  • Vertex AI
  • Cloud Storage

Learn about Vertex AI pricing and Cloud Storage pricing, and use the Pricing Calculator to generate a cost estimate based on your projected usage.

Get started

Install Vertex AI SDK for Python and other required packages

In [ ]:
! pip3 install --upgrade google-cloud-aiplatform \
                        google-cloud-pipeline-components \
                        tensorflow==2.15.1 \
                        tensorflow-hub -q

Restart runtime (Colab only)

To use the newly installed packages, you must restart the runtime on Google Colab.

In [ ]:
import sys

if "google.colab" in sys.modules:

    import IPython

    app = IPython.Application.instance()
    app.kernel.do_shutdown(True)
⚠️ The kernel is going to restart. Wait until it's finished before continuing to the next step. ⚠️

Authenticate your notebook environment (Colab only)

Authenticate your environment on Google Colab.

In [ ]:
import sys

if "google.colab" in sys.modules:

    from google.colab import auth

    auth.authenticate_user()

Set Google Cloud project information

Learn more about setting up a project and a development environment.

In [ ]:
PROJECT_ID = "[your-project-id]"  # @param {type:"string"}
LOCATION = "us-central1"  # @param {type:"string"}

Create a Cloud Storage bucket

Create a storage bucket to store intermediate artifacts such as datasets.

In [ ]:
BUCKET_URI = f"gs://your-bucket-name-{PROJECT_ID}-unique"  # @param {type:"string"}

If your bucket doesn't already exist: Run the following cell to create your Cloud Storage bucket.

In [ ]:
! gcloud storage buckets create --location={LOCATION} --project={PROJECT_ID} {BUCKET_URI}

Import libraries

In [ ]:
import json

import tensorflow as tf
import tensorflow_hub as hub
from google.cloud import aiplatform

Initialize Vertex AI SDK for Python

Initialize the Vertex AI SDK for Python for your project and corresponding bucket. To get started using Vertex AI, you must have an existing Google Cloud project and enable the Vertex AI API.

In [ ]:
aiplatform.init(project=PROJECT_ID, staging_bucket=BUCKET_URI)

Set hardware accelerators

You can set hardware accelerators for training and prediction.

Set the variables 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:

(aiplatform.gapic.AcceleratorType.NVIDIA_TESLA_T4, 4)

Otherwise specify (None, None) to use a container image to run on a CPU.

Learn more about hardware accelerator support for your region.

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. This 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.

In [ ]:
DEPLOY_GPU, DEPLOY_NGPU = (None, None)

Set machine type

Next, set the machine type to use for prediction.

  • Set the variable DEPLOY_COMPUTE to configure the compute resources for the VMs you use for for prediction.
  • machine type
    • n1-standard: 3.75GB of memory per vCPU.
    • n1-highmem: 6.5GB of memory per vCPU
    • n1-highcpu: 0.9 GB of memory per vCPU
  • vCPUs: number of [2, 4, 8, 16, 32, 64, 96 ]

Note: You may also use n2 and e2 machine types for training and deployment, but they do not support GPUs.

In [ ]:
MACHINE_TYPE = "n1-standard"

VCPU = "4"
DEPLOY_COMPUTE = MACHINE_TYPE + "-" + VCPU
print("Train machine type", DEPLOY_COMPUTE)

Enable Artifact Registry API

You must enable the Artifact Registry API service for your project.

Learn more about enabling services.

In [ ]:
! gcloud services enable artifactregistry.googleapis.com

Create a private Docker repository

Your first step is to create your own Docker repository in Google Artifact Registry.

  1. Run the gcloud artifacts repositories create command to create a new Docker repository with your region with the description "docker repository".

  2. Run the gcloud artifacts repositories list command to verify that your repository was created.

In [ ]:
PRIVATE_REPO = "my-docker-repo"

! gcloud artifacts repositories create {PRIVATE_REPO} --repository-format=docker --location={LOCATION} --description="Docker repository"

! gcloud artifacts repositories list

Configure authentication to your private repo

Before you push or pull container images, configure Docker to use the gcloud command-line tool to authenticate requests to Artifact Registry for your region.

In [ ]:
! gcloud auth configure-docker {LOCATION}-docker.pkg.dev --quiet

Container (Docker) image for serving

Set the TensorFlow Serving Docker container image for serving prediction.

1. Pull the corresponding CPU or GPU Docker image for TF Serving from Docker Hub.
2. Create a tag for registering the image with Artifact Registry
3. Register the image with Artifact Registry.

Learn more about TensorFlow Serving.

In [ ]:
import sys

IS_COLAB = "google.colab" in sys.modules

# Executes in Vertex AI Workbench
if DEPLOY_GPU:
    DEPLOY_IMAGE = (
        f"{LOCATION}-docker.pkg.dev/"
        + PROJECT_ID
        + f"/{PRIVATE_REPO}"
        + "/tf_serving:gpu"
    )
    TF_IMAGE = "tensorflow/serving:2.5.4-gpu"
else:
    DEPLOY_IMAGE = (
        f"{LOCATION}-docker.pkg.dev/"
        + PROJECT_ID
        + f"/{PRIVATE_REPO}"
        + "/tf_serving:cpu"
    )
    TF_IMAGE = "tensorflow/serving:2.5.4"

if not IS_COLAB:
    if DEPLOY_GPU:
        ! sudo docker pull tensorflow/serving:2.5.4-gpu
    else:
        ! sudo docker pull tensorflow/serving:2.5.4

    ! docker tag $TF_IMAGE $DEPLOY_IMAGE
    ! docker push $DEPLOY_IMAGE
else:
    # install docker daemon
    ! apt-get -qq install docker.io

print("Deployment:", DEPLOY_IMAGE, DEPLOY_GPU, DEPLOY_NGPU)

Executes in Colab

In [ ]:
%%bash -s $IS_COLAB $DEPLOY_IMAGE $TF_IMAGE
if [ $1 == "False" ]; then
  exit 0
fi
set -x
dockerd -b none --iptables=0 -l warn &
for i in $(seq 5); do [ ! -S "/var/run/docker.sock" ] && sleep 2 || break; done
docker pull $3
docker tag $3 $2
docker push $2
kill $(jobs -p)

Get pretrained model from TensorFlow Hub

For demonstration purposes, this tutorial uses a pretrained model from TensorFlow Hub (TFHub), which is then uploaded to a Vertex AI model resource. Once you have a Vertex AI model resource created, the model can then be deployed to a Vertex AI endpoint resource.

Download the pretrained model

First, you download the pretrained model from TensorFlow Hub. The model gets downloaded as a TF.Keras layer. To finalize the model, in this example, you create a Sequential() model with the downloaded TFHub model as a layer, and specify the input shape to the model.

In [ ]:
tfhub_model = tf.keras.Sequential(
    [hub.KerasLayer("https://tfhub.dev/google/imagenet/resnet_v2_101/classification/5")]
)

tfhub_model.build([None, 224, 224, 3])

tfhub_model.summary()

Save the model artifacts

At this point, the model is in memory. Next, you save the model artifacts to a Cloud Storage location.

Note: For TF Serving, the MODEL_DIR must end in a subfolder that is a number, e.g., 1.

In [ ]:
MODEL_DIR = BUCKET_URI + "/model/1"
tfhub_model.save(MODEL_DIR)

Upload the model for serving

Next, you upload your TF.Keras model from the custom job to Vertex AI model service, which creates a model resource for your custom model. During upload, you need to define a serving function to convert data to the format your model expects. If you send encoded data to Vertex AI, your serving function ensures that the data is decoded on the model server before it's passed as input to your model.

How does the serving function work

When you send a request to an online prediction server, the request is received by a HTTP server. The HTTP server extracts the prediction request from the HTTP request content body. The extracted prediction request is forwarded to the serving function. For Google pre-built prediction containers, the request content is passed to the serving function as a tf.string.

The serving function consists of two parts:

  • preprocessing function:
    • Converts the input (tf.string) to the input shape and data type of the underlying model (dynamic graph).
    • Performs the same preprocessing of the data that was done during training the underlying model -- e.g., normalizing, scaling, etc.
  • post-processing function:
    • Converts the model output to format expected by the receiving application -- e.q., compresses the output.
    • Packages the output for the the receiving application -- e.g., add headings, make JSON object, etc.

Both the preprocessing and post-processing functions are converted to static graphs which are fused to the model. The output from the underlying model is passed to the post-processing function. The post-processing function passes the converted/packaged output back to the HTTP server. The HTTP server returns the output as the HTTP response content.

One consideration you need to consider when building serving functions for TF.Keras models is that they run as static graphs. That means, you can't use TF graph operations that require a dynamic graph. If you do, you get an error during the compile of the serving function which indicates that you're using an EagerTensor which isn't supported.

Serving function for image data

Preprocessing

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, and then preprocessed to match the model input requirements, before it's passed as input to the deployed model.

To resolve this, you 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).

When you send a prediction or explanation request, the content of the request is base 64 decoded into a Tensorflow string (tf.string), which is passed to the serving function (serving_fn). The serving function preprocesses the tf.string into raw (uncompressed) numpy bytes (preprocess_fn) to match the input requirements of the model:

  • io.decode_jpeg- Decompresses the JPG image which is returned as a Tensorflow tensor with three channels (RGB).
  • image.convert_image_dtype - Changes integer pixel values to float 32, and rescales pixel data between 0 and 1.
  • image.resize - Resizes the image to match the input shape for the model.

At this point, the data can be passed to the model (m_call), via a concrete function. The serving function is a static graph, while the model is a dynamic graph. The concrete function performs the tasks of marshalling the input data from the serving function to the model, and marshalling the prediction result from the model back to the serving function.

In [ ]:
CONCRETE_INPUT = "numpy_inputs"


def _preprocess(bytes_input):
    decoded = tf.io.decode_jpeg(bytes_input, channels=3)
    decoded = tf.image.convert_image_dtype(decoded, tf.float32)
    resized = tf.image.resize(decoded, size=(224, 224))
    return resized


@tf.function(input_signature=[tf.TensorSpec([None], tf.string)])
def preprocess_fn(bytes_inputs):
    decoded_images = tf.map_fn(
        _preprocess, bytes_inputs, dtype=tf.float32, back_prop=False
    )
    return {
        CONCRETE_INPUT: decoded_images
    }  # User needs to make sure the key matches model's input


@tf.function(input_signature=[tf.TensorSpec([None], tf.string)])
def serving_fn(bytes_inputs):
    images = preprocess_fn(bytes_inputs)
    prob = m_call(**images)
    return prob


m_call = tf.function(tfhub_model.call).get_concrete_function(
    [tf.TensorSpec(shape=[None, 224, 224, 3], dtype=tf.float32, name=CONCRETE_INPUT)]
)

tf.saved_model.save(tfhub_model, MODEL_DIR, signatures={"serving_default": serving_fn})

Get the serving function signature

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.

For your purpose, you need the signature of the serving function. Why? Well, when you send our data for prediction as a HTTP request packet, the image data is base64 encoded, and our TF.Keras model takes numpy input. Your serving function does the conversion from base64 to a numpy array.

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 use later when you make a prediction request.

In [ ]:
loaded = tf.saved_model.load(MODEL_DIR)

serving_input = list(
    loaded.signatures["serving_default"].structured_input_signature[1].keys()
)[0]
print("Serving function input:", serving_input)

Upload the TensorFlow Hub model to a Vertex AI model resource

Finally, you upload the model artifacts from the TFHub model and serving function into a Vertex AI model resource. Since you're using a non Google pre-built serving binary -- i.e., TensorFlow Serving, you need to specify the following additional serving configuration settings:

  • serving_container_command: The serving binary (HTTP Server) to start up.
  • serving_container_args: The arguments to pass to the serving binary. For TensorFlow Serving, the required arguments are:
    • --model_name: The human readable name to assign to the model.
    • --model_base_name: Where to store the model artifacts in the container. The Vertex service sets the variable $(AIP_STORAGE_URI) to where the service installed the model artifacts in the container.
    • --rest_api_port: The port to which to send REST based prediction requests. Can either be 8080 or 8501 (default for TensorFlow Serving).
    • --port: The port to which to send gRPC based prediction requests. Should be 8500 for TensorFlow Serving.
  • serving_container_health_route: The URL for the service to periodically ping for a response to verify that the serving binary is running. For TensorFlow Serving, this is /v1/models/<model_name>.
  • serving_container_predict_route: The URL for the service to route REST-based prediction requests to. For TF Serving, this is /v1/models/[model_name]:predict.
  • serving_container_ports: A list of ports for the HTTP server to listen for requests.

Uploading a model into a Vertex model resource returns a long running operation, since it may take a few moments.

Note: You drop the ending number subfolder (e.g., /1) from the model path to upload. The Vertex service uploads the parent folder above the subfolder with the model artifacts -- which is what TensorFlow Serving binary expects.

Note: When you upload the model artifacts to a Vertex AI model resource, you specify the corresponding deployment container image.

In [ ]:
MODEL_NAME = "example_"

model = aiplatform.Model.upload(
    display_name="example_",
    artifact_uri=MODEL_DIR[:-2],
    serving_container_image_uri=DEPLOY_IMAGE,
    serving_container_health_route="/v1/models/" + MODEL_NAME,
    serving_container_predict_route="/v1/models/" + MODEL_NAME + ":predict",
    serving_container_command=["/usr/bin/tensorflow_model_server"],
    serving_container_args=[
        "--model_name=" + MODEL_NAME,
        "--model_base_path=" + "$(AIP_STORAGE_URI)",
        "--rest_api_port=8080",
        "--port=8500",
        "--file_system_poll_wait_seconds=31540000",
    ],
    serving_container_ports=[8080],
)

print(model)

Create a Vertex AI endpoint resource

You create a Vertex AI endpoint resource using the Endpoint.create() method. At a minimum, you specify the display name for the endpoint. Optionally, you can specify the project and location (region); otherwise the settings are inherited by the values you set when you initialized the Vertex AI SDK with the init() method.

In this example, the following parameters are specified:

  • display_name: A human readable name for the endpoint resource.
  • project: Your project ID.
  • location: Your region.
  • labels: (optional) User defined metadata for the endpoint in the form of key/value pairs.

This method returns a Vertex AI endpoint object.

Learn more about Vertex AI Endpoints.

In [ ]:
endpoint = aiplatform.Endpoint.create(
    display_name="example_",
    project=PROJECT_ID,
    location=LOCATION,
    labels={"your_key": "your_value"},
)

print(endpoint)

Deploy model to the endpoint

You can deploy one or more Vertex AI model resource instances to the same endpoint. Each model resource that is deployed has its own deployment container for the serving binary.

Note: For this example, you specified the deployment container for the TFHub model in the previous step of uploading the model artifacts to a Vertex AI model resource.

In the next example, you deploy the Vertex AI model resource to a Vertex AI endpoint resource. The model resource already has a container image defined for deployment. To deploy, you specify the following additional configuration settings:

  • The machine type.
  • The (if any) type and number of GPUs.
  • Static, manual or auto-scaling of VM instances.

In this example, you deploy the model with the minimal amount of specified parameters, as follows:

  • model: The Vertex AI model resource.
  • deployed_model_displayed_name: The human readable name for the deployed model instance.
  • machine_type: The machine type for each VM instance.

Do to the requirements to provision the resource, this may take upto a few minutes.

In [ ]:
response = endpoint.deploy(
    model=model,
    deployed_model_display_name="example_",
    machine_type=DEPLOY_COMPUTE,
)

print(endpoint)

Prepare test data for prediction

Next, you load a compressed JPEG image into memory and then base64 encode it. For demonstration purposes, you use an image from the Flowers dataset.

In [ ]:
! gcloud storage cp gs://cloud-ml-data/img/flower_photos/daisy/100080576_f52e8ee070_n.jpg test.jpg
In [ ]:
import base64

with open("test.jpg", "rb") as f:
    data = f.read()
b64str = base64.b64encode(data).decode("utf-8")

Make the prediction

Now that your model resource is deployed to an endpoint resource, you can do online predictions by sending prediction requests to the Endpoint resource.

Request

Since in this example your test item is in a Cloud Storage bucket, you open and read the contents of the image using tf.io.gfile.Gfile(). To pass the test data to the prediction service, you encode the bytes into base64 -- which makes the content safe from modification while transmitting binary data over the network.

The format of each instance is:

{ serving_input: { 'b64': base64_encoded_bytes } }

Since the predict() method can take multiple items (instances), send your single test item as a list of one test item.

Response

The response from the predict() call is a Python dictionary with the following entries:

  • ids: The internal assigned unique identifiers for each prediction request.
  • predictions: The predicted confidence, between 0 and 1, per class label.
  • deployed_model_id: The Vertex AI identifier for the deployed Model resource which did the predictions.
In [ ]:
# The format of each instance should conform to the deployed model's prediction input schema.
instances = [{serving_input: {"b64": b64str}}]

prediction = endpoint.predict(instances=instances)

print(prediction)

Introduction to batch prediction

Batch prediction provides the ability to do offline batch processing of large amounts of prediction requests. Resources are only provisioned during the batch process and then deprovisioned when the batch request is completed. The results are stored in Cloud Storage, in contrast to online prediction where the results are returned as a HTTP response packet.

The input format for your batch job is dependent on the format supported by your model server. Foremost, the web server in your model server must support a JSONL format, which the web server converts to a format support either directly by the model input interface or a serving function interface. For batch prediction, this JSONL format is referred to as the pivot format.

Input format for batch prediction jobs

The batch server accepts the following input formats:

  • JSONL
  • CSV
  • TFRecords
  • File-List

Pivot format

The batch server converts the input format to the pivot (JSONL) format as follows:

JSONL

Each input line (request) should contain one and only one valid json value.

{"values": [1, 2, 3, 4], "key": 1}
{"values": [5, 6, 7, 8], "key": 2}

The batch server generates the pivot data with the same format. The generated pivot data is then wrapped into a payload request:

{"instances": [
  {"values": [1, 2, 3, 4], "key": 1},
  {"values": [5, 6, 7, 8], "key": 2}
]}

CSV

The csv header in the first line is always ignored. String fields are required to be double quoted explicitly, otherwise the row is discarded and parsing error messages are outputted to error files. Non-quoted values are always transferred as floats.

col1,col2,col3
1,3,"cat1"
2,4,"cat2"

The batch server converts each input row (request) to a JSON array.

{"instances": [
 [1.0,3.0,"cat1"],
 [2.0,4.0,"cat2"]
]}

BigQuery

Each row is converted to a JSON array. For example:

[1.0,3.0,"cat1"]
[2.0,4.0,"cat2"]

The batch server generates the pivot data with the same format. The generated pivot data is then wrapped into a payload request:

{"instances": [
 [1.0,3.0,"cat1"],
 [2.0,4.0,"cat2"]
]}

TFRecords

Instances in TFRecord files are read as binary by apache_beam.io.tfrecordio module. The binary objects are then serialized as ASCII strings. Predictor server is responsible to know the decoder to recover the instance.

{"instances": [
 {"b64","b64EncodedASCIIString"},
 {"b64","b64EncodedASCIIString"}
]}

FileList

The FileList format contains a list of files. Each line in a “FileList” file specifies a single file path, specified as a Cloud Storage location.

gs://my-bucket/file1.txt
gs://my-bucket/file2.txt

The batch server reads the files as binaries. The binary objects are serialized as ASCII strings.

{"instances": [
 {"b64","b64EncodedASCIIString"},
 {"b64","b64EncodedASCIIString"}
]}

Make the batch input file

Next, make a batch input file, which you store in your local Cloud Storage bucket. For custom models, you format the batch input file in JSONL format. Each JSON object entry in the JSONL file is specified in the same format as you specified for the online prediction request.

In otherwords, both online and batch prediction use the same predict request format. The difference is that with online prediction, you pass the request as an in-memory dictionary object using the SDK method predict(). For batch prediction, you write each prediction request (dictionary entry) as a JSON object, one per line.

The dictionary contains the key/value pairs:

  • input_name: the name of the input layer of the underlying model.
  • 'b64': A key that indicates the content is base64 encoded.
  • content: The compressed JPG image bytes as a base64 encoded string.

Each instance in the prediction request is a dictionary entry of the form:

                    {serving_input: {'b64': content}}

To pass the image data to the prediction service you encode the bytes into base64 -- which makes the content safe from modification when transmitting binary data over the network.

In [ ]:
# For demonstration purposes, you write the same image (instance[0]) request twice to the JSONL file.
# You receive back two predictions, one for each instance.

with open("test.jsonl", "w") as f:
    json.dump(instances[0], f)
    f.write("\n")
    json.dump(instances[0], f)

! gcloud storage cp test.jsonl {BUCKET_URI}/test.jsonl

Make the batch prediction request

Now that your Model resource is trained, you can make a batch prediction by invoking the batch_predict() method, with the following parameters:

  • job_display_name: The human readable name for the batch prediction job.
  • gcs_source: A list of one or more batch request input files.
  • gcs_destination_prefix: The Cloud Storage location for storing the batch prediction resuls.
  • instances_format: The format for the input instances, either 'csv' or 'jsonl'. Defaults to 'jsonl'.
  • predictions_format: The format for the output predictions, either 'csv' or 'jsonl'. Defaults to 'jsonl'.
  • machine_type: The type of machine to use for training.
  • accelerator_type: The hardware accelerator type.
  • accelerator_count: The number of accelerators to attach to a worker replica.
  • sync: If set to True, the call gets blocked while waiting for the asynchronous batch job to complete.
In [ ]:
MIN_NODES = 1
MAX_NODES = 1

batch_predict_job = model.batch_predict(
    job_display_name="example_",
    instances_format="jsonl",
    predictions_format="jsonl",
    model_parameters=None,
    gcs_source=f"{BUCKET_URI}/test.jsonl",
    gcs_destination_prefix=f"{BUCKET_URI}/results",
    machine_type=DEPLOY_COMPUTE,
    accelerator_type=DEPLOY_GPU,
    accelerator_count=DEPLOY_NGPU,
    starting_replica_count=MIN_NODES,
    max_replica_count=MAX_NODES,
    sync=False,
)

Wait for completion of batch prediction job

Next, wait for the batch job to complete. Alternatively, you can set the parameter sync to True in the batch_predict() method to block until the batch prediction job is completed.

In [ ]:
batch_predict_job.wait()

Get the predictions

Next, get the results from the completed batch prediction job.

The results are written to the Cloud Storage output bucket you specified in the batch prediction request. You call the method iter_outputs() to get a list of each Cloud Storage file generated with the results. Each file contains one or more prediction requests in a JSON format:

  • instance: The prediction request.
  • prediction: The prediction response.
In [ ]:
bp_iter_outputs = batch_predict_job.iter_outputs()

prediction_results = list()
for blob in bp_iter_outputs:
    if blob.name.split("/")[-1].startswith("prediction"):
        prediction_results.append(blob.name)

tags = list()
for prediction_result in prediction_results:
    gfile_name = f"gs://{bp_iter_outputs.bucket.name}/{prediction_result}"
    with tf.io.gfile.GFile(name=gfile_name, mode="r") as gfile:
        for line in gfile.readlines():
            line = json.loads(line)
            print(line)
            break

Cleaning up

To clean up all Google Cloud resources used in this project, you can delete the Google Cloud project you used for the tutorial.

Otherwise, you can delete the individual resources you created in this tutorial:

In [ ]:
# set delete_bucket to True to delete your bucket
delete_bucket = False

# undeploy the model from the endpoint
endpoint.undeploy_all()

# delete the endpoint
endpoint.delete()

# delete the model
model.delete()

# delete the batch job
batch_predict_job.delete()

# delete the bucket
if delete_bucket:
    ! gcloud storage rm --recursive --continue-on-error {BUCKET_URI}