Added notebook sample for batch inference using the remote sensing VMG models

PiperOrigin-RevId: 866061602
This commit is contained in:
Vertex MG Team
2026-02-05 12:27:10 -08:00
committed by Copybara-Service
parent 531d9cfee0
commit 2990c53292
@@ -0,0 +1,320 @@
{
"cells": [
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"cellView": "form",
"id": "rPH7NVRWhCGT"
},
"outputs": [],
"source": [
"# Copyright 2025 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",
"# You may obtain a copy of the License at\n",
"#\n",
"# https://www.apache.org/licenses/LICENSE-2.0\n",
"#\n",
"# Unless required by applicable law or agreed to in writing, software\n",
"# distributed under the License is distributed on an \"AS IS\" BASIS,\n",
"# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n",
"# See the License for the specific language governing permissions and\n",
"# limitations under the License."
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "OOTGI5tjjWqL"
},
"source": [
"# RS Imagery Batch Inference on VertexAI\n",
"\n",
"This notebook shows how to run a Batch Prediction Job deployed VLMs (image and text) on Vertex AI.\n",
"\n",
"**Prepare the environment for interacting with Vertex AI:**\n",
"\n",
"Initialize the Vertex AI SDK using the aiplatform.init() function.\n",
"\n",
"Configure the SDK to work with your specific Google Cloud project (PROJECT_ID) and region (REGION) that were defined in the previous configuration cell. This step is necessary before using other SDK functions to manage Vertex AI resources."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"cellView": "form",
"id": "cH6TEJQ-F_ne"
},
"outputs": [],
"source": [
"# @title Setup Notebook\n",
"\n",
"# @markdown 1. [Make sure that billing is enabled for your project](https://cloud.google.com/billing/docs/how-to/modify-project).\n",
"\n",
"# @markdown 2. **[Optional]** Set region. If not set, the region will be set automatically according to Colab Enterprise environment.\n",
"\n",
"REGION = \"\" # @param {type:\"string\"}\n",
"\n",
"# @markdown 3. If you want to run predictions with A100 80GB or H100 GPUs, we recommend using the regions listed below. **NOTE:** Make sure you have associated quota in selected regions. Click the links to see your current quota for each GPU type: [Nvidia A100 80GB](https://console.cloud.google.com/iam-admin/quotas?metric=aiplatform.googleapis.com%2Fcustom_model_serving_nvidia_a100_80gb_gpus), [Nvidia H100 80GB](https://console.cloud.google.com/iam-admin/quotas?metric=aiplatform.googleapis.com%2Fcustom_model_serving_nvidia_h100_gpus). You can request for quota following the instructions at [\"Request a higher quota\"](https://cloud.google.com/docs/quota/view-manage#requesting_higher_quota).\n",
"\n",
"# @markdown | Machine Type | Accelerator Type | Recommended Regions |\n",
"# @markdown | ----------- | ----------- | ----------- |\n",
"# @markdown | a2-ultragpu-1g | 1 NVIDIA_A100_80GB | us-central1, us-east4, europe-west4, asia-southeast1, us-east4 |\n",
"# @markdown | a3-highgpu-2g | 2 NVIDIA_H100_80GB | us-west1, asia-southeast1, europe-west4 |\n",
"# @markdown | a3-highgpu-4g | 4 NVIDIA_H100_80GB | us-west1, asia-southeast1, europe-west4 |\n",
"# @markdown | a3-highgpu-8g | 8 NVIDIA_H100_80GB | us-central1, europe-west4, us-west1, asia-southeast1 |\n",
"\n",
"import base64\n",
"import io\n",
"import json\n",
"from typing import Any\n",
"\n",
"from google.cloud import aiplatform, storage\n",
"from PIL import Image\n",
"\n",
"# Import common utils\n",
"if os.environ.get(\"VERTEX_PRODUCT\") != \"COLAB_ENTERPRISE\":\n",
" ! pip install --upgrade tensorflow\n",
"! git clone https://github.com/GoogleCloudPlatform/vertex-ai-samples.git\n",
"\n",
"common_util = importlib.import_module(\n",
" \"vertex-ai-samples.notebooks.community.model_garden.docker_source_codes.notebook_util.common_util\"\n",
")\n",
"\n",
"# Setup GCP & VertexAI\n",
"\n",
"# Get the default cloud project id.\n",
"PROJECT_ID = os.environ[\"GOOGLE_CLOUD_PROJECT\"]\n",
"\n",
"# Get the default region for launching jobs.\n",
"if not REGION:\n",
" REGION = os.environ[\"GOOGLE_CLOUD_REGION\"]\n",
"\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",
"# Initialize Vertex AI API.\n",
"print(\"Initializing Vertex AI API.\")\n",
"aiplatform.init(project=PROJECT_ID, location=REGION)\n",
"\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",
"! gcloud config set project $PROJECT_ID\n",
"import vertexai\n",
"\n",
"vertexai.init(\n",
" project=PROJECT_ID,\n",
" location=REGION,\n",
")\n",
"\n",
"\n",
"def to_png_bytes(img: Image.Image) -> bytes:\n",
" \"\"\"Encodes the `img` as PNG bytes.\"\"\"\n",
" buf = io.BytesIO()\n",
" img.save(buf, format=\"PNG\")\n",
" return buf.getvalue()\n",
"\n",
"\n",
"def to_b64_png(img: Image.Image) -> str:\n",
" \"\"\"Converts the `img` to a b64 encoded PNG bytes.\"\"\"\n",
" return base64.b64encode(to_png_bytes(img)).decode()\n",
"\n",
"\n",
"def write_jsonl_instances(\n",
" bucket: storage.Bucket, path: str, instances: list[dict[str, Any]]\n",
"):\n",
" \"\"\"Writes the list of instances (dicts) as a JSONL serialized file.\n",
"\n",
" Each dict is an inference instance, matching one of the following structures:\n",
"\n",
" {'image': <b64 image>} - Image inference only.\n",
" {'text': <str>} - Text inference only.\n",
" {'image': <b64 image, 'texts': list<str>} - Image & text inference.\n",
" \"\"\"\n",
" with bucket.blob(path).open(\"wt\") as f:\n",
" f.writelines(json.dumps(instance) for instance in instances)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"cellView": "form",
"id": "qVHaf1GmKaT6"
},
"outputs": [],
"source": [
"# @title Initialize data bucket\n",
"# @markdown ### Enter a GCS bucket name and a path within the bucket:\n",
"\n",
"BUCKET_NAME = \"\" # @param { type : 'string' }\n",
"OUTPUT_PATH = \"batch_inference/inputs\" # @param { type : 'string' }\n",
"\n",
"storage_client = storage.Client()\n",
"bucket = storage_client.bucket(BUCKET_NAME)\n",
"\n",
"# Download sample image\n",
"!wget -O harbor.jpg https://mrsg.aegean.gr/images/uploads/it2zi0eidej4ql33llj.jpg\n",
"harbor_img = Image.open(\"harbor.jpg\")"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"cellView": "form",
"id": "0nOBY2kjGHob"
},
"outputs": [],
"source": [
"# @title Prepare data: Image list file\n",
"\n",
"input_uris = []\n",
"\n",
"# The sample image (harbor) is replicated 10 times as an example.\n",
"for i in range(10):\n",
" img_path = f\"{OUTPUT_PATH}/images/img{i}.png\"\n",
" input_uris.append(f\"gs://{BUCKET_NAME}/{img_path}\")\n",
" bucket.blob(img_path).upload_from_string(\n",
" to_png_bytes(harbor_img), content_type=\"image/png\"\n",
" )\n",
"\n",
"with bucket.blob(f\"{OUTPUT_PATH}/input_uris.txt\").open(\"wt\") as f:\n",
" f.writelines([f\"{i}\\n\" for i in input_uris])"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"cellView": "form",
"id": "ap9IjkphGHbZ"
},
"outputs": [],
"source": [
"# @title Prepare JSONL input\n",
"\n",
"# This cell generates sample inputs (JSONL files) in 3 formats:\n",
"# Image, text and image_text, the input files are sharded to optionally reduce\n",
"# the size of each file. The file pattern (with wildcards) is used as input for\n",
"# the batch pipeline, e.g. \"gs://bucket_path/image*.jsonl\"\n",
"\n",
"# Write 3 shards of text input instances (10 instances each).\n",
"instances = [{\"text\": \"test string\"}] * 10\n",
"for i in range(3):\n",
" write_jsonl_instances(bucket, f\"{OUTPUT_PATH}/text{i}.jsonl\", instances)\n",
"\n",
"# Write 10 image input instances into 3 shards.\n",
"instances = [{\"image\": to_b64_png(harbor_img)}] * 10\n",
"for p in range(3):\n",
" write_jsonl_instances(bucket, f\"{OUTPUT_PATH}/image{p}.jsonl\", instances)\n",
"\n",
"# Write 10 image & texts input instances into a single file.\n",
"instances = [\n",
" {\"image\": to_b64_png(harbor_img), \"texts\": [\"text1\", \"text2\"]},\n",
"] * 10\n",
"write_jsonl_instances(bucket, f\"{OUTPUT_PATH}/combined.jsonl\", instances)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"cellView": "form",
"id": "a2j33P9hGN9H"
},
"outputs": [],
"source": [
"# @title Run batch inference\n",
"\n",
"JOB_DISPLAY_NAME = \"batch-inference-vlm-test\" # @param { type: 'string' }\n",
"# @markdown Enter the project number and model id, the project number is not the\n",
"# @markdown same as project id (it can be found in the project settings).\n",
"PROJECT_NUMBER = \"<project_number_here>\" # @param { type: 'string' }\n",
"MODEL_ID = \"<model_id_here>\" # @param { type: 'string' }\n",
"MODEL_RESOURCE_NAME = f\"projects/{PROJECT_NUMBER}/locations/{REGION}/models/{MODEL_ID}\"\n",
"\n",
"# @markdown Choose the input (instances) format, either a file-list of images or\n",
"# @markdown a JSONL file pattern of JSON formatted inputs.\n",
"INPUT_SOURCE_FORMAT = \"file-list\" # @param[\"file-list\", \"jsonl\"]\n",
"# @markdown Configure batch input source This can use string wildcards such as\n",
"# @markdown '*' and '?' to support sharded inputs.\n",
"INPUT_SOURCE_PATTERN = \"gs://<bucket>/batch_inference/inputs/inputlist.txt\" # @param { type: 'string' }\n",
"# @markdown Configure the output folder path, predictions will be written here.\n",
"GCS_OUTPUT_PATH = \"gs://<bucket>/batch_inference/outputs\" # @param { type: 'string' }\n",
"# @markdown Configure the batch runtime setup\n",
"USE_GPU = True # @param { type: 'boolean' }\n",
"BATCH_SIZE = 16 # @param { type: 'number' }\n",
"REPLICA_COUNT = 1 # @param { type: 'number' }\n",
"MAX_REPLICA_COUNT = 4 # @param { type: 'number' }\n",
"\n",
"machine_type = \"g2-standard-8\"\n",
"if USE_GPU:\n",
" accelerator_type = \"NVIDIA_L4\"\n",
" accelerator_count = 1\n",
"else:\n",
" accelerator_type = None\n",
" accelerator_count = None\n",
"\n",
"model = aiplatform.Model(MODEL_RESOURCE_NAME)\n",
"\n",
"job = model.batch_predict(\n",
" job_display_name=JOB_DISPLAY_NAME,\n",
" gcs_source=INPUT_SOURCE_PATTERN,\n",
" gcs_destination_prefix=GCS_OUTPUT_PATH,\n",
" instances_format=INPUT_SOURCE_FORMAT,\n",
" machine_type=machine_type,\n",
" accelerator_count=accelerator_count,\n",
" accelerator_type=accelerator_type,\n",
" starting_replica_count=REPLICA_COUNT,\n",
" max_replica_count=MAX_REPLICA_COUNT,\n",
" labels={\n",
" \"task\": \"batch-inference\",\n",
" \"vertex-ai-pipelines-run-billing-id\": JOB_DISPLAY_NAME,\n",
" },\n",
" batch_size=BATCH_SIZE,\n",
" sync=False,\n",
")\n",
"\n",
"print(f\"Batch prediction job started: {job}\")"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"cellView": "form",
"id": "KF9Lwsb5GOIS"
},
"outputs": [],
"source": [
"# Monitor the job status\n",
"\n",
"print(\n",
" f\"Running batch prediction {job.display_name}, resource:\"\n",
" f\" {job.resource_name}. State: {job.state}\"\n",
")"
]
}
],
"metadata": {
"colab": {
"name": "model_garden_remote_sensing_batch_prediction.ipynb",
"toc_visible": true
},
"kernelspec": {
"display_name": "Python 3",
"name": "python3"
}
},
"nbformat": 4,
"nbformat_minor": 0
}