diff --git a/notebooks/community/model_garden/model_garden_pytorch_vilt_vqa.ipynb b/notebooks/community/model_garden/model_garden_pytorch_vilt_vqa.ipynb
index 8fb31992a..9a7b36f4d 100644
--- a/notebooks/community/model_garden/model_garden_pytorch_vilt_vqa.ipynb
+++ b/notebooks/community/model_garden/model_garden_pytorch_vilt_vqa.ipynb
@@ -8,7 +8,7 @@
},
"outputs": [],
"source": [
- "# Copyright 2023 Google LLC\n",
+ "# Copyright 2024 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",
@@ -26,37 +26,29 @@
{
"cell_type": "markdown",
"metadata": {
- "id": "2bd716bf3e39"
+ "id": "99c1c3fc2ca5"
},
"source": [
"# Vertex AI Model Garden - ViLT VQA\n",
"\n",
- "
\n",
- " \n",
- " \n",
- " Run in Colab\n",
+ "\n",
+ " \n",
+ " \n",
+ "  Run in Colab Enterprise\n",
" \n",
" | \n",
- " \n",
+ " | \n",
" \n",
- " \n",
- " View on GitHub\n",
+ "  View on GitHub\n",
" \n",
" | \n",
- " \n",
- " \n",
- " \n",
- "Open in Vertex AI Workbench\n",
- " \n",
- " (a Python-3 CPU notebook is recommended)\n",
- " | \n",
- " "
+ " |
"
]
},
{
"cell_type": "markdown",
"metadata": {
- "id": "d8cd12648da4"
+ "id": "3de7470326a2"
},
"source": [
"## Overview\n",
@@ -76,7 +68,7 @@
"* Vertex AI\n",
"* Cloud Storage\n",
"\n",
- "Learn about [Vertex AI pricing](https://cloud.google.com/vertex-ai/pricing) and [Cloud Storage pricing](https://cloud.google.com/storage/pricing), and use the [Pricing Calculator](https://cloud.google.com/products/calculator/) to generate a cost estimate based on your projected usage."
+ "Learn about [Vertex AI pricing](https://cloud.google.com/vertex-ai/pricing), [Cloud Storage pricing](https://cloud.google.com/storage/pricing), and use the [Pricing Calculator](https://cloud.google.com/products/calculator/) to generate a cost estimate based on your projected usage."
]
},
{
@@ -85,302 +77,217 @@
"id": "264c07757582"
},
"source": [
- "## Setup environment\n",
- "\n",
- "**NOTE**: Jupyter runs lines prefixed with `!` as shell commands, and it interpolates Python variables prefixed with `$` into these commands."
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {
- "id": "d73ffa0c0b83"
- },
- "source": [
- "### Colab only"
+ "## Run the notebook"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
- "id": "2707b02ef5df"
+ "cellView": "form",
+ "id": "ioensNKM8ned"
},
"outputs": [],
"source": [
- "if \"google.colab\" in str(get_ipython()):\n",
- " ! pip3 install --upgrade google-cloud-aiplatform\n",
- " from google.colab import auth as google_auth\n",
+ "# @title Setup Google Cloud project\n",
"\n",
- " google_auth.authenticate_user()\n",
+ "# @markdown 1. [Make sure that billing is enabled for your project](https://cloud.google.com/billing/docs/how-to/modify-project).\n",
"\n",
- " # Restart the notebook kernel after installs.\n",
- " import IPython\n",
+ "# @markdown 2. [Optional] [Create a Cloud Storage bucket](https://cloud.google.com/storage/docs/creating-buckets) for storing experiment outputs. Set the BUCKET_URI for the experiment environment. The specified Cloud Storage bucket (`BUCKET_URI`) should be located in the same region as where the notebook was launched. Note that a multi-region bucket (eg. \"us\") is not considered a match for a single region covered by the multi-region range (eg. \"us-central1\"). If not set, a unique GCS bucket will be created instead.\n",
"\n",
- " app = IPython.Application.instance()\n",
- " app.kernel.do_shutdown(True)"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {
- "id": "0f826ff482a2"
- },
- "source": [
- "### Setup Google Cloud project\n",
+ "import os\n",
+ "import uuid\n",
+ "from datetime import datetime\n",
"\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",
+ "from google.cloud import aiplatform\n",
"\n",
- "1. [Make sure that billing is enabled for your project](https://cloud.google.com/billing/docs/how-to/modify-project).\n",
"\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",
+ "# Get the default cloud project id.\n",
+ "PROJECT_ID = os.environ[\"GOOGLE_CLOUD_PROJECT\"]\n",
"\n",
- "1. [Create a Cloud Storage bucket](https://cloud.google.com/storage/docs/creating-buckets) for storing experiment outputs."
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {
- "id": "8958ebc71868"
- },
- "source": [
- "Fill following variables for experiments environment:"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "metadata": {
- "id": "9db30f827a65"
- },
- "outputs": [],
- "source": [
- "# Cloud project id.\n",
- "PROJECT_ID = \"\" # @param {type:\"string\"}\n",
+ "# Get the default region for launching jobs.\n",
+ "REGION = os.environ[\"GOOGLE_CLOUD_REGION\"]\n",
"\n",
- "# The region you want to launch jobs in.\n",
- "REGION = \"us-central1\" # @param {type:\"string\"}\n",
+ "# Enable the Vertex AI API and Compute Engine API, if not already.\n",
+ "print(\"Enabling Vertex AI API and Compute Engine API.\")\n",
+ "! gcloud services enable aiplatform.googleapis.com compute.googleapis.com\n",
"\n",
- "# The Cloud Storage bucket for storing experiments output. Fill it without the 'gs://' prefix.\n",
- "GCS_BUCKET = \"\" # @param {type:\"string\"}"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {
- "id": "92f16e22c20b"
- },
- "source": [
- "Initialize Vertex AI API:"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "metadata": {
- "id": "1680c257acfb"
- },
- "outputs": [],
- "source": [
- "from google.cloud import aiplatform\n",
+ "# Cloud Storage bucket for storing the experiment artifacts.\n",
+ "# A unique GCS bucket will be created for the purpose of this notebook. If you\n",
+ "# prefer using your own GCS bucket, change the value yourself below.\n",
+ "now = datetime.now().strftime(\"%Y%m%d%H%M%S\")\n",
+ "BUCKET_URI = \"gs://\" # @param {type:\"string\"}\n",
+ "BUCKET_NAME = \"/\".join(BUCKET_URI.split(\"/\")[:3])\n",
"\n",
- "aiplatform.init(project=PROJECT_ID, location=REGION, staging_bucket=GCS_BUCKET)"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {
- "id": "6ca48b699d17"
- },
- "source": [
- "### Define constants"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "metadata": {
- "id": "de9882ea89ea"
- },
- "outputs": [],
- "source": [
- "# The pre-built serving docker image. It contains serving scripts and models.\n",
- "SERVE_DOCKER_URI = \"us-docker.pkg.dev/vertex-ai/vertex-vision-model-garden-dockers/pytorch-transformers-serve\""
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {
- "id": "10188266a5cd"
- },
- "source": [
- "### Define common functions"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "metadata": {
- "id": "cac4478ae098"
- },
- "outputs": [],
- "source": [
- "import base64\n",
- "import os\n",
- "from datetime import datetime\n",
- "from io import BytesIO\n",
- "\n",
- "import requests\n",
- "from google.cloud import aiplatform\n",
- "from PIL import Image\n",
+ "if BUCKET_URI is None or BUCKET_URI.strip() == \"\" or BUCKET_URI == \"gs://\":\n",
+ " BUCKET_URI = f\"gs://{PROJECT_ID}-tmp-{now}-{str(uuid.uuid4())[:4]}\"\n",
+ " BUCKET_NAME = \"/\".join(BUCKET_URI.split(\"/\")[:3])\n",
+ " ! gsutil mb -l {REGION} {BUCKET_URI}\n",
+ "else:\n",
+ " assert BUCKET_URI.startswith(\"gs://\"), \"BUCKET_URI must start with `gs://`.\"\n",
+ " shell_output = ! gsutil ls -Lb {BUCKET_NAME} | grep \"Location constraint:\" | sed \"s/Location constraint://\"\n",
+ " bucket_region = shell_output[0].strip().lower()\n",
+ " if bucket_region != REGION:\n",
+ " raise ValueError(\n",
+ " \"Bucket region %s is different from notebook region %s\"\n",
+ " % (bucket_region, REGION)\n",
+ " )\n",
+ "print(f\"Using this GCS Bucket: {BUCKET_URI}\")\n",
"\n",
+ "STAGING_BUCKET = os.path.join(BUCKET_URI, \"temporal\")\n",
+ "MODEL_BUCKET = os.path.join(BUCKET_URI, \"vilt-vqa\")\n",
"\n",
- "def create_job_name(prefix):\n",
- " user = os.environ.get(\"USER\")\n",
- " now = datetime.now().strftime(\"%Y%m%d_%H%M%S\")\n",
- " job_name = f\"{prefix}-{user}-{now}\"\n",
- " return job_name\n",
"\n",
+ "# Initialize Vertex AI API.\n",
+ "print(\"Initializing Vertex AI API.\")\n",
+ "aiplatform.init(project=PROJECT_ID, location=REGION, staging_bucket=STAGING_BUCKET)\n",
"\n",
- "def download_image(url):\n",
- " response = requests.get(url)\n",
- " return Image.open(BytesIO(response.content))\n",
+ "# Gets the default SERVICE_ACCOUNT.\n",
+ "shell_output = ! gcloud projects describe $PROJECT_ID\n",
+ "project_number = shell_output[-1].split(\":\")[1].strip().replace(\"'\", \"\")\n",
+ "SERVICE_ACCOUNT = f\"{project_number}-compute@developer.gserviceaccount.com\"\n",
+ "print(\"Using this default Service Account:\", SERVICE_ACCOUNT)\n",
"\n",
"\n",
- "def image_to_base64(image, format=\"JPEG\"):\n",
- " buffer = BytesIO()\n",
- " image.save(buffer, format=format)\n",
- " image_str = base64.b64encode(buffer.getvalue()).decode(\"utf-8\")\n",
- " return image_str\n",
+ "# Provision permissions to the SERVICE_ACCOUNT with the GCS bucket\n",
+ "! gsutil iam ch serviceAccount:{SERVICE_ACCOUNT}:roles/storage.admin $BUCKET_NAME\n",
"\n",
+ "! gcloud config set project $PROJECT_ID\n",
"\n",
- "def base64_to_image(image_str):\n",
- " image = Image.open(BytesIO(base64.b64decode(image_str)))\n",
- " return image\n",
+ "# The pre-built serving docker image. It contains serving scripts and models.\n",
+ "SERVE_DOCKER_URI = \"us-docker.pkg.dev/deeplearning-platform-release/gcr.io/huggingface-pytorch-inference-cu121.2-2.transformers.4-41.ubuntu2204.py311\"\n",
"\n",
+ "models, endpoints = {}, {}\n",
"\n",
- "def image_grid(imgs, rows=2, cols=2):\n",
- " w, h = imgs[0].size\n",
- " grid = Image.new(\"RGB\", size=(cols * w, rows * h))\n",
- " for i, img in enumerate(imgs):\n",
- " grid.paste(img, box=(i % cols * w, i // cols * h))\n",
- " return grid\n",
"\n",
+ "def deploy_model(\n",
+ " model_id, task, machine_type=\"g2-standard-8\", accelerator_type=\"NVIDIA_L4\"\n",
+ "):\n",
+ " \"\"\"Create a Vertex AI Endpoint and deploy the specified model to the endpoint.\"\"\"\n",
+ " model_name = model_id\n",
"\n",
- "def deploy_model(model_id, task):\n",
- " model_name = \"vilt-vqa\"\n",
" endpoint = aiplatform.Endpoint.create(display_name=f\"{model_name}-endpoint\")\n",
" serving_env = {\n",
- " \"MODEL_ID\": model_id,\n",
- " \"TASK\": task,\n",
+ " \"HF_MODEL_ID\": model_id,\n",
+ " \"HF_TASK\": task,\n",
" \"DEPLOY_SOURCE\": \"notebook\",\n",
" }\n",
- " # If the model_id is a GCS path, use artifact_uri to pass it to serving docker.\n",
- " artifact_uri = model_id if model_id.startswith(\"gs://\") else None\n",
+ "\n",
" model = aiplatform.Model.upload(\n",
" display_name=model_name,\n",
" serving_container_image_uri=SERVE_DOCKER_URI,\n",
" serving_container_ports=[7080],\n",
- " serving_container_predict_route=\"/predictions/transformers_serving\",\n",
+ " serving_container_predict_route=\"/pred\",\n",
" serving_container_health_route=\"/ping\",\n",
" serving_container_environment_variables=serving_env,\n",
- " artifact_uri=artifact_uri,\n",
" )\n",
+ "\n",
" model.deploy(\n",
" endpoint=endpoint,\n",
- " machine_type=\"n1-standard-8\",\n",
- " accelerator_type=\"NVIDIA_TESLA_T4\",\n",
+ " machine_type=machine_type,\n",
+ " accelerator_type=accelerator_type,\n",
" accelerator_count=1,\n",
" deploy_request_timeout=1800,\n",
+ " service_account=SERVICE_ACCOUNT,\n",
" )\n",
" return model, endpoint"
]
},
- {
- "cell_type": "markdown",
- "metadata": {
- "id": "d2d72ecdb8c9"
- },
- "source": [
- "## Upload and deploy models"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {
- "id": "9448c5f545fa"
- },
- "source": [
- "This section uploads the pre-trained model to Model Registry and deploys it on the Endpoint with 1 T4 GPU.\n",
- "\n",
- "The model deployment step will take ~15 minutes to complete.\n",
- "\n",
- "Once deployed, you can send images and questions to get answers."
- ]
- },
{
"cell_type": "code",
"execution_count": null,
"metadata": {
- "id": "b4b46c28d8b1"
+ "cellView": "form",
+ "id": "2707b02ef5df"
},
"outputs": [],
"source": [
- "model, endpoint = deploy_model(\n",
- " model_id=\"dandelin/vilt-b32-finetuned-vqa\", task=\"visual-question-answering\"\n",
- ")"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {
- "id": "80b3fd2ace09"
- },
- "source": [
- "NOTE: The model weights will be downloaded after the deployment succeeds. Thus additional 5 minutes of waiting time is needed **after** the above model deployment step succeeds and before you run the next step below. Otherwise you might see a `ServiceUnavailable: 503 502:Bad Gateway` error when you send requests to the endpoint."
+ "# @title Deploy the model to Vertex for online predictions\n",
+ "\n",
+ "# @markdown This section uploads the model to Model Registry and deploys it on the Endpoint. It takes ~15 minutes to finish.\n",
+ "\n",
+ "MODEL_ID = \"dandelin/vilt-b32-finetuned-vqa\"\n",
+ "task = \"visual-question-answering\"\n",
+ "\n",
+ "models[\"model\"], endpoints[\"endpoint\"] = deploy_model(model_id=MODEL_ID, task=task)\n",
+ "\n",
+ "print(\"endpoint_name:\", endpoints[\"endpoint\"].name)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
- "id": "6be655247cb1"
+ "cellView": "form",
+ "id": "bb7adab99e41"
},
"outputs": [],
"source": [
- "image = download_image(\"http://images.cocodataset.org/val2017/000000039769.jpg\")\n",
- "display(image)\n",
- "\n",
- "question = \"Which cat is bigger?\"\n",
- "instances = [\n",
- " {\"image\": image_to_base64(image), \"text\": question},\n",
- "]\n",
- "preds = endpoint.predict(instances=instances).predictions\n",
- "print(question)\n",
- "print(preds)"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {
- "id": "db7ffebdb4be"
- },
- "source": [
- "### Clean up resources"
+ "# @title Predict\n",
+ "# @markdown Once deployment succeeds, you can send requests to the endpoint with images and questions.\n",
+ "\n",
+ "# @markdown Example: \n",
+ "\n",
+ "# @markdown ```\n",
+ "# @markdown {\n",
+ "# @markdown \"image\": \"http://images.cocodataset.org/val2017/000000039769.jpg\"\n",
+ "# @markdown \"question\": \"Which cat is bigger?\"\n",
+ "# @markdown }\n",
+ "# @markdown ```\n",
+ "\n",
+ "# @markdown Note that `image` should be an http uri (starting with \"http://\" or \"https://\"), a local path, or base64 encoded bytes.\n",
+ "\n",
+ "# Loads an existing endpoint instance using the endpoint name:\n",
+ "# - Using `endpoint_name = endpoint.name` allows us to get the endpoint name of\n",
+ "# the endpoint `endpoint` created in the cell above.\n",
+ "# - Alternatively, you can set `endpoint_name = \"1234567890123456789\"` to load\n",
+ "# an existing endpoint with the ID 1234567890123456789.\n",
+ "\n",
+ "# You may uncomment the code below to load an existing endpoint.\n",
+ "# endpoint_name = \"\" # @param {type:\"string\"}\n",
+ "# aip_endpoint_name = (\n",
+ "# f\"projects/{PROJECT_ID}/locations/{REGION}/endpoints/{endpoint_name}\"\n",
+ "# )\n",
+ "# endpoint = aiplatform.Endpoint(aip_endpoint_name)\n",
+ "# print(\"Using this existing endpoint from a different session: {aip_endpoint_name}\")\n",
+ "\n",
+ "image = \"http://images.cocodataset.org/val2017/000000039769.jpg\" # @param {type: \"string\"}\n",
+ "question = \"Which cat is bigger?\" # @param {type: \"string\"}\n",
+ "\n",
+ "instances = [{\n",
+ " \"image\": image,\n",
+ " \"question\": question,\n",
+ "}]\n",
+ "\n",
+ "response = endpoints[\"endpoint\"].predict(instances=instances)\n",
+ "for prediction in response.predictions:\n",
+ " print(prediction)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
- "id": "2ccf3714dbe9"
+ "cellView": "form",
+ "id": "6c460088b873"
},
"outputs": [],
"source": [
+ "# @title Clean up resources\n",
+ "# @markdown Delete the experiment models and endpoints to recycle the resources\n",
+ "# @markdown and avoid unnecessary continuous charges that may incur.\n",
+ "\n",
"# Undeploy model and delete endpoint.\n",
- "endpoint.delete(force=True)\n",
+ "for endpoint in endpoints.values():\n",
+ " endpoint.delete(force=True)\n",
"\n",
"# Delete models.\n",
- "model.delete()"
+ "for model in models.values():\n",
+ " model.delete()\n",
+ "\n",
+ "delete_bucket = False # @param {type:\"boolean\"}\n",
+ "if delete_bucket:\n",
+ " ! gsutil -m rm -r $BUCKET_NAME"
]
}
],