mirror of
https://github.com/GoogleCloudPlatform/vertex-ai-samples.git
synced 2026-09-26 14:42:04 +00:00
Delete deprecated LoRA fine-tuning notebooks and related tutorials.
PiperOrigin-RevId: 976392412
This commit is contained in:
committed by
Copybara-Service
parent
4b983a2701
commit
9cf8ce16fa
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large
Load Diff
@@ -1,406 +1,406 @@
|
||||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"language": "python",
|
||||
"metadata": {
|
||||
"cellView": "form",
|
||||
"id": "B8S-yo8qTIcO"
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Copyright 2026 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": "MTRywGxLTZfU"
|
||||
},
|
||||
"source": [
|
||||
"# Vertex AI Model Garden - Gemma Evaluation\n",
|
||||
"\n",
|
||||
"<table><tbody><tr>\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%2Fcommunity%2Fmodel_garden%2Fmodel_garden_gemma_evaluation.ipynb\">\n",
|
||||
" <img alt=\"Google Cloud Colab Enterprise logo\" src=\"https://lh3.googleusercontent.com/JmcxdQi-qOpctIvWKgPtrzZdJJK-J3sWE1RsfjZNwshCFgE_9fULcNpuXYTilIR2hjwN\" width=\"32px\"><br> Run in Colab Enterprise\n",
|
||||
" </a>\n",
|
||||
" </td>\n",
|
||||
" <td style=\"text-align: center\">\n",
|
||||
" <a href=\"https://github.com/GoogleCloudPlatform/vertex-ai-samples/blob/main/notebooks/community/model_garden/model_garden_gemma_evaluation.ipynb\">\n",
|
||||
" <img alt=\"GitHub logo\" src=\"https://github.githubassets.com/assets/GitHub-Mark-ea2971cee799.png\" width=\"32px\"><br> View on GitHub\n",
|
||||
" </a>\n",
|
||||
" </td>\n",
|
||||
"</tr></tbody></table>"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "2CXS0vZfT8_7"
|
||||
},
|
||||
"source": [
|
||||
"## Overview\n",
|
||||
"\n",
|
||||
"This notebook demonstrates evaluating pre-trained and instruction-tuned Gemma models in Vertex AI.\n",
|
||||
"\n",
|
||||
"### Objective\n",
|
||||
"\n",
|
||||
"- Evaluate pre-trained and instruction-tuned Gemma model on any of the benchmark datasets\n",
|
||||
"- Clean up the resources\n",
|
||||
"\n",
|
||||
"| Models |\n",
|
||||
"| :- |\n",
|
||||
"| [google/gemma-2b](https://huggingface.co/google/gemma-2b)\n",
|
||||
"| [google/gemma-2b-it](https://huggingface.co/google/gemma-2b-it)\n",
|
||||
"| [google/gemma-7b](https://huggingface.co/google/gemma-7b)\n",
|
||||
"| [google/gemma-7b-it](https://huggingface.co/google/gemma-7b-it)\n",
|
||||
"| [google/gemma-1.1-2b-it](https://huggingface.co/google/gemma-1.1-2b-it)\n",
|
||||
"| [google/gemma-1.1-7b-it](https://huggingface.co/google/gemma-1.1-7b-it)\n",
|
||||
"\n",
|
||||
"### Costs\n",
|
||||
"\n",
|
||||
"This tutorial uses billable components of Google Cloud:\n",
|
||||
"\n",
|
||||
"* Vertex AI\n",
|
||||
"* Cloud Storage\n",
|
||||
"\n",
|
||||
"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."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "HCY8PGrFUbT1"
|
||||
},
|
||||
"source": [
|
||||
"## Run the notebook"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"language": "python",
|
||||
"metadata": {
|
||||
"cellView": "form",
|
||||
"id": "81CC3tL1T_TL"
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# @title Setup Google Cloud project\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]** [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",
|
||||
"BUCKET_URI = \"gs://\" # @param {type:\"string\"}\n",
|
||||
"\n",
|
||||
"# @markdown 3. **[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",
|
||||
"# Import the necessary packages\n",
|
||||
"\n",
|
||||
"! git clone https://github.com/GoogleCloudPlatform/vertex-ai-samples.git\n",
|
||||
"\n",
|
||||
"import datetime\n",
|
||||
"import importlib\n",
|
||||
"import os\n",
|
||||
"import uuid\n",
|
||||
"\n",
|
||||
"from google.cloud import aiplatform\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",
|
||||
"models, endpoints = {}, {}\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",
|
||||
" if not os.environ.get(\"GOOGLE_CLOUD_REGION\"):\n",
|
||||
" raise ValueError(\n",
|
||||
" \"REGION must be set. See\"\n",
|
||||
" \" https://cloud.google.com/vertex-ai/docs/general/locations for\"\n",
|
||||
" \" available cloud locations.\"\n",
|
||||
" )\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",
|
||||
"# 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.datetime.now().strftime(\"%Y%m%d%H%M%S\")\n",
|
||||
"BUCKET_NAME = \"/\".join(BUCKET_URI.split(\"/\")[:3])\n",
|
||||
"\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, \"gemma\")\n",
|
||||
"\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",
|
||||
"# 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",
|
||||
"# 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",
|
||||
"! gcloud projects add-iam-policy-binding --no-user-output-enabled {PROJECT_ID} --member=serviceAccount:{SERVICE_ACCOUNT} --role=\"roles/storage.admin\"\n",
|
||||
"! gcloud projects add-iam-policy-binding --no-user-output-enabled {PROJECT_ID} --member=serviceAccount:{SERVICE_ACCOUNT} --role=\"roles/aiplatform.user\""
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"language": "python",
|
||||
"metadata": {
|
||||
"cellView": "form",
|
||||
"id": "pNHMbjr0UjrK"
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# @title Evaluate Gemma models\n",
|
||||
"\n",
|
||||
"# @markdown This section demonstrates how to evaluate the Gemma models with and without finetuned LoRA adapters using EleutherAI's [Language Model Evaluation Harness (lm-evaluation-harness)](https://github.com/EleutherAI/lm-evaluation-harness) with Vertex CustomJob. Refer the peak GPU memory usage for serving and adjust the machine type, accelerator type and accelerator count accordingly.\n",
|
||||
"\n",
|
||||
"# @markdown You must provide a Hugging Face User Access Token (with read access) to access the Gemma models. You can follow the [Hugging Face documentation](https://huggingface.co/docs/hub/en/security-tokens) to create a **read** access token and put it in the `HF_TOKEN` field below.\n",
|
||||
"HF_TOKEN = \"\" # @param {type:\"string\", isTemplate:true}\n",
|
||||
"\n",
|
||||
"# @markdown This example uses the dataset [HellaSwag](https://arxiv.org/abs/1905.07830). All supported tasks are listed in [this task table](https://github.com/EleutherAI/lm-evaluation-harness/blob/master/docs/task_table.md).\n",
|
||||
"# @markdown Set evaluation dataset.\n",
|
||||
"eval_dataset = \"hellaswag\" # @param {type:\"string\"}\n",
|
||||
"\n",
|
||||
"# Worker pool spec.\n",
|
||||
"# Find Vertex AI supported accelerators and regions in:\n",
|
||||
"# https://cloud.google.com/vertex-ai/docs/training/configure-compute\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"# Setup evaluation job.\n",
|
||||
"# @markdown Set the base model id.\n",
|
||||
"base_model_id = \"google/gemma-1.1-2b-it\" # @param[\"google/gemma-2b\", \"google/gemma-2b-it\", \"google/gemma-7b\", \"google/gemma-7b-it\", \"google/gemma-1.1-2b-it\", \"google/gemma-1.1-7b-it\"] {isTemplate:true}\n",
|
||||
"job_name = common_util.get_job_name_with_datetime(prefix=\"gemma-eval\")\n",
|
||||
"eval_output_dir = os.path.join(MODEL_BUCKET, job_name)\n",
|
||||
"eval_output_dir_gcsfuse = eval_output_dir.replace(\"gs://\", \"/gcs/\")\n",
|
||||
"\n",
|
||||
"# @markdown Set the accelerator type.\n",
|
||||
"accelerator_type = \"NVIDIA_L4\" # @param[\"NVIDIA_TESLA_V100\", \"NVIDIA_L4\", \"NVIDIA_TESLA_A100\"]\n",
|
||||
"\n",
|
||||
"# @markdown To evaluate a PEFT-finetuned model, enter the PEFT output directory to the LoRA adapter below.\n",
|
||||
"# @markdown Otherwise, leave it empty.\n",
|
||||
"# @markdown See the [finetuning notebook](https://github.com/GoogleCloudPlatform/vertex-ai-samples/blob/main/notebooks/community/model_garden/model_garden_gemma_finetuning_on_vertex.ipynb) for more details.\n",
|
||||
"# @markdown Set the PEFT output directory.\n",
|
||||
"peft_output_dir = \"\" # @param {type:\"string\"}\n",
|
||||
"peft_output_dir_gcsfuse = peft_output_dir.replace(\"gs://\", \"/gcs/\")\n",
|
||||
"\n",
|
||||
"if accelerator_type == \"NVIDIA_TESLA_A100\":\n",
|
||||
" machine_type = \"a2-highgpu-1g\"\n",
|
||||
" accelerator_count = 1\n",
|
||||
"elif accelerator_type == \"NVIDIA_TESLA_V100\":\n",
|
||||
" machine_type = \"n1-standard-8\"\n",
|
||||
" accelerator_count = 2\n",
|
||||
"elif accelerator_type == \"NVIDIA_L4\":\n",
|
||||
" machine_type = \"g2-standard-8\"\n",
|
||||
" accelerator_count = 1\n",
|
||||
"else:\n",
|
||||
" print(f\"Unsupported accelerator type: {accelerator_type}\")\n",
|
||||
"\n",
|
||||
"replica_count = 1\n",
|
||||
"\n",
|
||||
"common_util.check_quota(\n",
|
||||
" project_id=PROJECT_ID,\n",
|
||||
" region=REGION,\n",
|
||||
" accelerator_type=accelerator_type,\n",
|
||||
" accelerator_count=accelerator_count,\n",
|
||||
" is_for_training=True,\n",
|
||||
")\n",
|
||||
"\n",
|
||||
"# Prepare evaluation command that runs the evaluation harness.\n",
|
||||
"# Set `trust_remote_code = True` because evaluating the model requires\n",
|
||||
"# executing code from the model repository.\n",
|
||||
"# Set `use_accelerate = True` to enable evaluation across multiple GPUs.\n",
|
||||
"eval_command = [\n",
|
||||
" \"lm_eval\",\n",
|
||||
" \"--model\",\n",
|
||||
" \"hf\",\n",
|
||||
" \"--tasks\",\n",
|
||||
" f\"{eval_dataset}\",\n",
|
||||
" \"--output_path\",\n",
|
||||
" f\"{eval_output_dir_gcsfuse}\",\n",
|
||||
"]\n",
|
||||
"\n",
|
||||
"if peft_output_dir_gcsfuse:\n",
|
||||
" eval_command += [\n",
|
||||
" \"--model_args\",\n",
|
||||
" f\"pretrained={base_model_id},peft={peft_output_dir_gcsfuse},trust_remote_code=True,parallelize=True\",\n",
|
||||
" ]\n",
|
||||
"else:\n",
|
||||
" eval_command += [\n",
|
||||
" \"--model_args\",\n",
|
||||
" f\"pretrained={base_model_id},trust_remote_code=True,parallelize=True\",\n",
|
||||
" ]\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"# The evaluation docker image.\n",
|
||||
"EVAL_DOCKER_URI = \"us-docker.pkg.dev/vertex-ai/vertex-vision-model-garden-dockers/pytorch-lm-evaluation-harness:20241016_0934_RC00\"\n",
|
||||
"\n",
|
||||
"# Pass evaluation arguments and launch job.\n",
|
||||
"worker_pool_specs = [\n",
|
||||
" {\n",
|
||||
" \"machine_spec\": {\n",
|
||||
" \"machine_type\": machine_type,\n",
|
||||
" \"accelerator_type\": accelerator_type,\n",
|
||||
" \"accelerator_count\": accelerator_count,\n",
|
||||
" },\n",
|
||||
" \"replica_count\": replica_count,\n",
|
||||
" \"disk_spec\": {\n",
|
||||
" \"boot_disk_size_gb\": 500,\n",
|
||||
" },\n",
|
||||
" \"container_spec\": {\n",
|
||||
" \"image_uri\": EVAL_DOCKER_URI,\n",
|
||||
" \"env\": [\n",
|
||||
" {\n",
|
||||
" \"name\": \"HF_TOKEN\",\n",
|
||||
" \"value\": HF_TOKEN,\n",
|
||||
" }\n",
|
||||
" ],\n",
|
||||
" \"command\": eval_command,\n",
|
||||
" \"args\": [],\n",
|
||||
" },\n",
|
||||
" }\n",
|
||||
"]\n",
|
||||
"\n",
|
||||
"eval_job = aiplatform.CustomJob(\n",
|
||||
" display_name=job_name,\n",
|
||||
" worker_pool_specs=worker_pool_specs,\n",
|
||||
" base_output_dir=eval_output_dir,\n",
|
||||
")\n",
|
||||
"\n",
|
||||
"eval_job.run()\n",
|
||||
"\n",
|
||||
"print(\"Evaluation results were saved in:\", eval_output_dir)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"cellView": "form",
|
||||
"id": "CVBxGpwWU3kY"
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# @title Fetch and print evaluation results\n",
|
||||
"import json\n",
|
||||
"import re\n",
|
||||
"\n",
|
||||
"from google.cloud import storage\n",
|
||||
"\n",
|
||||
"# Fetch evaluation results.\n",
|
||||
"storage_client = storage.Client()\n",
|
||||
"BUCKET_NAME = BUCKET_URI.split(\"gs://\")[1]\n",
|
||||
"bucket = storage_client.get_bucket(BUCKET_NAME)\n",
|
||||
"\n",
|
||||
"blobs = [b.name for b in bucket.list_blobs()]\n",
|
||||
"\n",
|
||||
"result_file_path = None\n",
|
||||
"for file_path in filter(re.compile(\".*/*.json\").match, blobs):\n",
|
||||
" result_file_path = file_path\n",
|
||||
" print(f\"Found result file: {file_path}\")\n",
|
||||
"\n",
|
||||
"if result_file_path is None:\n",
|
||||
" raise ValueError(\"No result file found.\")\n",
|
||||
"\n",
|
||||
"blob = bucket.blob(result_file_path)\n",
|
||||
"raw_result = blob.download_as_string()\n",
|
||||
"\n",
|
||||
"# Print evaluation results.\n",
|
||||
"result = json.loads(raw_result)\n",
|
||||
"result_formatted = json.dumps(result, indent=2)\n",
|
||||
"print(f\"Evaluation result:\\n{result_formatted}\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"id": "unjukbcjEBOd"
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"## Clean up resources"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"cellView": "form",
|
||||
"id": "qWN3cl_VU7pa"
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Delete evaluation job.\n",
|
||||
"\n",
|
||||
"delete_bucket = False # @param {type:\"boolean\"}\n",
|
||||
"if delete_bucket:\n",
|
||||
" ! gsutil -m rm -r $BUCKET_URI\n",
|
||||
" # Uncomment below to delete all artifacts\n",
|
||||
" # !gsutil -m rm -r $STAGING_BUCKET $MODEL_BUCKET $EXPERIMENT_BUCKET\n",
|
||||
"\n",
|
||||
"eval_job.delete()"
|
||||
]
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"colab": {
|
||||
"name": "model_garden_gemma_evaluation.ipynb",
|
||||
"toc_visible": true
|
||||
},
|
||||
"kernelspec": {
|
||||
"display_name": "Python 3",
|
||||
"name": "python3"
|
||||
}
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"language": "python",
|
||||
"metadata": {
|
||||
"cellView": "form",
|
||||
"id": "B8S-yo8qTIcO"
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Copyright 2026 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."
|
||||
]
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 0
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "MTRywGxLTZfU"
|
||||
},
|
||||
"source": [
|
||||
"# Vertex AI Model Garden - Gemma Evaluation\n",
|
||||
"\n",
|
||||
"<table><tbody><tr>\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%2Fcommunity%2Fmodel_garden%2Fmodel_garden_gemma_evaluation.ipynb\">\n",
|
||||
" <img alt=\"Google Cloud Colab Enterprise logo\" src=\"https://lh3.googleusercontent.com/JmcxdQi-qOpctIvWKgPtrzZdJJK-J3sWE1RsfjZNwshCFgE_9fULcNpuXYTilIR2hjwN\" width=\"32px\"><br> Run in Colab Enterprise\n",
|
||||
" </a>\n",
|
||||
" </td>\n",
|
||||
" <td style=\"text-align: center\">\n",
|
||||
" <a href=\"https://github.com/GoogleCloudPlatform/vertex-ai-samples/blob/main/notebooks/community/model_garden/model_garden_gemma_evaluation.ipynb\">\n",
|
||||
" <img alt=\"GitHub logo\" src=\"https://github.githubassets.com/assets/GitHub-Mark-ea2971cee799.png\" width=\"32px\"><br> View on GitHub\n",
|
||||
" </a>\n",
|
||||
" </td>\n",
|
||||
"</tr></tbody></table>"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "2CXS0vZfT8_7"
|
||||
},
|
||||
"source": [
|
||||
"## Overview\n",
|
||||
"\n",
|
||||
"This notebook demonstrates evaluating pre-trained and instruction-tuned Gemma models in Vertex AI.\n",
|
||||
"\n",
|
||||
"### Objective\n",
|
||||
"\n",
|
||||
"- Evaluate pre-trained and instruction-tuned Gemma model on any of the benchmark datasets\n",
|
||||
"- Clean up the resources\n",
|
||||
"\n",
|
||||
"| Models |\n",
|
||||
"| :- |\n",
|
||||
"| [google/gemma-2b](https://huggingface.co/google/gemma-2b)\n",
|
||||
"| [google/gemma-2b-it](https://huggingface.co/google/gemma-2b-it)\n",
|
||||
"| [google/gemma-7b](https://huggingface.co/google/gemma-7b)\n",
|
||||
"| [google/gemma-7b-it](https://huggingface.co/google/gemma-7b-it)\n",
|
||||
"| [google/gemma-1.1-2b-it](https://huggingface.co/google/gemma-1.1-2b-it)\n",
|
||||
"| [google/gemma-1.1-7b-it](https://huggingface.co/google/gemma-1.1-7b-it)\n",
|
||||
"\n",
|
||||
"### Costs\n",
|
||||
"\n",
|
||||
"This tutorial uses billable components of Google Cloud:\n",
|
||||
"\n",
|
||||
"* Vertex AI\n",
|
||||
"* Cloud Storage\n",
|
||||
"\n",
|
||||
"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."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "HCY8PGrFUbT1"
|
||||
},
|
||||
"source": [
|
||||
"## Run the notebook"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"language": "python",
|
||||
"metadata": {
|
||||
"cellView": "form",
|
||||
"id": "81CC3tL1T_TL"
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# @title Setup Google Cloud project\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]** [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",
|
||||
"BUCKET_URI = \"gs://\" # @param {type:\"string\"}\n",
|
||||
"\n",
|
||||
"# @markdown 3. **[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",
|
||||
"# Import the necessary packages\n",
|
||||
"\n",
|
||||
"! git clone https://github.com/GoogleCloudPlatform/vertex-ai-samples.git\n",
|
||||
"\n",
|
||||
"import datetime\n",
|
||||
"import importlib\n",
|
||||
"import os\n",
|
||||
"import uuid\n",
|
||||
"\n",
|
||||
"from google.cloud import aiplatform\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",
|
||||
"models, endpoints = {}, {}\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",
|
||||
" if not os.environ.get(\"GOOGLE_CLOUD_REGION\"):\n",
|
||||
" raise ValueError(\n",
|
||||
" \"REGION must be set. See\"\n",
|
||||
" \" https://cloud.google.com/vertex-ai/docs/general/locations for\"\n",
|
||||
" \" available cloud locations.\"\n",
|
||||
" )\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",
|
||||
"# 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.datetime.now().strftime(\"%Y%m%d%H%M%S\")\n",
|
||||
"BUCKET_NAME = \"/\".join(BUCKET_URI.split(\"/\")[:3])\n",
|
||||
"\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, \"gemma\")\n",
|
||||
"\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",
|
||||
"# 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",
|
||||
"# 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",
|
||||
"! gcloud projects add-iam-policy-binding --no-user-output-enabled {PROJECT_ID} --member=serviceAccount:{SERVICE_ACCOUNT} --role=\"roles/storage.admin\"\n",
|
||||
"! gcloud projects add-iam-policy-binding --no-user-output-enabled {PROJECT_ID} --member=serviceAccount:{SERVICE_ACCOUNT} --role=\"roles/aiplatform.user\""
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"language": "python",
|
||||
"metadata": {
|
||||
"cellView": "form",
|
||||
"id": "pNHMbjr0UjrK"
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# @title Evaluate Gemma models\n",
|
||||
"\n",
|
||||
"# @markdown This section demonstrates how to evaluate the Gemma models with and without finetuned LoRA adapters using EleutherAI's [Language Model Evaluation Harness (lm-evaluation-harness)](https://github.com/EleutherAI/lm-evaluation-harness) with Vertex CustomJob. Refer the peak GPU memory usage for serving and adjust the machine type, accelerator type and accelerator count accordingly.\n",
|
||||
"\n",
|
||||
"# @markdown You must provide a Hugging Face User Access Token (with read access) to access the Gemma models. You can follow the [Hugging Face documentation](https://huggingface.co/docs/hub/en/security-tokens) to create a **read** access token and put it in the `HF_TOKEN` field below.\n",
|
||||
"HF_TOKEN = \"\" # @param {type:\"string\", isTemplate:true}\n",
|
||||
"\n",
|
||||
"# @markdown This example uses the dataset [HellaSwag](https://arxiv.org/abs/1905.07830). All supported tasks are listed in [this task table](https://github.com/EleutherAI/lm-evaluation-harness/blob/master/docs/task_table.md).\n",
|
||||
"# @markdown Set evaluation dataset.\n",
|
||||
"eval_dataset = \"hellaswag\" # @param {type:\"string\"}\n",
|
||||
"\n",
|
||||
"# Worker pool spec.\n",
|
||||
"# Find Vertex AI supported accelerators and regions in:\n",
|
||||
"# https://cloud.google.com/vertex-ai/docs/training/configure-compute\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"# Setup evaluation job.\n",
|
||||
"# @markdown Set the base model id.\n",
|
||||
"base_model_id = \"google/gemma-1.1-2b-it\" # @param[\"google/gemma-2b\", \"google/gemma-2b-it\", \"google/gemma-7b\", \"google/gemma-7b-it\", \"google/gemma-1.1-2b-it\", \"google/gemma-1.1-7b-it\"] {isTemplate:true}\n",
|
||||
"job_name = common_util.get_job_name_with_datetime(prefix=\"gemma-eval\")\n",
|
||||
"eval_output_dir = os.path.join(MODEL_BUCKET, job_name)\n",
|
||||
"eval_output_dir_gcsfuse = eval_output_dir.replace(\"gs://\", \"/gcs/\")\n",
|
||||
"\n",
|
||||
"# @markdown Set the accelerator type.\n",
|
||||
"accelerator_type = \"NVIDIA_L4\" # @param[\"NVIDIA_TESLA_V100\", \"NVIDIA_L4\", \"NVIDIA_TESLA_A100\"]\n",
|
||||
"\n",
|
||||
"# @markdown To evaluate a PEFT-finetuned model, enter the PEFT output directory to the LoRA adapter below.\n",
|
||||
"# @markdown Otherwise, leave it empty.\n",
|
||||
"# @markdown See the [finetuning notebook](https://github.com/GoogleCloudPlatform/vertex-ai-samples/blob/main/notebooks/community/model_garden/model_garden_gemma_finetuning_on_vertex.ipynb) for more details.\n",
|
||||
"# @markdown Set the PEFT output directory.\n",
|
||||
"peft_output_dir = \"\" # @param {type:\"string\"}\n",
|
||||
"peft_output_dir_gcsfuse = peft_output_dir.replace(\"gs://\", \"/gcs/\")\n",
|
||||
"\n",
|
||||
"if accelerator_type == \"NVIDIA_TESLA_A100\":\n",
|
||||
" machine_type = \"a2-highgpu-1g\"\n",
|
||||
" accelerator_count = 1\n",
|
||||
"elif accelerator_type == \"NVIDIA_TESLA_V100\":\n",
|
||||
" machine_type = \"n1-standard-8\"\n",
|
||||
" accelerator_count = 2\n",
|
||||
"elif accelerator_type == \"NVIDIA_L4\":\n",
|
||||
" machine_type = \"g2-standard-8\"\n",
|
||||
" accelerator_count = 1\n",
|
||||
"else:\n",
|
||||
" print(f\"Unsupported accelerator type: {accelerator_type}\")\n",
|
||||
"\n",
|
||||
"replica_count = 1\n",
|
||||
"\n",
|
||||
"common_util.check_quota(\n",
|
||||
" project_id=PROJECT_ID,\n",
|
||||
" region=REGION,\n",
|
||||
" accelerator_type=accelerator_type,\n",
|
||||
" accelerator_count=accelerator_count,\n",
|
||||
" is_for_training=True,\n",
|
||||
")\n",
|
||||
"\n",
|
||||
"# Prepare evaluation command that runs the evaluation harness.\n",
|
||||
"# Set `trust_remote_code = True` because evaluating the model requires\n",
|
||||
"# executing code from the model repository.\n",
|
||||
"# Set `use_accelerate = True` to enable evaluation across multiple GPUs.\n",
|
||||
"eval_command = [\n",
|
||||
" \"lm_eval\",\n",
|
||||
" \"--model\",\n",
|
||||
" \"hf\",\n",
|
||||
" \"--tasks\",\n",
|
||||
" f\"{eval_dataset}\",\n",
|
||||
" \"--output_path\",\n",
|
||||
" f\"{eval_output_dir_gcsfuse}\",\n",
|
||||
"]\n",
|
||||
"\n",
|
||||
"if peft_output_dir_gcsfuse:\n",
|
||||
" eval_command += [\n",
|
||||
" \"--model_args\",\n",
|
||||
" f\"pretrained={base_model_id},peft={peft_output_dir_gcsfuse},trust_remote_code=True,parallelize=True\",\n",
|
||||
" ]\n",
|
||||
"else:\n",
|
||||
" eval_command += [\n",
|
||||
" \"--model_args\",\n",
|
||||
" f\"pretrained={base_model_id},trust_remote_code=True,parallelize=True\",\n",
|
||||
" ]\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"# The evaluation docker image.\n",
|
||||
"EVAL_DOCKER_URI = \"us-docker.pkg.dev/vertex-ai/vertex-vision-model-garden-dockers/pytorch-lm-evaluation-harness:20241016_0934_RC00\"\n",
|
||||
"\n",
|
||||
"# Pass evaluation arguments and launch job.\n",
|
||||
"worker_pool_specs = [\n",
|
||||
" {\n",
|
||||
" \"machine_spec\": {\n",
|
||||
" \"machine_type\": machine_type,\n",
|
||||
" \"accelerator_type\": accelerator_type,\n",
|
||||
" \"accelerator_count\": accelerator_count,\n",
|
||||
" },\n",
|
||||
" \"replica_count\": replica_count,\n",
|
||||
" \"disk_spec\": {\n",
|
||||
" \"boot_disk_size_gb\": 500,\n",
|
||||
" },\n",
|
||||
" \"container_spec\": {\n",
|
||||
" \"image_uri\": EVAL_DOCKER_URI,\n",
|
||||
" \"env\": [\n",
|
||||
" {\n",
|
||||
" \"name\": \"HF_TOKEN\",\n",
|
||||
" \"value\": HF_TOKEN,\n",
|
||||
" }\n",
|
||||
" ],\n",
|
||||
" \"command\": eval_command,\n",
|
||||
" \"args\": [],\n",
|
||||
" },\n",
|
||||
" }\n",
|
||||
"]\n",
|
||||
"\n",
|
||||
"eval_job = aiplatform.CustomJob(\n",
|
||||
" display_name=job_name,\n",
|
||||
" worker_pool_specs=worker_pool_specs,\n",
|
||||
" base_output_dir=eval_output_dir,\n",
|
||||
")\n",
|
||||
"\n",
|
||||
"eval_job.run()\n",
|
||||
"\n",
|
||||
"print(\"Evaluation results were saved in:\", eval_output_dir)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"cellView": "form",
|
||||
"id": "CVBxGpwWU3kY"
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# @title Fetch and print evaluation results\n",
|
||||
"import json\n",
|
||||
"import re\n",
|
||||
"\n",
|
||||
"from google.cloud import storage\n",
|
||||
"\n",
|
||||
"# Fetch evaluation results.\n",
|
||||
"storage_client = storage.Client()\n",
|
||||
"BUCKET_NAME = BUCKET_URI.split(\"gs://\")[1]\n",
|
||||
"bucket = storage_client.get_bucket(BUCKET_NAME)\n",
|
||||
"\n",
|
||||
"blobs = [b.name for b in bucket.list_blobs()]\n",
|
||||
"\n",
|
||||
"result_file_path = None\n",
|
||||
"for file_path in filter(re.compile(\".*/*.json\").match, blobs):\n",
|
||||
" result_file_path = file_path\n",
|
||||
" print(f\"Found result file: {file_path}\")\n",
|
||||
"\n",
|
||||
"if result_file_path is None:\n",
|
||||
" raise ValueError(\"No result file found.\")\n",
|
||||
"\n",
|
||||
"blob = bucket.blob(result_file_path)\n",
|
||||
"raw_result = blob.download_as_string()\n",
|
||||
"\n",
|
||||
"# Print evaluation results.\n",
|
||||
"result = json.loads(raw_result)\n",
|
||||
"result_formatted = json.dumps(result, indent=2)\n",
|
||||
"print(f\"Evaluation result:\\n{result_formatted}\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"id": "unjukbcjEBOd"
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"## Clean up resources"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"cellView": "form",
|
||||
"id": "qWN3cl_VU7pa"
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Delete evaluation job.\n",
|
||||
"\n",
|
||||
"delete_bucket = False # @param {type:\"boolean\"}\n",
|
||||
"if delete_bucket:\n",
|
||||
" ! gsutil -m rm -r $BUCKET_URI\n",
|
||||
" # Uncomment below to delete all artifacts\n",
|
||||
" # !gsutil -m rm -r $STAGING_BUCKET $MODEL_BUCKET $EXPERIMENT_BUCKET\n",
|
||||
"\n",
|
||||
"eval_job.delete()"
|
||||
]
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"colab": {
|
||||
"name": "model_garden_gemma_evaluation.ipynb",
|
||||
"toc_visible": true
|
||||
},
|
||||
"kernelspec": {
|
||||
"display_name": "Python 3",
|
||||
"name": "python3"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 0
|
||||
}
|
||||
|
||||
@@ -1,964 +0,0 @@
|
||||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"cellView": "form",
|
||||
"id": "7d9bbf86da5e"
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Copyright 2026 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": "99c1c3fc2ca5"
|
||||
},
|
||||
"source": [
|
||||
"# Vertex AI Model Garden - Gemma Finetuning\n",
|
||||
"\n",
|
||||
"<table><tbody><tr>\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%2Fcommunity%2Fmodel_garden%2Fmodel_garden_gemma_finetuning_on_vertex.ipynb\">\n",
|
||||
" <img alt=\"Google Cloud Colab Enterprise logo\" src=\"https://lh3.googleusercontent.com/JmcxdQi-qOpctIvWKgPtrzZdJJK-J3sWE1RsfjZNwshCFgE_9fULcNpuXYTilIR2hjwN\" width=\"32px\"><br> Run in Colab Enterprise\n",
|
||||
" </a>\n",
|
||||
" </td>\n",
|
||||
" <td style=\"text-align: center\">\n",
|
||||
" <a href=\"https://github.com/GoogleCloudPlatform/vertex-ai-samples/blob/main/notebooks/community/model_garden/model_garden_gemma_finetuning_on_vertex.ipynb\">\n",
|
||||
" <img alt=\"GitHub logo\" src=\"https://github.githubassets.com/assets/GitHub-Mark-ea2971cee799.png\" width=\"32px\"><br> View on GitHub\n",
|
||||
" </a>\n",
|
||||
" </td>\n",
|
||||
"</tr></tbody></table>"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "3de7470326a2"
|
||||
},
|
||||
"source": [
|
||||
"## Overview\n",
|
||||
"\n",
|
||||
"This notebook demonstrates finetuning and deploying Gemma models with [Vertex AI Custom Training Job](https://cloud.google.com/vertex-ai/docs/training/create-custom-job). All of the examples in this notebook use parameter efficient finetuning methods [PEFT (LoRA)](https://github.com/huggingface/peft) to reduce training and storage costs. LoRA (Low-Rank Adaptation) is one approach of Parameter Efficient FineTuning (PEFT), where pretrained model weights are frozen and rank decomposition matrices representing the change in model weights are trained during finetuning. Read more about LoRA in the following publication: [Hu, E.J., Shen, Y., Wallis, P., Allen-Zhu, Z., Li, Y., Wang, S., Wang, L. and Chen, W., 2021. Lora: Low-rank adaptation of large language models. *arXiv preprint arXiv:2106.09685*](https://arxiv.org/abs/2106.09685).\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"After tuning, we can deploy models on Vertex.\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"### Objective\n",
|
||||
"\n",
|
||||
"- Finetune and deploy Gemma models with Vertex AI Custom Training Jobs.\n",
|
||||
"- Send prediction requests to your finetuned Gemma model.\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"### Costs\n",
|
||||
"\n",
|
||||
"This tutorial uses billable components of Google Cloud:\n",
|
||||
"\n",
|
||||
"* Vertex AI\n",
|
||||
"* Cloud Storage\n",
|
||||
"\n",
|
||||
"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."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "264c07757582"
|
||||
},
|
||||
"source": [
|
||||
"## Before you begin"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"cellView": "form",
|
||||
"id": "BNAlJh_pGxbL"
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# @title Install Python Packages for Finetuning\n",
|
||||
"\n",
|
||||
"# @markdown 1. Install google-cloud-aiplatform package and restart the session if instructed.\n",
|
||||
"! pip install --upgrade --quiet google-cloud-aiplatform==1.130.0\n",
|
||||
"\n",
|
||||
"# @markdown 2. Install packages to validate dataset with template.\n",
|
||||
"! pip install --upgrade --quiet accelerate==0.31.0\n",
|
||||
"! pip install --upgrade --quiet transformers==4.43.1\n",
|
||||
"! pip install --upgrade --quiet datasets==2.19.2\n",
|
||||
"\n",
|
||||
"# Load local tensorboard.\n",
|
||||
"%load_ext tensorboard"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"cellView": "form",
|
||||
"id": "8CQcnBfWvc-f"
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# @title Setup Google Cloud project\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. For finetuning, **[click here](https://console.cloud.google.com/iam-admin/quotas?location=us-central1&metric=aiplatform.googleapis.com%2Frestricted_image_training_nvidia_a100_80gb_gpus)** to check if your project already has the required 8 Nvidia A100 80 GB GPUs in the us-central1 region. If yes, then run this notebook in the us-central1 region. If you do not have 8 Nvidia A100 80 GPUs or have more GPU requirements than this, then schedule your job with Nvidia H100 GPUs via Dynamic Workload Scheduler using [these instructions](https://cloud.google.com/vertex-ai/docs/training/schedule-jobs-dws). For Dynamic Workload Scheduler, check the [us-central1](https://console.cloud.google.com/iam-admin/quotas?location=us-central1&metric=aiplatform.googleapis.com%2Fcustom_model_training_preemptible_nvidia_h100_gpus) or [europe-west4](https://console.cloud.google.com/iam-admin/quotas?location=europe-west4&metric=aiplatform.googleapis.com%2Fcustom_model_training_preemptible_nvidia_h100_gpus) quota for Nvidia H100 GPUs. If you do not have enough GPUs, then you can follow [these instructions](https://cloud.google.com/docs/quotas/view-manage#viewing_your_quota_console) to request quota.\n",
|
||||
"\n",
|
||||
"# @markdown 3. For serving, **[click here](https://console.cloud.google.com/iam-admin/quotas?location=us-central1&metric=aiplatform.googleapis.com%2Fcustom_model_serving_nvidia_l4_gpus)** to check if your project already has the required 1 L4 GPU in the us-central1 region. If yes, then run this notebook in the us-central1 region. If you need more L4 GPUs for your project, then you can follow [these instructions](https://cloud.google.com/docs/quotas/view-manage#viewing_your_quota_console) to request more. Alternatively, 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).\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",
|
||||
"# @markdown 4. **[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",
|
||||
"BUCKET_URI = \"gs://\" # @param {type:\"string\"}\n",
|
||||
"\n",
|
||||
"# @markdown 5. **[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",
|
||||
"# Import the necessary packages\n",
|
||||
"! rm -rf vertex-ai-samples && git clone https://github.com/GoogleCloudPlatform/vertex-ai-samples.git\n",
|
||||
"! cd vertex-ai-samples && git reset --hard 7ae13b346a72ee2a2dc8152dd40c6ddd72d6c810\n",
|
||||
"\n",
|
||||
"import datetime\n",
|
||||
"import importlib\n",
|
||||
"import os\n",
|
||||
"import uuid\n",
|
||||
"from typing import Tuple\n",
|
||||
"\n",
|
||||
"from google.cloud import aiplatform\n",
|
||||
"from google.cloud.aiplatform.compat.types import \\\n",
|
||||
" custom_job as gca_custom_job_compat\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",
|
||||
"models, endpoints = {}, {}\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",
|
||||
" if not os.environ.get(\"GOOGLE_CLOUD_REGION\"):\n",
|
||||
" raise ValueError(\n",
|
||||
" \"REGION must be set. See\"\n",
|
||||
" \" https://cloud.google.com/vertex-ai/docs/general/locations for\"\n",
|
||||
" \" available cloud locations.\"\n",
|
||||
" )\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",
|
||||
"# 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.datetime.now().strftime(\"%Y%m%d%H%M%S\")\n",
|
||||
"BUCKET_NAME = \"/\".join(BUCKET_URI.split(\"/\")[:3])\n",
|
||||
"\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, \"gemma\")\n",
|
||||
"\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",
|
||||
"# 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",
|
||||
"# 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",
|
||||
"! gcloud projects add-iam-policy-binding --no-user-output-enabled {PROJECT_ID} --member=serviceAccount:{SERVICE_ACCOUNT} --role=\"roles/storage.admin\"\n",
|
||||
"! gcloud projects add-iam-policy-binding --no-user-output-enabled {PROJECT_ID} --member=serviceAccount:{SERVICE_ACCOUNT} --role=\"roles/aiplatform.user\"\n",
|
||||
"\n",
|
||||
"# @markdown ## Access Gemma Models\n",
|
||||
"# @markdown For GPU based finetuning and serving, choose between accessing Gemma models on [Hugging Face](https://huggingface.co/)\n",
|
||||
"# @markdown or Vertex AI as described below.\n",
|
||||
"\n",
|
||||
"# @markdown If you already obtained access to Gemma models on [Hugging Face](https://huggingface.co/), you can load models from there.\n",
|
||||
"# @markdown Alternatively, you can also load the original Gemma models for finetuning and serving from Vertex AI after accepting the agreement.\n",
|
||||
"\n",
|
||||
"# @markdown **Select and fill one of the three following sections.**\n",
|
||||
"LOAD_MODEL_FROM = \"Hugging Face\" # @param [\"Hugging Face\", \"Google Cloud\"] {isTemplate:true}\n",
|
||||
"\n",
|
||||
"# @markdown ---\n",
|
||||
"\n",
|
||||
"# @markdown ### Access Gemma models on Hugging Face for GPU based finetuning and serving\n",
|
||||
"# @markdown You must provide a Hugging Face User Access Token (with read access) to access the Gemma models. You can follow the [Hugging Face documentation](https://huggingface.co/docs/hub/en/security-tokens) to create a **read** access token and put it in the `HF_TOKEN` field below.\n",
|
||||
"\n",
|
||||
"HF_TOKEN = \"\" # @param {type:\"string\", isTemplate:true}\n",
|
||||
"if LOAD_MODEL_FROM == \"Hugging Face\":\n",
|
||||
" assert (\n",
|
||||
" HF_TOKEN\n",
|
||||
" ), \"Provide a read HF_TOKEN to load models from Hugging Face, or select a different model source.\"\n",
|
||||
"\n",
|
||||
"# @markdown *--- Or ---*\n",
|
||||
"# @markdown ### Access Gemma models on Vertex AI for GPU based finetuning and serving\n",
|
||||
"# @markdown Accept the model agreement to access the models:\n",
|
||||
"# @markdown 1. Open the [Gemma model card](https://console.cloud.google.com/vertex-ai/publishers/google/model-garden/335) from [Vertex AI Model Garden](https://cloud.google.com/model-garden).\n",
|
||||
"# @markdown 2. Review the agreement on the model card page.\n",
|
||||
"# @markdown 3. After accepting the agreement of Gemma, a `https://` link containing Gemma pretrained and finetuned models will be shared.\n",
|
||||
"# @markdown 4. Paste the link in the `VERTEX_MODEL_GARDEN_GEMMA` field below.\n",
|
||||
"# @markdown **Note:** This will unzip and copy the Gemma model artifacts to your Cloud Storage bucket, which will take around 1 hour.\n",
|
||||
"\n",
|
||||
"VERTEX_AI_MODEL_GARDEN_GEMMA = \"\" # @param {type:\"string\", isTemplate:true}\n",
|
||||
"\n",
|
||||
"if LOAD_MODEL_FROM == \"Google Cloud\":\n",
|
||||
" assert (\n",
|
||||
" VERTEX_AI_MODEL_GARDEN_GEMMA\n",
|
||||
" ), \"Accept the agreement of Gemma in Vertex AI Model Garden and get the URL to Gemma model artifacts, or select a different model source.\"\n",
|
||||
"\n",
|
||||
" # Only use the last part in case a full command is pasted.\n",
|
||||
" signed_url = VERTEX_AI_MODEL_GARDEN_GEMMA.split(\" \")[-1].strip('\"')\n",
|
||||
"\n",
|
||||
" ! mkdir -p ./gemma\n",
|
||||
" ! curl -X GET \"{signed_url}\" | tar -xzvf - -C ./gemma/\n",
|
||||
" ! gsutil -m cp -R ./gemma/* {MODEL_BUCKET}\n",
|
||||
"\n",
|
||||
" model_path_prefix = MODEL_BUCKET\n",
|
||||
" HF_TOKEN = \"\"\n",
|
||||
"else:\n",
|
||||
" model_path_prefix = \"google/\"\n",
|
||||
"\n",
|
||||
"conversion_job = None"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "cb56d402e84a"
|
||||
},
|
||||
"source": [
|
||||
"## Finetune with HuggingFace PEFT and Deploy with vLLM on GPUs"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"cellView": "form",
|
||||
"id": "KwAW99YZHTdy"
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# @title Set dataset\n",
|
||||
"\n",
|
||||
"# @markdown Use the Vertex AI SDK to create and run the custom training jobs.\n",
|
||||
"\n",
|
||||
"# @markdown This notebook uses [timdettmers/openassistant-guanaco](https://huggingface.co/datasets/timdettmers/openassistant-guanaco) dataset as an example.\n",
|
||||
"# @markdown You can set `dataset_name` to any existing [Hugging Face dataset](https://huggingface.co/datasets) name, and set `instruct_column_in_dataset` to the name of the dataset column containing training data. The [timdettmers/openassistant-guanaco](https://huggingface.co/datasets/timdettmers/openassistant-guanaco) has only one column `text`, and therefore we set `instruct_column_in_dataset` to `text` in this notebook.\n",
|
||||
"\n",
|
||||
"# @markdown ### (Optional) Prepare a custom JSONL dataset for finetuning\n",
|
||||
"\n",
|
||||
"# @markdown You can prepare a JSONL file where each line is a valid JSON string as your custom training dataset. For example, here is one line from the [timdettmers/openassistant-guanaco](https://huggingface.co/datasets/timdettmers/openassistant-guanaco) dataset:\n",
|
||||
"# @markdown ```\n",
|
||||
"# @markdown {\"text\": \"### Human: Hola### Assistant: \\u00a1Hola! \\u00bfEn qu\\u00e9 puedo ayudarte hoy?\"}\n",
|
||||
"# @markdown ```\n",
|
||||
"\n",
|
||||
"# @markdown The JSON object has a key `text`, which should match `instruct_column_in_dataset`; The value should be one training data point, i.e. a string. After you prepared your JSONL file, you can either upload it to [Hugging Face datasets](https://huggingface.co/datasets) or [Google Cloud Storage](https://cloud.google.com/storage).\n",
|
||||
"\n",
|
||||
"# @markdown - To upload a JSONL dataset to [Hugging Face datasets](https://huggingface.co/datasets), follow the instructions on [Uploading Datasets](https://huggingface.co/docs/hub/en/datasets-adding). Then, set `dataset_name` to the name of your newly created dataset on Hugging Face.\n",
|
||||
"\n",
|
||||
"# @markdown - To upload a JSONL dataset to [Google Cloud Storage](https://cloud.google.com/storage), follow the instructions on [Upload objects from a filesystem](https://cloud.google.com/storage/docs/uploading-objects). Then, set `dataset_name` to the `gs://` URI to your JSONL file. For example: `gs://cloud-samples-data/vertex-ai/model-evaluation/peft_train_sample.jsonl`.\n",
|
||||
"\n",
|
||||
"# @markdown Optionally update the `instruct_column_in_dataset` field below if your JSON objects use a key other than the default `text`.\n",
|
||||
"\n",
|
||||
"# @markdown ### (Optional) Format your data with custom JSON template\n",
|
||||
"\n",
|
||||
"# @markdown Sometimes, your dataset might have multiple text columns and you want to construct the training data with a template. You can prepare a JSON template in the following format:\n",
|
||||
"\n",
|
||||
"# @markdown ```\n",
|
||||
"# @markdown {\n",
|
||||
"# @markdown \"description\": \"Template that accepts text-bison format.\",\n",
|
||||
"# @markdown \"source\": \"https://cloud.google.com/vertex-ai/generative-ai/docs/models/tune-text-models-supervised#dataset-format\",\n",
|
||||
"# @markdown \"prompt_input\": \"\\n\\n<|start_header_id|>user<|end_header_id|>\\n\\n{input_text}<|eot_id|>\\n\\n<|start_header_id|>assistant<|end_header_id|>\\n\\n{output_text}<|eot_id|>\",\n",
|
||||
"# @markdown \"instruction_separator\": \"<|start_header_id|>user<|end_header_id|>\\n\\n\",\n",
|
||||
"# @markdown \"response_separator\": \"<|start_header_id|>assistant<|end_header_id|>\\n\\n\"\n",
|
||||
"# @markdown }\n",
|
||||
"# @markdown ```\n",
|
||||
"\n",
|
||||
"# @markdown As an example, the template above can be used to format the following training data (this line comes from `gs://cloud-samples-data/vertex-ai/model-evaluation/peft_train_sample.jsonl`):\n",
|
||||
"\n",
|
||||
"# @markdown ```\n",
|
||||
"# @markdown {\"input_text\":\"TRANSCRIPT: \\nREASON FOR EVALUATION:,\\n\\n LABEL:\",\"output_text\":\"Chiropractic\"}\n",
|
||||
"# @markdown ```\n",
|
||||
"\n",
|
||||
"# @markdown This example template simply concatenates `input_text` with `output_text` with some special tokens in between.\n",
|
||||
"# @markdown\n",
|
||||
"# @markdown To try such custom dataset, you can make the following changes:\n",
|
||||
"# @markdown 1. Set `template` to `llama3-text-bison`\n",
|
||||
"# @markdown 1. Set `train_dataset_name` to `gs://cloud-samples-data/vertex-ai/model-evaluation/peft_train_sample.jsonl`\n",
|
||||
"# @markdown 1. Set `train_split_name` to `train`\n",
|
||||
"# @markdown 1. Set `eval_dataset_name` to `gs://cloud-samples-data/vertex-ai/model-evaluation/peft_eval_sample.jsonl`\n",
|
||||
"# @markdown 1. Set `eval_split_name` to `train` (**NOT** `test`)\n",
|
||||
"# @markdown 1. Set `instruct_column_in_dataset` as `input_text`.\n",
|
||||
"\n",
|
||||
"# Template name or gs:// URI to a custom template.\n",
|
||||
"template = \"openassistant-guanaco\" # @param {type:\"string\"}\n",
|
||||
"\n",
|
||||
"# Hugging Face dataset name or gs:// URI to a custom JSONL dataset.\n",
|
||||
"train_dataset_name = \"timdettmers/openassistant-guanaco\" # @param {type:\"string\"}\n",
|
||||
"train_split_name = \"train\" # @param {type:\"string\"}\n",
|
||||
"eval_dataset_name = \"timdettmers/openassistant-guanaco\" # @param {type:\"string\"}\n",
|
||||
"eval_split_name = \"test\" # @param {type:\"string\"}\n",
|
||||
"\n",
|
||||
"# Name of the dataset column containing training text input.\n",
|
||||
"instruct_column_in_dataset = \"text\" # @param {type:\"string\"}"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"cellView": "form",
|
||||
"id": "SdiyOeyFGxbM"
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# @title Set model\n",
|
||||
"\n",
|
||||
"# @markdown Select a model variant of Gemma 2.\n",
|
||||
"base_model_id = \"gemma-2b\" # @param[\"gemma-2b\", \"gemma-2b-it\", \"gemma-7b\", \"gemma-7b-it\", \"gemma-1.1-2b-it\", \"gemma-1.1-7b-it\"] {isTemplate:true}\n",
|
||||
"pretrained_model_id = os.path.join(model_path_prefix, base_model_id)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"cellView": "form",
|
||||
"id": "R5PcRc0MGxbM"
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# @title Validate Dataset with Template\n",
|
||||
"\n",
|
||||
"# @markdown This section validates the train and eval datasets with the template before starting the fine tuning process.\n",
|
||||
"\n",
|
||||
"import transformers\n",
|
||||
"\n",
|
||||
"dataset_validation_util = importlib.import_module(\n",
|
||||
" \"vertex-ai-samples.community-content.vertex_model_garden.model_oss.notebook_util.dataset_validation_util\"\n",
|
||||
")\n",
|
||||
"\n",
|
||||
"if dataset_validation_util.is_gcs_path(pretrained_model_id):\n",
|
||||
" # Download tokenizer.\n",
|
||||
" ! mkdir tokenizer\n",
|
||||
" ! gsutil cp {pretrained_model_id}/tokenizer.json ./tokenizer\n",
|
||||
" ! gsutil cp {pretrained_model_id}/config.json ./tokenizer\n",
|
||||
" tokenizer_path = \"./tokenizer\"\n",
|
||||
" access_token = \"\"\n",
|
||||
"else:\n",
|
||||
" tokenizer_path = pretrained_model_id\n",
|
||||
" access_token = HF_TOKEN\n",
|
||||
"\n",
|
||||
"tokenizer = transformers.AutoTokenizer.from_pretrained(\n",
|
||||
" tokenizer_path,\n",
|
||||
" trust_remote_code=False,\n",
|
||||
" use_fast=True,\n",
|
||||
" token=access_token,\n",
|
||||
")\n",
|
||||
"\n",
|
||||
"# Validate the train dataset.\n",
|
||||
"dataset_validation_util.validate_dataset_with_template(\n",
|
||||
" dataset_name=train_dataset_name,\n",
|
||||
" split=train_split_name,\n",
|
||||
" input_column=instruct_column_in_dataset,\n",
|
||||
" template=template,\n",
|
||||
" use_multiprocessing=False,\n",
|
||||
" tokenizer=tokenizer,\n",
|
||||
")\n",
|
||||
"\n",
|
||||
"# Validate the eval dataset.\n",
|
||||
"dataset_validation_util.validate_dataset_with_template(\n",
|
||||
" dataset_name=eval_dataset_name,\n",
|
||||
" split=eval_split_name,\n",
|
||||
" input_column=instruct_column_in_dataset,\n",
|
||||
" template=template,\n",
|
||||
" use_multiprocessing=False,\n",
|
||||
" tokenizer=tokenizer,\n",
|
||||
")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"cellView": "form",
|
||||
"id": "ivVGS9dHXPOz"
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# @title Finetune\n",
|
||||
"# @markdown This section demonstrates how to finetune the Gemma model and merge the finetuned LoRA adapter with the base model on Vertex AI. It uses the Vertex AI SDK to create and run the custom training jobs.\n",
|
||||
"\n",
|
||||
"# @markdown The training job takes approximately between 10 to 20 mins to set-up. Once done, the training job is expected to take around 20 mins with the default configuration. To find the training time, throughput, and memory usage of your training job, you can go to the training logs and check the log line of the last training epoch.\n",
|
||||
"\n",
|
||||
"# @markdown **Note**:\n",
|
||||
"# @markdown 1. We recommend setting `finetuning_precision_mode` to `4bit` because it enables using fewer hardware resources for finetuning.\n",
|
||||
"# @markdown 1. If `max_steps > 0`, it takes precedence over `epochs`. One can set a small `max_steps` value to quickly check the pipeline.\n",
|
||||
"\n",
|
||||
"# Add labels for the finetuning job.\n",
|
||||
"labels = {\n",
|
||||
" \"mg-source\": \"notebook\",\n",
|
||||
" \"mg-notebook-name\": \"model_garden_gemma_finetuning_on_vertex.ipynb\".split(\".\")[0],\n",
|
||||
"}\n",
|
||||
"\n",
|
||||
"labels[\"mg-tune\"] = \"publishers-google-models-gemma\"\n",
|
||||
"versioned_model_id = base_model_id.lower().replace(\".\", \"-\")\n",
|
||||
"labels[\"versioned-mg-tune\"] = f\"{labels['mg-tune']}-{versioned_model_id}\"\n",
|
||||
"\n",
|
||||
"# @markdown Accelerator type to use for training.\n",
|
||||
"training_accelerator_type = \"NVIDIA_A100_80GB\" # @param [\"NVIDIA_A100_80GB\", \"NVIDIA_H100_80GB\"]\n",
|
||||
"\n",
|
||||
"# The pre-built training docker image.\n",
|
||||
"if training_accelerator_type == \"NVIDIA_A100_80GB\":\n",
|
||||
" repo = \"us-docker.pkg.dev/vertex-ai-restricted\"\n",
|
||||
" is_restricted_image = True\n",
|
||||
" is_dynamic_workload_scheduler = False\n",
|
||||
" dws_kwargs = {}\n",
|
||||
"else:\n",
|
||||
" repo = \"us-docker.pkg.dev/vertex-ai\"\n",
|
||||
" is_restricted_image = False\n",
|
||||
" is_dynamic_workload_scheduler = True\n",
|
||||
" dws_kwargs = {\n",
|
||||
" \"max_wait_duration\": 1800, # 30 minutes\n",
|
||||
" \"scheduling_strategy\": gca_custom_job_compat.Scheduling.Strategy.FLEX_START,\n",
|
||||
" }\n",
|
||||
"\n",
|
||||
"TRAIN_DOCKER_URI = (\n",
|
||||
" f\"{repo}/vertex-vision-model-garden-dockers/pytorch-peft-train:stable_20240909\"\n",
|
||||
")\n",
|
||||
"\n",
|
||||
"# Worker pool spec.\n",
|
||||
"if training_accelerator_type == \"NVIDIA_A100_80GB\":\n",
|
||||
" per_node_accelerator_count = 8\n",
|
||||
" training_machine_type = \"a2-ultragpu-8g\"\n",
|
||||
"elif training_accelerator_type == \"NVIDIA_H100_80GB\":\n",
|
||||
" per_node_accelerator_count = 8\n",
|
||||
" training_machine_type = \"a3-highgpu-8g\"\n",
|
||||
"else:\n",
|
||||
" raise ValueError(\n",
|
||||
" f\"Recommended machine settings not found for: {training_accelerator_type}. To use another accelerator type, edit this code block to pass in an appropriate `training_machine_type`, `training_accelerator_type`, and `per_node_accelerator_count` to the deploy_model_vllm function by clicking `Show Code` and then modifying the code.\"\n",
|
||||
" )\n",
|
||||
"\n",
|
||||
"# @markdown Batch size for finetuning.\n",
|
||||
"per_device_train_batch_size = 1 # @param{type:\"integer\"}\n",
|
||||
"# @markdown Number of updates steps to accumulate the gradients for, before performing a backward/update pass.\n",
|
||||
"gradient_accumulation_steps = 4 # @param{type:\"integer\"}\n",
|
||||
"# @markdown Maximum sequence length.\n",
|
||||
"max_seq_length = 4096 # @param{type:\"integer\"}\n",
|
||||
"# @markdown Setting a positive `max_steps` here will override `num_epochs`.\n",
|
||||
"max_steps = -1 # @param{type:\"integer\"}\n",
|
||||
"num_epochs = 1.0 # @param{type:\"number\"}\n",
|
||||
"# @markdown Precision mode for finetuning.\n",
|
||||
"finetuning_precision_mode = \"4bit\" # @param [\"4bit\", \"8bit\", \"float16\"]\n",
|
||||
"# @markdown Learning rate.\n",
|
||||
"learning_rate = 5e-5 # @param{type:\"number\"}\n",
|
||||
"# @markdown The scheduler type to use.\n",
|
||||
"lr_scheduler_type = \"cosine\" # @param{type:\"string\"}\n",
|
||||
"# @markdown LoRA parameters.\n",
|
||||
"lora_rank = 16 # @param{type:\"integer\"}\n",
|
||||
"lora_alpha = 32 # @param{type:\"integer\"}\n",
|
||||
"lora_dropout = 0.05 # @param{type:\"number\"}\n",
|
||||
"# Activates gradient checkpointing for the current model (may be referred to as activation checkpointing or checkpoint activations in other frameworks).\n",
|
||||
"enable_gradient_checkpointing = True\n",
|
||||
"# Attention implementation to use in the model.\n",
|
||||
"attn_implementation = \"eager\"\n",
|
||||
"# The optimizer for which to schedule the learning rate.\n",
|
||||
"optimizer = \"paged_adamw_32bit\"\n",
|
||||
"# Define the proportion of training to be dedicated to a linear warmup where learning rate gradually increases.\n",
|
||||
"warmup_ratio = \"0.01\"\n",
|
||||
"# The list or string of integrations to report the results and logs to.\n",
|
||||
"report_to = \"tensorboard\"\n",
|
||||
"# Number of updates steps before two checkpoint saves.\n",
|
||||
"save_steps = 10\n",
|
||||
"# Number of update steps between two logs.\n",
|
||||
"logging_steps = save_steps\n",
|
||||
"# Train precision of the model.\n",
|
||||
"train_precision = \"bfloat16\"\n",
|
||||
"\n",
|
||||
"replica_count = 1\n",
|
||||
"\n",
|
||||
"common_util.check_quota(\n",
|
||||
" project_id=PROJECT_ID,\n",
|
||||
" region=REGION,\n",
|
||||
" accelerator_type=training_accelerator_type,\n",
|
||||
" accelerator_count=per_node_accelerator_count * replica_count,\n",
|
||||
" is_for_training=True,\n",
|
||||
" is_restricted_image=is_restricted_image,\n",
|
||||
" is_dynamic_workload_scheduler=is_dynamic_workload_scheduler,\n",
|
||||
")\n",
|
||||
"\n",
|
||||
"job_name = common_util.get_job_name_with_datetime(\"gemma-lora-train\")\n",
|
||||
"\n",
|
||||
"base_output_dir = os.path.join(STAGING_BUCKET, job_name)\n",
|
||||
"# Create a GCS folder to store the LORA adapter.\n",
|
||||
"lora_output_dir = os.path.join(base_output_dir, \"adapter\")\n",
|
||||
"# Create a GCS folder to store the merged model with the base model and the\n",
|
||||
"# finetuned LORA adapter.\n",
|
||||
"merged_model_output_dir = os.path.join(base_output_dir, \"merged-model\")\n",
|
||||
"\n",
|
||||
"eval_args = [\n",
|
||||
" f\"--eval_dataset_path={eval_dataset_name}\",\n",
|
||||
" f\"--eval_column={instruct_column_in_dataset}\",\n",
|
||||
" f\"--eval_template={template}\",\n",
|
||||
" f\"--eval_split={eval_split_name}\",\n",
|
||||
" f\"--eval_steps={save_steps}\",\n",
|
||||
" \"--eval_tasks=builtin_eval\",\n",
|
||||
" \"--eval_metric_name=loss\",\n",
|
||||
"]\n",
|
||||
"\n",
|
||||
"train_job_args = [\n",
|
||||
" \"--config_file=vertex_vision_model_garden_peft/deepspeed_zero2_8gpu.yaml\",\n",
|
||||
" \"--task=instruct-lora\",\n",
|
||||
" \"--completion_only=True\",\n",
|
||||
" f\"--pretrained_model_id={pretrained_model_id}\",\n",
|
||||
" f\"--dataset_name={train_dataset_name}\",\n",
|
||||
" f\"--train_split_name={train_split_name}\",\n",
|
||||
" f\"--instruct_column_in_dataset={instruct_column_in_dataset}\",\n",
|
||||
" f\"--output_dir={lora_output_dir}\",\n",
|
||||
" f\"--merge_base_and_lora_output_dir={merged_model_output_dir}\",\n",
|
||||
" f\"--per_device_train_batch_size={per_device_train_batch_size}\",\n",
|
||||
" f\"--gradient_accumulation_steps={gradient_accumulation_steps}\",\n",
|
||||
" f\"--lora_rank={lora_rank}\",\n",
|
||||
" f\"--lora_alpha={lora_alpha}\",\n",
|
||||
" f\"--lora_dropout={lora_dropout}\",\n",
|
||||
" f\"--max_steps={max_steps}\",\n",
|
||||
" f\"--max_seq_length={max_seq_length}\",\n",
|
||||
" f\"--learning_rate={learning_rate}\",\n",
|
||||
" f\"--lr_scheduler_type={lr_scheduler_type}\",\n",
|
||||
" f\"--precision_mode={finetuning_precision_mode}\",\n",
|
||||
" f\"--train_precision={train_precision}\",\n",
|
||||
" f\"--enable_gradient_checkpointing={enable_gradient_checkpointing}\",\n",
|
||||
" f\"--num_epochs={num_epochs}\",\n",
|
||||
" f\"--attn_implementation={attn_implementation}\",\n",
|
||||
" f\"--optimizer={optimizer}\",\n",
|
||||
" f\"--warmup_ratio={warmup_ratio}\",\n",
|
||||
" f\"--report_to={report_to}\",\n",
|
||||
" f\"--logging_output_dir={base_output_dir}\",\n",
|
||||
" f\"--save_steps={save_steps}\",\n",
|
||||
" f\"--logging_steps={logging_steps}\",\n",
|
||||
" f\"--template={template}\",\n",
|
||||
" f\"--huggingface_access_token={HF_TOKEN}\",\n",
|
||||
"] + eval_args\n",
|
||||
"\n",
|
||||
"# Pass training arguments and launch job.\n",
|
||||
"train_job = aiplatform.CustomContainerTrainingJob(\n",
|
||||
" display_name=job_name,\n",
|
||||
" container_uri=TRAIN_DOCKER_URI,\n",
|
||||
" labels=labels,\n",
|
||||
")\n",
|
||||
"\n",
|
||||
"print(\"Running training job with args:\")\n",
|
||||
"print(\" \\\\\\n\".join(train_job_args))\n",
|
||||
"train_job.run(\n",
|
||||
" args=train_job_args,\n",
|
||||
" replica_count=replica_count,\n",
|
||||
" machine_type=training_machine_type,\n",
|
||||
" accelerator_type=training_accelerator_type,\n",
|
||||
" accelerator_count=per_node_accelerator_count,\n",
|
||||
" boot_disk_size_gb=500,\n",
|
||||
" service_account=SERVICE_ACCOUNT,\n",
|
||||
" base_output_dir=base_output_dir,\n",
|
||||
" sync=False, # Non-blocking call to run.\n",
|
||||
" **dws_kwargs,\n",
|
||||
")\n",
|
||||
"\n",
|
||||
"# Wait until resource has been created.\n",
|
||||
"train_job.wait_for_resource_creation()\n",
|
||||
"\n",
|
||||
"print(\"LoRA adapter will be saved in:\", lora_output_dir)\n",
|
||||
"print(\"Trained and merged models will be saved in:\", merged_model_output_dir)\n",
|
||||
"\n",
|
||||
"# @markdown Click \"Show Code\" to see more details."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"cellView": "form",
|
||||
"id": "FvJV3FwFGxbM"
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# @title Run TensorBoard\n",
|
||||
"# @markdown This section shows how to launch TensorBoard in a [Cloud Shell](https://cloud.google.com/shell/docs).\n",
|
||||
"# @markdown 1. Click the Cloud Shell icon() on the top right to open the Cloud Shell.\n",
|
||||
"# @markdown 2. Copy the `tensorboard` command shown below by running this cell.\n",
|
||||
"# @markdown 3. Paste and run the command in the Cloud Shell to launch TensorBoard.\n",
|
||||
"# @markdown 4. Once the command runs (You may have to click `Authorize` if prompted), click the link starting with `http://localhost`.\n",
|
||||
"\n",
|
||||
"# @markdown Note: You may need to wait around 10 minutes after the job starts in order for the TensorBoard logs to be written to the GCS bucket.\n",
|
||||
"print(f\"Command to copy: tensorboard --logdir {base_output_dir}/logs\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"cellView": "form",
|
||||
"id": "qmHW6m8xG_4U"
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# @title Deploy\n",
|
||||
"\n",
|
||||
"# @markdown This section uploads the model to Model Registry and deploys it on the Endpoint. It takes 15 minutes to 1 hour to finish.\n",
|
||||
"\n",
|
||||
"# The pre-built serving docker image for vLLM.\n",
|
||||
"VLLM_DOCKER_URI = \"us-docker.pkg.dev/vertex-ai/vertex-vision-model-garden-dockers/pytorch-vllm-serve:20240815_1634_RC00\"\n",
|
||||
"\n",
|
||||
"# @markdown Set `use_dedicated_endpoint` to False if you don't want to use [dedicated endpoint](https://cloud.google.com/vertex-ai/docs/general/deployment#create-dedicated-endpoint).\n",
|
||||
"use_dedicated_endpoint = True # @param {type:\"boolean\"}\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"def get_deploy_source() -> str:\n",
|
||||
" \"\"\"Gets deploy_source string based on running environment.\"\"\"\n",
|
||||
" vertex_product = os.environ.get(\"VERTEX_PRODUCT\", \"\")\n",
|
||||
" if vertex_product == \"COLAB_ENTERPRISE\":\n",
|
||||
" return \"notebook_colab_enterprise\"\n",
|
||||
" elif vertex_product == \"WORKBENCH_INSTANCE\":\n",
|
||||
" return \"notebook_workbench\"\n",
|
||||
" else:\n",
|
||||
" # Legacy workbench, legacy colab, or other custom environments.\n",
|
||||
" return \"notebook_environment_unspecified\"\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"def deploy_model_vllm(\n",
|
||||
" model_name: str,\n",
|
||||
" model_id: str,\n",
|
||||
" publisher: str,\n",
|
||||
" publisher_model_id: str,\n",
|
||||
" service_account: str,\n",
|
||||
" base_model_id: str = None,\n",
|
||||
" machine_type: str = \"g2-standard-8\",\n",
|
||||
" accelerator_type: str = \"NVIDIA_L4\",\n",
|
||||
" accelerator_count: int = 1,\n",
|
||||
" gpu_memory_utilization: float = 0.9,\n",
|
||||
" max_model_len: int = 4096,\n",
|
||||
" dtype: str = \"auto\",\n",
|
||||
" enable_trust_remote_code: bool = False,\n",
|
||||
" enforce_eager: bool = False,\n",
|
||||
" enable_lora: bool = False,\n",
|
||||
" enable_chunked_prefill: bool = False,\n",
|
||||
" enable_prefix_cache: bool = False,\n",
|
||||
" host_prefix_kv_cache_utilization_target: float = 0.0,\n",
|
||||
" max_loras: int = 1,\n",
|
||||
" max_cpu_loras: int = 8,\n",
|
||||
" use_dedicated_endpoint: bool = False,\n",
|
||||
" max_num_seqs: int = 256,\n",
|
||||
" model_type: str = None,\n",
|
||||
" enable_llama_tool_parser: bool = False,\n",
|
||||
" is_spot: bool = False,\n",
|
||||
") -> Tuple[aiplatform.Model, aiplatform.Endpoint]:\n",
|
||||
" \"\"\"Deploys trained models with vLLM into Vertex AI.\"\"\"\n",
|
||||
" endpoint = aiplatform.Endpoint.create(\n",
|
||||
" display_name=f\"{model_name}-endpoint\",\n",
|
||||
" dedicated_endpoint_enabled=use_dedicated_endpoint,\n",
|
||||
" )\n",
|
||||
"\n",
|
||||
" if not base_model_id:\n",
|
||||
" base_model_id = model_id\n",
|
||||
"\n",
|
||||
" # See https://docs.vllm.ai/en/latest/models/engine_args.html for a list of possible arguments with descriptions.\n",
|
||||
" vllm_args = [\n",
|
||||
" \"python\",\n",
|
||||
" \"-m\",\n",
|
||||
" \"vllm.entrypoints.api_server\",\n",
|
||||
" \"--host=0.0.0.0\",\n",
|
||||
" \"--port=8080\",\n",
|
||||
" f\"--model={model_id}\",\n",
|
||||
" f\"--tensor-parallel-size={accelerator_count}\",\n",
|
||||
" \"--swap-space=16\",\n",
|
||||
" f\"--max-model-len={max_model_len}\",\n",
|
||||
" f\"--dtype={dtype}\",\n",
|
||||
" f\"--max-loras={max_loras}\",\n",
|
||||
" f\"--max-cpu-loras={max_cpu_loras}\",\n",
|
||||
" f\"--max-num-seqs={max_num_seqs}\",\n",
|
||||
" \"--disable-log-stats\",\n",
|
||||
" ]\n",
|
||||
"\n",
|
||||
" if gpu_memory_utilization:\n",
|
||||
" vllm_args.append(f\"--gpu-memory-utilization={gpu_memory_utilization}\")\n",
|
||||
"\n",
|
||||
" if enable_trust_remote_code:\n",
|
||||
" vllm_args.append(\"--trust-remote-code\")\n",
|
||||
"\n",
|
||||
" if enforce_eager:\n",
|
||||
" vllm_args.append(\"--enforce-eager\")\n",
|
||||
"\n",
|
||||
" if enable_lora:\n",
|
||||
" vllm_args.append(\"--enable-lora\")\n",
|
||||
"\n",
|
||||
" if enable_chunked_prefill:\n",
|
||||
" vllm_args.append(\"--enable-chunked-prefill\")\n",
|
||||
"\n",
|
||||
" if enable_prefix_cache:\n",
|
||||
" vllm_args.append(\"--enable-prefix-caching\")\n",
|
||||
"\n",
|
||||
" if 0 < host_prefix_kv_cache_utilization_target < 1:\n",
|
||||
" vllm_args.append(\n",
|
||||
" f\"--host-prefix-kv-cache-utilization-target={host_prefix_kv_cache_utilization_target}\"\n",
|
||||
" )\n",
|
||||
"\n",
|
||||
" if model_type:\n",
|
||||
" vllm_args.append(f\"--model-type={model_type}\")\n",
|
||||
"\n",
|
||||
" if enable_llama_tool_parser:\n",
|
||||
" vllm_args.append(\"--enable-auto-tool-choice\")\n",
|
||||
" vllm_args.append(\"--tool-call-parser=vertex-llama-3\")\n",
|
||||
"\n",
|
||||
" env_vars = {\n",
|
||||
" \"MODEL_ID\": base_model_id,\n",
|
||||
" \"DEPLOY_SOURCE\": \"notebook\",\n",
|
||||
" }\n",
|
||||
"\n",
|
||||
" # HF_TOKEN is not a compulsory field and may not be defined.\n",
|
||||
" try:\n",
|
||||
" if HF_TOKEN:\n",
|
||||
" env_vars[\"HF_TOKEN\"] = HF_TOKEN\n",
|
||||
" except NameError:\n",
|
||||
" pass\n",
|
||||
"\n",
|
||||
" model = aiplatform.Model.upload(\n",
|
||||
" display_name=model_name,\n",
|
||||
" serving_container_image_uri=VLLM_DOCKER_URI,\n",
|
||||
" serving_container_args=vllm_args,\n",
|
||||
" serving_container_ports=[8080],\n",
|
||||
" serving_container_predict_route=\"/generate\",\n",
|
||||
" serving_container_health_route=\"/ping\",\n",
|
||||
" serving_container_environment_variables=env_vars,\n",
|
||||
" serving_container_shared_memory_size_mb=(16 * 1024), # 16 GB\n",
|
||||
" serving_container_deployment_timeout=7200,\n",
|
||||
" model_garden_source_model_name=(\n",
|
||||
" f\"publishers/{publisher}/models/{publisher_model_id}\"\n",
|
||||
" ),\n",
|
||||
" )\n",
|
||||
" print(\n",
|
||||
" f\"Deploying {model_name} on {machine_type} with {accelerator_count} {accelerator_type} GPU(s).\"\n",
|
||||
" )\n",
|
||||
" model.deploy(\n",
|
||||
" endpoint=endpoint,\n",
|
||||
" machine_type=machine_type,\n",
|
||||
" accelerator_type=accelerator_type,\n",
|
||||
" accelerator_count=accelerator_count,\n",
|
||||
" deploy_request_timeout=1800,\n",
|
||||
" service_account=service_account,\n",
|
||||
" spot=is_spot,\n",
|
||||
" system_labels={\n",
|
||||
" \"NOTEBOOK_NAME\": \"model_garden_gemma_finetuning_on_vertex.ipynb\",\n",
|
||||
" \"NOTEBOOK_ENVIRONMENT\": get_deploy_source(),\n",
|
||||
" },\n",
|
||||
" )\n",
|
||||
" print(\"endpoint_name:\", endpoint.name)\n",
|
||||
"\n",
|
||||
" return model, endpoint\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"if train_job.end_time is None:\n",
|
||||
" print(\"Waiting for the training job to finish...\")\n",
|
||||
" train_job.wait()\n",
|
||||
" print(\"The training job has finished.\")\n",
|
||||
"\n",
|
||||
"print(\"Deploying models in: \", merged_model_output_dir)\n",
|
||||
"\n",
|
||||
"# Find Vertex AI prediction supported accelerators and regions in [here](https://cloud.google.com/vertex-ai/docs/predictions/configure-compute).\n",
|
||||
"# Sets 1 L4 (24G) to deploy Gemma models.\n",
|
||||
"serve_machine_type = \"g2-standard-12\"\n",
|
||||
"serve_accelerator_type = \"NVIDIA_L4\"\n",
|
||||
"serve_accelerator_count = 1\n",
|
||||
"\n",
|
||||
"common_util.check_quota(\n",
|
||||
" project_id=PROJECT_ID,\n",
|
||||
" region=REGION,\n",
|
||||
" accelerator_type=serve_accelerator_type,\n",
|
||||
" accelerator_count=serve_accelerator_count,\n",
|
||||
" is_for_training=False,\n",
|
||||
")\n",
|
||||
"\n",
|
||||
"# Note that a larger max_model_len will require more GPU memory.\n",
|
||||
"max_model_len = 2048\n",
|
||||
"\n",
|
||||
"models[\"vllm_gpu\"], endpoints[\"vllm_gpu\"] = deploy_model_vllm(\n",
|
||||
" model_name=common_util.get_job_name_with_datetime(prefix=\"gemma-vllm-serve\"),\n",
|
||||
" base_model_id=f\"google/{base_model_id}\",\n",
|
||||
" publisher=\"google\",\n",
|
||||
" publisher_model_id=\"gemma\",\n",
|
||||
" model_id=merged_model_output_dir,\n",
|
||||
" service_account=SERVICE_ACCOUNT,\n",
|
||||
" machine_type=serve_machine_type,\n",
|
||||
" accelerator_type=serve_accelerator_type,\n",
|
||||
" accelerator_count=serve_accelerator_count,\n",
|
||||
" max_model_len=max_model_len,\n",
|
||||
" use_dedicated_endpoint=use_dedicated_endpoint,\n",
|
||||
")\n",
|
||||
"print(\"endpoint_name:\", endpoints[\"vllm_gpu\"].name)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"cellView": "form",
|
||||
"id": "2UYUNn60G_4U"
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# @title Predict\n",
|
||||
"\n",
|
||||
"# @markdown Once deployment succeeds, you can send requests to the endpoint with text prompts.\n",
|
||||
"\n",
|
||||
"# @markdown Here we use an example from the [timdettmers/openassistant-guanaco](https://huggingface.co/datasets/timdettmers/openassistant-guanaco) to show the finetuning outcome:\n",
|
||||
"\n",
|
||||
"# @markdown ```\n",
|
||||
"# @markdown ### Human: How would the Future of AI in 10 Years look?### Assistant: Predicting the future is always a challenging task, but here are some possible ways that AI could evolve over the next 10 years: Continued advancements in deep learning: Deep learning has been one of the main drivers of recent AI breakthroughs, and we can expect continued advancements in this area. This may include improvements to existing algorithms, as well as the development of new architectures that are better suited to specific types of data and tasks. Increased use of AI in healthcare: AI has the potential to revolutionize healthcare, by improving the accuracy of diagnoses, developing new treatments, and personalizing patient care. We can expect to see continued investment in this area, with more healthcare providers and researchers using AI to improve patient outcomes. Greater automation in the workplace: Automation is already transforming many industries, and AI is likely to play an increasingly important role in this process. We can expect to see more jobs being automated, as well as the development of new types of jobs that require a combination of human and machine skills. More natural and intuitive interactions with technology: As AI becomes more advanced, we can expect to see more natural and intuitive ways of interacting with technology. This may include voice and gesture recognition, as well as more sophisticated chatbots and virtual assistants. Increased focus on ethical considerations: As AI becomes more powerful, there will be a growing need to consider its ethical implications. This may include issues such as bias in AI algorithms, the impact of automation on employment, and the use of AI in surveillance and policing. Overall, the future of AI in 10 years is likely to be shaped by a combination of technological advancements, societal changes, and ethical considerations. While there are many exciting possibilities for AI in the future, it will be important to carefully consider its potential impact on society and to work towards ensuring that its benefits are shared fairly and equitably.\n",
|
||||
"# @markdown ```\n",
|
||||
"\n",
|
||||
"# @markdown Additionally, you can moderate the generated text with Vertex AI. See [Moderate text documentation](https://cloud.google.com/natural-language/docs/moderating-text) for more details.\n",
|
||||
"\n",
|
||||
"# Loads an existing endpoint instance using the endpoint name:\n",
|
||||
"# - Using `endpoint_name = endpoint.name` allows us to get the\n",
|
||||
"# endpoint name of the endpoint `endpoint` created in the cell\n",
|
||||
"# above.\n",
|
||||
"# - Alternatively, you can set `endpoint_name = \"1234567890123456789\"` to load\n",
|
||||
"# an existing endpoint with the ID 1234567890123456789.\n",
|
||||
"# You may uncomment the code below to load an existing endpoint.\n",
|
||||
"\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",
|
||||
"\n",
|
||||
"prompt = \"How would the Future of AI in 10 Years look?\" # @param {type: \"string\"}\n",
|
||||
"max_tokens = 128 # @param {type:\"integer\"}\n",
|
||||
"temperature = 1.0 # @param {type:\"number\"}\n",
|
||||
"top_p = 0.9 # @param {type:\"number\"}\n",
|
||||
"top_k = 1 # @param {type:\"integer\"}\n",
|
||||
"\n",
|
||||
"# Overrides max_tokens and top_k parameters during inferences.\n",
|
||||
"# If you encounter the issue like `ServiceUnavailable: 503 Took too long to respond when processing`,\n",
|
||||
"# you can reduce the max length, such as set max_tokens as 20.\n",
|
||||
"instances = [\n",
|
||||
" {\n",
|
||||
" \"prompt\": f\"### Human: {prompt}### Assistant: \",\n",
|
||||
" \"max_tokens\": max_tokens,\n",
|
||||
" \"temperature\": temperature,\n",
|
||||
" \"top_p\": top_p,\n",
|
||||
" \"top_k\": top_k,\n",
|
||||
" },\n",
|
||||
"]\n",
|
||||
"response = endpoints[\"vllm_gpu\"].predict(\n",
|
||||
" instances=instances, use_dedicated_endpoint=use_dedicated_endpoint\n",
|
||||
")\n",
|
||||
"\n",
|
||||
"for prediction in response.predictions:\n",
|
||||
" print(prediction)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "af21a3cff1e0"
|
||||
},
|
||||
"source": [
|
||||
"## Clean up resources"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"cellView": "form",
|
||||
"id": "911406c1561e"
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Delete the train job.\n",
|
||||
"train_job.delete()\n",
|
||||
"\n",
|
||||
"# Delete the conversion job.\n",
|
||||
"if conversion_job:\n",
|
||||
" conversion_job.delete()\n",
|
||||
"\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",
|
||||
"for endpoint in endpoints.values():\n",
|
||||
" endpoint.delete(force=True)\n",
|
||||
"\n",
|
||||
"# Delete models.\n",
|
||||
"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"
|
||||
]
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"colab": {
|
||||
"name": "model_garden_gemma_finetuning_on_vertex.ipynb",
|
||||
"toc_visible": true
|
||||
},
|
||||
"kernelspec": {
|
||||
"display_name": "Python 3",
|
||||
"name": "python3"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 0
|
||||
}
|
||||
-1614
File diff suppressed because it is too large
Load Diff
@@ -1,374 +1,373 @@
|
||||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"id": "7d9bbf86da5e"
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Copyright 2023 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": "99c1c3fc2ca5"
|
||||
},
|
||||
"source": [
|
||||
"# Vertex AI Model Garden - Falcon Evaluation\n",
|
||||
"\n",
|
||||
"<table><tbody><tr>\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%2Fcommunity%2Fmodel_garden%2Fmodel_garden_pytorch_falcon_evaluation.ipynb\">\n",
|
||||
" <img alt=\"Google Cloud Colab Enterprise logo\" src=\"https://lh3.googleusercontent.com/JmcxdQi-qOpctIvWKgPtrzZdJJK-J3sWE1RsfjZNwshCFgE_9fULcNpuXYTilIR2hjwN\" width=\"32px\"><br> Run in Colab Enterprise\n",
|
||||
" </a>\n",
|
||||
" </td>\n",
|
||||
" <td style=\"text-align: center\">\n",
|
||||
" <a href=\"https://github.com/GoogleCloudPlatform/vertex-ai-samples/blob/main/notebooks/community/model_garden/model_garden_pytorch_falcon_evaluation.ipynb\">\n",
|
||||
" <img alt=\"GitHub logo\" src=\"https://github.githubassets.com/assets/GitHub-Mark-ea2971cee799.png\" width=\"32px\"><br> View on GitHub\n",
|
||||
" </a>\n",
|
||||
" </td>\n",
|
||||
"</tr></tbody></table>"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "3de7470326a2"
|
||||
},
|
||||
"source": [
|
||||
"## Overview\n",
|
||||
"\n",
|
||||
"This notebook demonstrates evaluating a pre-trained or a PEFT-finetuned Falcon Instruct models in Vertex AI.\n",
|
||||
"\n",
|
||||
"### Objective\n",
|
||||
"\n",
|
||||
"- Evaluate a pre-trained or a PEFT-finetuned Falcon model on any of the benchmark datasets\n",
|
||||
"- Clean up the resources\n",
|
||||
"\n",
|
||||
"| Models |\n",
|
||||
"| :- |\n",
|
||||
"| [tiiuae/falcon-7b-instruct](https://huggingface.co/tiiuae/falcon-7b-instruct)\n",
|
||||
"| [tiiuae/falcon-40b-instruct](https://huggingface.co/tiiuae/falcon-40b-instruct)\n",
|
||||
"\n",
|
||||
"### Costs\n",
|
||||
"\n",
|
||||
"This tutorial uses billable components of Google Cloud:\n",
|
||||
"\n",
|
||||
"* 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."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "HsAZ1ozfRQt7"
|
||||
},
|
||||
"source": [
|
||||
"## Run the notebook"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"cellView": "form",
|
||||
"id": "855d6b96f291"
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# @title Setup Google Cloud project\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] [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",
|
||||
"# Import the necessary packages\n",
|
||||
"import os\n",
|
||||
"from datetime import datetime\n",
|
||||
"\n",
|
||||
"from google.cloud import aiplatform\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",
|
||||
"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",
|
||||
"# 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, please 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",
|
||||
"assert BUCKET_URI.startswith(\"gs://\"), \"BUCKET_URI must start with `gs://`.\"\n",
|
||||
"if BUCKET_URI is None or BUCKET_URI.strip() == \"\" or BUCKET_URI == \"gs://\":\n",
|
||||
" # Create a unique GCS bucket for this notebook, if not specified by the user\n",
|
||||
" BUCKET_URI = f\"gs://{PROJECT_ID}-tmp-{now}\"\n",
|
||||
" ! gsutil mb -l {REGION} {BUCKET_URI}\n",
|
||||
"else:\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",
|
||||
"\n",
|
||||
"print(f\"Using this GCS Bucket: {BUCKET_URI}\")\n",
|
||||
"\n",
|
||||
"STAGING_BUCKET = os.path.join(BUCKET_URI, \"temporal\")\n",
|
||||
"EXPERIMENT_BUCKET = os.path.join(BUCKET_URI, \"peft\")\n",
|
||||
"MODEL_BUCKET = os.path.join(EXPERIMENT_BUCKET, \"model\")\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",
|
||||
"# Gets the default BUCKET_URI and SERVICE_ACCOUNT if they were not specified by the user.\n",
|
||||
"SERVICE_ACCOUNT = None\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",
|
||||
"# Provision permissions to the SERVICE_ACCOUNT with the GCS bucket\n",
|
||||
"BUCKET_NAME = \"/\".join(BUCKET_URI.split(\"/\")[:3])\n",
|
||||
"! gsutil iam ch serviceAccount:{SERVICE_ACCOUNT}:roles/storage.admin $BUCKET_NAME\n",
|
||||
"\n",
|
||||
"! gcloud config set project $PROJECT_ID\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"aiplatform.init(project=PROJECT_ID, location=REGION, staging_bucket=STAGING_BUCKET)\n",
|
||||
"\n",
|
||||
"# The evaluation docker image.\n",
|
||||
"EVAL_DOCKER_URI = \"us-docker.pkg.dev/vertex-ai/vertex-vision-model-garden-dockers/pytorch-lm-evaluation-harness:20231011_0934_RC00\"\n",
|
||||
"\n",
|
||||
"# Define common functions\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"def get_job_name_with_datetime(prefix: str) -> str:\n",
|
||||
" \"\"\"Gets the job name with date time when triggering training or deployment\n",
|
||||
" jobs in Vertex AI.\n",
|
||||
" \"\"\"\n",
|
||||
" return prefix + datetime.now().strftime(\"_%Y%m%d_%H%M%S\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"cellView": "form",
|
||||
"id": "g0t0RBixIw0P"
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# @title Evaluate PEFT-finetuned Falcon Instruct models\n",
|
||||
"\n",
|
||||
"# @markdown This section demonstrates how to evaluate the Falcon Instruct models fintuned with PEFT LoRA using EleutherAI's [Language Model Evaluation Harness (lm-evaluation-harness)](https://github.com/EleutherAI/lm-evaluation-harness) with Vertex CustomJob. Please reference the peak GPU memory usage for serving and adjust the machine type, accelerator type and accelerator count accordingly.\n",
|
||||
"\n",
|
||||
"# @markdown This example uses the dataset [TruthfulQA](https://arxiv.org/abs/2109.07958). All supported tasks are listed in [this task table](https://github.com/EleutherAI/lm-evaluation-harness/blob/master/docs/task_table.md).\n",
|
||||
"# @markdown Set evaluation dataset.\n",
|
||||
"eval_dataset = \"truthfulqa_mc\" # @param {type:\"string\"}\n",
|
||||
"\n",
|
||||
"# Worker pool spec.\n",
|
||||
"# Find Vertex AI supported accelerators and regions in:\n",
|
||||
"# https://cloud.google.com/vertex-ai/docs/training/configure-compute\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"# Setup evaluation job.\n",
|
||||
"# @markdown Set the base model id.\n",
|
||||
"base_model_id = \"tiiuae/falcon-7b-instruct\" # @param [\"tiiuae/falcon-7b-instruct\", \"tiiuae/falcon-40b-instruct\"]\n",
|
||||
"job_name = get_job_name_with_datetime(prefix=\"falcon-instruct-peft-eval\")\n",
|
||||
"eval_output_dir = os.path.join(MODEL_BUCKET, job_name)\n",
|
||||
"eval_output_dir_gcsfuse = eval_output_dir.replace(\"gs://\", \"/gcs/\")\n",
|
||||
"\n",
|
||||
"# @markdown Sets V100 (16G) to evaluate `tiiuae/falcon-7b-instruct` or `tiiuae/falcon-40b-instruct`.\n",
|
||||
"# @markdown If A100 is not available, you may evaluate tiiuae/falcon-40b-instruct with\n",
|
||||
"# @markdown multiple V100s. Please keep in mind that the efficiency of evaluating with\n",
|
||||
"# @markdown multiple V100s is inferior to that of evaluating with A100s.\n",
|
||||
"\n",
|
||||
"# @markdown Set the accelerator type.\n",
|
||||
"accelerator_type = \"NVIDIA_TESLA_V100\" # @param[\"NVIDIA_TESLA_V100\", \"NVIDIA_L4\", \"NVIDIA_TESLA_A100\", \"NVIDIA_TESLA_A100_80G\"]\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"# @markdown To evaluate a PEFT-finetuned model, enter the PEFT output directory below.\n",
|
||||
"# @markdown Otherwise, leave it empty.\n",
|
||||
"# @markdown See the finetuning notebook for more details: https://github.com/GoogleCloudPlatform/vertex-ai-samples/blob/main/notebooks/community/model_garden/model_garden_pytorch_llama2_peft_finetuning.ipynb\n",
|
||||
"peft_output_dir = \"\" # @param {type:\"string\"}\n",
|
||||
"peft_output_dir_gcsfuse = peft_output_dir.replace(\"gs://\", \"/gcs/\")\n",
|
||||
"\n",
|
||||
"if \"7b\" in base_model_id:\n",
|
||||
" # For models containing '7b', set configurations based on the accelerator type provided.\n",
|
||||
" if accelerator_type == \"NVIDIA_TESLA_A100\":\n",
|
||||
" machine_type = \"a2-highgpu-1g\"\n",
|
||||
" accelerator_count = 1\n",
|
||||
" elif accelerator_type == \"NVIDIA_TESLA_V100\":\n",
|
||||
" machine_type = \"n1-standard-8\"\n",
|
||||
" accelerator_count = 1\n",
|
||||
" elif accelerator_type == \"NVIDIA_L4\":\n",
|
||||
" machine_type = \"g2-standard-8\"\n",
|
||||
" accelerator_count = 1\n",
|
||||
" else:\n",
|
||||
" print(f\"Unsupported accelerator type: {accelerator_type}\")\n",
|
||||
"elif \"40b\" in base_model_id:\n",
|
||||
" # For models containing '40b', set configurations based on the accelerator type provided.\n",
|
||||
" if accelerator_type == \"NVIDIA_TESLA_A100_80GB\":\n",
|
||||
" machine_type = \"a2-ultragpu-1g\"\n",
|
||||
" accelerator_count = 2\n",
|
||||
" elif accelerator_type == \"NVIDIA_L4\":\n",
|
||||
" machine_type = \"g2-standard-48\"\n",
|
||||
" accelerator_count = 4\n",
|
||||
" elif (\n",
|
||||
" accelerator_type == \"NVIDIA_TESLA_V100\"\n",
|
||||
" ): # Assuming V100 can be used as a fallback for 40b models\n",
|
||||
" machine_type = \"n1-standard-8\"\n",
|
||||
" accelerator_count = 8\n",
|
||||
" else:\n",
|
||||
" print(f\"Unsupported accelerator type: {accelerator_type}\")\n",
|
||||
"else:\n",
|
||||
" print(\"The base_model_id does not specify a recognized model version.\")\n",
|
||||
"\n",
|
||||
"replica_count = 1\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"# Prepare evaluation command that runs the evaluation harness.\n",
|
||||
"# Set `trust_remote_code = True` because evaluating the model requires\n",
|
||||
"# executing code from the model repository.\n",
|
||||
"# Set `use_accelerate = True` to enable evaluation across multiple GPUs.\n",
|
||||
"eval_command = [\n",
|
||||
" \"python\",\n",
|
||||
" \"main.py\",\n",
|
||||
" \"--model\",\n",
|
||||
" \"hf-causal-experimental\",\n",
|
||||
" \"--tasks\",\n",
|
||||
" f\"{eval_dataset}\",\n",
|
||||
" \"--output_path\",\n",
|
||||
" f\"{eval_output_dir_gcsfuse}\",\n",
|
||||
"]\n",
|
||||
"\n",
|
||||
"if peft_output_dir_gcsfuse:\n",
|
||||
" eval_command += [\n",
|
||||
" \"--model_args\",\n",
|
||||
" f\"pretrained={base_model_id},peft={peft_output_dir_gcsfuse},trust_remote_code=True,use_accelerate=True,device_map_option=auto\",\n",
|
||||
" ]\n",
|
||||
"else:\n",
|
||||
" eval_command += [\n",
|
||||
" \"--model_args\",\n",
|
||||
" f\"pretrained={base_model_id},trust_remote_code=True,use_accelerate=True,device_map_option=auto\",\n",
|
||||
" ]\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"# Pass evaluation arguments and launch job.\n",
|
||||
"worker_pool_specs = [\n",
|
||||
" {\n",
|
||||
" \"machine_spec\": {\n",
|
||||
" \"machine_type\": machine_type,\n",
|
||||
" \"accelerator_type\": accelerator_type,\n",
|
||||
" \"accelerator_count\": accelerator_count,\n",
|
||||
" },\n",
|
||||
" \"replica_count\": replica_count,\n",
|
||||
" \"disk_spec\": {\n",
|
||||
" \"boot_disk_size_gb\": 500,\n",
|
||||
" },\n",
|
||||
" \"container_spec\": {\n",
|
||||
" \"image_uri\": EVAL_DOCKER_URI,\n",
|
||||
" \"command\": eval_command,\n",
|
||||
" \"args\": [],\n",
|
||||
" },\n",
|
||||
" }\n",
|
||||
"]\n",
|
||||
"\n",
|
||||
"# Submit evaluation custom job.\n",
|
||||
"eval_job = aiplatform.CustomJob(\n",
|
||||
" display_name=job_name,\n",
|
||||
" worker_pool_specs=worker_pool_specs,\n",
|
||||
" base_output_dir=eval_output_dir,\n",
|
||||
")\n",
|
||||
"\n",
|
||||
"eval_job.run()\n",
|
||||
"\n",
|
||||
"print(\"Evaluation results were saved in:\", eval_output_dir)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"cellView": "form",
|
||||
"id": "1f15ed6d375a"
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# @title Fetch and print evaluation results\n",
|
||||
"import json\n",
|
||||
"\n",
|
||||
"from google.cloud import storage\n",
|
||||
"\n",
|
||||
"# Fetch evaluation results.\n",
|
||||
"storage_client = storage.Client()\n",
|
||||
"BUCKET_NAME = BUCKET_URI.split(\"gs://\")[1]\n",
|
||||
"bucket = storage_client.get_bucket(BUCKET_NAME)\n",
|
||||
"RESULT_FILE_PATH = eval_output_dir[len(BUCKET_URI) + 1 :]\n",
|
||||
"blob = bucket.blob(RESULT_FILE_PATH)\n",
|
||||
"raw_result = blob.download_as_string()\n",
|
||||
"\n",
|
||||
"# Print evaluation results.\n",
|
||||
"result = json.loads(raw_result)\n",
|
||||
"result_formatted = json.dumps(result, indent=2)\n",
|
||||
"print(f\"Evaluation result:\\n{result_formatted}\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"cellView": "form",
|
||||
"id": "911406c1561e"
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# @title Clean up resources\n",
|
||||
"# Delete evaluation job.\n",
|
||||
"\n",
|
||||
"delete_bucket = False # @param {type:\"boolean\"}\n",
|
||||
"if delete_bucket:\n",
|
||||
" ! gsutil -m rm -r $BUCKET_URI\n",
|
||||
"\n",
|
||||
"eval_job.delete()"
|
||||
]
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"colab": {
|
||||
"name": "model_garden_pytorch_falcon_evaluation.ipynb",
|
||||
"toc_visible": true
|
||||
},
|
||||
"kernelspec": {
|
||||
"display_name": "Python 3",
|
||||
"name": "python3"
|
||||
}
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"id": "7d9bbf86da5e"
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Copyright 2023 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."
|
||||
]
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 0
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "99c1c3fc2ca5"
|
||||
},
|
||||
"source": [
|
||||
"# Vertex AI Model Garden - Falcon Evaluation\n",
|
||||
"\n",
|
||||
"<table><tbody><tr>\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%2Fcommunity%2Fmodel_garden%2Fmodel_garden_pytorch_falcon_evaluation.ipynb\">\n",
|
||||
" <img alt=\"Google Cloud Colab Enterprise logo\" src=\"https://lh3.googleusercontent.com/JmcxdQi-qOpctIvWKgPtrzZdJJK-J3sWE1RsfjZNwshCFgE_9fULcNpuXYTilIR2hjwN\" width=\"32px\"><br> Run in Colab Enterprise\n",
|
||||
" </a>\n",
|
||||
" </td>\n",
|
||||
" <td style=\"text-align: center\">\n",
|
||||
" <a href=\"https://github.com/GoogleCloudPlatform/vertex-ai-samples/blob/main/notebooks/community/model_garden/model_garden_pytorch_falcon_evaluation.ipynb\">\n",
|
||||
" <img alt=\"GitHub logo\" src=\"https://github.githubassets.com/assets/GitHub-Mark-ea2971cee799.png\" width=\"32px\"><br> View on GitHub\n",
|
||||
" </a>\n",
|
||||
" </td>\n",
|
||||
"</tr></tbody></table>"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "3de7470326a2"
|
||||
},
|
||||
"source": [
|
||||
"## Overview\n",
|
||||
"\n",
|
||||
"This notebook demonstrates evaluating a pre-trained or a PEFT-finetuned Falcon Instruct models in Vertex AI.\n",
|
||||
"\n",
|
||||
"### Objective\n",
|
||||
"\n",
|
||||
"- Evaluate a pre-trained or a PEFT-finetuned Falcon model on any of the benchmark datasets\n",
|
||||
"- Clean up the resources\n",
|
||||
"\n",
|
||||
"| Models |\n",
|
||||
"| :- |\n",
|
||||
"| [tiiuae/falcon-7b-instruct](https://huggingface.co/tiiuae/falcon-7b-instruct)\n",
|
||||
"| [tiiuae/falcon-40b-instruct](https://huggingface.co/tiiuae/falcon-40b-instruct)\n",
|
||||
"\n",
|
||||
"### Costs\n",
|
||||
"\n",
|
||||
"This tutorial uses billable components of Google Cloud:\n",
|
||||
"\n",
|
||||
"* 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."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "HsAZ1ozfRQt7"
|
||||
},
|
||||
"source": [
|
||||
"## Run the notebook"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"cellView": "form",
|
||||
"id": "855d6b96f291"
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# @title Setup Google Cloud project\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] [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",
|
||||
"# Import the necessary packages\n",
|
||||
"import os\n",
|
||||
"from datetime import datetime\n",
|
||||
"\n",
|
||||
"from google.cloud import aiplatform\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",
|
||||
"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",
|
||||
"# 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, please 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",
|
||||
"assert BUCKET_URI.startswith(\"gs://\"), \"BUCKET_URI must start with `gs://`.\"\n",
|
||||
"if BUCKET_URI is None or BUCKET_URI.strip() == \"\" or BUCKET_URI == \"gs://\":\n",
|
||||
" # Create a unique GCS bucket for this notebook, if not specified by the user\n",
|
||||
" BUCKET_URI = f\"gs://{PROJECT_ID}-tmp-{now}\"\n",
|
||||
" ! gsutil mb -l {REGION} {BUCKET_URI}\n",
|
||||
"else:\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",
|
||||
"\n",
|
||||
"print(f\"Using this GCS Bucket: {BUCKET_URI}\")\n",
|
||||
"\n",
|
||||
"STAGING_BUCKET = os.path.join(BUCKET_URI, \"temporal\")\n",
|
||||
"EXPERIMENT_BUCKET = os.path.join(BUCKET_URI, \"peft\")\n",
|
||||
"MODEL_BUCKET = os.path.join(EXPERIMENT_BUCKET, \"model\")\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",
|
||||
"# Gets the default BUCKET_URI and SERVICE_ACCOUNT if they were not specified by the user.\n",
|
||||
"SERVICE_ACCOUNT = None\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",
|
||||
"# Provision permissions to the SERVICE_ACCOUNT with the GCS bucket\n",
|
||||
"BUCKET_NAME = \"/\".join(BUCKET_URI.split(\"/\")[:3])\n",
|
||||
"! gsutil iam ch serviceAccount:{SERVICE_ACCOUNT}:roles/storage.admin $BUCKET_NAME\n",
|
||||
"\n",
|
||||
"! gcloud config set project $PROJECT_ID\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"aiplatform.init(project=PROJECT_ID, location=REGION, staging_bucket=STAGING_BUCKET)\n",
|
||||
"\n",
|
||||
"# The evaluation docker image.\n",
|
||||
"EVAL_DOCKER_URI = \"us-docker.pkg.dev/vertex-ai/vertex-vision-model-garden-dockers/pytorch-lm-evaluation-harness:20231011_0934_RC00\"\n",
|
||||
"\n",
|
||||
"# Define common functions\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"def get_job_name_with_datetime(prefix: str) -> str:\n",
|
||||
" \"\"\"Gets the job name with date time when triggering training or deployment\n",
|
||||
" jobs in Vertex AI.\n",
|
||||
" \"\"\"\n",
|
||||
" return prefix + datetime.now().strftime(\"_%Y%m%d_%H%M%S\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"cellView": "form",
|
||||
"id": "g0t0RBixIw0P"
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# @title Evaluate PEFT-finetuned Falcon Instruct models\n",
|
||||
"\n",
|
||||
"# @markdown This section demonstrates how to evaluate the Falcon Instruct models fintuned with PEFT LoRA using EleutherAI's [Language Model Evaluation Harness (lm-evaluation-harness)](https://github.com/EleutherAI/lm-evaluation-harness) with Vertex CustomJob. Please reference the peak GPU memory usage for serving and adjust the machine type, accelerator type and accelerator count accordingly.\n",
|
||||
"\n",
|
||||
"# @markdown This example uses the dataset [TruthfulQA](https://arxiv.org/abs/2109.07958). All supported tasks are listed in [this task table](https://github.com/EleutherAI/lm-evaluation-harness/blob/master/docs/task_table.md).\n",
|
||||
"# @markdown Set evaluation dataset.\n",
|
||||
"eval_dataset = \"truthfulqa_mc\" # @param {type:\"string\"}\n",
|
||||
"\n",
|
||||
"# Worker pool spec.\n",
|
||||
"# Find Vertex AI supported accelerators and regions in:\n",
|
||||
"# https://cloud.google.com/vertex-ai/docs/training/configure-compute\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"# Setup evaluation job.\n",
|
||||
"# @markdown Set the base model id.\n",
|
||||
"base_model_id = \"tiiuae/falcon-7b-instruct\" # @param [\"tiiuae/falcon-7b-instruct\", \"tiiuae/falcon-40b-instruct\"]\n",
|
||||
"job_name = get_job_name_with_datetime(prefix=\"falcon-instruct-peft-eval\")\n",
|
||||
"eval_output_dir = os.path.join(MODEL_BUCKET, job_name)\n",
|
||||
"eval_output_dir_gcsfuse = eval_output_dir.replace(\"gs://\", \"/gcs/\")\n",
|
||||
"\n",
|
||||
"# @markdown Sets V100 (16G) to evaluate `tiiuae/falcon-7b-instruct` or `tiiuae/falcon-40b-instruct`.\n",
|
||||
"# @markdown If A100 is not available, you may evaluate tiiuae/falcon-40b-instruct with\n",
|
||||
"# @markdown multiple V100s. Please keep in mind that the efficiency of evaluating with\n",
|
||||
"# @markdown multiple V100s is inferior to that of evaluating with A100s.\n",
|
||||
"\n",
|
||||
"# @markdown Set the accelerator type.\n",
|
||||
"accelerator_type = \"NVIDIA_TESLA_V100\" # @param[\"NVIDIA_TESLA_V100\", \"NVIDIA_L4\", \"NVIDIA_TESLA_A100\", \"NVIDIA_TESLA_A100_80G\"]\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"# @markdown To evaluate a PEFT-finetuned model, enter the PEFT output directory below.\n",
|
||||
"# @markdown Otherwise, leave it empty.\n",
|
||||
"peft_output_dir = \"\" # @param {type:\"string\"}\n",
|
||||
"peft_output_dir_gcsfuse = peft_output_dir.replace(\"gs://\", \"/gcs/\")\n",
|
||||
"\n",
|
||||
"if \"7b\" in base_model_id:\n",
|
||||
" # For models containing '7b', set configurations based on the accelerator type provided.\n",
|
||||
" if accelerator_type == \"NVIDIA_TESLA_A100\":\n",
|
||||
" machine_type = \"a2-highgpu-1g\"\n",
|
||||
" accelerator_count = 1\n",
|
||||
" elif accelerator_type == \"NVIDIA_TESLA_V100\":\n",
|
||||
" machine_type = \"n1-standard-8\"\n",
|
||||
" accelerator_count = 1\n",
|
||||
" elif accelerator_type == \"NVIDIA_L4\":\n",
|
||||
" machine_type = \"g2-standard-8\"\n",
|
||||
" accelerator_count = 1\n",
|
||||
" else:\n",
|
||||
" print(f\"Unsupported accelerator type: {accelerator_type}\")\n",
|
||||
"elif \"40b\" in base_model_id:\n",
|
||||
" # For models containing '40b', set configurations based on the accelerator type provided.\n",
|
||||
" if accelerator_type == \"NVIDIA_TESLA_A100_80GB\":\n",
|
||||
" machine_type = \"a2-ultragpu-1g\"\n",
|
||||
" accelerator_count = 2\n",
|
||||
" elif accelerator_type == \"NVIDIA_L4\":\n",
|
||||
" machine_type = \"g2-standard-48\"\n",
|
||||
" accelerator_count = 4\n",
|
||||
" elif (\n",
|
||||
" accelerator_type == \"NVIDIA_TESLA_V100\"\n",
|
||||
" ): # Assuming V100 can be used as a fallback for 40b models\n",
|
||||
" machine_type = \"n1-standard-8\"\n",
|
||||
" accelerator_count = 8\n",
|
||||
" else:\n",
|
||||
" print(f\"Unsupported accelerator type: {accelerator_type}\")\n",
|
||||
"else:\n",
|
||||
" print(\"The base_model_id does not specify a recognized model version.\")\n",
|
||||
"\n",
|
||||
"replica_count = 1\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"# Prepare evaluation command that runs the evaluation harness.\n",
|
||||
"# Set `trust_remote_code = True` because evaluating the model requires\n",
|
||||
"# executing code from the model repository.\n",
|
||||
"# Set `use_accelerate = True` to enable evaluation across multiple GPUs.\n",
|
||||
"eval_command = [\n",
|
||||
" \"python\",\n",
|
||||
" \"main.py\",\n",
|
||||
" \"--model\",\n",
|
||||
" \"hf-causal-experimental\",\n",
|
||||
" \"--tasks\",\n",
|
||||
" f\"{eval_dataset}\",\n",
|
||||
" \"--output_path\",\n",
|
||||
" f\"{eval_output_dir_gcsfuse}\",\n",
|
||||
"]\n",
|
||||
"\n",
|
||||
"if peft_output_dir_gcsfuse:\n",
|
||||
" eval_command += [\n",
|
||||
" \"--model_args\",\n",
|
||||
" f\"pretrained={base_model_id},peft={peft_output_dir_gcsfuse},trust_remote_code=True,use_accelerate=True,device_map_option=auto\",\n",
|
||||
" ]\n",
|
||||
"else:\n",
|
||||
" eval_command += [\n",
|
||||
" \"--model_args\",\n",
|
||||
" f\"pretrained={base_model_id},trust_remote_code=True,use_accelerate=True,device_map_option=auto\",\n",
|
||||
" ]\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"# Pass evaluation arguments and launch job.\n",
|
||||
"worker_pool_specs = [\n",
|
||||
" {\n",
|
||||
" \"machine_spec\": {\n",
|
||||
" \"machine_type\": machine_type,\n",
|
||||
" \"accelerator_type\": accelerator_type,\n",
|
||||
" \"accelerator_count\": accelerator_count,\n",
|
||||
" },\n",
|
||||
" \"replica_count\": replica_count,\n",
|
||||
" \"disk_spec\": {\n",
|
||||
" \"boot_disk_size_gb\": 500,\n",
|
||||
" },\n",
|
||||
" \"container_spec\": {\n",
|
||||
" \"image_uri\": EVAL_DOCKER_URI,\n",
|
||||
" \"command\": eval_command,\n",
|
||||
" \"args\": [],\n",
|
||||
" },\n",
|
||||
" }\n",
|
||||
"]\n",
|
||||
"\n",
|
||||
"# Submit evaluation custom job.\n",
|
||||
"eval_job = aiplatform.CustomJob(\n",
|
||||
" display_name=job_name,\n",
|
||||
" worker_pool_specs=worker_pool_specs,\n",
|
||||
" base_output_dir=eval_output_dir,\n",
|
||||
")\n",
|
||||
"\n",
|
||||
"eval_job.run()\n",
|
||||
"\n",
|
||||
"print(\"Evaluation results were saved in:\", eval_output_dir)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"cellView": "form",
|
||||
"id": "1f15ed6d375a"
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# @title Fetch and print evaluation results\n",
|
||||
"import json\n",
|
||||
"\n",
|
||||
"from google.cloud import storage\n",
|
||||
"\n",
|
||||
"# Fetch evaluation results.\n",
|
||||
"storage_client = storage.Client()\n",
|
||||
"BUCKET_NAME = BUCKET_URI.split(\"gs://\")[1]\n",
|
||||
"bucket = storage_client.get_bucket(BUCKET_NAME)\n",
|
||||
"RESULT_FILE_PATH = eval_output_dir[len(BUCKET_URI) + 1 :]\n",
|
||||
"blob = bucket.blob(RESULT_FILE_PATH)\n",
|
||||
"raw_result = blob.download_as_string()\n",
|
||||
"\n",
|
||||
"# Print evaluation results.\n",
|
||||
"result = json.loads(raw_result)\n",
|
||||
"result_formatted = json.dumps(result, indent=2)\n",
|
||||
"print(f\"Evaluation result:\\n{result_formatted}\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"cellView": "form",
|
||||
"id": "911406c1561e"
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# @title Clean up resources\n",
|
||||
"# Delete evaluation job.\n",
|
||||
"\n",
|
||||
"delete_bucket = False # @param {type:\"boolean\"}\n",
|
||||
"if delete_bucket:\n",
|
||||
" ! gsutil -m rm -r $BUCKET_URI\n",
|
||||
"\n",
|
||||
"eval_job.delete()"
|
||||
]
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"colab": {
|
||||
"name": "model_garden_pytorch_falcon_evaluation.ipynb",
|
||||
"toc_visible": true
|
||||
},
|
||||
"kernelspec": {
|
||||
"display_name": "Python 3",
|
||||
"name": "python3"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 0
|
||||
}
|
||||
|
||||
-605
@@ -1,605 +0,0 @@
|
||||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"cellView": "form",
|
||||
"id": "7d9bbf86da5e"
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# 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",
|
||||
"# 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": "99c1c3fc2ca5"
|
||||
},
|
||||
"source": [
|
||||
"# Vertex AI Model Garden - Falcon Instruct (PEFT Finetuning)\n",
|
||||
"\n",
|
||||
"<table><tbody><tr>\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%2Fcommunity%2Fmodel_garden%2Fmodel_garden_pytorch_falcon_instruct_finetuning.ipynb\">\n",
|
||||
" <img alt=\"Google Cloud Colab Enterprise logo\" src=\"https://lh3.googleusercontent.com/JmcxdQi-qOpctIvWKgPtrzZdJJK-J3sWE1RsfjZNwshCFgE_9fULcNpuXYTilIR2hjwN\" width=\"32px\"><br> Run in Colab Enterprise\n",
|
||||
" </a>\n",
|
||||
" </td>\n",
|
||||
" <td style=\"text-align: center\">\n",
|
||||
" <a href=\"https://github.com/GoogleCloudPlatform/vertex-ai-samples/blob/main/notebooks/community/model_garden/model_garden_pytorch_falcon_instruct_finetuning.ipynb\">\n",
|
||||
" <img alt=\"GitHub logo\" src=\"https://github.githubassets.com/assets/GitHub-Mark-ea2971cee799.png\" width=\"32px\"><br> View on GitHub\n",
|
||||
" </a>\n",
|
||||
" </td>\n",
|
||||
"</tr></tbody></table>"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "3de7470326a2"
|
||||
},
|
||||
"source": [
|
||||
"## Overview\n",
|
||||
"\n",
|
||||
"This notebook demonstrates finetuning and deploying Falcon Instruct models with performance efficient finetuning libraries ([PEFT](https://github.com/huggingface/peft)) Falcon Instruct models in Vertex AI.\n",
|
||||
"\n",
|
||||
"### Objective\n",
|
||||
"\n",
|
||||
"- Finetune and deploy Falcon Instruct models with PEFT\n",
|
||||
"- Cleanup the resources used\n",
|
||||
"\n",
|
||||
"| Models | LoRA |\n",
|
||||
"| :- | :- |\n",
|
||||
"| [tiiuae/falcon-7b-instruct](https://huggingface.co/tiiuae/falcon-7b-instruct) | Y |\n",
|
||||
"| [tiiuae/falcon-40b-instruct](https://huggingface.co/tiiuae/falcon-40b-instruct) | Y |\n",
|
||||
"\n",
|
||||
"### Costs\n",
|
||||
"\n",
|
||||
"This tutorial uses billable components of Google Cloud:\n",
|
||||
"\n",
|
||||
"* 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."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "264c07757582"
|
||||
},
|
||||
"source": [
|
||||
"## Run the notebook"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"cellView": "form",
|
||||
"id": "855d6b96f291"
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# @title Setup Google Cloud project\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] [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",
|
||||
"# Import the necessary packages\n",
|
||||
"import os\n",
|
||||
"from datetime import datetime\n",
|
||||
"from typing import Tuple\n",
|
||||
"\n",
|
||||
"from google.cloud import aiplatform\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",
|
||||
"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",
|
||||
"# 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, please change the value yourself below.\n",
|
||||
"now = datetime.now().strftime(\"%Y%m%d%H%M%S\")\n",
|
||||
"BUCKET_URI = \"gs://\" # @param {type:\"string\"}\n",
|
||||
"if BUCKET_URI is None or BUCKET_URI.strip() == \"\" or BUCKET_URI == \"gs://\":\n",
|
||||
" # Create a unique GCS bucket for this notebook if not specified\n",
|
||||
" BUCKET_URI = f\"gs://{PROJECT_ID}-tmp-{now}\"\n",
|
||||
" ! gsutil mb -l {REGION} {BUCKET_URI}\n",
|
||||
"else:\n",
|
||||
" assert BUCKET_URI.startswith(\"gs://\"), \"BUCKET_URI must start with `gs://`.\"\n",
|
||||
" BUCKET_NAME = \"/\".join(BUCKET_URI.split(\"/\")[:3])\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",
|
||||
"EXPERIMENT_BUCKET = os.path.join(BUCKET_URI, \"peft\")\n",
|
||||
"DATA_BUCKET = os.path.join(EXPERIMENT_BUCKET, \"data\")\n",
|
||||
"MODEL_BUCKET = os.path.join(EXPERIMENT_BUCKET, \"model\")\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",
|
||||
"# Gets the default BUCKET_URI and SERVICE_ACCOUNT if they were not specified by the user.\n",
|
||||
"SERVICE_ACCOUNT = None\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",
|
||||
"# Create a unique GCS bucket for this notebook, if not specified by the user.\n",
|
||||
"if BUCKET_URI is None or BUCKET_URI.strip() == \"\" or BUCKET_URI == \"gs://\":\n",
|
||||
" BUCKET_URI = f\"gs://{PROJECT_ID}-tmp-{now}\"\n",
|
||||
" ! gsutil mb -l {REGION} {BUCKET_URI}\n",
|
||||
"else:\n",
|
||||
" shell_output = ! gsutil ls -Lb {BUCKET_URI} | 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",
|
||||
"\n",
|
||||
"print(f\"Using this GCS Bucket: {BUCKET_URI}\")\n",
|
||||
"\n",
|
||||
"# Provision permissions to the SERVICE_ACCOUNT with the GCS bucket\n",
|
||||
"BUCKET_NAME = \"/\".join(BUCKET_URI.split(\"/\")[:3])\n",
|
||||
"! gsutil iam ch serviceAccount:{SERVICE_ACCOUNT}:roles/storage.admin $BUCKET_NAME\n",
|
||||
"\n",
|
||||
"! gcloud config set project $PROJECT_ID\n",
|
||||
"\n",
|
||||
"# The pre-built training and serving docker images.\n",
|
||||
"TRAIN_DOCKER_URI = \"us-docker.pkg.dev/vertex-ai/vertex-vision-model-garden-dockers/pytorch-peft-train:20231222_0936_RC00\"\n",
|
||||
"PREDICTION_DOCKER_URI = \"us-docker.pkg.dev/vertex-ai/vertex-vision-model-garden-dockers/pytorch-peft-serve:20231129_0948_RC00\"\n",
|
||||
"VLLM_DOCKER_URI = \"us-docker.pkg.dev/vertex-ai/vertex-vision-model-garden-dockers/pytorch-vllm-serve:20240410_0916_RC00\"\n",
|
||||
"\n",
|
||||
"aiplatform.init(project=PROJECT_ID, location=REGION, staging_bucket=STAGING_BUCKET)\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"def create_name_with_datetime(prefix: str) -> str:\n",
|
||||
" \"\"\"Creates a name with date time when triggering training or deployment\n",
|
||||
" jobs in Vertex AI.\n",
|
||||
" \"\"\"\n",
|
||||
" return prefix + datetime.now().strftime(\"_%Y%m%d_%H%M%S\")\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"def deploy_model(\n",
|
||||
" model_name: str,\n",
|
||||
" base_model_id: str,\n",
|
||||
" finetuned_lora_model_path: str,\n",
|
||||
" service_account: str,\n",
|
||||
" task: str,\n",
|
||||
" machine_type: str = \"n1-standard-8\",\n",
|
||||
" accelerator_type: str = \"NVIDIA_TESLA_V100\",\n",
|
||||
" accelerator_count: int = 1,\n",
|
||||
") -> Tuple[aiplatform.Model, aiplatform.Endpoint]:\n",
|
||||
" \"\"\"Deploys trained models into Vertex AI.\"\"\"\n",
|
||||
" endpoint = aiplatform.Endpoint.create(display_name=f\"{model_name}-endpoint\")\n",
|
||||
" serving_env = {\n",
|
||||
" \"BASE_MODEL_ID\": base_model_id,\n",
|
||||
" \"TASK\": task,\n",
|
||||
" \"DEPLOY_SOURCE\": \"notebook\",\n",
|
||||
" }\n",
|
||||
" if finetuned_lora_model_path:\n",
|
||||
" serving_env[\"FINETUNED_LORA_MODEL_PATH\"] = finetuned_lora_model_path\n",
|
||||
" model = aiplatform.Model.upload(\n",
|
||||
" display_name=model_name,\n",
|
||||
" serving_container_image_uri=PREDICTION_DOCKER_URI,\n",
|
||||
" serving_container_ports=[7080],\n",
|
||||
" serving_container_predict_route=\"/predictions/peft_serving\",\n",
|
||||
" serving_container_health_route=\"/ping\",\n",
|
||||
" serving_container_environment_variables=serving_env,\n",
|
||||
" model_garden_source_model_name=\"publishers/tiiuae/models/falcon-instruct-7b-peft\"\n",
|
||||
" )\n",
|
||||
" model.deploy(\n",
|
||||
" endpoint=endpoint,\n",
|
||||
" machine_type=machine_type,\n",
|
||||
" accelerator_type=accelerator_type,\n",
|
||||
" accelerator_count=accelerator_count,\n",
|
||||
" deploy_request_timeout=1800,\n",
|
||||
" service_account=service_account,\n",
|
||||
" system_labels={\n",
|
||||
" \"NOTEBOOK_NAME\": \"model_garden_pytorch_falcon_instruct_finetuning.ipynb\"\n",
|
||||
" },\n",
|
||||
" )\n",
|
||||
" return model, endpoint\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"def deploy_model_vllm(\n",
|
||||
" model_name: str,\n",
|
||||
" model_id: str,\n",
|
||||
" service_account: str,\n",
|
||||
" machine_type: str = \"n1-standard-8\",\n",
|
||||
" accelerator_type: str = \"NVIDIA_TESLA_V100\",\n",
|
||||
" accelerator_count: int = 1,\n",
|
||||
" quantization_method: str = \"\",\n",
|
||||
") -> Tuple[aiplatform.Model, aiplatform.Endpoint]:\n",
|
||||
" \"\"\"Deploys trained models with vLLM into Vertex AI.\"\"\"\n",
|
||||
" endpoint = aiplatform.Endpoint.create(display_name=f\"{model_name}-endpoint\")\n",
|
||||
"\n",
|
||||
" vllm_args = [\n",
|
||||
" \"--host=0.0.0.0\",\n",
|
||||
" \"--port=7080\",\n",
|
||||
" f\"--model={model_id}\",\n",
|
||||
" f\"--tensor-parallel-size={accelerator_count}\",\n",
|
||||
" \"--swap-space=16\",\n",
|
||||
" \"--gpu-memory-utilization=0.9\",\n",
|
||||
" \"--disable-log-stats\",\n",
|
||||
" \"--dtype=float16\",\n",
|
||||
" \"--trust-remote-code\",\n",
|
||||
" ]\n",
|
||||
" if quantization_method:\n",
|
||||
" vllm_args.append(f\"--quantization={quantization_method}\")\n",
|
||||
"\n",
|
||||
" model = aiplatform.Model.upload(\n",
|
||||
" display_name=model_name,\n",
|
||||
" serving_container_image_uri=VLLM_DOCKER_URI,\n",
|
||||
" serving_container_command=[\"python\", \"-m\", \"vllm.entrypoints.api_server\"],\n",
|
||||
" serving_container_args=vllm_args,\n",
|
||||
" serving_container_ports=[7080],\n",
|
||||
" serving_container_predict_route=\"/generate\",\n",
|
||||
" serving_container_health_route=\"/ping\",\n",
|
||||
" model_garden_source_model_name=\"publishers/tiiuae/models/falcon-instruct-7b-peft\"\n",
|
||||
" )\n",
|
||||
"\n",
|
||||
" model.deploy(\n",
|
||||
" endpoint=endpoint,\n",
|
||||
" machine_type=machine_type,\n",
|
||||
" accelerator_type=accelerator_type,\n",
|
||||
" accelerator_count=accelerator_count,\n",
|
||||
" deploy_request_timeout=1800,\n",
|
||||
" service_account=service_account,\n",
|
||||
" )\n",
|
||||
" return model, endpoint"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"cellView": "form",
|
||||
"id": "65467b361315"
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# @title Finetune and deploy Falcon Instruct models with PEFT\n",
|
||||
"\n",
|
||||
"# @markdown This section demonstrates how to finetune and deploy Falcon Instruct models with PEFT LoRA.\n",
|
||||
"\n",
|
||||
"# @markdown The peak GPU memory usages are ~11G and ~34G for finetuning LoRA models for [tiiuae/falcon-7b-instruct](https://huggingface.co/tiiuae/falcon-7b-instruct), and [tiiuae/falcon-40b-instruct](https://huggingface.co/tiiuae/falcon-40b-instruct) separately with default training parameters and the example dataset. Falcon-7b-instruct can be finetuned on 1 P100/V100 and falcon-40b-instruct can be finetuned on 1 A100 (40G).\n",
|
||||
"\n",
|
||||
"# @markdown This example uses the dataset [timdettmers/openassistant-guanaco](https://huggingface.co/datasets/timdettmers/openassistant-guanaco). You can either use a [dataset from huggingface](https://huggingface.co/datasets) or a custom JSONL dataset in [Vertex text model dataset format](https://cloud.google.com/vertex-ai/docs/generative-ai/models/tune-text-models-supervised#dataset-format) stored in Cloud Storage. The `template` parameter is optional.\n",
|
||||
"\n",
|
||||
"# @markdown To use a custom dataset, you should supply a `gs://` URI to a JSONL file in [Vertex text model dataset format](https://cloud.google.com/vertex-ai/docs/generative-ai/models/tune-text-models-supervised#dataset-format) in the `dataset_name` below.\n",
|
||||
"\n",
|
||||
"# @markdown For example, here is one data point from the sample dataset `gs://cloud-samples-data/vertex-ai/model-evaluation/peft_train_sample.jsonl`:\n",
|
||||
"\n",
|
||||
"# @markdown ```json\n",
|
||||
"# @markdown {\"input_text\":\"TRANSCRIPT: \\nREASON FOR EVALUATION:,\\n\\n LABEL:\",\"output_text\":\"Chiropractic\"}\n",
|
||||
"# @markdown ```\n",
|
||||
"\n",
|
||||
"# @markdown To use this sample dataset that contains `input_text` and `output_text` fields, set `dataset_name` to `gs://cloud-samples-data/vertex-ai/model-evaluation/peft_train_sample.jsonl` and `template` to `vertex_sample`. For advanced usage with custom datatset fields, see [the template example](https://github.com/tloen/alpaca-lora/blob/main/templates/alpaca.json) and supply your own JSON template as `gs://` URIs.\n",
|
||||
"\n",
|
||||
"# @markdown Set the base model id.\n",
|
||||
"base_model_id = \"tiiuae/falcon-7b-instruct\" # @param [\"tiiuae/falcon-7b-instruct\", \"tiiuae/falcon-40b-instruct\"]\n",
|
||||
"\n",
|
||||
"# @markdown Set the accelerator type.\n",
|
||||
"accelerator_type = \"NVIDIA_TESLA_V100\" # @param[\"NVIDIA_TESLA_V100\", \"NVIDIA_L4\", \"NVIDIA_TESLA_A100\", \"NVIDIA_TESLA_A100_80G\"]\n",
|
||||
"\n",
|
||||
"# Huggingface dataset name or gs:// URI to a custom JSONL dataset.\n",
|
||||
"dataset_name = \"timdettmers/openassistant-guanaco\" # @param {type:\"string\"}\n",
|
||||
"# Optional. Template name or gs:// URI to a custom template.\n",
|
||||
"template = \"\" # @param {type:\"string\"}\n",
|
||||
"\n",
|
||||
"# @markdown Set the number of steps in the finetuning job.\n",
|
||||
"max_steps = 10 # @param {type:\"integer\"}\n",
|
||||
"\n",
|
||||
"# Worker pool spec.\n",
|
||||
"# Find Vertex AI supported accelerators and regions in:\n",
|
||||
"# https://cloud.google.com/vertex-ai/docs/training/configure-compute\n",
|
||||
"\n",
|
||||
"if \"7b\" in base_model_id:\n",
|
||||
" # Uses V100 (16G) to finetune falcon-7b-instruct.\n",
|
||||
" if accelerator_type == \"NVIDIA_TESLA_V100\":\n",
|
||||
" machine_type = \"n1-standard-8\"\n",
|
||||
" accelerator_count = 2\n",
|
||||
" # Uses L4 (24G) to finetune falcon-7b-instruct.\n",
|
||||
" elif accelerator_type == \"NVIDIA_L4\":\n",
|
||||
" machine_type = \"g2-standard-24\"\n",
|
||||
" accelerator_count = 2\n",
|
||||
" else:\n",
|
||||
" raise ValueError(\n",
|
||||
" f\"Recommended GPU setting not found for: {accelerator_type} and {base_model_name}.\"\n",
|
||||
" )\n",
|
||||
"elif \"40b\" in base_model_id:\n",
|
||||
" if accelerator_type == \"NVIDIA_TESLA_A100\":\n",
|
||||
" machine_type = \"a2-highgpu-1g\"\n",
|
||||
" accelerator_count = 1\n",
|
||||
" elif accelerator_type == \"NVIDIA_TESLA_V100\":\n",
|
||||
" machine_type = \"n1-standard-16\"\n",
|
||||
" accelerator_count = 4\n",
|
||||
" elif accelerator_type == \"NVIDIA_L4\":\n",
|
||||
" machine_type = \"g2-standard-24\"\n",
|
||||
" accelerator_count = 2\n",
|
||||
" else:\n",
|
||||
" raise ValueError(\n",
|
||||
" f\"Recommended GPU setting not found for: {accelerator_type} and {base_model_name}.\"\n",
|
||||
" )\n",
|
||||
"\n",
|
||||
"replica_count = 1\n",
|
||||
"\n",
|
||||
"# Add labels for the finetuning job.\n",
|
||||
"labels = {\n",
|
||||
" \"mg-source\": \"notebook\",\n",
|
||||
" \"mg-notebook-name\": (\n",
|
||||
" \"model_garden_pytorch_falcon_instruct_finetuning.ipynb\".split(\".\")[0]\n",
|
||||
" ),\n",
|
||||
"}\n",
|
||||
"\n",
|
||||
"labels[\"mg-tune\"] = \"publishers/tiiuae/models/falcon\"\n",
|
||||
"versioned_model_id = base_model_id.split(\"/\")[1].replace(\"_\", \"-\")\n",
|
||||
"labels[\"versioned-mg-tune\"] = f\"{labels['mg-tune']}-{versioned_model_id}\"\n",
|
||||
"\n",
|
||||
"# Setup training job.\n",
|
||||
"job_name = create_name_with_datetime(\"falcon-finetune-train\")\n",
|
||||
"train_job = aiplatform.CustomContainerTrainingJob(\n",
|
||||
" display_name=job_name,\n",
|
||||
" container_uri=TRAIN_DOCKER_URI,\n",
|
||||
" labels=labels,\n",
|
||||
")\n",
|
||||
"\n",
|
||||
"# Create a GCS folder to store the LORA adapter.\n",
|
||||
"finetune_dir = create_name_with_datetime(\"falcon-finetune\")\n",
|
||||
"finetune_output_dir = os.path.join(MODEL_BUCKET, finetune_dir)\n",
|
||||
"finetune_output_dir_gcsfuse = finetune_output_dir.replace(\"gs://\", \"/gcs/\")\n",
|
||||
"\n",
|
||||
"# Create a GCS folder to store the merged model with the base model and the\n",
|
||||
"# finetuned LORA adapter.\n",
|
||||
"merged_model_dir = create_name_with_datetime(\"falcon-merged-model\")\n",
|
||||
"merged_model_output_dir = os.path.join(MODEL_BUCKET, merged_model_dir)\n",
|
||||
"merged_model_output_dir_gcsfuse = merged_model_output_dir.replace(\"gs://\", \"/gcs/\")\n",
|
||||
"\n",
|
||||
"# Pass training arguments and launch job.\n",
|
||||
"train_job.run(\n",
|
||||
" args=[\n",
|
||||
" \"--task=instruct-lora\",\n",
|
||||
" f\"--pretrained_model_id={base_model_id}\",\n",
|
||||
" f\"--dataset_name={dataset_name}\",\n",
|
||||
" f\"--output_dir={finetune_output_dir_gcsfuse}\",\n",
|
||||
" f\"--merge_base_and_lora_output_dir={merged_model_output_dir_gcsfuse}\",\n",
|
||||
" \"--lora_rank=16\",\n",
|
||||
" \"--lora_alpha=32\",\n",
|
||||
" \"--lora_dropout=0.05\",\n",
|
||||
" \"--warmup_steps=10\",\n",
|
||||
" f\"--max_steps={max_steps}\",\n",
|
||||
" \"--learning_rate=2e-4\",\n",
|
||||
" f\"--template={template}\",\n",
|
||||
" \"--per_device_train_batch_size=1\",\n",
|
||||
" ],\n",
|
||||
" replica_count=replica_count,\n",
|
||||
" machine_type=machine_type,\n",
|
||||
" accelerator_type=accelerator_type,\n",
|
||||
" accelerator_count=accelerator_count,\n",
|
||||
" boot_disk_size_gb=500,\n",
|
||||
")\n",
|
||||
"\n",
|
||||
"print(\"The finetuned model can be found at: \", finetune_output_dir)\n",
|
||||
"print(\n",
|
||||
" \"The finetuned model merged with the base model can be found at: \",\n",
|
||||
" merged_model_output_dir,\n",
|
||||
")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"cellView": "form",
|
||||
"id": "bf55e38815dc"
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# @title Deploy to endpoint\n",
|
||||
"\n",
|
||||
"# @markdown This section uploads the model to Model Registry and deploys it on the Endpoint.\n",
|
||||
"\n",
|
||||
"# @markdown The model deployment step will take 15 minutes to 40 minutes to complete.\n",
|
||||
"\n",
|
||||
"# @markdown The peak GPU memory usages for [tiiuae/falcon-7b-instruct](https://huggingface.co/tiiuae/falcon-7b-instruct), and [tiiuae/falcon-40b-instruct](https://huggingface.co/tiiuae/falcon-40b-instruct) with LoRA weights are ~15.5G and ~84G separately with the default settings. Please adjust the machine type, accelerator type and accelerator count accordingly. We use V100 in deployments as an example. Note that V100 serving generally offers better throughput and latency performance than L4 serving, while L4 serving is generally more cost efficient than V100 serving. The serving efficiency of V100 and L4 GPUs is inferior to that of A100 GPUs, but V100 and L4 GPUs are nevertheless good serving solutions if you do not have A100 quota.\n",
|
||||
"\n",
|
||||
"# Find Vertex AI supported accelerators and regions in:\n",
|
||||
"# https://cloud.google.com/vertex-ai/docs/predictions/configure-compute\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"# @markdown Set the base model id.\n",
|
||||
"base_model_id = \"tiiuae/falcon-7b-instruct\" # @param [\"tiiuae/falcon-7b-instruct\", \"tiiuae/falcon-40b-instruct\"]\n",
|
||||
"\n",
|
||||
"# @markdown Set the accelerator type.\n",
|
||||
"accelerator_type = \"NVIDIA_TESLA_V100\" # @param[\"NVIDIA_TESLA_V100\", \"NVIDIA_L4\", \"NVIDIA_TESLA_A100\", \"NVIDIA_TESLA_A100_80G\"]\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"if \"7b\" in base_model_id:\n",
|
||||
" if accelerator_type == \"NVIDIA_TESLA_A100\":\n",
|
||||
" machine_type = \"a2-highgpu-1g\"\n",
|
||||
" accelerator_count = 1\n",
|
||||
" if accelerator_type == \"NVIDIA_TESLA_V100\":\n",
|
||||
" machine_type = \"n1-standard-8\"\n",
|
||||
" accelerator_count = 1\n",
|
||||
" elif accelerator_type == \"NVIDIA_L4\":\n",
|
||||
" machine_type = \"g2-standard-8\"\n",
|
||||
" accelerator_count = 1\n",
|
||||
" else:\n",
|
||||
" raise ValueError(\n",
|
||||
" f\"Recommended GPU setting not found for: {accelerator_type} and {base_model_id}.\"\n",
|
||||
" )\n",
|
||||
"elif \"40b\" in base_model_id:\n",
|
||||
" if accelerator_type == \"NVIDIA_TESLA_A100_80GB\":\n",
|
||||
" machine_type = \"a2-ultragpu-1g\"\n",
|
||||
" accelerator_count = 2\n",
|
||||
" elif accelerator_type == \"NVIDIA_TESLA_A100\":\n",
|
||||
" machine_type = \"a2-highgpu-1g\"\n",
|
||||
" accelerator_count = 4\n",
|
||||
" elif accelerator_type == \"NVIDIA_TESLA_V100\":\n",
|
||||
" machine_type = \"n1-standard-8\"\n",
|
||||
" accelerator_count = 8\n",
|
||||
" elif accelerator_type == \"NVIDIA_L4\":\n",
|
||||
" machine_type = \"g2-standard-48\"\n",
|
||||
" accelerator_count = 4\n",
|
||||
" else:\n",
|
||||
" raise ValueError(\n",
|
||||
" f\"Recommended GPU setting not found for: {accelerator_type} and {base_model_id}.\"\n",
|
||||
" )\n",
|
||||
"\n",
|
||||
"if base_model_id == \"tiiuae/falcon-7b-instruct\":\n",
|
||||
" model, endpoint = deploy_model(\n",
|
||||
" model_name=create_name_with_datetime(prefix=\"falcon-instruct-serve\"),\n",
|
||||
" base_model_id=base_model_id,\n",
|
||||
" finetuned_lora_model_path=os.path.join(\n",
|
||||
" finetune_output_dir, f\"checkpoint-{max_steps}\"\n",
|
||||
" ), # This will avoid override finetuning models.\n",
|
||||
" service_account=SERVICE_ACCOUNT,\n",
|
||||
" task=\"instruct-lora\",\n",
|
||||
" machine_type=machine_type,\n",
|
||||
" accelerator_type=accelerator_type,\n",
|
||||
" accelerator_count=accelerator_count,\n",
|
||||
" )\n",
|
||||
"else:\n",
|
||||
" model, endpoint = deploy_model_vllm(\n",
|
||||
" model_name=create_name_with_datetime(prefix=\"falcon-instruct-vllm\"),\n",
|
||||
" model_id=merged_model_output_dir,\n",
|
||||
" service_account=SERVICE_ACCOUNT,\n",
|
||||
" machine_type=machine_type,\n",
|
||||
" accelerator_type=accelerator_type,\n",
|
||||
" accelerator_count=accelerator_count,\n",
|
||||
" )\n",
|
||||
"\n",
|
||||
"print(\"endpoint_name:\", endpoint.name)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"id": "4ab04da3ec9a"
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# @markdown NOTE: After the deployment succeeds, the base model weights will be downloaded on the fly from the original location and LoRA model weights will be downloaded from the GCS bucket used in training above. Thus, an additional 10-30 minutes of waiting time is needed **after** the above model deployment step succeeds and before you can run the next step below. Otherwise you might see a `ServiceUnavailable: 503 502:Bad Gateway` error when you send requests to the endpoint.\n",
|
||||
"\n",
|
||||
"# @markdown Once deployment succeeds, you can send requests to the endpoint with text prompts.\n",
|
||||
"\n",
|
||||
"# @markdown Example:\n",
|
||||
"\n",
|
||||
"# @markdown ```\n",
|
||||
"# @markdown Human: What is a car?\n",
|
||||
"# @markdown Assistant: A car, or a motor car, is a road-connected human-transportation system used to move people or goods from one place to another. The term also encompasses a wide range of vehicles, including motorboats, trains, and aircrafts. Cars typically have four wheels, a cabin for passengers, and an engine or motor. They have been around since the early 19th century and are now one of the most popular forms of transportation, used for daily commuting, shopping, and other purposes.\n",
|
||||
"# @markdown ```\n",
|
||||
"\n",
|
||||
"# @markdown Additionally, you can moderate the generated text with Vertex AI. See [Moderate text documentation](https://cloud.google.com/natural-language/docs/moderating-text) for more details.\n",
|
||||
"\n",
|
||||
"# Loads an existing endpoint instance using the endpoint name:\n",
|
||||
"# - Using `endpoint_name = endpoint.name` allows us to get the\n",
|
||||
"# endpoint name of the endpoint `endpoint` created in the cell\n",
|
||||
"# above.\n",
|
||||
"# - Alternatively, you can set `endpoint_name = \"1234567890123456789\"` to load\n",
|
||||
"# an existing endpoint with the ID 1234567890123456789.\n",
|
||||
"# You may uncomment the code below to load an existing endpoint.\n",
|
||||
"\n",
|
||||
"# endpoint_name = endpoint.name\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",
|
||||
"\n",
|
||||
"prompt = \"What is a car?\" # @param {type:\"string\"}\n",
|
||||
"max_tokens = 50 # @param {type:\"integer\"}\n",
|
||||
"temperature = 1.0 # @param {type:\"number\"}\n",
|
||||
"top_p = 1.0 # @param {type:\"number\"}\n",
|
||||
"top_k = 10 # @param {type:\"number\"}\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"instances = [\n",
|
||||
" {\n",
|
||||
" \"prompt\": prompt,\n",
|
||||
" \"max_tokens\": max_tokens,\n",
|
||||
" \"temperature\": temperature,\n",
|
||||
" \"top_p\": top_p,\n",
|
||||
" \"top_k\": top_k,\n",
|
||||
" },\n",
|
||||
"]\n",
|
||||
"response = endpoint.predict(instances=instances)\n",
|
||||
"\n",
|
||||
"for prediction in response.predictions:\n",
|
||||
" print(prediction)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"cellView": "form",
|
||||
"id": "911406c1561e"
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# @markdown Delete the experiment models and endpoints to recycle the resources\n",
|
||||
"# @markdown and avoid unnecessary continouous charges that may incur.\n",
|
||||
"\n",
|
||||
"# @title Clean up resources\n",
|
||||
"\n",
|
||||
"delete_bucket = False # @param {type:\"boolean\"}\n",
|
||||
"if delete_bucket:\n",
|
||||
" ! gsutil -m rm -r $BUCKET_URI\n",
|
||||
"\n",
|
||||
"# Delete custom train, quantization, and evaluation jobs.\n",
|
||||
"train_job.delete()\n",
|
||||
"\n",
|
||||
"# Undeploy models and delete endpoints.\n",
|
||||
"endpoint.delete(force=True)\n",
|
||||
"\n",
|
||||
"# Delete models.\n",
|
||||
"model.delete()"
|
||||
]
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"colab": {
|
||||
"name": "model_garden_pytorch_falcon_instruct_finetuning.ipynb",
|
||||
"toc_visible": true
|
||||
},
|
||||
"kernelspec": {
|
||||
"display_name": "Python 3",
|
||||
"name": "python3"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 0
|
||||
}
|
||||
@@ -1,966 +0,0 @@
|
||||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"cellView": "form",
|
||||
"id": "7d9bbf86da5e"
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Copyright 2026 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": "99c1c3fc2ca5"
|
||||
},
|
||||
"source": [
|
||||
"# Vertex AI Model Garden - Gemma Finetuning (PEFT + vLLM)\n",
|
||||
"\n",
|
||||
"<table><tbody><tr>\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%2Fcommunity%2Fmodel_garden%2Fmodel_garden_pytorch_gemma_peft_finetuning_hf.ipynb\">\n",
|
||||
" <img alt=\"Google Cloud Colab Enterprise logo\" src=\"https://lh3.googleusercontent.com/JmcxdQi-qOpctIvWKgPtrzZdJJK-J3sWE1RsfjZNwshCFgE_9fULcNpuXYTilIR2hjwN\" width=\"32px\"><br> Run in Colab Enterprise\n",
|
||||
" </a>\n",
|
||||
" </td>\n",
|
||||
" <td style=\"text-align: center\">\n",
|
||||
" <a href=\"https://github.com/GoogleCloudPlatform/vertex-ai-samples/blob/main/notebooks/community/model_garden/model_garden_pytorch_gemma_peft_finetuning_hf.ipynb\">\n",
|
||||
" <img alt=\"GitHub logo\" src=\"https://github.githubassets.com/assets/GitHub-Mark-ea2971cee799.png\" width=\"32px\"><br> View on GitHub\n",
|
||||
" </a>\n",
|
||||
" </td>\n",
|
||||
"</tr></tbody></table>"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "3de7470326a2"
|
||||
},
|
||||
"source": [
|
||||
"## Overview\n",
|
||||
"\n",
|
||||
"This notebook demonstrates finetuning and deploying Gemma models with [Vertex AI Custom Training Job](https://cloud.google.com/vertex-ai/docs/training/create-custom-job). Using Vertex AI Pipelines is the quickest way to start finetuning Gemma models, while using a Vertex AI Custom Training Job allows for a higher level of customization and control over the finetuning job. All of the examples in this notebook use parameter efficient finetuning methods [PEFT](https://github.com/huggingface/peft) to reduce training and storage costs.\n",
|
||||
"\n",
|
||||
"This notebook deploys the model with the [vLLM](https://github.com/vllm-project/vllm) docker and uses [Text moderation APIs](https://cloud.google.com/natural-language/docs/moderating-text) to analyze predictions against a list of safety attributes.\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"### Objective\n",
|
||||
"\n",
|
||||
"- Finetune and deploy Gemma models with a Vertex AI Custom Training Job.\n",
|
||||
"- Send prediction requests to your finetuned Gemma model.\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"### Costs\n",
|
||||
"\n",
|
||||
"This tutorial uses billable components of Google Cloud:\n",
|
||||
"\n",
|
||||
"* Vertex AI\n",
|
||||
"* Cloud Storage\n",
|
||||
"* Cloud NL APIs\n",
|
||||
"\n",
|
||||
"Learn about [Vertex AI pricing](https://cloud.google.com/vertex-ai/pricing), [Cloud Storage pricing](https://cloud.google.com/storage/pricing), [Cloud NL API pricing](https://cloud.google.com/natural-language/pricing) and use the [Pricing Calculator](https://cloud.google.com/products/calculator/) to generate a cost estimate based on your projected usage."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "264c07757582"
|
||||
},
|
||||
"source": [
|
||||
"## Before you begin"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"cellView": "form",
|
||||
"id": "wQf_xXTXzjaS"
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# @title Install Python Packages for Finetuning\n",
|
||||
"\n",
|
||||
"# @markdown 1. Install google-cloud-aiplatform package and restart the session if instructed.\n",
|
||||
"! pip install --upgrade --quiet google-cloud-aiplatform==1.130.0\n",
|
||||
"\n",
|
||||
"# @markdown 2. Install packages to validate dataset with template.\n",
|
||||
"! pip install --upgrade --quiet accelerate==0.31.0\n",
|
||||
"! pip install --upgrade --quiet transformers==4.43.1\n",
|
||||
"! pip install --upgrade --quiet datasets==2.19.2\n",
|
||||
"\n",
|
||||
"# Load local tensorboard.\n",
|
||||
"%load_ext tensorboard"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"cellView": "form",
|
||||
"id": "B9p8QmmcD_OP"
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# @title Setup Google Cloud project\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. For finetuning, **[click here](https://console.cloud.google.com/iam-admin/quotas?location=us-central1&metric=aiplatform.googleapis.com%2Frestricted_image_training_nvidia_a100_80gb_gpus)** to check if your project already has the required 8 Nvidia A100 80 GB GPUs in the us-central1 region. If yes, then run this notebook in the us-central1 region. If you do not have 8 Nvidia A100 80 GPUs or have more GPU requirements than this, then schedule your job with Nvidia H100 GPUs via Dynamic Workload Scheduler using [these instructions](https://cloud.google.com/vertex-ai/docs/training/schedule-jobs-dws). For Dynamic Workload Scheduler, check the [us-central1](https://console.cloud.google.com/iam-admin/quotas?location=us-central1&metric=aiplatform.googleapis.com%2Fcustom_model_training_preemptible_nvidia_h100_gpus) or [europe-west4](https://console.cloud.google.com/iam-admin/quotas?location=europe-west4&metric=aiplatform.googleapis.com%2Fcustom_model_training_preemptible_nvidia_h100_gpus) quota for Nvidia H100 GPUs. If you do not have enough GPUs, then you can follow [these instructions](https://cloud.google.com/docs/quotas/view-manage#viewing_your_quota_console) to request quota.\n",
|
||||
"\n",
|
||||
"# @markdown 3. For serving, **[click here](https://console.cloud.google.com/iam-admin/quotas?location=us-central1&metric=aiplatform.googleapis.com%2Fcustom_model_serving_nvidia_l4_gpus)** to check if your project already has the required 1 L4 GPU in the us-central1 region. If yes, then run this notebook in the us-central1 region. If you need more L4 GPUs for your project, then you can follow [these instructions](https://cloud.google.com/docs/quotas/view-manage#viewing_your_quota_console) to request more. Alternatively, 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).\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",
|
||||
"# @markdown 4. **[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",
|
||||
"BUCKET_URI = \"gs://\" # @param {type:\"string\"}\n",
|
||||
"\n",
|
||||
"# @markdown 5. **[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",
|
||||
"# Import the necessary packages\n",
|
||||
"! rm -rf vertex-ai-samples && git clone https://github.com/GoogleCloudPlatform/vertex-ai-samples.git\n",
|
||||
"! cd vertex-ai-samples && git reset --hard 0727e19520cf7957bceb701c248221bd3dbe4f1f\n",
|
||||
"\n",
|
||||
"import datetime\n",
|
||||
"import importlib\n",
|
||||
"import os\n",
|
||||
"import uuid\n",
|
||||
"from typing import Tuple\n",
|
||||
"\n",
|
||||
"from google.cloud import aiplatform, language\n",
|
||||
"from google.cloud.aiplatform.compat.types import \\\n",
|
||||
" custom_job as gca_custom_job_compat\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",
|
||||
"models, endpoints = {}, {}\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",
|
||||
" if not os.environ.get(\"GOOGLE_CLOUD_REGION\"):\n",
|
||||
" raise ValueError(\n",
|
||||
" \"REGION must be set. See\"\n",
|
||||
" \" https://cloud.google.com/vertex-ai/docs/general/locations for\"\n",
|
||||
" \" available cloud locations.\"\n",
|
||||
" )\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",
|
||||
"# 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.datetime.now().strftime(\"%Y%m%d%H%M%S\")\n",
|
||||
"BUCKET_NAME = \"/\".join(BUCKET_URI.split(\"/\")[:3])\n",
|
||||
"\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, \"gemma\")\n",
|
||||
"\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",
|
||||
"# 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",
|
||||
"# 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",
|
||||
"! gcloud projects add-iam-policy-binding --no-user-output-enabled {PROJECT_ID} --member=serviceAccount:{SERVICE_ACCOUNT} --role=\"roles/storage.admin\"\n",
|
||||
"! gcloud projects add-iam-policy-binding --no-user-output-enabled {PROJECT_ID} --member=serviceAccount:{SERVICE_ACCOUNT} --role=\"roles/aiplatform.user\"\n",
|
||||
"\n",
|
||||
"# @markdown ## Access Gemma Models\n",
|
||||
"\n",
|
||||
"# @markdown Provide a Hugging Face User Access Token (read) to access the Gemma models. You can follow the [Hugging Face documentation](https://huggingface.co/docs/hub/en/security-tokens) to create a **read** access token and put it in the `HF_TOKEN` field below.\n",
|
||||
"HF_TOKEN = \"\" # @param {type:\"string\", isTemplate:true}\n",
|
||||
"assert HF_TOKEN, \"Provide a read HF_TOKEN to load models from Hugging Face.\"\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"def moderate_text(text: str) -> language.ModerateTextResponse:\n",
|
||||
" \"\"\"Calls Vertex AI APIs to analyze text moderations.\"\"\"\n",
|
||||
" client = language.LanguageServiceClient()\n",
|
||||
" document = language.Document(\n",
|
||||
" content=text,\n",
|
||||
" type_=language.Document.Type.PLAIN_TEXT,\n",
|
||||
" )\n",
|
||||
" return client.moderate_text(document=document)\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"def show_text_moderation(text: str, response: language.ModerateTextResponse) -> None:\n",
|
||||
" \"\"\"Shows text moderation results.\"\"\"\n",
|
||||
" import pandas as pd\n",
|
||||
"\n",
|
||||
" def confidence(category: language.ClassificationCategory) -> float:\n",
|
||||
" return category.confidence\n",
|
||||
"\n",
|
||||
" columns = [\"category\", \"confidence\"]\n",
|
||||
" categories = sorted(response.moderation_categories, key=confidence, reverse=True)\n",
|
||||
" data = ((category.name, category.confidence) for category in categories)\n",
|
||||
" df = pd.DataFrame(columns=columns, data=data)\n",
|
||||
"\n",
|
||||
" print(f\"Text analyzed:\\n{text}\")\n",
|
||||
" print(df.to_markdown(index=False, tablefmt=\"presto\", floatfmt=\".0%\"))"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "Pq4iF00YG_4T"
|
||||
},
|
||||
"source": [
|
||||
"## Finetune with Vertex AI Custom Training Jobs\n",
|
||||
"\n",
|
||||
"This section demonstrates how to finetune and deploy Gemma models with PEFT LoRA on Vertex AI Custom Training Jobs. LoRA (Low-Rank Adaptation) is one approach of PEFT (Parameter Efficient FineTuning), where pretrained model weights are frozen and rank decomposition matrices representing the change in model weights are trained during finetuning. Read more about LoRA in the following publication: [Hu, E.J., Shen, Y., Wallis, P., Allen-Zhu, Z., Li, Y., Wang, S., Wang, L. and Chen, W., 2021. Lora: Low-rank adaptation of large language models. *arXiv preprint arXiv:2106.09685*](https://arxiv.org/abs/2106.09685)."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"cellView": "form",
|
||||
"id": "FD1TvpYZzjaS"
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# @title Set dataset\n",
|
||||
"\n",
|
||||
"# @markdown Use the Vertex AI SDK to create and run the custom training jobs.\n",
|
||||
"\n",
|
||||
"# @markdown This notebook uses [timdettmers/openassistant-guanaco](https://huggingface.co/datasets/timdettmers/openassistant-guanaco) dataset as an example.\n",
|
||||
"# @markdown You can set `dataset_name` to any existing [Hugging Face dataset](https://huggingface.co/datasets) name, and set `instruct_column_in_dataset` to the name of the dataset column containing training data. The [timdettmers/openassistant-guanaco](https://huggingface.co/datasets/timdettmers/openassistant-guanaco) has only one column `text`, and therefore we set `instruct_column_in_dataset` to `text` in this notebook.\n",
|
||||
"\n",
|
||||
"# @markdown ### (Optional) Prepare a custom JSONL dataset for finetuning\n",
|
||||
"\n",
|
||||
"# @markdown You can prepare a JSONL file where each line is a valid JSON string as your custom training dataset. For example, here is one line from the [timdettmers/openassistant-guanaco](https://huggingface.co/datasets/timdettmers/openassistant-guanaco) dataset:\n",
|
||||
"# @markdown ```\n",
|
||||
"# @markdown {\"text\": \"### Human: Hola### Assistant: \\u00a1Hola! \\u00bfEn qu\\u00e9 puedo ayudarte hoy?\"}\n",
|
||||
"# @markdown ```\n",
|
||||
"\n",
|
||||
"# @markdown The JSON object has a key `text`, which should match `instruct_column_in_dataset`; The value should be one training data point, i.e. a string. After you prepared your JSONL file, you can either upload it to [Hugging Face datasets](https://huggingface.co/datasets) or [Google Cloud Storage](https://cloud.google.com/storage).\n",
|
||||
"\n",
|
||||
"# @markdown - To upload a JSONL dataset to [Hugging Face datasets](https://huggingface.co/datasets), follow the instructions on [Uploading Datasets](https://huggingface.co/docs/hub/en/datasets-adding). Then, set `dataset_name` to the name of your newly created dataset on Hugging Face.\n",
|
||||
"\n",
|
||||
"# @markdown - To upload a JSONL dataset to [Google Cloud Storage](https://cloud.google.com/storage), follow the instructions on [Upload objects from a filesystem](https://cloud.google.com/storage/docs/uploading-objects). Then, set `dataset_name` to the `gs://` URI to your JSONL file. For example: `gs://cloud-samples-data/vertex-ai/model-evaluation/peft_train_sample.jsonl`.\n",
|
||||
"\n",
|
||||
"# @markdown Optionally update the `instruct_column_in_dataset` field below if your JSON objects use a key other than the default `text`.\n",
|
||||
"\n",
|
||||
"# @markdown ### (Optional) Format your data with custom JSON template\n",
|
||||
"\n",
|
||||
"# @markdown Sometimes, your dataset might have multiple text columns and you want to construct the training data with a template. You can prepare a JSON template in the following format:\n",
|
||||
"\n",
|
||||
"# @markdown ```\n",
|
||||
"# @markdown {\n",
|
||||
"# @markdown \"description\": \"Template that accepts text-bison format.\",\n",
|
||||
"# @markdown \"source\": \"https://cloud.google.com/vertex-ai/generative-ai/docs/models/tune-text-models-supervised#dataset-format\",\n",
|
||||
"# @markdown \"prompt_input\": \"\\n\\n<|start_header_id|>user<|end_header_id|>\\n\\n{input_text}<|eot_id|>\\n\\n<|start_header_id|>assistant<|end_header_id|>\\n\\n{output_text}<|eot_id|>\",\n",
|
||||
"# @markdown \"instruction_separator\": \"<|start_header_id|>user<|end_header_id|>\\n\\n\",\n",
|
||||
"# @markdown \"response_separator\": \"<|start_header_id|>assistant<|end_header_id|>\\n\\n\"\n",
|
||||
"# @markdown }\n",
|
||||
"# @markdown ```\n",
|
||||
"\n",
|
||||
"# @markdown As an example, the template above can be used to format the following training data (this line comes from `gs://cloud-samples-data/vertex-ai/model-evaluation/peft_train_sample.jsonl`):\n",
|
||||
"\n",
|
||||
"# @markdown ```\n",
|
||||
"# @markdown {\"input_text\":\"TRANSCRIPT: \\nREASON FOR EVALUATION:,\\n\\n LABEL:\",\"output_text\":\"Chiropractic\"}\n",
|
||||
"# @markdown ```\n",
|
||||
"\n",
|
||||
"# @markdown This example template simply concatenates `input_text` with `output_text` with some special tokens in between.\n",
|
||||
"# @markdown\n",
|
||||
"# @markdown To try such custom dataset, you can make the following changes:\n",
|
||||
"# @markdown 1. Set `template` to `llama3-text-bison`\n",
|
||||
"# @markdown 1. Set `train_dataset_name` to `gs://cloud-samples-data/vertex-ai/model-evaluation/peft_train_sample.jsonl`\n",
|
||||
"# @markdown 1. Set `train_split_name` to `train`\n",
|
||||
"# @markdown 1. Set `eval_dataset_name` to `gs://cloud-samples-data/vertex-ai/model-evaluation/peft_eval_sample.jsonl`\n",
|
||||
"# @markdown 1. Set `eval_split_name` to `train` (**NOT** `test`)\n",
|
||||
"# @markdown 1. Set `instruct_column_in_dataset` as `input_text`.\n",
|
||||
"\n",
|
||||
"# Template name or gs:// URI to a custom template.\n",
|
||||
"template = \"openassistant-guanaco\" # @param {type:\"string\"}\n",
|
||||
"\n",
|
||||
"# Hugging Face dataset name or gs:// URI to a custom JSONL dataset.\n",
|
||||
"train_dataset_name = \"timdettmers/openassistant-guanaco\" # @param {type:\"string\"}\n",
|
||||
"train_split_name = \"train\" # @param {type:\"string\"}\n",
|
||||
"eval_dataset_name = \"timdettmers/openassistant-guanaco\" # @param {type:\"string\"}\n",
|
||||
"eval_split_name = \"test\" # @param {type:\"string\"}\n",
|
||||
"\n",
|
||||
"# Name of the dataset column containing training text input.\n",
|
||||
"instruct_column_in_dataset = \"text\" # @param {type:\"string\"}"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"cellView": "form",
|
||||
"id": "wBxu3rEyzjaT"
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# @title Set model\n",
|
||||
"\n",
|
||||
"# @markdown Select a model variant of Gemma.\n",
|
||||
"base_model_id = \"gemma-1.1-2b-it\" # @param[\"gemma-2b\", \"gemma-2b-it\", \"gemma-7b\", \"gemma-7b-it\", \"gemma-1.1-2b-it\", \"gemma-1.1-7b-it\"] {isTemplate:true}\n",
|
||||
"pretrained_model_id = os.path.join(\"google/\", base_model_id)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"cellView": "form",
|
||||
"id": "jIEDYAnPzjaT"
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# @title Validate Dataset with Template\n",
|
||||
"\n",
|
||||
"# @markdown This section validates the train and eval datasets with the template before starting the fine tuning process.\n",
|
||||
"\n",
|
||||
"import transformers\n",
|
||||
"\n",
|
||||
"dataset_validation_util = importlib.import_module(\n",
|
||||
" \"vertex-ai-samples.community-content.vertex_model_garden.model_oss.notebook_util.dataset_validation_util\"\n",
|
||||
")\n",
|
||||
"\n",
|
||||
"if dataset_validation_util.is_gcs_path(pretrained_model_id):\n",
|
||||
" # Download tokenizer.\n",
|
||||
" ! mkdir tokenizer\n",
|
||||
" ! gsutil cp {pretrained_model_id}/tokenizer.json ./tokenizer\n",
|
||||
" ! gsutil cp {pretrained_model_id}/config.json ./tokenizer\n",
|
||||
" tokenizer_path = \"./tokenizer\"\n",
|
||||
" access_token = \"\"\n",
|
||||
"else:\n",
|
||||
" tokenizer_path = pretrained_model_id\n",
|
||||
" access_token = HF_TOKEN\n",
|
||||
"\n",
|
||||
"tokenizer = transformers.AutoTokenizer.from_pretrained(\n",
|
||||
" tokenizer_path,\n",
|
||||
" trust_remote_code=False,\n",
|
||||
" use_fast=True,\n",
|
||||
" token=access_token,\n",
|
||||
")\n",
|
||||
"\n",
|
||||
"# Validate the train dataset.\n",
|
||||
"dataset_validation_util.validate_dataset_with_template(\n",
|
||||
" dataset_name=train_dataset_name,\n",
|
||||
" split=train_split_name,\n",
|
||||
" input_column=instruct_column_in_dataset,\n",
|
||||
" template=template,\n",
|
||||
" use_multiprocessing=False,\n",
|
||||
" tokenizer=tokenizer,\n",
|
||||
")\n",
|
||||
"\n",
|
||||
"# Validate the eval dataset.\n",
|
||||
"dataset_validation_util.validate_dataset_with_template(\n",
|
||||
" dataset_name=eval_dataset_name,\n",
|
||||
" split=eval_split_name,\n",
|
||||
" input_column=instruct_column_in_dataset,\n",
|
||||
" template=template,\n",
|
||||
" use_multiprocessing=False,\n",
|
||||
" tokenizer=tokenizer,\n",
|
||||
")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"cellView": "form",
|
||||
"id": "rU7ekq-0zjaT"
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# @title Finetune\n",
|
||||
"# @markdown This section demonstrates how to finetune the Gemma model and merge the finetuned LoRA adapter with the base model on Vertex AI. It uses the Vertex AI SDK to create and run the custom training jobs.\n",
|
||||
"\n",
|
||||
"# @markdown The training job takes approximately between 10 to 20 mins to set-up. Once done, the training job is expected to take around 20 mins with the default configuration. To find the training time, throughput, and memory usage of your training job, you can go to the training logs and check the log line of the last training epoch.\n",
|
||||
"\n",
|
||||
"# @markdown **Note**:\n",
|
||||
"# @markdown 1. We recommend setting `finetuning_precision_mode` to `4bit` because it enables using fewer hardware resources for finetuning.\n",
|
||||
"# @markdown 1. If `max_steps > 0`, it takes precedence over `epochs`. One can set a small `max_steps` value to quickly check the pipeline.\n",
|
||||
"\n",
|
||||
"# @markdown Accelerator type to use for training.\n",
|
||||
"training_accelerator_type = \"NVIDIA_A100_80GB\" # @param [\"NVIDIA_A100_80GB\", \"NVIDIA_H100_80GB\"]\n",
|
||||
"\n",
|
||||
"# The pre-built training docker image.\n",
|
||||
"if training_accelerator_type == \"NVIDIA_A100_80GB\":\n",
|
||||
" repo = \"us-docker.pkg.dev/vertex-ai-restricted\"\n",
|
||||
" is_restricted_image = True\n",
|
||||
" is_dynamic_workload_scheduler = False\n",
|
||||
" dws_kwargs = {}\n",
|
||||
"else:\n",
|
||||
" repo = \"us-docker.pkg.dev/vertex-ai\"\n",
|
||||
" is_restricted_image = False\n",
|
||||
" is_dynamic_workload_scheduler = True\n",
|
||||
" dws_kwargs = {\n",
|
||||
" \"max_wait_duration\": 1800, # 30 minutes\n",
|
||||
" \"scheduling_strategy\": gca_custom_job_compat.Scheduling.Strategy.FLEX_START,\n",
|
||||
" }\n",
|
||||
"\n",
|
||||
"TRAIN_DOCKER_URI = (\n",
|
||||
" f\"{repo}/vertex-vision-model-garden-dockers/pytorch-peft-train:stable_20240909\"\n",
|
||||
")\n",
|
||||
"\n",
|
||||
"# Worker pool spec.\n",
|
||||
"if training_accelerator_type == \"NVIDIA_A100_80GB\":\n",
|
||||
" per_node_accelerator_count = 8\n",
|
||||
" training_machine_type = \"a2-ultragpu-8g\"\n",
|
||||
"elif training_accelerator_type == \"NVIDIA_H100_80GB\":\n",
|
||||
" per_node_accelerator_count = 8\n",
|
||||
" training_machine_type = \"a3-highgpu-8g\"\n",
|
||||
"else:\n",
|
||||
" raise ValueError(\n",
|
||||
" f\"Recommended machine settings not found for: {training_accelerator_type}. To use another accelerator type, edit this code block to pass in an appropriate `training_machine_type`, `training_accelerator_type`, and `per_node_accelerator_count` to the deploy_model_vllm function by clicking `Show Code` and then modifying the code.\"\n",
|
||||
" )\n",
|
||||
"\n",
|
||||
"# @markdown Batch size for finetuning.\n",
|
||||
"per_device_train_batch_size = 1 # @param{type:\"integer\"}\n",
|
||||
"# @markdown Number of updates steps to accumulate the gradients for, before performing a backward/update pass.\n",
|
||||
"gradient_accumulation_steps = 4 # @param{type:\"integer\"}\n",
|
||||
"# @markdown Maximum sequence length.\n",
|
||||
"max_seq_length = 4096 # @param{type:\"integer\"}\n",
|
||||
"# @markdown Setting a positive `max_steps` here will override `num_epochs`.\n",
|
||||
"max_steps = -1 # @param{type:\"integer\"}\n",
|
||||
"num_epochs = 1.0 # @param{type:\"number\"}\n",
|
||||
"# @markdown Precision mode for finetuning.\n",
|
||||
"finetuning_precision_mode = \"4bit\" # @param [\"4bit\", \"8bit\", \"float16\"]\n",
|
||||
"# @markdown Learning rate.\n",
|
||||
"learning_rate = 5e-5 # @param{type:\"number\"}\n",
|
||||
"# @markdown The scheduler type to use.\n",
|
||||
"lr_scheduler_type = \"cosine\" # @param{type:\"string\"}\n",
|
||||
"# @markdown LoRA parameters.\n",
|
||||
"lora_rank = 16 # @param{type:\"integer\"}\n",
|
||||
"lora_alpha = 32 # @param{type:\"integer\"}\n",
|
||||
"lora_dropout = 0.05 # @param{type:\"number\"}\n",
|
||||
"# Activates gradient checkpointing for the current model (may be referred to as activation checkpointing or checkpoint activations in other frameworks).\n",
|
||||
"enable_gradient_checkpointing = True\n",
|
||||
"# Attention implementation to use in the model.\n",
|
||||
"attn_implementation = \"eager\"\n",
|
||||
"# The optimizer for which to schedule the learning rate.\n",
|
||||
"optimizer = \"paged_adamw_32bit\"\n",
|
||||
"# Define the proportion of training to be dedicated to a linear warmup where learning rate gradually increases.\n",
|
||||
"warmup_ratio = \"0.01\"\n",
|
||||
"# The list or string of integrations to report the results and logs to.\n",
|
||||
"report_to = \"tensorboard\"\n",
|
||||
"# Number of updates steps before two checkpoint saves.\n",
|
||||
"save_steps = 10\n",
|
||||
"# Number of update steps between two logs.\n",
|
||||
"logging_steps = save_steps\n",
|
||||
"# Train precision of the model.\n",
|
||||
"train_precision = \"bfloat16\"\n",
|
||||
"\n",
|
||||
"replica_count = 1\n",
|
||||
"\n",
|
||||
"common_util.check_quota(\n",
|
||||
" project_id=PROJECT_ID,\n",
|
||||
" region=REGION,\n",
|
||||
" accelerator_type=training_accelerator_type,\n",
|
||||
" accelerator_count=per_node_accelerator_count * replica_count,\n",
|
||||
" is_for_training=True,\n",
|
||||
" is_restricted_image=is_restricted_image,\n",
|
||||
" is_dynamic_workload_scheduler=is_dynamic_workload_scheduler,\n",
|
||||
")\n",
|
||||
"\n",
|
||||
"job_name = common_util.get_job_name_with_datetime(\"gemma-lora-train\")\n",
|
||||
"\n",
|
||||
"base_output_dir = os.path.join(STAGING_BUCKET, job_name)\n",
|
||||
"# Create a GCS folder to store the LORA adapter.\n",
|
||||
"lora_output_dir = os.path.join(base_output_dir, \"adapter\")\n",
|
||||
"# Create a GCS folder to store the merged model with the base model and the\n",
|
||||
"# finetuned LORA adapter.\n",
|
||||
"merged_model_output_dir = os.path.join(base_output_dir, \"merged-model\")\n",
|
||||
"\n",
|
||||
"# Add labels for the finetuning job.\n",
|
||||
"labels = {\n",
|
||||
" \"mg-source\": \"notebook\",\n",
|
||||
" \"mg-notebook-name\": \"model_garden_pytorch_gemma_peft_finetuning_hf.ipynb\".split(\n",
|
||||
" \".\"\n",
|
||||
" )[0],\n",
|
||||
"}\n",
|
||||
"\n",
|
||||
"labels[\"mg-tune\"] = \"publishers-google-models-gemma\"\n",
|
||||
"versioned_model_id = base_model_id.lower().replace(\".\", \"-\")\n",
|
||||
"labels[\"versioned-mg-tune\"] = f\"{labels['mg-tune']}-{versioned_model_id}\"\n",
|
||||
"\n",
|
||||
"eval_args = [\n",
|
||||
" f\"--eval_dataset_path={eval_dataset_name}\",\n",
|
||||
" f\"--eval_column={instruct_column_in_dataset}\",\n",
|
||||
" f\"--eval_template={template}\",\n",
|
||||
" f\"--eval_split={eval_split_name}\",\n",
|
||||
" f\"--eval_steps={save_steps}\",\n",
|
||||
" \"--eval_tasks=builtin_eval\",\n",
|
||||
" \"--eval_metric_name=loss\",\n",
|
||||
"]\n",
|
||||
"\n",
|
||||
"train_job_args = [\n",
|
||||
" \"--config_file=vertex_vision_model_garden_peft/deepspeed_zero2_8gpu.yaml\",\n",
|
||||
" \"--task=instruct-lora\",\n",
|
||||
" \"--completion_only=True\",\n",
|
||||
" f\"--pretrained_model_id={pretrained_model_id}\",\n",
|
||||
" f\"--dataset_name={train_dataset_name}\",\n",
|
||||
" f\"--train_split_name={train_split_name}\",\n",
|
||||
" f\"--instruct_column_in_dataset={instruct_column_in_dataset}\",\n",
|
||||
" f\"--output_dir={lora_output_dir}\",\n",
|
||||
" f\"--merge_base_and_lora_output_dir={merged_model_output_dir}\",\n",
|
||||
" f\"--per_device_train_batch_size={per_device_train_batch_size}\",\n",
|
||||
" f\"--gradient_accumulation_steps={gradient_accumulation_steps}\",\n",
|
||||
" f\"--lora_rank={lora_rank}\",\n",
|
||||
" f\"--lora_alpha={lora_alpha}\",\n",
|
||||
" f\"--lora_dropout={lora_dropout}\",\n",
|
||||
" f\"--max_steps={max_steps}\",\n",
|
||||
" f\"--max_seq_length={max_seq_length}\",\n",
|
||||
" f\"--learning_rate={learning_rate}\",\n",
|
||||
" f\"--lr_scheduler_type={lr_scheduler_type}\",\n",
|
||||
" f\"--precision_mode={finetuning_precision_mode}\",\n",
|
||||
" f\"--train_precision={train_precision}\",\n",
|
||||
" f\"--enable_gradient_checkpointing={enable_gradient_checkpointing}\",\n",
|
||||
" f\"--num_epochs={num_epochs}\",\n",
|
||||
" f\"--attn_implementation={attn_implementation}\",\n",
|
||||
" f\"--optimizer={optimizer}\",\n",
|
||||
" f\"--warmup_ratio={warmup_ratio}\",\n",
|
||||
" f\"--report_to={report_to}\",\n",
|
||||
" f\"--logging_output_dir={base_output_dir}\",\n",
|
||||
" f\"--save_steps={save_steps}\",\n",
|
||||
" f\"--logging_steps={logging_steps}\",\n",
|
||||
" f\"--template={template}\",\n",
|
||||
" f\"--huggingface_access_token={HF_TOKEN}\",\n",
|
||||
"] + eval_args\n",
|
||||
"\n",
|
||||
"# Pass training arguments and launch job.\n",
|
||||
"train_job = aiplatform.CustomContainerTrainingJob(\n",
|
||||
" display_name=job_name,\n",
|
||||
" container_uri=TRAIN_DOCKER_URI,\n",
|
||||
" labels=labels,\n",
|
||||
")\n",
|
||||
"\n",
|
||||
"print(\"Running training job with args:\")\n",
|
||||
"print(\" \\\\\\n\".join(train_job_args))\n",
|
||||
"train_job.run(\n",
|
||||
" args=train_job_args,\n",
|
||||
" replica_count=replica_count,\n",
|
||||
" machine_type=training_machine_type,\n",
|
||||
" accelerator_type=training_accelerator_type,\n",
|
||||
" accelerator_count=per_node_accelerator_count,\n",
|
||||
" boot_disk_size_gb=500,\n",
|
||||
" service_account=SERVICE_ACCOUNT,\n",
|
||||
" base_output_dir=base_output_dir,\n",
|
||||
" sync=False, # Non-blocking call to run.\n",
|
||||
" **dws_kwargs,\n",
|
||||
")\n",
|
||||
"\n",
|
||||
"# Wait until resource has been created.\n",
|
||||
"train_job.wait_for_resource_creation()\n",
|
||||
"\n",
|
||||
"print(\"LoRA adapter will be saved in:\", lora_output_dir)\n",
|
||||
"print(\"Trained and merged models will be saved in:\", merged_model_output_dir)\n",
|
||||
"\n",
|
||||
"# @markdown Click \"Show Code\" to see more details."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"cellView": "form",
|
||||
"id": "NdBE5YabzjaT"
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# @title Run TensorBoard\n",
|
||||
"# @markdown This section shows how to launch TensorBoard in a [Cloud Shell](https://cloud.google.com/shell/docs).\n",
|
||||
"# @markdown 1. Click the Cloud Shell icon() on the top right to open the Cloud Shell.\n",
|
||||
"# @markdown 2. Copy the `tensorboard` command shown below by running this cell.\n",
|
||||
"# @markdown 3. Paste and run the command in the Cloud Shell to launch TensorBoard.\n",
|
||||
"# @markdown 4. Once the command runs (You may have to click `Authorize` if prompted), click the link starting with `http://localhost`.\n",
|
||||
"\n",
|
||||
"# @markdown Note: You may need to wait around 10 minutes after the job starts in order for the TensorBoard logs to be written to the GCS bucket.\n",
|
||||
"print(f\"Command to copy: tensorboard --logdir {base_output_dir}/logs\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"cellView": "form",
|
||||
"id": "qmHW6m8xG_4U"
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# @title Deploy with vLLM\n",
|
||||
"# @markdown This section uploads the model to Model Registry and deploys it on the Endpoint. It takes 15 minutes to 1 hour to finish.\n",
|
||||
"\n",
|
||||
"if train_job.end_time is None:\n",
|
||||
" print(\"Waiting for the training job to finish...\")\n",
|
||||
" train_job.wait()\n",
|
||||
" print(\"The training job has finished.\")\n",
|
||||
"\n",
|
||||
"print(\"Deploying models in:\", merged_model_output_dir)\n",
|
||||
"\n",
|
||||
"# The pre-built serving docker image for vLLM.\n",
|
||||
"VLLM_DOCKER_URI = \"us-docker.pkg.dev/vertex-ai/vertex-vision-model-garden-dockers/pytorch-vllm-serve:20241010_0916_RC00\"\n",
|
||||
"\n",
|
||||
"# Find Vertex AI prediction supported accelerators and regions in [here](https://cloud.google.com/vertex-ai/docs/predictions/configure-compute).\n",
|
||||
"# Sets 1 L4 (24G) to deploy Gemma models.\n",
|
||||
"serve_machine_type = \"g2-standard-12\"\n",
|
||||
"serve_accelerator_type = \"NVIDIA_L4\"\n",
|
||||
"serve_accelerator_count = 1\n",
|
||||
"\n",
|
||||
"# @markdown Set `use_dedicated_endpoint` to False if you don't want to use [dedicated endpoint](https://cloud.google.com/vertex-ai/docs/general/deployment#create-dedicated-endpoint).\n",
|
||||
"use_dedicated_endpoint = True # @param {type:\"boolean\"}\n",
|
||||
"\n",
|
||||
"common_util.check_quota(\n",
|
||||
" project_id=PROJECT_ID,\n",
|
||||
" region=REGION,\n",
|
||||
" accelerator_type=serve_accelerator_type,\n",
|
||||
" accelerator_count=serve_accelerator_count,\n",
|
||||
" is_for_training=False,\n",
|
||||
")\n",
|
||||
"\n",
|
||||
"# Note that a larger max_model_len will require more GPU memory.\n",
|
||||
"max_model_len = 2048\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"def get_deploy_source() -> str:\n",
|
||||
" \"\"\"Gets deploy_source string based on running environment.\"\"\"\n",
|
||||
" vertex_product = os.environ.get(\"VERTEX_PRODUCT\", \"\")\n",
|
||||
" if vertex_product == \"COLAB_ENTERPRISE\":\n",
|
||||
" return \"notebook_colab_enterprise\"\n",
|
||||
" elif vertex_product == \"WORKBENCH_INSTANCE\":\n",
|
||||
" return \"notebook_workbench\"\n",
|
||||
" else:\n",
|
||||
" # Legacy workbench, legacy colab, or other custom environments.\n",
|
||||
" return \"notebook_environment_unspecified\"\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"def deploy_model_vllm(\n",
|
||||
" model_name: str,\n",
|
||||
" model_id: str,\n",
|
||||
" publisher: str,\n",
|
||||
" publisher_model_id: str,\n",
|
||||
" service_account: str,\n",
|
||||
" base_model_id: str = None,\n",
|
||||
" machine_type: str = \"g2-standard-8\",\n",
|
||||
" accelerator_type: str = \"NVIDIA_L4\",\n",
|
||||
" accelerator_count: int = 1,\n",
|
||||
" gpu_memory_utilization: float = 0.9,\n",
|
||||
" max_model_len: int = 4096,\n",
|
||||
" dtype: str = \"auto\",\n",
|
||||
" enable_trust_remote_code: bool = False,\n",
|
||||
" enforce_eager: bool = False,\n",
|
||||
" enable_lora: bool = False,\n",
|
||||
" enable_chunked_prefill: bool = False,\n",
|
||||
" enable_prefix_cache: bool = False,\n",
|
||||
" host_prefix_kv_cache_utilization_target: float = 0.0,\n",
|
||||
" max_loras: int = 1,\n",
|
||||
" max_cpu_loras: int = 8,\n",
|
||||
" use_dedicated_endpoint: bool = False,\n",
|
||||
" max_num_seqs: int = 256,\n",
|
||||
" model_type: str = None,\n",
|
||||
" enable_llama_tool_parser: bool = False,\n",
|
||||
" is_spot: bool = False,\n",
|
||||
") -> Tuple[aiplatform.Model, aiplatform.Endpoint]:\n",
|
||||
" \"\"\"Deploys trained models with vLLM into Vertex AI.\"\"\"\n",
|
||||
" endpoint = aiplatform.Endpoint.create(\n",
|
||||
" display_name=f\"{model_name}-endpoint\",\n",
|
||||
" dedicated_endpoint_enabled=use_dedicated_endpoint,\n",
|
||||
" )\n",
|
||||
"\n",
|
||||
" if not base_model_id:\n",
|
||||
" base_model_id = model_id\n",
|
||||
"\n",
|
||||
" # See https://docs.vllm.ai/en/latest/models/engine_args.html for a list of possible arguments with descriptions.\n",
|
||||
" vllm_args = [\n",
|
||||
" \"python\",\n",
|
||||
" \"-m\",\n",
|
||||
" \"vllm.entrypoints.api_server\",\n",
|
||||
" \"--host=0.0.0.0\",\n",
|
||||
" \"--port=8080\",\n",
|
||||
" f\"--model={model_id}\",\n",
|
||||
" f\"--tensor-parallel-size={accelerator_count}\",\n",
|
||||
" \"--swap-space=16\",\n",
|
||||
" f\"--max-model-len={max_model_len}\",\n",
|
||||
" f\"--dtype={dtype}\",\n",
|
||||
" f\"--max-loras={max_loras}\",\n",
|
||||
" f\"--max-cpu-loras={max_cpu_loras}\",\n",
|
||||
" f\"--max-num-seqs={max_num_seqs}\",\n",
|
||||
" \"--disable-log-stats\",\n",
|
||||
" ]\n",
|
||||
"\n",
|
||||
" if gpu_memory_utilization:\n",
|
||||
" vllm_args.append(f\"--gpu-memory-utilization={gpu_memory_utilization}\")\n",
|
||||
"\n",
|
||||
" if enable_trust_remote_code:\n",
|
||||
" vllm_args.append(\"--trust-remote-code\")\n",
|
||||
"\n",
|
||||
" if enforce_eager:\n",
|
||||
" vllm_args.append(\"--enforce-eager\")\n",
|
||||
"\n",
|
||||
" if enable_lora:\n",
|
||||
" vllm_args.append(\"--enable-lora\")\n",
|
||||
"\n",
|
||||
" if enable_chunked_prefill:\n",
|
||||
" vllm_args.append(\"--enable-chunked-prefill\")\n",
|
||||
"\n",
|
||||
" if enable_prefix_cache:\n",
|
||||
" vllm_args.append(\"--enable-prefix-caching\")\n",
|
||||
"\n",
|
||||
" if 0 < host_prefix_kv_cache_utilization_target < 1:\n",
|
||||
" vllm_args.append(\n",
|
||||
" f\"--host-prefix-kv-cache-utilization-target={host_prefix_kv_cache_utilization_target}\"\n",
|
||||
" )\n",
|
||||
"\n",
|
||||
" if model_type:\n",
|
||||
" vllm_args.append(f\"--model-type={model_type}\")\n",
|
||||
"\n",
|
||||
" if enable_llama_tool_parser:\n",
|
||||
" vllm_args.append(\"--enable-auto-tool-choice\")\n",
|
||||
" vllm_args.append(\"--tool-call-parser=vertex-llama-3\")\n",
|
||||
"\n",
|
||||
" env_vars = {\n",
|
||||
" \"MODEL_ID\": base_model_id,\n",
|
||||
" \"DEPLOY_SOURCE\": \"notebook\",\n",
|
||||
" }\n",
|
||||
"\n",
|
||||
" # HF_TOKEN is not a compulsory field and may not be defined.\n",
|
||||
" try:\n",
|
||||
" if HF_TOKEN:\n",
|
||||
" env_vars[\"HF_TOKEN\"] = HF_TOKEN\n",
|
||||
" except NameError:\n",
|
||||
" pass\n",
|
||||
"\n",
|
||||
" model = aiplatform.Model.upload(\n",
|
||||
" display_name=model_name,\n",
|
||||
" serving_container_image_uri=VLLM_DOCKER_URI,\n",
|
||||
" serving_container_args=vllm_args,\n",
|
||||
" serving_container_ports=[8080],\n",
|
||||
" serving_container_predict_route=\"/generate\",\n",
|
||||
" serving_container_health_route=\"/ping\",\n",
|
||||
" serving_container_environment_variables=env_vars,\n",
|
||||
" serving_container_shared_memory_size_mb=(16 * 1024), # 16 GB\n",
|
||||
" serving_container_deployment_timeout=7200,\n",
|
||||
" model_garden_source_model_name=(\n",
|
||||
" f\"publishers/{publisher}/models/{publisher_model_id}\"\n",
|
||||
" ),\n",
|
||||
" )\n",
|
||||
" print(\n",
|
||||
" f\"Deploying {model_name} on {machine_type} with {accelerator_count} {accelerator_type} GPU(s).\"\n",
|
||||
" )\n",
|
||||
" model.deploy(\n",
|
||||
" endpoint=endpoint,\n",
|
||||
" machine_type=machine_type,\n",
|
||||
" accelerator_type=accelerator_type,\n",
|
||||
" accelerator_count=accelerator_count,\n",
|
||||
" deploy_request_timeout=1800,\n",
|
||||
" service_account=service_account,\n",
|
||||
" spot=is_spot,\n",
|
||||
" system_labels={\n",
|
||||
" \"NOTEBOOK_NAME\": \"model_garden_pytorch_gemma_peft_finetuning_hf.ipynb\",\n",
|
||||
" \"NOTEBOOK_ENVIRONMENT\": get_deploy_source(),\n",
|
||||
" },\n",
|
||||
" )\n",
|
||||
" print(\"endpoint_name:\", endpoint.name)\n",
|
||||
"\n",
|
||||
" return model, endpoint\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"models[\"vllm_gpu\"], endpoints[\"vllm_gpu\"] = deploy_model_vllm(\n",
|
||||
" model_name=common_util.get_job_name_with_datetime(prefix=\"gemma-vllm-serve\"),\n",
|
||||
" base_model_id=f\"google/{base_model_id}\",\n",
|
||||
" publisher=\"google\",\n",
|
||||
" publisher_model_id=\"gemma\",\n",
|
||||
" model_id=merged_model_output_dir,\n",
|
||||
" service_account=SERVICE_ACCOUNT,\n",
|
||||
" machine_type=serve_machine_type,\n",
|
||||
" accelerator_type=serve_accelerator_type,\n",
|
||||
" accelerator_count=serve_accelerator_count,\n",
|
||||
" max_model_len=max_model_len,\n",
|
||||
" use_dedicated_endpoint=use_dedicated_endpoint,\n",
|
||||
")\n",
|
||||
"\n",
|
||||
"# @markdown Click \"Show Code\" to see more details."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"cellView": "form",
|
||||
"id": "2UYUNn60G_4U"
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# @title Predict\n",
|
||||
"# @markdown Once deployment succeeds, you can send requests to the endpoint with text prompts. Sampling parameters supported by vLLM can be found [here](https://docs.vllm.ai/en/latest/dev/sampling_params.html).\n",
|
||||
"\n",
|
||||
"# @markdown Example:\n",
|
||||
"\n",
|
||||
"# @markdown ```\n",
|
||||
"# @markdown Human: What is a car?\n",
|
||||
"# @markdown Assistant: A car, or a motor car, is a road-connected human-transportation system used to move people or goods from one place to another. The term also encompasses a wide range of vehicles, including motorboats, trains, and aircrafts. Cars typically have four wheels, a cabin for passengers, and an engine or motor. They have been around since the early 19th century and are now one of the most popular forms of transportation, used for daily commuting, shopping, and other purposes.\n",
|
||||
"# @markdown ```\n",
|
||||
"# @markdown Additionally, you can moderate the generated text with Vertex AI. See [Moderate text documentation](https://cloud.google.com/natural-language/docs/moderating-text) for more details.\n",
|
||||
"\n",
|
||||
"# Loads an existing endpoint instance using the endpoint name:\n",
|
||||
"# - Using `endpoint_name = endpoint.name` allows us to get the\n",
|
||||
"# endpoint name of the endpoint `endpoint` created in the cell\n",
|
||||
"# above.\n",
|
||||
"# - Alternatively, you can set `endpoint_name = \"1234567890123456789\"` to load\n",
|
||||
"# an existing endpoint with the ID 1234567890123456789.\n",
|
||||
"# You may uncomment the code below to load an existing endpoint.\n",
|
||||
"\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",
|
||||
"\n",
|
||||
"prompt = \"What is a car?\" # @param {type: \"string\"}\n",
|
||||
"# @markdown If you encounter an issue like `ServiceUnavailable: 503 Took too long to respond when processing`, you can reduce the maximum number of output tokens, by lowering `max_tokens`.\n",
|
||||
"max_tokens = 50 # @param {type:\"integer\"}\n",
|
||||
"temperature = 1.0 # @param {type:\"number\"}\n",
|
||||
"top_p = 1.0 # @param {type:\"number\"}\n",
|
||||
"top_k = 1 # @param {type:\"integer\"}\n",
|
||||
"# @markdown Set `raw_response` to `True` to obtain the raw model output. Set `raw_response` to `False` to apply additional formatting in the structure of `\"Prompt:\\n{prompt.strip()}\\nOutput:\\n{output}\"`.\n",
|
||||
"raw_response = False # @param {type:\"boolean\"}\n",
|
||||
"\n",
|
||||
"# Overrides parameters for inferences.\n",
|
||||
"instances = [\n",
|
||||
" {\n",
|
||||
" \"prompt\": prompt,\n",
|
||||
" \"max_tokens\": max_tokens,\n",
|
||||
" \"temperature\": temperature,\n",
|
||||
" \"top_p\": top_p,\n",
|
||||
" \"top_k\": top_k,\n",
|
||||
" \"raw_response\": raw_response,\n",
|
||||
" },\n",
|
||||
"]\n",
|
||||
"response = endpoints[\"vllm_gpu\"].predict(\n",
|
||||
" instances=instances, use_dedicated_endpoint=use_dedicated_endpoint\n",
|
||||
")\n",
|
||||
"\n",
|
||||
"for prediction in response.predictions:\n",
|
||||
" print(prediction)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"cellView": "form",
|
||||
"id": "2T_cXYJhG_4U"
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# @markdown Text moderation analyzes a document against a list of safety attributes, which include \"harmful categories\" and topics that may be considered sensitive.\n",
|
||||
"\n",
|
||||
"for generated_text in response.predictions:\n",
|
||||
" # Send a request to the API.\n",
|
||||
" response = moderate_text(generated_text)\n",
|
||||
" # Show the results.\n",
|
||||
" show_text_moderation(generated_text, response)\n",
|
||||
"\n",
|
||||
"# @markdown Click \"Show Code\" to see more details."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "af21a3cff1e0"
|
||||
},
|
||||
"source": [
|
||||
"## Clean up resources"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"cellView": "form",
|
||||
"id": "911406c1561e"
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Delete the train job.\n",
|
||||
"train_job.delete()\n",
|
||||
"\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",
|
||||
"for endpoint in endpoints.values():\n",
|
||||
" endpoint.delete(force=True)\n",
|
||||
"\n",
|
||||
"# Delete models.\n",
|
||||
"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"
|
||||
]
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"colab": {
|
||||
"name": "model_garden_pytorch_gemma_peft_finetuning_hf.ipynb",
|
||||
"toc_visible": true
|
||||
},
|
||||
"kernelspec": {
|
||||
"display_name": "Python 3",
|
||||
"name": "python3"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 0
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,682 +0,0 @@
|
||||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"id": "7d9bbf86da5e"
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# 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",
|
||||
"# 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": "99c1c3fc2ca5"
|
||||
},
|
||||
"source": [
|
||||
"# Vertex AI Model Garden - LLaMA2 (PEFT Finetuning)\n",
|
||||
"\n",
|
||||
"<table><tbody><tr>\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%2Fcommunity%2Fmodel_garden%2Fmodel_garden_pytorch_llama2_peft_finetuning.ipynb\">\n",
|
||||
" <img alt=\"Google Cloud Colab Enterprise logo\" src=\"https://lh3.googleusercontent.com/JmcxdQi-qOpctIvWKgPtrzZdJJK-J3sWE1RsfjZNwshCFgE_9fULcNpuXYTilIR2hjwN\" width=\"32px\"><br> Run in Colab Enterprise\n",
|
||||
" </a>\n",
|
||||
" </td>\n",
|
||||
" <td style=\"text-align: center\">\n",
|
||||
" <a href=\"https://github.com/GoogleCloudPlatform/vertex-ai-samples/blob/main/notebooks/community/model_garden/model_garden_pytorch_llama2_peft_finetuning.ipynb\">\n",
|
||||
" <img alt=\"GitHub logo\" src=\"https://github.githubassets.com/assets/GitHub-Mark-ea2971cee799.png\" width=\"32px\"><br> View on GitHub\n",
|
||||
" </a>\n",
|
||||
" </td>\n",
|
||||
"</tr></tbody></table>"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "3de7470326a2"
|
||||
},
|
||||
"source": [
|
||||
"## Overview\n",
|
||||
"\n",
|
||||
"This notebook demonstrates downloading [LLaMA2 models](https://huggingface.co/meta-llama), finetuning with parameter efficient finetuning libraries ([PEFT](https://github.com/huggingface/peft)), and deploying the finetuned model on Vertex AI.\n",
|
||||
"\n",
|
||||
"### Objective\n",
|
||||
"\n",
|
||||
"- Download prebuilt LLaMA2 models.\n",
|
||||
"- Finetune and deploy LLaMA2 models with Vertex AI SDK.\n",
|
||||
"\n",
|
||||
"### Costs\n",
|
||||
"\n",
|
||||
"This tutorial uses billable components of Google Cloud:\n",
|
||||
"\n",
|
||||
"* Vertex AI\n",
|
||||
"* Cloud Storage\n",
|
||||
"\n",
|
||||
"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."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "264c07757582"
|
||||
},
|
||||
"source": [
|
||||
"## Run the notebook"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"cellView": "form",
|
||||
"id": "QJgmw34Xwctp"
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# @title (Optional) Finetune with Vertex AI Pipeline\n",
|
||||
"\n",
|
||||
"# @markdown Vertex Model Garden offers a pre-configured pipeline that can be launched from the UI, which will fine-tune, evaluate, upload, and deploy your desired LLaMA2 model.\n",
|
||||
"# @markdown This pipeline currently supports [huggingface datasets](https://huggingface.co/datasets) for finetuning.\n",
|
||||
"\n",
|
||||
"# @markdown To launch a LLaMA 2 finetuning pipeline, open the [LLaMA 2 model card](https://console.cloud.google.com/vertex-ai/publishers/google/model-garden/139) and click the \"FINE-TUNE\" button.\n",
|
||||
"# @markdown Then, click \"CREATE RUN\" button near the top of the pipeline details page, and follow the instructions to fill in pipeline parameters.\n",
|
||||
"\n",
|
||||
"# @markdown Learn about [Vertex AI Pipelines](https://cloud.google.com/vertex-ai/docs/pipelines/introduction)."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"cellView": "form",
|
||||
"id": "IoPsYDwDdFBf"
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# @title Setup Google Cloud project\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] [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",
|
||||
"# @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).\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, us-east5, europe-west4, us-west1, asia-southeast1 |\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"# Upgrade Vertex AI SDK.\n",
|
||||
"! pip3 install --upgrade --quiet 'google-cloud-aiplatform>=1.64.0'\n",
|
||||
"! git clone https://github.com/GoogleCloudPlatform/vertex-ai-samples.git\n",
|
||||
"\n",
|
||||
"# Import the necessary packages\n",
|
||||
"import importlib\n",
|
||||
"import os\n",
|
||||
"import uuid\n",
|
||||
"from datetime import datetime\n",
|
||||
"from typing import Tuple\n",
|
||||
"\n",
|
||||
"from google.cloud import aiplatform\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",
|
||||
"# Get the default cloud project id.\n",
|
||||
"PROJECT_ID = os.environ[\"GOOGLE_CLOUD_PROJECT\"]\n",
|
||||
"\n",
|
||||
"# Get the default region for launching jobs.\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",
|
||||
"# 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 below.\n",
|
||||
"now = datetime.now().strftime(\"%Y%m%d%H%M%S\")\n",
|
||||
"BUCKET_URI = \"gs://\" # @param {type:\"string\"}\n",
|
||||
"\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",
|
||||
" ! gsutil mb -l {REGION} {BUCKET_URI}\n",
|
||||
"else:\n",
|
||||
" assert BUCKET_URI.startswith(\"gs://\"), \"BUCKET_URI must start with `gs://`.\"\n",
|
||||
" BUCKET_NAME = \"/\".join(BUCKET_URI.split(\"/\")[:3])\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",
|
||||
"EXPERIMENT_BUCKET = os.path.join(BUCKET_URI, \"peft\")\n",
|
||||
"MODEL_BUCKET = os.path.join(BUCKET_URI, \"llama2\")\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",
|
||||
"# Gets the default BUCKET_URI and SERVICE_ACCOUNT if they were not specified by the user.\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",
|
||||
"# Provision permissions to the SERVICE_ACCOUNT with the GCS bucket\n",
|
||||
"BUCKET_NAME = \"/\".join(BUCKET_URI.split(\"/\")[:3])\n",
|
||||
"! gsutil iam ch serviceAccount:{SERVICE_ACCOUNT}:roles/storage.admin $BUCKET_NAME\n",
|
||||
"\n",
|
||||
"! gcloud config set project $PROJECT_ID"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"cellView": "form",
|
||||
"id": "zI30m3bqDtCj"
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# @title Access LLaMA2 models on Vertex AI for GPU based serving\n",
|
||||
"# @markdown The original models from Meta are converted into the Hugging Face format for serving in Vertex AI.\n",
|
||||
"# @markdown Accept the model agreement to access the models:\n",
|
||||
"# @markdown 1. Open the [LLaMA2 model card](https://console.cloud.google.com/vertex-ai/publishers/google/model-garden/139) from [Vertex AI Model Garden](https://cloud.google.com/model-garden).\n",
|
||||
"# @markdown 2. Review and accept the agreement in the pop-up window on the model card page. If you have previously accepted the model agreement, there will not be a pop-up window on the model card page and this step is not needed.\n",
|
||||
"# @markdown 3. A Cloud Storage bucket (starting with `gs://`) containing LLaMA 2 pretrained and finetuned models will be shared under the “Documentation” section and its “Get started” subsection.\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"VERTEX_AI_MODEL_GARDEN_LLAMA2 = \"\" # @param {type:\"string\", isTemplate:true}\n",
|
||||
"assert (\n",
|
||||
" VERTEX_AI_MODEL_GARDEN_LLAMA2\n",
|
||||
"), \"Model artifact path is required. Click the agreement of LLaMA2 in Vertex AI Model Garden, and get the GCS path of LLaMA2 model artifacts.\"\n",
|
||||
"print(\n",
|
||||
" \"Copying LLaMA2 model artifacts from\",\n",
|
||||
" VERTEX_AI_MODEL_GARDEN_LLAMA2,\n",
|
||||
" \"to\",\n",
|
||||
" MODEL_BUCKET,\n",
|
||||
")\n",
|
||||
"\n",
|
||||
"! gsutil -m cp -R $VERTEX_AI_MODEL_GARDEN_LLAMA2/* $MODEL_BUCKET\n",
|
||||
"\n",
|
||||
"# The pre-built serving and training docker images.\n",
|
||||
"VLLM_DOCKER_URI = \"us-docker.pkg.dev/vertex-ai/vertex-vision-model-garden-dockers/pytorch-vllm-serve:20240326_0916_RC00\"\n",
|
||||
"TRAIN_DOCKER_URI = \"us-docker.pkg.dev/vertex-ai/vertex-vision-model-garden-dockers/pytorch-peft-train:20240321_0936_RC00\"\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"def get_job_name_with_datetime(prefix: str) -> str:\n",
|
||||
" \"\"\"Gets the job name with date time when triggering training or deployment\n",
|
||||
" jobs in Vertex AI.\n",
|
||||
" \"\"\"\n",
|
||||
" return prefix + datetime.now().strftime(\"_%Y%m%d_%H%M%S\")\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"def deploy_model_vllm(\n",
|
||||
" model_name: str,\n",
|
||||
" model_id: str,\n",
|
||||
" service_account: str,\n",
|
||||
" machine_type: str = \"g2-standard-8\",\n",
|
||||
" accelerator_type: str = \"NVIDIA_L4\",\n",
|
||||
" accelerator_count: int = 1,\n",
|
||||
" max_model_len: int = 4096,\n",
|
||||
") -> Tuple[aiplatform.Model, aiplatform.Endpoint]:\n",
|
||||
" \"\"\"Deploys trained models with vLLM into Vertex AI.\"\"\"\n",
|
||||
" common_util.check_quota(\n",
|
||||
" project_id=PROJECT_ID,\n",
|
||||
" region=REGION,\n",
|
||||
" accelerator_type=accelerator_type,\n",
|
||||
" accelerator_count=accelerator_count,\n",
|
||||
" is_for_training=False,\n",
|
||||
" )\n",
|
||||
"\n",
|
||||
" endpoint = aiplatform.Endpoint.create(display_name=f\"{model_name}-endpoint\")\n",
|
||||
"\n",
|
||||
" vllm_args = [\n",
|
||||
" \"--host=0.0.0.0\",\n",
|
||||
" \"--port=7080\",\n",
|
||||
" f\"--tensor-parallel-size={accelerator_count}\",\n",
|
||||
" \"--swap-space=16\",\n",
|
||||
" \"--gpu-memory-utilization=0.8\",\n",
|
||||
" f\"--max-model-len={max_model_len}\",\n",
|
||||
" \"--max-num-batched-tokens=4096\",\n",
|
||||
" \"--disable-log-stats\",\n",
|
||||
" ]\n",
|
||||
"\n",
|
||||
" env_vars = {\"MODEL_ID\": model_id, \"DEPLOY_SOURCE\": \"notebook\"}\n",
|
||||
" model = aiplatform.Model.upload(\n",
|
||||
" display_name=model_name,\n",
|
||||
" serving_container_image_uri=VLLM_DOCKER_URI,\n",
|
||||
" serving_container_command=[\"python\", \"-m\", \"vllm.entrypoints.api_server\"],\n",
|
||||
" serving_container_args=vllm_args,\n",
|
||||
" serving_container_ports=[7080],\n",
|
||||
" serving_container_predict_route=\"/generate\",\n",
|
||||
" serving_container_health_route=\"/ping\",\n",
|
||||
" serving_container_environment_variables=env_vars,\n",
|
||||
" artifact_uri=model_id,\n",
|
||||
" model_garden_source_model_name=\"publishers/meta/models/llama2\"\n",
|
||||
" )\n",
|
||||
" print(\n",
|
||||
" f\"Deploying {model_name} on {machine_type} with {accelerator_count} {accelerator_type} GPU(s).\"\n",
|
||||
" )\n",
|
||||
" model.deploy(\n",
|
||||
" endpoint=endpoint,\n",
|
||||
" machine_type=machine_type,\n",
|
||||
" accelerator_type=accelerator_type,\n",
|
||||
" accelerator_count=accelerator_count,\n",
|
||||
" deploy_request_timeout=1800,\n",
|
||||
" service_account=service_account,\n",
|
||||
" system_labels={\n",
|
||||
" \"NOTEBOOK_NAME\": \"model_garden_pytorch_llama2_peft_finetuning.ipynb\"\n",
|
||||
" },\n",
|
||||
" )\n",
|
||||
" print(\"endpoint_name:\", endpoint.name)\n",
|
||||
"\n",
|
||||
" print(\"To load this existing endpoint from a different session:\")\n",
|
||||
" print(\"from google.cloud import aiplatform\")\n",
|
||||
" print(\n",
|
||||
" f'endpoint = aiplatform.Endpoint(\"projects/{PROJECT_ID}/locations/{REGION}/endpoints/{endpoint.name}\")'\n",
|
||||
" )\n",
|
||||
" return model, endpoint"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"cellView": "form",
|
||||
"id": "Ax6GlzzMk-sc"
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# @title Set training dataset\n",
|
||||
"\n",
|
||||
"# @markdown This notebook uses [timdettmers/openassistant-guanaco](https://huggingface.co/datasets/timdettmers/openassistant-guanaco) dataset as an example.\n",
|
||||
"# @markdown You can set `dataset_name` to any existing [Hugging Face dataset](https://huggingface.co/datasets) name, and set `instruct_column_in_dataset` to the name of the dataset column containing training data. The [timdettmers/openassistant-guanaco](https://huggingface.co/datasets/timdettmers/openassistant-guanaco) has only one column `text`, and therefore we set `instruct_column_in_dataset` to `text` in this notebook.\n",
|
||||
"\n",
|
||||
"# @markdown #### (Optional) Prepare a custom JSONL dataset for finetuning\n",
|
||||
"\n",
|
||||
"# @markdown You can prepare a JSONL file where each line is a valid JSON string as your custom training dataset. For example, here is one line from the [timdettmers/openassistant-guanaco](https://huggingface.co/datasets/timdettmers/openassistant-guanaco) dataset:\n",
|
||||
"# @markdown ```\n",
|
||||
"# @markdown {\"text\": \"### Human: Hola### Assistant: \\u00a1Hola! \\u00bfEn qu\\u00e9 puedo ayudarte hoy?\"}\n",
|
||||
"# @markdown ```\n",
|
||||
"\n",
|
||||
"# @markdown The JSON object has a key `text`, which should match `instruct_column_in_dataset`; The value should be one training data point, i.e. a string. After you prepared your JSONL file, you can either upload it to [Hugging Face datasets](https://huggingface.co/datasets) or [Google Cloud Storage](https://cloud.google.com/storage).\n",
|
||||
"\n",
|
||||
"# @markdown - To upload a JSONL dataset to [Hugging Face datasets](https://huggingface.co/datasets), follow the instructions on [Uploading Datasets](https://huggingface.co/docs/hub/en/datasets-adding). Then, set `dataset_name` to the name of your newly created dataset on Hugging Face.\n",
|
||||
"\n",
|
||||
"# @markdown - To upload a JSONL dataset to [Google Cloud Storage](https://cloud.google.com/storage), follow the instructions on [Upload objects from a filesystem](https://cloud.google.com/storage/docs/uploading-objects). Then, set `dataset_name` to the `gs://` URI to your JSONL file. For example: `gs://cloud-samples-data/vertex-ai/model-evaluation/peft_train_sample.jsonl`.\n",
|
||||
"\n",
|
||||
"# @markdown Optionally update the `instruct_column_in_dataset` field below if your JSON objects use a key other than the default `text`.\n",
|
||||
"\n",
|
||||
"# @markdown #### (Optional) Format your data with custom JSON template\n",
|
||||
"\n",
|
||||
"# @markdown Sometimes, your dataset might have multiple text columns and you want to construct the training data with a template. You can prepare a JSON template in the following format:\n",
|
||||
"\n",
|
||||
"# @markdown ```\n",
|
||||
"# @markdown {\n",
|
||||
"# @markdown \"description\": \"A short template for vertex sample dataset.\",\n",
|
||||
"# @markdown \"prompt_input\": \"{input_text}{output_text}\",\n",
|
||||
"# @markdown \"prompt_no_input\": \"{input_text}{output_text}\"\n",
|
||||
"# @markdown }\n",
|
||||
"# @markdown ```\n",
|
||||
"\n",
|
||||
"# @markdown As an example, the template above can be used to format the following training data (this line comes from `gs://cloud-samples-data/vertex-ai/model-evaluation/peft_train_sample.jsonl`):\n",
|
||||
"\n",
|
||||
"# @markdown ```\n",
|
||||
"# @markdown {\"input_text\":\"TRANSCRIPT: \\nREASON FOR EVALUATION:,\\n\\n LABEL:\",\"output_text\":\"Chiropractic\"}\n",
|
||||
"# @markdown ```\n",
|
||||
"\n",
|
||||
"# @markdown This example template simply concatenates `input_text` with `output_text`. You can set `template` to `vertex_sample` to try out this built-in template with the dataset `gs://cloud-samples-data/vertex-ai/model-evaluation/peft_train_sample.jsonl`, or build more complicated JSON templates such as [the alpaca example](https://github.com/tloen/alpaca-lora/blob/main/templates/alpaca.json). To use your own JSON template, [upload it to Google Cloud Storage](https://cloud.google.com/storage/docs/uploading-objects) and put the `gs://` URI in the `template` field below. Leave `instruct_column_in_dataset` as `text`.\n",
|
||||
"\n",
|
||||
"# Hugging Face dataset name or gs:// URI to a custom JSONL dataset.\n",
|
||||
"dataset_name = \"timdettmers/openassistant-guanaco\" # @param {type:\"string\"}\n",
|
||||
"\n",
|
||||
"# Name of the dataset column containing training text input.\n",
|
||||
"instruct_column_in_dataset = \"text\" # @param {type:\"string\"}\n",
|
||||
"\n",
|
||||
"# Optional. Template name or gs:// URI to a custom template.\n",
|
||||
"template = \"\" # @param {type:\"string\"}"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"cellView": "form",
|
||||
"id": "e1289e21a9d3"
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# @title Finetune with PEFT\n",
|
||||
"\n",
|
||||
"# @markdown This section demonstrates how to finetune the LLaMA 2 models with PEFT LoRA.\n",
|
||||
"\n",
|
||||
"# @markdown By default, the model will be finetuned for 500 steps on a batch size of 1 to save GPU resources.\n",
|
||||
"# @markdown Finetuning `llama2-7b` models is expected to take around 30 minutes.\n",
|
||||
"# @markdown To customize finetuning settings and parameters, click \"Show code\" to see more details.\n",
|
||||
"\n",
|
||||
"# @markdown Set the base model id.\n",
|
||||
"base_model_id = \"llama2-7b-hf\" # @param [\"llama2-7b-hf\", \"llama2-7b-chat-hf\", \"llama2-13b-hf\", \"llama2-13b-chat-hf\", \"llama2-70b-hf\", \"llama2-70b-chat-hf\"]\n",
|
||||
"model_id = os.path.join(MODEL_BUCKET, base_model_id)\n",
|
||||
"\n",
|
||||
"# @markdown Set the accelerator type.\n",
|
||||
"accelerator_type = \"NVIDIA_TESLA_V100\" # @param [\"NVIDIA_TESLA_V100\", \"NVIDIA_L4\", \"NVIDIA_TESLA_A100\"]\n",
|
||||
"\n",
|
||||
"# Worker pool spec.\n",
|
||||
"# Find Vertex AI supported accelerators and regions in:\n",
|
||||
"# https://cloud.google.com/vertex-ai/docs/training/configure-compute\n",
|
||||
"machine_type = None\n",
|
||||
"if \"7b\" in model_id:\n",
|
||||
" if accelerator_type == \"NVIDIA_TESLA_A100\":\n",
|
||||
" machine_type = \"a2-highgpu-1g\"\n",
|
||||
" accelerator_count = 1\n",
|
||||
" elif accelerator_type == \"NVIDIA_TESLA_V100\":\n",
|
||||
" machine_type = \"n1-standard-16\"\n",
|
||||
" accelerator_count = 2\n",
|
||||
" elif accelerator_type == \"NVIDIA_L4\":\n",
|
||||
" machine_type = \"g2-standard-8\"\n",
|
||||
" accelerator_count = 1\n",
|
||||
"elif \"13b\" in model_id:\n",
|
||||
" if accelerator_type == \"NVIDIA_TESLA_A100\":\n",
|
||||
" machine_type = \"a2-highgpu-1g\"\n",
|
||||
" accelerator_count = 1\n",
|
||||
" elif accelerator_type == \"NVIDIA_TESLA_V100\":\n",
|
||||
" machine_type = \"n1-standard-32\"\n",
|
||||
" accelerator_count = 4\n",
|
||||
" elif accelerator_type == \"NVIDIA_L4\":\n",
|
||||
" machine_type = \"g2-standard-24\"\n",
|
||||
" accelerator_count = 2\n",
|
||||
"elif \"70b\" in model_id:\n",
|
||||
" if accelerator_type == \"NVIDIA_TESLA_A100\":\n",
|
||||
" machine_type = \"a2-highgpu-4g\"\n",
|
||||
" accelerator_count = 4\n",
|
||||
" elif accelerator_type == \"NVIDIA_L4\":\n",
|
||||
" machine_type = \"g2-standard-96\"\n",
|
||||
" accelerator_count = 8\n",
|
||||
"\n",
|
||||
"if machine_type is None:\n",
|
||||
" raise ValueError(\n",
|
||||
" f\"Recommended machine settings not found for: {accelerator_type}. To use another another accelerator, edit this code block to set an appropriate `machine_type`, `accelerator_type`, and `accelerator_count` in worker_pool_specs.\"\n",
|
||||
" )\n",
|
||||
"\n",
|
||||
"common_util.check_quota(\n",
|
||||
" project_id=PROJECT_ID,\n",
|
||||
" region=REGION,\n",
|
||||
" accelerator_type=accelerator_type,\n",
|
||||
" accelerator_count=accelerator_count,\n",
|
||||
" is_for_training=True,\n",
|
||||
")\n",
|
||||
"\n",
|
||||
"job_name = get_job_name_with_datetime(\"llama2-train\")\n",
|
||||
"output_dir = os.path.join(EXPERIMENT_BUCKET, job_name)\n",
|
||||
"merge_job_name = get_job_name_with_datetime(\"llama2-merge\")\n",
|
||||
"merged_model_output_dir = os.path.join(EXPERIMENT_BUCKET, merge_job_name)\n",
|
||||
"finetune_precision_mode = \"float16\"\n",
|
||||
"\n",
|
||||
"replica_count = 1\n",
|
||||
"\n",
|
||||
"# Runs 500 training steps.\n",
|
||||
"max_steps = 500 # @param {type: \"integer\"}\n",
|
||||
"per_device_train_batch_size = 1\n",
|
||||
"# LoRA parameters.\n",
|
||||
"lora_rank = 16 # @param {type: \"integer\"}\n",
|
||||
"lora_alpha = 32\n",
|
||||
"lora_dropout = 0.05\n",
|
||||
"\n",
|
||||
"flags = {\n",
|
||||
" \"learning_rate\": 2e-4,\n",
|
||||
" \"precision_mode\": finetune_precision_mode,\n",
|
||||
" \"task\": \"instruct-lora\",\n",
|
||||
" \"per_device_train_batch_size\": per_device_train_batch_size,\n",
|
||||
" \"dataset_name\": dataset_name,\n",
|
||||
" \"instruct_column_in_dataset\": instruct_column_in_dataset,\n",
|
||||
" \"template\": template,\n",
|
||||
" \"pretrained_model_id\": model_id,\n",
|
||||
" \"output_dir\": output_dir,\n",
|
||||
" \"merge_base_and_lora_output_dir\": merged_model_output_dir,\n",
|
||||
" \"warmup_steps\": 10,\n",
|
||||
" \"max_steps\": max_steps,\n",
|
||||
" \"lora_rank\": lora_rank,\n",
|
||||
" \"lora_alpha\": lora_alpha,\n",
|
||||
" \"lora_dropout\": lora_dropout,\n",
|
||||
"}\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"# Add labels for the finetuning job.\n",
|
||||
"labels = {\n",
|
||||
" \"mg-source\": \"notebook\",\n",
|
||||
" \"mg-notebook-name\": \"model_garden_pytorch_llama2_peft_finetuning.ipynb\".split(\".\")[\n",
|
||||
" 0\n",
|
||||
" ],\n",
|
||||
"}\n",
|
||||
"\n",
|
||||
"labels[\"mg-tune\"] = \"publishers-meta-models-llama2\"\n",
|
||||
"versioned_model_id = base_model_id\n",
|
||||
"labels[\"versioned-mg-tune\"] = f\"{labels['mg-tune']}-{versioned_model_id}\"\n",
|
||||
"\n",
|
||||
"train_job = aiplatform.CustomJob(\n",
|
||||
" display_name=job_name,\n",
|
||||
" worker_pool_specs=[\n",
|
||||
" {\n",
|
||||
" \"machine_spec\": {\n",
|
||||
" \"machine_type\": machine_type,\n",
|
||||
" \"accelerator_type\": accelerator_type,\n",
|
||||
" \"accelerator_count\": accelerator_count,\n",
|
||||
" },\n",
|
||||
" \"replica_count\": replica_count,\n",
|
||||
" \"container_spec\": {\n",
|
||||
" \"image_uri\": TRAIN_DOCKER_URI,\n",
|
||||
" \"args\": [\"--{}={}\".format(k, v) for k, v in flags.items()],\n",
|
||||
" },\n",
|
||||
" }\n",
|
||||
" ],\n",
|
||||
" staging_bucket=STAGING_BUCKET,\n",
|
||||
" labels=labels,\n",
|
||||
")\n",
|
||||
"train_job.run()\n",
|
||||
"\n",
|
||||
"print(\"The finetuned models of different trials can be found at: \", output_dir)\n",
|
||||
"print(\n",
|
||||
" \"The finetuned model merged with the base model can be found at: \",\n",
|
||||
" merged_model_output_dir,\n",
|
||||
")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"cellView": "form",
|
||||
"id": "h0hGj09CuRFQ"
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# @title Deploy\n",
|
||||
"# @markdown This section uploads the model to Model Registry and deploys it on the Endpoint. It takes 15 minutes to 1 hour to finish.\n",
|
||||
"# @markdown Click \"Show code\" to see more details.\n",
|
||||
"\n",
|
||||
"print(\"Deploying models in: \", merged_model_output_dir)\n",
|
||||
"\n",
|
||||
"# The max_model_len must not exceed the model's context length.\n",
|
||||
"# A larger max_model_len will require more GPU memory.\n",
|
||||
"max_model_len = 2048\n",
|
||||
"# Worker pool spec.\n",
|
||||
"# Find Vertex AI supported accelerators and regions in:\n",
|
||||
"# https://cloud.google.com/vertex-ai/docs/training/configure-compute\n",
|
||||
"machine_type = None\n",
|
||||
"accelerator_type = \"NVIDIA_L4\" # @param [\"NVIDIA_L4\", \"NVIDIA_TESLA_V100\", \"NVIDIA_TESLA_A100\", \"NVIDIA_H100_80GB\"]\n",
|
||||
"\n",
|
||||
"if \"7b\" in model_id:\n",
|
||||
" if accelerator_type == \"NVIDIA_TESLA_A100\":\n",
|
||||
" machine_type = \"a2-highgpu-1g\"\n",
|
||||
" accelerator_count = 1\n",
|
||||
" elif accelerator_type == \"NVIDIA_TESLA_V100\":\n",
|
||||
" machine_type = \"n1-standard-8\"\n",
|
||||
" accelerator_count = 1\n",
|
||||
" elif accelerator_type == \"NVIDIA_L4\":\n",
|
||||
" machine_type = \"g2-standard-8\"\n",
|
||||
" accelerator_count = 1\n",
|
||||
"elif \"13b\" in model_id:\n",
|
||||
" if accelerator_type == \"NVIDIA_TESLA_A100\":\n",
|
||||
" machine_type = \"a2-highgpu-1g\"\n",
|
||||
" accelerator_count = 1\n",
|
||||
" elif accelerator_type == \"NVIDIA_TESLA_V100\":\n",
|
||||
" machine_type = \"n1-standard-16\"\n",
|
||||
" accelerator_count = 2\n",
|
||||
" elif accelerator_type == \"NVIDIA_L4\":\n",
|
||||
" machine_type = \"g2-standard-24\"\n",
|
||||
" accelerator_count = 2\n",
|
||||
"elif \"70b\" in model_id:\n",
|
||||
" if accelerator_type == \"NVIDIA_TESLA_A100\":\n",
|
||||
" machine_type = \"a2-highgpu-4g\"\n",
|
||||
" accelerator_count = 4\n",
|
||||
" elif accelerator_type == \"NVIDIA_L4\":\n",
|
||||
" machine_type = \"g2-standard-96\"\n",
|
||||
" accelerator_count = 8\n",
|
||||
" elif accelerator_type == \"NVIDIA_H100_80GB\":\n",
|
||||
" machine_type = \"a3-highgpu-4g\"\n",
|
||||
" accelerator_count = 4\n",
|
||||
"\n",
|
||||
"if machine_type is None:\n",
|
||||
" raise ValueError(\n",
|
||||
" f\"Recommended machine settings not found for: {accelerator_type}. To use another another accelerator, edit this code block to pass in an appropriate `machine_type`, `accelerator_type`, and `accelerator_count` to the deploy_model_vllm function.\"\n",
|
||||
" )\n",
|
||||
"\n",
|
||||
"model, endpoint = deploy_model_vllm(\n",
|
||||
" model_name=get_job_name_with_datetime(prefix=\"llama-vllm-serve\"),\n",
|
||||
" model_id=merged_model_output_dir,\n",
|
||||
" service_account=SERVICE_ACCOUNT,\n",
|
||||
" machine_type=machine_type,\n",
|
||||
" accelerator_type=accelerator_type,\n",
|
||||
" accelerator_count=accelerator_count,\n",
|
||||
" max_model_len=max_model_len,\n",
|
||||
")\n",
|
||||
"print(\"endpoint_name:\", endpoint.name)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"cellView": "form",
|
||||
"id": "vgU_qYHNuy3w"
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# @title Predict\n",
|
||||
"# @markdown Once deployment succeeds, you can send requests to the endpoint with text prompts.\n",
|
||||
"\n",
|
||||
"# @markdown Here we use an example from the [timdettmers/openassistant-guanaco](https://huggingface.co/datasets/timdettmers/openassistant-guanaco) to show the finetuning outcome:\n",
|
||||
"\n",
|
||||
"# @markdown ```\n",
|
||||
"# @markdown ### Human: How would the Future of AI in 10 Years look?### Assistant: Predicting the future is always a challenging task, but here are some possible ways that AI could evolve over the next 10 years: Continued advancements in deep learning: Deep learning has been one of the main drivers of recent AI breakthroughs, and we can expect continued advancements in this area. This may include improvements to existing algorithms, as well as the development of new architectures that are better suited to specific types of data and tasks. Increased use of AI in healthcare: AI has the potential to revolutionize healthcare, by improving the accuracy of diagnoses, developing new treatments, and personalizing patient care. We can expect to see continued investment in this area, with more healthcare providers and researchers using AI to improve patient outcomes. Greater automation in the workplace: Automation is already transforming many industries, and AI is likely to play an increasingly important role in this process. We can expect to see more jobs being automated, as well as the development of new types of jobs that require a combination of human and machine skills. More natural and intuitive interactions with technology: As AI becomes more advanced, we can expect to see more natural and intuitive ways of interacting with technology. This may include voice and gesture recognition, as well as more sophisticated chatbots and virtual assistants. Increased focus on ethical considerations: As AI becomes more powerful, there will be a growing need to consider its ethical implications. This may include issues such as bias in AI algorithms, the impact of automation on employment, and the use of AI in surveillance and policing. Overall, the future of AI in 10 years is likely to be shaped by a combination of technological advancements, societal changes, and ethical considerations. While there are many exciting possibilities for AI in the future, it will be important to carefully consider its potential impact on society and to work towards ensuring that its benefits are shared fairly and equitably.\n",
|
||||
"# @markdown ```\n",
|
||||
"\n",
|
||||
"# @markdown Additionally, you can moderate the generated text with Vertex AI. See [Moderate text documentation](https://cloud.google.com/natural-language/docs/moderating-text) for more details.\n",
|
||||
"\n",
|
||||
"# Loads an existing endpoint instance using the endpoint name:\n",
|
||||
"# - Using `endpoint_name = endpoint.name` allows us to get the\n",
|
||||
"# endpoint name of the endpoint `endpoint` created in the cell\n",
|
||||
"# above.\n",
|
||||
"# - Alternatively, you can set `endpoint_name = \"1234567890123456789\"` to load\n",
|
||||
"# an existing endpoint with the ID 1234567890123456789.\n",
|
||||
"# You may uncomment the code below to load an existing endpoint.\n",
|
||||
"\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",
|
||||
"\n",
|
||||
"prompt = \"How would the Future of AI in 10 Years look?\" # @param {type: \"string\"}\n",
|
||||
"max_tokens = 128 # @param {type:\"integer\"}\n",
|
||||
"temperature = 1.0 # @param {type:\"number\"}\n",
|
||||
"top_p = 0.9 # @param {type:\"number\"}\n",
|
||||
"top_k = 1 # @param {type:\"integer\"}\n",
|
||||
"\n",
|
||||
"# Overrides max_tokens and top_k parameters during inferences.\n",
|
||||
"# If you encounter the issue like `ServiceUnavailable: 503 Took too long to respond when processing`,\n",
|
||||
"# you can reduce the max length, such as set max_tokens as 20.\n",
|
||||
"instances = [\n",
|
||||
" {\n",
|
||||
" \"prompt\": f\"### Human: {prompt}### Assistant: \",\n",
|
||||
" \"max_tokens\": max_tokens,\n",
|
||||
" \"temperature\": temperature,\n",
|
||||
" \"top_p\": top_p,\n",
|
||||
" \"top_k\": top_k,\n",
|
||||
" },\n",
|
||||
"]\n",
|
||||
"response = endpoint.predict(instances=instances)\n",
|
||||
"\n",
|
||||
"for prediction in response.predictions:\n",
|
||||
" print(prediction)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"cellView": "form",
|
||||
"id": "911406c1561e"
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# @title Clean up resources\n",
|
||||
"\n",
|
||||
"# @markdown Delete the experiment models and endpoints to recycle the resources\n",
|
||||
"# @markdown and avoid unnecessary continuous charges that may incur.\n",
|
||||
"\n",
|
||||
"if train_job._gca_resource.name:\n",
|
||||
" # Training job is submitted.\n",
|
||||
" train_job.delete()\n",
|
||||
"\n",
|
||||
"# Undeploy model and delete endpoint.\n",
|
||||
"endpoint.delete(force=True)\n",
|
||||
"\n",
|
||||
"# Delete model.\n",
|
||||
"model.delete()\n",
|
||||
"\n",
|
||||
"# Delete Cloud Storage objects that were created.\n",
|
||||
"delete_bucket = False # @param {type:\"boolean\"}\n",
|
||||
"if delete_bucket:\n",
|
||||
" ! gsutil -m rm -r $BUCKET_URI"
|
||||
]
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"colab": {
|
||||
"name": "model_garden_pytorch_llama2_peft_finetuning.ipynb",
|
||||
"toc_visible": true
|
||||
},
|
||||
"kernelspec": {
|
||||
"display_name": "Python 3",
|
||||
"name": "python3"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 0
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -1,857 +0,0 @@
|
||||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"cellView": "form",
|
||||
"id": "7d9bbf86da5e"
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Copyright 2026 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": "99c1c3fc2ca5"
|
||||
},
|
||||
"source": [
|
||||
"# Vertex AI Model Garden - Llama 3 Finetuning\n",
|
||||
"\n",
|
||||
"<table><tbody><tr>\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%2Fcommunity%2Fmodel_garden%2Fmodel_garden_pytorch_llama3_finetuning.ipynb\">\n",
|
||||
" <img alt=\"Google Cloud Colab Enterprise logo\" src=\"https://lh3.googleusercontent.com/JmcxdQi-qOpctIvWKgPtrzZdJJK-J3sWE1RsfjZNwshCFgE_9fULcNpuXYTilIR2hjwN\" width=\"32px\"><br> Run in Colab Enterprise\n",
|
||||
" </a>\n",
|
||||
" </td>\n",
|
||||
" <td style=\"text-align: center\">\n",
|
||||
" <a href=\"https://github.com/GoogleCloudPlatform/vertex-ai-samples/blob/main/notebooks/community/model_garden/model_garden_pytorch_llama3_finetuning.ipynb\">\n",
|
||||
" <img alt=\"GitHub logo\" src=\"https://github.githubassets.com/assets/GitHub-Mark-ea2971cee799.png\" width=\"32px\"><br> View on GitHub\n",
|
||||
" </a>\n",
|
||||
" </td>\n",
|
||||
"</tr></tbody></table>"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "3de7470326a2"
|
||||
},
|
||||
"source": [
|
||||
"## Overview\n",
|
||||
"\n",
|
||||
"This notebook demonstrates finetuning and deploying Llama 3 models with Vertex AI. All of the examples in this notebook use parameter efficient finetuning methods [PEFT (LoRA)](https://github.com/huggingface/peft) to reduce training and storage costs. LoRA (Low-Rank Adaptation) is one approach of Parameter Efficient FineTuning (PEFT), where pretrained model weights are frozen and rank decomposition matrices representing the change in model weights are trained during finetuning. Read more about LoRA in the following publication: [Hu, E.J., Shen, Y., Wallis, P., Allen-Zhu, Z., Li, Y., Wang, S., Wang, L. and Chen, W., 2021. Lora: Low-rank adaptation of large language models. *arXiv preprint arXiv:2106.09685*](https://arxiv.org/abs/2106.09685).\n",
|
||||
"\n",
|
||||
"After finetuning, we can deploy models on Vertex with GPU.\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"### Objective\n",
|
||||
"\n",
|
||||
"- Finetune Llama 3 models with Vertex AI Custom Training Jobs.\n",
|
||||
"- Deploy finetuned Llama 3 models on Vertex AI Prediction.\n",
|
||||
"- Send prediction requests to your finetuned Llama 3 models.\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"### Costs\n",
|
||||
"\n",
|
||||
"This tutorial uses billable components of Google Cloud:\n",
|
||||
"\n",
|
||||
"* Vertex AI\n",
|
||||
"* Cloud Storage\n",
|
||||
"\n",
|
||||
"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."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "264c07757582"
|
||||
},
|
||||
"source": [
|
||||
"## Before you begin"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"cellView": "form",
|
||||
"id": "855d6b96f291"
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# @title Setup Google Cloud project\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]** [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",
|
||||
"BUCKET_URI = \"gs://\" # @param {type:\"string\"}\n",
|
||||
"\n",
|
||||
"# @markdown 3. **[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 4. 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",
|
||||
"# @markdown 5. [Make sure that you have GPU quota for Vertex Training (finetuing) and Vertex Prediction (serving)](https://cloud.google.com/docs/quotas/view-manage). The quota name for Vertex Training is \"Custom model training your-gpu-type per region\" and the quota name for Vertex Prediction is \"Custom model serving your-gpu-type per region\" such as `Custom model training Nvidia L4 GPUs per region` and `Custom model serving Nvidia L4 GPUs per region` for L4 GPUs. [Submit a quota increase request](https://cloud.google.com/docs/quotas/view-manage#requesting_higher_quota) if additional quota is needed. At minimum, running this notebook requires 4 L4s for finetuning and 1 L4 for serving. More GPUs may be needed for larger models and different finetuning configurations. To secure GPUs for larger models, ask your customer engineer to get you allowlisted for a Shared Reservation or a Dynamic Workload Scheduler.\n",
|
||||
"\n",
|
||||
"# Import the necessary packages\n",
|
||||
"# Upgrade Vertex AI SDK.\n",
|
||||
"! pip3 install --upgrade --quiet 'google-cloud-aiplatform>=1.64.0'\n",
|
||||
"! git clone https://github.com/GoogleCloudPlatform/vertex-ai-samples.git\n",
|
||||
"\n",
|
||||
"import datetime\n",
|
||||
"import importlib\n",
|
||||
"import os\n",
|
||||
"import uuid\n",
|
||||
"from typing import Tuple\n",
|
||||
"\n",
|
||||
"from google.cloud import aiplatform\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",
|
||||
"models, endpoints = {}, {}\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",
|
||||
" if not os.environ.get(\"GOOGLE_CLOUD_REGION\"):\n",
|
||||
" raise ValueError(\n",
|
||||
" \"REGION must be set. See\"\n",
|
||||
" \" https://cloud.google.com/vertex-ai/docs/general/locations for\"\n",
|
||||
" \" available cloud locations.\"\n",
|
||||
" )\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",
|
||||
"# 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.datetime.now().strftime(\"%Y%m%d%H%M%S\")\n",
|
||||
"BUCKET_NAME = \"/\".join(BUCKET_URI.split(\"/\")[:3])\n",
|
||||
"\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, \"llama3\")\n",
|
||||
"\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",
|
||||
"# 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",
|
||||
"# 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",
|
||||
"! gcloud projects add-iam-policy-binding --no-user-output-enabled {PROJECT_ID} --member=serviceAccount:{SERVICE_ACCOUNT} --role=\"roles/storage.admin\"\n",
|
||||
"! gcloud projects add-iam-policy-binding --no-user-output-enabled {PROJECT_ID} --member=serviceAccount:{SERVICE_ACCOUNT} --role=\"roles/aiplatform.user\""
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"cellView": "form",
|
||||
"id": "36c21f10355f"
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# @title Access Llama 3 models\n",
|
||||
"\n",
|
||||
"# @markdown For GPU based finetuning and serving, choose between accessing Llama 3 models on [Hugging Face](https://huggingface.co/)\n",
|
||||
"# @markdown or Vertex AI as described below.\n",
|
||||
"\n",
|
||||
"# @markdown If you already obtained access to Llama 3 models on [Hugging Face](https://huggingface.co/), you can load models from there.\n",
|
||||
"# @markdown Alternatively, you can also load the original Llama 3 models for finetuning and serving from Vertex AI after accepting the agreement.\n",
|
||||
"\n",
|
||||
"# @markdown **Only select and fill one of the following sections.**\n",
|
||||
"# fmt: off\n",
|
||||
"LOAD_MODEL_FROM = \"Hugging Face\" # @param [\"Hugging Face\", \"Google Cloud\"] {isTemplate:true}\n",
|
||||
"# fmt: on\n",
|
||||
"\n",
|
||||
"# @markdown ---\n",
|
||||
"\n",
|
||||
"# @markdown ### Access Llama 3 models on Hugging Face for GPU based finetuning and serving\n",
|
||||
"# @markdown You must provide a Hugging Face User Access Token (with read access) to access the Llama 3 models. You can follow the [Hugging Face documentation](https://huggingface.co/docs/hub/en/security-tokens) to create a **read** access token and put it in the `HF_TOKEN` field below.\n",
|
||||
"\n",
|
||||
"HF_TOKEN = \"\" # @param {type:\"string\", isTemplate:true}\n",
|
||||
"if LOAD_MODEL_FROM == \"Hugging Face\":\n",
|
||||
" assert (\n",
|
||||
" HF_TOKEN\n",
|
||||
" ), \"Provide a read HF_TOKEN to load models from Hugging Face, or select a different model source.\"\n",
|
||||
"\n",
|
||||
"# @markdown *--- Or ---*\n",
|
||||
"# @markdown ### Access Llama 3 models on Vertex AI for GPU based serving\n",
|
||||
"# @markdown The original models from Meta are converted into the Hugging Face format for serving in Vertex AI.\n",
|
||||
"# @markdown Accept the model agreement to access the models:\n",
|
||||
"# @markdown 1. Open the [Llama 3 model card](https://console.cloud.google.com/vertex-ai/publishers/meta/model-garden/llama3) from [Vertex AI Model Garden](https://cloud.google.com/model-garden).\n",
|
||||
"# @markdown 2. Review and accept the agreement in the pop-up window on the model card page. If you have previously accepted the model agreement, there will not be a pop-up window on the model card page and this step is not needed.\n",
|
||||
"# @markdown 3. After accepting the agreement of Llama 3, a `gs://` URI containing Llama 3 pretrained and finetuned models will be shared.\n",
|
||||
"# @markdown 4. Paste the URI in the `VERTEX_AI_MODEL_GARDEN_LLAMA3` field below.\n",
|
||||
"\n",
|
||||
"VERTEX_AI_MODEL_GARDEN_LLAMA3 = \"\" # @param {type:\"string\", isTemplate:true}\n",
|
||||
"\n",
|
||||
"if LOAD_MODEL_FROM == \"Google Cloud\":\n",
|
||||
" assert (\n",
|
||||
" VERTEX_AI_MODEL_GARDEN_LLAMA3\n",
|
||||
" ), \"Click the agreement of Llama 3 in Vertex AI Model Garden, and get the GCS path of Llama 3 model artifacts.\"\n",
|
||||
" print(\n",
|
||||
" \"Copying Llama 3 model artifacts from\",\n",
|
||||
" VERTEX_AI_MODEL_GARDEN_LLAMA3,\n",
|
||||
" \"to \",\n",
|
||||
" MODEL_BUCKET,\n",
|
||||
" )\n",
|
||||
" HF_TOKEN = \"\"\n",
|
||||
"\n",
|
||||
" ! gsutil -m cp -R $VERTEX_AI_MODEL_GARDEN_LLAMA3/* $MODEL_BUCKET\n",
|
||||
"\n",
|
||||
"# @markdown ---"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "cb56d402e84a"
|
||||
},
|
||||
"source": [
|
||||
"## Finetune with HuggingFace PEFT and deploy with vLLM on GPUs"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"cellView": "form",
|
||||
"id": "KwAW99YZHTdy"
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# @title Set dataset\n",
|
||||
"\n",
|
||||
"# @markdown Use the Vertex AI SDK to create and run the custom training jobs.\n",
|
||||
"\n",
|
||||
"# @markdown This notebook uses [timdettmers/openassistant-guanaco](https://huggingface.co/datasets/timdettmers/openassistant-guanaco) dataset as an example.\n",
|
||||
"# @markdown You can set `dataset_name` to any existing [Hugging Face dataset](https://huggingface.co/datasets) name, and set `instruct_column_in_dataset` to the name of the dataset column containing training data. The [timdettmers/openassistant-guanaco](https://huggingface.co/datasets/timdettmers/openassistant-guanaco) has only one column `text`, and therefore we set `instruct_column_in_dataset` to `text` in this notebook.\n",
|
||||
"\n",
|
||||
"# @markdown ### (Optional) Prepare a custom JSONL dataset for finetuning\n",
|
||||
"\n",
|
||||
"# @markdown You can prepare a JSONL file where each line is a valid JSON string as your custom training dataset. For example, here is one line from the [timdettmers/openassistant-guanaco](https://huggingface.co/datasets/timdettmers/openassistant-guanaco) dataset:\n",
|
||||
"# @markdown ```\n",
|
||||
"# @markdown {\"text\": \"### Human: Hola### Assistant: \\u00a1Hola! \\u00bfEn qu\\u00e9 puedo ayudarte hoy?\"}\n",
|
||||
"# @markdown ```\n",
|
||||
"\n",
|
||||
"# @markdown The JSON object has a key `text`, which should match `instruct_column_in_dataset`; The value should be one training data point, i.e. a string. After you prepared your JSONL file, you can either upload it to [Hugging Face datasets](https://huggingface.co/datasets) or [Google Cloud Storage](https://cloud.google.com/storage).\n",
|
||||
"\n",
|
||||
"# @markdown - To upload a JSONL dataset to [Hugging Face datasets](https://huggingface.co/datasets), follow the instructions on [Uploading Datasets](https://huggingface.co/docs/hub/en/datasets-adding). Then, set `dataset_name` to the name of your newly created dataset on Hugging Face.\n",
|
||||
"\n",
|
||||
"# @markdown - To upload a JSONL dataset to [Google Cloud Storage](https://cloud.google.com/storage), follow the instructions on [Upload objects from a filesystem](https://cloud.google.com/storage/docs/uploading-objects). Then, set `dataset_name` to the `gs://` URI to your JSONL file. For example: `gs://cloud-samples-data/vertex-ai/model-evaluation/peft_train_sample.jsonl`.\n",
|
||||
"\n",
|
||||
"# @markdown Optionally update the `instruct_column_in_dataset` field below if your JSON objects use a key other than the default `text`.\n",
|
||||
"\n",
|
||||
"# @markdown ### (Optional) Format your data with custom JSON template\n",
|
||||
"\n",
|
||||
"# @markdown Sometimes, your dataset might have multiple text columns and you want to construct the training data with a template. You can prepare a JSON template in the following format:\n",
|
||||
"\n",
|
||||
"# @markdown ```\n",
|
||||
"# @markdown {\n",
|
||||
"# @markdown \"description\": \"Template used by Llama 3, accepting text-bison format.\",\n",
|
||||
"# @markdown \"source\": \"https://cloud.google.com/vertex-ai/generative-ai/docs/models/tune-text-models-supervised#dataset-format\",\n",
|
||||
"# @markdown \"prompt_input\": \"<|start_header_id|>user<|end_header_id|>\\n\\n{input_text}<|eot_id|><|start_header_id|>assistant<|end_header_id|>\\n\\n{output_text}<|eot_id|>\",\n",
|
||||
"# @markdown \"instruction_separator\": \"<|start_header_id|>user<|end_header_id|>\\n\\n\",\n",
|
||||
"# @markdown \"response_separator\": \"<|start_header_id|>assistant<|end_header_id|>\\n\\n\"\n",
|
||||
"# @markdown }\n",
|
||||
"# @markdown ```\n",
|
||||
"\n",
|
||||
"# @markdown As an example, the template above can be used to format the following training data (this line comes from `gs://cloud-samples-data/vertex-ai/model-evaluation/peft_train_sample.jsonl`):\n",
|
||||
"\n",
|
||||
"# @markdown ```\n",
|
||||
"# @markdown {\"input_text\":\"TRANSCRIPT: \\nREASON FOR EVALUATION:,\\n\\n LABEL:\",\"output_text\":\"Chiropractic\"}\n",
|
||||
"# @markdown ```\n",
|
||||
"\n",
|
||||
"# @markdown This example template simply concatenates `input_text` with `output_text` with some special tokens in between.\n",
|
||||
"# @markdown\n",
|
||||
"# @markdown To try such custom dataset, you can make the following changes:\n",
|
||||
"# @markdown 1. Set `template` to `llama3-text-bison`\n",
|
||||
"# @markdown 1. Set `train_dataset_name` to `gs://cloud-samples-data/vertex-ai/model-evaluation/peft_train_sample.jsonl`\n",
|
||||
"# @markdown 1. Set `train_split_name` to `train`\n",
|
||||
"# @markdown 1. Set `eval_dataset_name` to `gs://cloud-samples-data/vertex-ai/model-evaluation/peft_eval_sample.jsonl`\n",
|
||||
"# @markdown 1. Set `eval_split_name` to `train` (**NOT** `test`)\n",
|
||||
"# @markdown 1. Set `instruct_column_in_dataset` as `input_text`.\n",
|
||||
"\n",
|
||||
"# Template name or gs:// URI to a custom template.\n",
|
||||
"template = \"openassistant-guanaco\" # @param {type:\"string\"}\n",
|
||||
"\n",
|
||||
"# Hugging Face dataset name or gs:// URI to a custom JSONL dataset.\n",
|
||||
"train_dataset_name = \"timdettmers/openassistant-guanaco\" # @param {type:\"string\"}\n",
|
||||
"train_split_name = \"train\" # @param {type:\"string\"}\n",
|
||||
"eval_dataset_name = \"timdettmers/openassistant-guanaco\" # @param {type:\"string\"}\n",
|
||||
"eval_split_name = \"test\" # @param {type:\"string\"}\n",
|
||||
"\n",
|
||||
"# Name of the dataset column containing training text input.\n",
|
||||
"instruct_column_in_dataset = \"text\" # @param {type:\"string\"}"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"cellView": "form",
|
||||
"id": "ivVGS9dHXPOz"
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# @title Finetune\n",
|
||||
"# @markdown Use the Vertex AI SDK to create and run the custom training jobs.\n",
|
||||
"\n",
|
||||
"# @markdown **Note**:\n",
|
||||
"# @markdown 1. We recommend setting `finetuning_precision_mode` to `4bit` because it enables using fewer hardware resources for finetuning.\n",
|
||||
"# @markdown 1. We recommend using NVIDIA_L4 for 8B models and NVIDIA_A100_80GB for 70B models.\n",
|
||||
"# @markdown 1. If `max_steps>0`, it will precedence over `epochs`. One can set a small `max_steps` value to quickly check the pipeline.\n",
|
||||
"# @markdown 1. With the default setting, training takes between 1.5 ~ 2 hours.\n",
|
||||
"\n",
|
||||
"TRAIN_DOCKER_URI = \"us-docker.pkg.dev/vertex-ai/vertex-vision-model-garden-dockers/pytorch-peft-train:stable_20240909\"\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"# The Llama 3 base model.\n",
|
||||
"MODEL_ID = \"meta-llama/Meta-Llama-3-8B-Instruct\" # @param [\"meta-llama/Meta-Llama-3-8B\", \"meta-llama/Meta-Llama-3-8B-Instruct\", \"meta-llama/Meta-Llama-3-70B\", \"meta-llama/Meta-Llama-3-70B-Instruct\"] {isTemplate:true}\n",
|
||||
"if LOAD_MODEL_FROM == \"Google Cloud\":\n",
|
||||
" if MODEL_ID == \"meta-llama/Meta-Llama-3-8B\":\n",
|
||||
" base_model_id = \"llama3-8b-hf\"\n",
|
||||
" elif MODEL_ID == \"meta-llama/Meta-Llama-3-8B-Instruct\":\n",
|
||||
" base_model_id = \"llama3-8b-chat-hf\"\n",
|
||||
" elif MODEL_ID == \"meta-llama/Meta-Llama-3-70B\":\n",
|
||||
" base_model_id = \"llama3-70b-hf\"\n",
|
||||
" elif MODEL_ID == \"meta-llama/Meta-Llama-3-70B-Instruct\":\n",
|
||||
" base_model_id = \"llama3-70b-chat-hf\"\n",
|
||||
" else:\n",
|
||||
" raise ValueError(f\"Undefined model ID: {MODEL_ID}.\")\n",
|
||||
" base_model_id = os.path.join(MODEL_BUCKET, base_model_id)\n",
|
||||
"else:\n",
|
||||
" base_model_id = MODEL_ID\n",
|
||||
"\n",
|
||||
"# The accelerator to use.\n",
|
||||
"accelerator_type = \"NVIDIA_L4\" # @param [\"NVIDIA_L4\", \"NVIDIA_A100_80GB\"]\n",
|
||||
"\n",
|
||||
"# Batch size for finetuning.\n",
|
||||
"per_device_train_batch_size = 1 # @param{type:\"integer\"}\n",
|
||||
"gradient_accumulation_steps = 8 # @param{type:\"integer\"}\n",
|
||||
"# Maximum sequence length.\n",
|
||||
"max_seq_length = 4096 # @param{type:\"integer\"}\n",
|
||||
"# Setting a positive `max_steps` here will override `num_epochs`\n",
|
||||
"max_steps = -1 # @param{type:\"integer\"}\n",
|
||||
"num_epochs = 1.0 # @param{type:\"number\"}\n",
|
||||
"# Precision mode for finetuning.\n",
|
||||
"finetuning_precision_mode = \"4bit\" # @param [\"4bit\", \"8bit\", \"float16\"]\n",
|
||||
"# Learning rate.\n",
|
||||
"learning_rate = 5e-5 # @param{type:\"number\"}\n",
|
||||
"lr_scheduler_type = \"cosine\" # @param{type:\"string\"}\n",
|
||||
"# LoRA parameters.\n",
|
||||
"lora_rank = 16 # @param{type:\"integer\"}\n",
|
||||
"lora_alpha = 32 # @param{type:\"integer\"}\n",
|
||||
"lora_dropout = 0.05 # @param{type:\"number\"}\n",
|
||||
"enable_gradient_checkpointing = True\n",
|
||||
"attn_implementation = \"flash_attention_2\"\n",
|
||||
"optimizer = \"paged_adamw_32bit\"\n",
|
||||
"warmup_ratio = \"0.01\"\n",
|
||||
"report_to = \"tensorboard\"\n",
|
||||
"save_steps = 10\n",
|
||||
"logging_steps = save_steps\n",
|
||||
"\n",
|
||||
"# Worker pool spec.\n",
|
||||
"machine_type = None\n",
|
||||
"if \"8b\" in MODEL_ID.lower():\n",
|
||||
" if accelerator_type == \"NVIDIA_L4\":\n",
|
||||
" accelerator_count = 4\n",
|
||||
" machine_type = \"g2-standard-48\"\n",
|
||||
" else:\n",
|
||||
" raise ValueError(\n",
|
||||
" f\"Recommended machine settings not found for: {accelerator_type}. To use another accelerator, edit this code block to pass in an appropriate `machine_type`, `accelerator_type`, and `accelerator_count` to the deploy_model_vllm function by clicking `Show Code` and then modifying the code.\"\n",
|
||||
" )\n",
|
||||
"elif \"70b\" in MODEL_ID.lower():\n",
|
||||
" if accelerator_type == \"NVIDIA_A100_80GB\":\n",
|
||||
" accelerator_count = 4\n",
|
||||
" machine_type = \"a2-ultragpu-4g\"\n",
|
||||
" else:\n",
|
||||
" raise ValueError(\n",
|
||||
" f\"Recommended machine settings not found for: {accelerator_type}. To use another accelerator, edit this code block to pass in an appropriate `machine_type`, `accelerator_type`, and `accelerator_count` to the deploy_model_vllm function by clicking `Show Code` and then modifying the code.\"\n",
|
||||
" )\n",
|
||||
"else:\n",
|
||||
" raise ValueError(f\"Unsupported model ID or GCS path: {MODEL_ID}.\")\n",
|
||||
"\n",
|
||||
"replica_count = 1\n",
|
||||
"\n",
|
||||
"common_util.check_quota(\n",
|
||||
" project_id=PROJECT_ID,\n",
|
||||
" region=REGION,\n",
|
||||
" accelerator_type=accelerator_type,\n",
|
||||
" accelerator_count=accelerator_count,\n",
|
||||
" is_for_training=True,\n",
|
||||
")\n",
|
||||
"\n",
|
||||
"job_name = common_util.get_job_name_with_datetime(\"llama3-lora-train\")\n",
|
||||
"\n",
|
||||
"base_output_dir = os.path.join(STAGING_BUCKET, job_name)\n",
|
||||
"# Create a GCS folder to store the LORA adapter.\n",
|
||||
"lora_output_dir = os.path.join(base_output_dir, \"adapter\")\n",
|
||||
"# Create a GCS folder to store the merged model with the base model and the\n",
|
||||
"# finetuned LORA adapter.\n",
|
||||
"merged_model_output_dir = os.path.join(base_output_dir, \"merged-model\")\n",
|
||||
"\n",
|
||||
"# Add labels for the finetuning job.\n",
|
||||
"labels = {\n",
|
||||
" \"mg-source\": \"notebook\",\n",
|
||||
" \"mg-notebook-name\": \"model_garden_pytorch_llama3_finetuning.ipynb\".split(\".\")[0],\n",
|
||||
"}\n",
|
||||
"\n",
|
||||
"labels[\"mg-tune\"] = \"publishers-meta-models-llama3\"\n",
|
||||
"versioned_model_id = base_model_id.split(\"/\")[1].lower().replace(\".\", \"-\")\n",
|
||||
"labels[\"versioned-mg-tune\"] = f\"{labels['mg-tune']}-{versioned_model_id}\"\n",
|
||||
"\n",
|
||||
"eval_args = [\n",
|
||||
" f\"--eval_dataset_path={eval_dataset_name}\",\n",
|
||||
" f\"--eval_column={instruct_column_in_dataset}\",\n",
|
||||
" f\"--eval_template={template}\",\n",
|
||||
" f\"--eval_split={eval_split_name}\",\n",
|
||||
" f\"--eval_steps={save_steps}\",\n",
|
||||
" \"--eval_tasks=builtin_eval\",\n",
|
||||
" \"--eval_metric_name=loss\",\n",
|
||||
"]\n",
|
||||
"\n",
|
||||
"train_job_args = [\n",
|
||||
" \"--config_file=vertex_vision_model_garden_peft/deepspeed_zero2_4gpu.yaml\",\n",
|
||||
" \"--task=instruct-lora\",\n",
|
||||
" \"--completion_only=True\",\n",
|
||||
" f\"--pretrained_model_id={base_model_id}\",\n",
|
||||
" f\"--dataset_name={train_dataset_name}\",\n",
|
||||
" f\"--train_split_name={train_split_name}\",\n",
|
||||
" f\"--instruct_column_in_dataset={instruct_column_in_dataset}\",\n",
|
||||
" f\"--output_dir={lora_output_dir}\",\n",
|
||||
" f\"--merge_base_and_lora_output_dir={merged_model_output_dir}\",\n",
|
||||
" f\"--per_device_train_batch_size={per_device_train_batch_size}\",\n",
|
||||
" f\"--gradient_accumulation_steps={gradient_accumulation_steps}\",\n",
|
||||
" f\"--lora_rank={lora_rank}\",\n",
|
||||
" f\"--lora_alpha={lora_alpha}\",\n",
|
||||
" f\"--lora_dropout={lora_dropout}\",\n",
|
||||
" f\"--max_steps={max_steps}\",\n",
|
||||
" f\"--max_seq_length={max_seq_length}\",\n",
|
||||
" f\"--learning_rate={learning_rate}\",\n",
|
||||
" f\"--lr_scheduler_type={lr_scheduler_type}\",\n",
|
||||
" f\"--precision_mode={finetuning_precision_mode}\",\n",
|
||||
" f\"--enable_gradient_checkpointing={enable_gradient_checkpointing}\",\n",
|
||||
" f\"--num_epochs={num_epochs}\",\n",
|
||||
" f\"--attn_implementation={attn_implementation}\",\n",
|
||||
" f\"--optimizer={optimizer}\",\n",
|
||||
" f\"--warmup_ratio={warmup_ratio}\",\n",
|
||||
" f\"--report_to={report_to}\",\n",
|
||||
" f\"--logging_output_dir={base_output_dir}\",\n",
|
||||
" f\"--save_steps={save_steps}\",\n",
|
||||
" f\"--logging_steps={logging_steps}\",\n",
|
||||
" f\"--template={template}\",\n",
|
||||
" f\"--huggingface_access_token={HF_TOKEN}\",\n",
|
||||
"] + eval_args\n",
|
||||
"\n",
|
||||
"# Create TensorBoard\n",
|
||||
"tensorboard = aiplatform.Tensorboard.create(job_name)\n",
|
||||
"exp = aiplatform.TensorboardExperiment.create(\n",
|
||||
" tensorboard_experiment_id=job_name, tensorboard_name=tensorboard.name\n",
|
||||
")\n",
|
||||
"\n",
|
||||
"# Pass training arguments and launch job.\n",
|
||||
"train_job = aiplatform.CustomContainerTrainingJob(\n",
|
||||
" display_name=job_name,\n",
|
||||
" container_uri=TRAIN_DOCKER_URI,\n",
|
||||
" labels=labels,\n",
|
||||
")\n",
|
||||
"\n",
|
||||
"train_job.run(\n",
|
||||
" args=train_job_args,\n",
|
||||
" environment_variables={\"WANDB_DISABLED\": True},\n",
|
||||
" replica_count=replica_count,\n",
|
||||
" machine_type=machine_type,\n",
|
||||
" accelerator_type=accelerator_type,\n",
|
||||
" accelerator_count=accelerator_count,\n",
|
||||
" boot_disk_size_gb=500,\n",
|
||||
" service_account=SERVICE_ACCOUNT,\n",
|
||||
" tensorboard=tensorboard.resource_name,\n",
|
||||
" base_output_dir=base_output_dir,\n",
|
||||
")\n",
|
||||
"\n",
|
||||
"print(\"LoRA adapter was saved in: \", lora_output_dir)\n",
|
||||
"print(\"Trained and merged models were saved in: \", merged_model_output_dir)\n",
|
||||
"\n",
|
||||
"# @markdown Click \"Show Code\" to see more details."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"cellView": "form",
|
||||
"id": "qmHW6m8xG_4U"
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# @title Deploy\n",
|
||||
"# @markdown This section uploads the model to Model Registry and deploys it on the Endpoint. It takes 15 minutes to 1 hour to finish.\n",
|
||||
"\n",
|
||||
"print(\"Deploying models in: \", merged_model_output_dir)\n",
|
||||
"\n",
|
||||
"# The pre-built serving docker image for vLLM.\n",
|
||||
"VLLM_DOCKER_URI = \"us-docker.pkg.dev/vertex-ai/vertex-vision-model-garden-dockers/pytorch-vllm-serve:20240721_0916_RC00\"\n",
|
||||
"\n",
|
||||
"accelerator_type = \"NVIDIA_H100_80GB\" # @param [\"NVIDIA_L4\", \"NVIDIA_H100_80GB\"]\n",
|
||||
"machine_type = None\n",
|
||||
"\n",
|
||||
"# @markdown Set `use_dedicated_endpoint` to False if you don't want to use [dedicated endpoint](https://cloud.google.com/vertex-ai/docs/general/deployment#create-dedicated-endpoint).\n",
|
||||
"use_dedicated_endpoint = True # @param {type:\"boolean\"}\n",
|
||||
"\n",
|
||||
"# Find Vertex AI prediction supported accelerators and regions in [here](https://cloud.google.com/vertex-ai/docs/predictions/configure-compute).\n",
|
||||
"if \"8b\" in MODEL_ID.lower():\n",
|
||||
" if accelerator_type == \"NVIDIA_L4\":\n",
|
||||
" machine_type = \"g2-standard-12\"\n",
|
||||
" accelerator_count = 1\n",
|
||||
" elif accelerator_type == \"NVIDIA_H100_80GB\":\n",
|
||||
" machine_type = \"a3-highgpu-2g\"\n",
|
||||
" accelerator_count = 2\n",
|
||||
"else:\n",
|
||||
" if accelerator_type == \"NVIDIA_L4\":\n",
|
||||
" machine_type = \"g2-standard-96\"\n",
|
||||
" accelerator_count = 8\n",
|
||||
" elif accelerator_type == \"NVIDIA_H100_80GB\":\n",
|
||||
" machine_type = \"a3-highgpu-4g\"\n",
|
||||
" accelerator_count = 4\n",
|
||||
"\n",
|
||||
"if machine_type is None:\n",
|
||||
" raise ValueError(\n",
|
||||
" f\"Recommended GPU setting not found for: {accelerator_type} and {MODEL_ID.lower()}.\"\n",
|
||||
" )\n",
|
||||
"\n",
|
||||
"common_util.check_quota(\n",
|
||||
" project_id=PROJECT_ID,\n",
|
||||
" region=REGION,\n",
|
||||
" accelerator_type=accelerator_type,\n",
|
||||
" accelerator_count=accelerator_count,\n",
|
||||
" is_for_training=False,\n",
|
||||
")\n",
|
||||
"\n",
|
||||
"gpu_memory_utilization = 0.85\n",
|
||||
"max_model_len = 8192 # Maximum context length.\n",
|
||||
"\n",
|
||||
"# Ensure max_model_len does not exceed the limit\n",
|
||||
"if max_model_len > 8192:\n",
|
||||
" raise ValueError(\"max_model_len cannot exceed 8192\")\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"def deploy_model_vllm(\n",
|
||||
" model_name: str,\n",
|
||||
" model_id: str,\n",
|
||||
" publisher: str,\n",
|
||||
" publisher_model_id: str,\n",
|
||||
" service_account: str,\n",
|
||||
" base_model_id: str = None,\n",
|
||||
" machine_type: str = \"g2-standard-8\",\n",
|
||||
" accelerator_type: str = \"NVIDIA_L4\",\n",
|
||||
" accelerator_count: int = 1,\n",
|
||||
" gpu_memory_utilization: float = 0.9,\n",
|
||||
" max_model_len: int = 4096,\n",
|
||||
" dtype: str = \"auto\",\n",
|
||||
" enable_trust_remote_code: bool = False,\n",
|
||||
" enforce_eager: bool = False,\n",
|
||||
" enable_lora: bool = False,\n",
|
||||
" enable_chunked_prefill: bool = False,\n",
|
||||
" enable_prefix_cache: bool = False,\n",
|
||||
" host_prefix_kv_cache_utilization_target: float = 0.0,\n",
|
||||
" max_loras: int = 1,\n",
|
||||
" max_cpu_loras: int = 8,\n",
|
||||
" use_dedicated_endpoint: bool = False,\n",
|
||||
" max_num_seqs: int = 256,\n",
|
||||
" model_type: str = None,\n",
|
||||
" enable_llama_tool_parser: bool = False,\n",
|
||||
") -> Tuple[aiplatform.Model, aiplatform.Endpoint]:\n",
|
||||
" \"\"\"Deploys trained models with vLLM into Vertex AI.\"\"\"\n",
|
||||
" endpoint = aiplatform.Endpoint.create(\n",
|
||||
" display_name=f\"{model_name}-endpoint\",\n",
|
||||
" dedicated_endpoint_enabled=use_dedicated_endpoint,\n",
|
||||
" )\n",
|
||||
"\n",
|
||||
" if not base_model_id:\n",
|
||||
" base_model_id = model_id\n",
|
||||
"\n",
|
||||
" # See https://docs.vllm.ai/en/latest/models/engine_args.html for a list of possible arguments with descriptions.\n",
|
||||
" vllm_args = [\n",
|
||||
" \"python\",\n",
|
||||
" \"-m\",\n",
|
||||
" \"vllm.entrypoints.api_server\",\n",
|
||||
" \"--host=0.0.0.0\",\n",
|
||||
" \"--port=8080\",\n",
|
||||
" f\"--model={model_id}\",\n",
|
||||
" f\"--tensor-parallel-size={accelerator_count}\",\n",
|
||||
" \"--swap-space=16\",\n",
|
||||
" f\"--max-model-len={max_model_len}\",\n",
|
||||
" f\"--dtype={dtype}\",\n",
|
||||
" f\"--max-loras={max_loras}\",\n",
|
||||
" f\"--max-cpu-loras={max_cpu_loras}\",\n",
|
||||
" f\"--max-num-seqs={max_num_seqs}\",\n",
|
||||
" \"--disable-log-stats\",\n",
|
||||
" ]\n",
|
||||
"\n",
|
||||
" if gpu_memory_utilization:\n",
|
||||
" vllm_args.append(f\"--gpu-memory-utilization={gpu_memory_utilization}\")\n",
|
||||
"\n",
|
||||
" if enable_trust_remote_code:\n",
|
||||
" vllm_args.append(\"--trust-remote-code\")\n",
|
||||
"\n",
|
||||
" if enforce_eager:\n",
|
||||
" vllm_args.append(\"--enforce-eager\")\n",
|
||||
"\n",
|
||||
" if enable_lora:\n",
|
||||
" vllm_args.append(\"--enable-lora\")\n",
|
||||
"\n",
|
||||
" if enable_chunked_prefill:\n",
|
||||
" vllm_args.append(\"--enable-chunked-prefill\")\n",
|
||||
"\n",
|
||||
" if enable_prefix_cache:\n",
|
||||
" vllm_args.append(\"--enable-prefix-caching\")\n",
|
||||
"\n",
|
||||
" if 0 < host_prefix_kv_cache_utilization_target < 1:\n",
|
||||
" vllm_args.append(\n",
|
||||
" f\"--host-prefix-kv-cache-utilization-target={host_prefix_kv_cache_utilization_target}\"\n",
|
||||
" )\n",
|
||||
"\n",
|
||||
" if model_type:\n",
|
||||
" vllm_args.append(f\"--model-type={model_type}\")\n",
|
||||
"\n",
|
||||
" if enable_llama_tool_parser:\n",
|
||||
" vllm_args.append(\"--enable-auto-tool-choice\")\n",
|
||||
" vllm_args.append(\"--tool-call-parser=vertex-llama-3\")\n",
|
||||
"\n",
|
||||
" env_vars = {\n",
|
||||
" \"MODEL_ID\": base_model_id,\n",
|
||||
" \"DEPLOY_SOURCE\": \"notebook\",\n",
|
||||
" }\n",
|
||||
"\n",
|
||||
" # HF_TOKEN is not a compulsory field and may not be defined.\n",
|
||||
" try:\n",
|
||||
" if HF_TOKEN:\n",
|
||||
" env_vars[\"HF_TOKEN\"] = HF_TOKEN\n",
|
||||
" except NameError:\n",
|
||||
" pass\n",
|
||||
"\n",
|
||||
" model = aiplatform.Model.upload(\n",
|
||||
" display_name=model_name,\n",
|
||||
" serving_container_image_uri=VLLM_DOCKER_URI,\n",
|
||||
" serving_container_args=vllm_args,\n",
|
||||
" serving_container_ports=[8080],\n",
|
||||
" serving_container_predict_route=\"/generate\",\n",
|
||||
" serving_container_health_route=\"/ping\",\n",
|
||||
" serving_container_environment_variables=env_vars,\n",
|
||||
" serving_container_shared_memory_size_mb=(16 * 1024), # 16 GB\n",
|
||||
" serving_container_deployment_timeout=7200,\n",
|
||||
" model_garden_source_model_name=(\n",
|
||||
" f\"publishers/{publisher}/models/{publisher_model_id}\"\n",
|
||||
" ),\n",
|
||||
" )\n",
|
||||
" print(\n",
|
||||
" f\"Deploying {model_name} on {machine_type} with {accelerator_count} {accelerator_type} GPU(s).\"\n",
|
||||
" )\n",
|
||||
" model.deploy(\n",
|
||||
" endpoint=endpoint,\n",
|
||||
" machine_type=machine_type,\n",
|
||||
" accelerator_type=accelerator_type,\n",
|
||||
" accelerator_count=accelerator_count,\n",
|
||||
" deploy_request_timeout=1800,\n",
|
||||
" service_account=service_account,\n",
|
||||
" system_labels={\n",
|
||||
" \"NOTEBOOK_NAME\": \"model_garden_pytorch_llama3_finetuning.ipynb\",\n",
|
||||
" \"NOTEBOOK_ENVIRONMENT\": common_util.get_deploy_source(),\n",
|
||||
" },\n",
|
||||
" )\n",
|
||||
" print(\"endpoint_name:\", endpoint.name)\n",
|
||||
"\n",
|
||||
" return model, endpoint\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"models[\"vllm_gpu\"], endpoints[\"vllm_gpu\"] = deploy_model_vllm(\n",
|
||||
" model_name=common_util.get_job_name_with_datetime(prefix=\"llama3-vllm-serve\"),\n",
|
||||
" model_id=merged_model_output_dir,\n",
|
||||
" publisher=\"meta\",\n",
|
||||
" publisher_model_id=\"llama3\",\n",
|
||||
" service_account=SERVICE_ACCOUNT,\n",
|
||||
" machine_type=machine_type,\n",
|
||||
" accelerator_type=accelerator_type,\n",
|
||||
" accelerator_count=accelerator_count,\n",
|
||||
" gpu_memory_utilization=gpu_memory_utilization,\n",
|
||||
" max_model_len=max_model_len,\n",
|
||||
" use_dedicated_endpoint=use_dedicated_endpoint,\n",
|
||||
")\n",
|
||||
"\n",
|
||||
"# @markdown Click \"Show Code\" to see more details."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"cellView": "form",
|
||||
"id": "2UYUNn60G_4U"
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# @title Predict\n",
|
||||
"\n",
|
||||
"# @markdown Once deployment succeeds, you can send requests to the endpoint with text prompts. Sampling parameters supported by vLLM can be found [here](https://docs.vllm.ai/en/latest/dev/sampling_params.html).\n",
|
||||
"\n",
|
||||
"# @markdown Example:\n",
|
||||
"\n",
|
||||
"# @markdown ```\n",
|
||||
"# @markdown Human: What is a car?\n",
|
||||
"# @markdown Assistant: A car, or a motor car, is a road-connected human-transportation system used to move people or goods from one place to another. The term also encompasses a wide range of vehicles, including motorboats, trains, and aircrafts. Cars typically have four wheels, a cabin for passengers, and an engine or motor. They have been around since the early 19th century and are now one of the most popular forms of transportation, used for daily commuting, shopping, and other purposes.\n",
|
||||
"# @markdown ```\n",
|
||||
"# @markdown Additionally, you can moderate the generated text with Vertex AI. See [Moderate text documentation](https://cloud.google.com/natural-language/docs/moderating-text) for more details.\n",
|
||||
"\n",
|
||||
"# Loads an existing endpoint instance using the endpoint name:\n",
|
||||
"# - Using `endpoint_name = endpoint.name` allows us to get the\n",
|
||||
"# endpoint name of the endpoint `endpoint` created in the cell\n",
|
||||
"# above.\n",
|
||||
"# - Alternatively, you can set `endpoint_name = \"1234567890123456789\"` to load\n",
|
||||
"# an existing endpoint with the ID 1234567890123456789.\n",
|
||||
"# You may uncomment the code below to load an existing endpoint.\n",
|
||||
"\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",
|
||||
"\n",
|
||||
"prompt = \"What is a car?\" # @param {type: \"string\"}\n",
|
||||
"# @markdown If you encounter an issue like `ServiceUnavailable: 503 Took too long to respond when processing`, you can reduce the maximum number of output tokens, by lowering `max_tokens`.\n",
|
||||
"max_tokens = 50 # @param {type:\"integer\"}\n",
|
||||
"temperature = 1.0 # @param {type:\"number\"}\n",
|
||||
"top_p = 1.0 # @param {type:\"number\"}\n",
|
||||
"top_k = 1 # @param {type:\"integer\"}\n",
|
||||
"# @markdown Set `raw_response` to `True` to obtain the raw model output. Set `raw_response` to `False` to apply additional formatting in the structure of `\"Prompt:\\n{prompt.strip()}\\nOutput:\\n{output}\"`.\n",
|
||||
"raw_response = False # @param {type:\"boolean\"}\n",
|
||||
"\n",
|
||||
"# Overrides parameters for inferences.\n",
|
||||
"instances = [\n",
|
||||
" {\n",
|
||||
" \"prompt\": prompt,\n",
|
||||
" \"max_tokens\": max_tokens,\n",
|
||||
" \"temperature\": temperature,\n",
|
||||
" \"top_p\": top_p,\n",
|
||||
" \"top_k\": top_k,\n",
|
||||
" \"raw_response\": raw_response,\n",
|
||||
" },\n",
|
||||
"]\n",
|
||||
"response = endpoints[\"vllm_gpu\"].predict(\n",
|
||||
" instances=instances, use_dedicated_endpoint=use_dedicated_endpoint\n",
|
||||
")\n",
|
||||
"\n",
|
||||
"for prediction in response.predictions:\n",
|
||||
" print(prediction)\n",
|
||||
"\n",
|
||||
"# @markdown Click \"Show Code\" to see more details."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "af21a3cff1e0"
|
||||
},
|
||||
"source": [
|
||||
"## Clean up resources"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"cellView": "form",
|
||||
"id": "911406c1561e"
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# @title Delete the model and endpoint\n",
|
||||
"\n",
|
||||
"train_job.delete()\n",
|
||||
"\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",
|
||||
"for endpoint in endpoints.values():\n",
|
||||
" endpoint.delete(force=True)\n",
|
||||
"\n",
|
||||
"# Delete models.\n",
|
||||
"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"
|
||||
]
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"colab": {
|
||||
"name": "model_garden_pytorch_llama3_finetuning.ipynb",
|
||||
"toc_visible": true
|
||||
},
|
||||
"kernelspec": {
|
||||
"display_name": "Python 3",
|
||||
"name": "python3"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 0
|
||||
}
|
||||
@@ -1,913 +0,0 @@
|
||||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"cellView": "form",
|
||||
"id": "iJc36RtD90jd"
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Copyright 2026 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": "b9EezHSo90jf"
|
||||
},
|
||||
"source": [
|
||||
"# Vertex AI Model Garden - Mistral-7B (PEFT)\n",
|
||||
"\n",
|
||||
"<table><tbody><tr>\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%2Fcommunity%2Fmodel_garden%2Fmodel_garden_pytorch_mistral_peft_tuning.ipynb\">\n",
|
||||
" <img alt=\"Google Cloud Colab Enterprise logo\" src=\"https://lh3.googleusercontent.com/JmcxdQi-qOpctIvWKgPtrzZdJJK-J3sWE1RsfjZNwshCFgE_9fULcNpuXYTilIR2hjwN\" width=\"32px\"><br> Run in Colab Enterprise\n",
|
||||
" </a>\n",
|
||||
" </td>\n",
|
||||
" <td style=\"text-align: center\">\n",
|
||||
" <a href=\"https://github.com/GoogleCloudPlatform/vertex-ai-samples/blob/main/notebooks/community/model_garden/model_garden_pytorch_mistral_peft_tuning.ipynb\">\n",
|
||||
" <img alt=\"GitHub logo\" src=\"https://github.githubassets.com/assets/GitHub-Mark-ea2971cee799.png\" width=\"32px\"><br> View on GitHub\n",
|
||||
" </a>\n",
|
||||
" </td>\n",
|
||||
"</tr></tbody></table>"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "ybMCVFh0_5R8"
|
||||
},
|
||||
"source": [
|
||||
"## Overview\n",
|
||||
"In this notebook you will learn how to fine tune Mistral with QLoRa and\n",
|
||||
"deploy to Vertex AI endpoint.\n",
|
||||
"\n",
|
||||
"### Objective\n",
|
||||
"\n",
|
||||
"* Finetune and merge Mistral model using PEFT training docker image.\n",
|
||||
"* Deploy the finetuned model with vLLM docker image on a Vertex AI Endpoint.\n",
|
||||
"* Run inference on the deployed Vertex AI Endpoint.\n",
|
||||
"\n",
|
||||
"### File a bug\n",
|
||||
"\n",
|
||||
"File a bug on [GitHub](https://github.com/GoogleCloudPlatform/vertex-ai-samples/issues/new) if you encounter any issue with the notebook.\n",
|
||||
"\n",
|
||||
"### Costs\n",
|
||||
"\n",
|
||||
"This tutorial uses billable components of Google Cloud:\n",
|
||||
"\n",
|
||||
"* Vertex AI\n",
|
||||
"* Cloud Storage\n",
|
||||
"\n",
|
||||
"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."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "vzvFJU27a8si"
|
||||
},
|
||||
"source": [
|
||||
"## Run the notebook"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"cellView": "form",
|
||||
"id": "Q86d4aDSgGCu"
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# @title Install Python Packages for Finetuning\n",
|
||||
"\n",
|
||||
"# @markdown 1. Install google-cloud-aiplatform package and restart the session if instructed.\n",
|
||||
"! pip install --upgrade --quiet google-cloud-aiplatform==1.130.0\n",
|
||||
"\n",
|
||||
"# @markdown 2. Install packages to validate dataset with template.\n",
|
||||
"! pip install --upgrade --quiet gcsfs==2024.3.1\n",
|
||||
"! pip install --upgrade --quiet accelerate==0.31.0\n",
|
||||
"! pip install --upgrade --quiet transformers==4.43.1\n",
|
||||
"! pip install --upgrade --quiet datasets==2.19.2\n",
|
||||
"\n",
|
||||
"# Load local tensorboard.\n",
|
||||
"%load_ext tensorboard"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"cellView": "form",
|
||||
"id": "I-OjzhpyMHsu"
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# @title Setup Google Cloud project\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. For finetuning, **[click here](https://console.cloud.google.com/iam-admin/quotas?location=us-central1&metric=aiplatform.googleapis.com%2Frestricted_image_training_nvidia_a100_80gb_gpus)** to check if your project already has the required 8 Nvidia A100 80 GB GPUs in the us-central1 region. If yes, then run this notebook in the us-central1 region. If you do not have 8 Nvidia A100 80 GPUs or have more GPU requirements than this, then schedule your job with Nvidia H100 GPUs via Dynamic Workload Scheduler using [these instructions](https://cloud.google.com/vertex-ai/docs/training/schedule-jobs-dws). For Dynamic Workload Scheduler, check the [us-central1](https://console.cloud.google.com/iam-admin/quotas?location=us-central1&metric=aiplatform.googleapis.com%2Fcustom_model_training_preemptible_nvidia_h100_gpus) or [europe-west4](https://console.cloud.google.com/iam-admin/quotas?location=europe-west4&metric=aiplatform.googleapis.com%2Fcustom_model_training_preemptible_nvidia_h100_gpus) quota for Nvidia H100 GPUs. If you do not have enough GPUs, then you can follow [these instructions](https://cloud.google.com/docs/quotas/view-manage#viewing_your_quota_console) to request quota.\n",
|
||||
"\n",
|
||||
"# @markdown 3. For serving, **[click here](https://console.cloud.google.com/iam-admin/quotas?location=us-central1&metric=aiplatform.googleapis.com%2Fcustom_model_serving_nvidia_l4_gpus)** to check if your project already has the required 1 L4 GPU in the us-central1 region. If yes, then run this notebook in the us-central1 region. If you need more L4 GPUs for your project, then you can follow [these instructions](https://cloud.google.com/docs/quotas/view-manage#viewing_your_quota_console) to request more. Alternatively, 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).\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",
|
||||
"# @markdown 4. **[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",
|
||||
"BUCKET_URI = \"gs://\" # @param {type:\"string\"}\n",
|
||||
"\n",
|
||||
"# @markdown 5. **[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",
|
||||
"# Import the necessary packages\n",
|
||||
"! rm -rf vertex-ai-samples && git clone https://github.com/GoogleCloudPlatform/vertex-ai-samples.git\n",
|
||||
"! cd vertex-ai-samples && git reset --hard 0727e19520cf7957bceb701c248221bd3dbe4f1f\n",
|
||||
"\n",
|
||||
"import datetime\n",
|
||||
"import importlib\n",
|
||||
"import os\n",
|
||||
"import uuid\n",
|
||||
"from typing import Tuple\n",
|
||||
"\n",
|
||||
"from google.cloud import aiplatform\n",
|
||||
"from google.cloud.aiplatform.compat.types import \\\n",
|
||||
" custom_job as gca_custom_job_compat\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",
|
||||
"models, endpoints = {}, {}\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",
|
||||
" if not os.environ.get(\"GOOGLE_CLOUD_REGION\"):\n",
|
||||
" raise ValueError(\n",
|
||||
" \"REGION must be set. See\"\n",
|
||||
" \" https://cloud.google.com/vertex-ai/docs/general/locations for\"\n",
|
||||
" \" available cloud locations.\"\n",
|
||||
" )\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",
|
||||
"# 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.datetime.now().strftime(\"%Y%m%d%H%M%S\")\n",
|
||||
"BUCKET_NAME = \"/\".join(BUCKET_URI.split(\"/\")[:3])\n",
|
||||
"\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, \"mistral\")\n",
|
||||
"\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",
|
||||
"# 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",
|
||||
"# 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",
|
||||
"! gcloud projects add-iam-policy-binding --no-user-output-enabled {PROJECT_ID} --member=serviceAccount:{SERVICE_ACCOUNT} --role=\"roles/storage.admin\"\n",
|
||||
"! gcloud projects add-iam-policy-binding --no-user-output-enabled {PROJECT_ID} --member=serviceAccount:{SERVICE_ACCOUNT} --role=\"roles/aiplatform.user\""
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"cellView": "form",
|
||||
"id": "5K169qf_udor"
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# @title Set dataset\n",
|
||||
"\n",
|
||||
"# @markdown Use the Vertex AI SDK to create and run the custom training jobs.\n",
|
||||
"\n",
|
||||
"# @markdown This notebook uses [timdettmers/openassistant-guanaco](https://huggingface.co/datasets/timdettmers/openassistant-guanaco) dataset as an example.\n",
|
||||
"# @markdown You can set `dataset_name` to any existing [Hugging Face dataset](https://huggingface.co/datasets) name, and set `instruct_column_in_dataset` to the name of the dataset column containing training data. The [timdettmers/openassistant-guanaco](https://huggingface.co/datasets/timdettmers/openassistant-guanaco) has only one column `text`, and therefore we set `instruct_column_in_dataset` to `text` in this notebook.\n",
|
||||
"\n",
|
||||
"# @markdown ### (Optional) Prepare a custom JSONL dataset for finetuning\n",
|
||||
"\n",
|
||||
"# @markdown You can prepare a JSONL file where each line is a valid JSON string as your custom training dataset. For example, here is one line from the [timdettmers/openassistant-guanaco](https://huggingface.co/datasets/timdettmers/openassistant-guanaco) dataset:\n",
|
||||
"# @markdown ```\n",
|
||||
"# @markdown {\"text\": \"### Human: Hola### Assistant: \\u00a1Hola! \\u00bfEn qu\\u00e9 puedo ayudarte hoy?\"}\n",
|
||||
"# @markdown ```\n",
|
||||
"\n",
|
||||
"# @markdown The JSON object has a key `text`, which should match `instruct_column_in_dataset`; The value should be one training data point, i.e. a string. After you prepared your JSONL file, you can either upload it to [Hugging Face datasets](https://huggingface.co/datasets) or [Google Cloud Storage](https://cloud.google.com/storage).\n",
|
||||
"\n",
|
||||
"# @markdown - To upload a JSONL dataset to [Hugging Face datasets](https://huggingface.co/datasets), follow the instructions on [Uploading Datasets](https://huggingface.co/docs/hub/en/datasets-adding). Then, set `dataset_name` to the name of your newly created dataset on Hugging Face.\n",
|
||||
"\n",
|
||||
"# @markdown - To upload a JSONL dataset to [Google Cloud Storage](https://cloud.google.com/storage), follow the instructions on [Upload objects from a filesystem](https://cloud.google.com/storage/docs/uploading-objects). Then, set `dataset_name` to the `gs://` URI to your JSONL file. For example: `gs://cloud-samples-data/vertex-ai/model-evaluation/peft_train_sample.jsonl`.\n",
|
||||
"\n",
|
||||
"# @markdown Optionally update the `instruct_column_in_dataset` field below if your JSON objects use a key other than the default `text`.\n",
|
||||
"\n",
|
||||
"# @markdown ### (Optional) Format your data with custom JSON template\n",
|
||||
"\n",
|
||||
"# @markdown Sometimes, your dataset might have multiple text columns and you want to construct the training data with a template. You can prepare a JSON template in the following format:\n",
|
||||
"\n",
|
||||
"# @markdown ```\n",
|
||||
"# @markdown {\n",
|
||||
"# @markdown \"description\": \"Template that accepts text-bison format.\",\n",
|
||||
"# @markdown \"source\": \"https://cloud.google.com/vertex-ai/generative-ai/docs/models/tune-text-models-supervised#dataset-format\",\n",
|
||||
"# @markdown \"prompt_input\": \"\\n\\n<|start_header_id|>user<|end_header_id|>\\n\\n{input_text}<|eot_id|>\\n\\n<|start_header_id|>assistant<|end_header_id|>\\n\\n{output_text}<|eot_id|>\",\n",
|
||||
"# @markdown \"instruction_separator\": \"<|start_header_id|>user<|end_header_id|>\\n\\n\",\n",
|
||||
"# @markdown \"response_separator\": \"<|start_header_id|>assistant<|end_header_id|>\\n\\n\"\n",
|
||||
"# @markdown }\n",
|
||||
"# @markdown ```\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"# @markdown As an example, the template above can be used to format the following training data (this line comes from `gs://cloud-samples-data/vertex-ai/model-evaluation/peft_train_sample.jsonl`):\n",
|
||||
"\n",
|
||||
"# @markdown ```\n",
|
||||
"# @markdown {\"input_text\":\"TRANSCRIPT: \\nREASON FOR EVALUATION:,\\n\\n LABEL:\",\"output_text\":\"Chiropractic\"}\n",
|
||||
"# @markdown ```\n",
|
||||
"\n",
|
||||
"# @markdown This example template simply concatenates `input_text` with `output_text` with some special tokens in between.\n",
|
||||
"# @markdown\n",
|
||||
"# @markdown To try such custom dataset, you can make the following changes:\n",
|
||||
"# @markdown 1. Set `template` to `llama3-text-bison`\n",
|
||||
"# @markdown 1. Set `train_dataset_name` to `gs://cloud-samples-data/vertex-ai/model-evaluation/peft_train_sample.jsonl`\n",
|
||||
"# @markdown 1. Set `train_split_name` to `train`\n",
|
||||
"# @markdown 1. Set `eval_dataset_name` to `gs://cloud-samples-data/vertex-ai/model-evaluation/peft_eval_sample.jsonl`\n",
|
||||
"# @markdown 1. Set `eval_split_name` to `train` (**NOT** `test`)\n",
|
||||
"# @markdown 1. Set `instruct_column_in_dataset` as `input_text`.\n",
|
||||
"\n",
|
||||
"# Template name or gs:// URI to a custom template.\n",
|
||||
"template = \"openassistant-guanaco\" # @param {type:\"string\"}\n",
|
||||
"\n",
|
||||
"# Hugging Face dataset name or gs:// URI to a custom JSONL dataset.\n",
|
||||
"train_dataset_name = \"timdettmers/openassistant-guanaco\" # @param {type:\"string\"}\n",
|
||||
"train_split_name = \"train\" # @param {type:\"string\"}\n",
|
||||
"eval_dataset_name = \"timdettmers/openassistant-guanaco\" # @param {type:\"string\"}\n",
|
||||
"eval_split_name = \"test\" # @param {type:\"string\"}\n",
|
||||
"\n",
|
||||
"# Name of the dataset column containing training text input.\n",
|
||||
"instruct_column_in_dataset = \"text\" # @param {type:\"string\"}"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"cellView": "form",
|
||||
"id": "ncoBBZXq2qxf"
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# @title Set model\n",
|
||||
"\n",
|
||||
"# @markdown Select a model variant of Mistral.\n",
|
||||
"base_model_id = \"mistralai/Mistral-7B-v0.1\" # @param [\"mistralai/Mistral-7B-v0.1\"] {isTemplate: true}\n",
|
||||
"pretrained_model_id = f\"gs://vertex-model-garden-public-us/{base_model_id}\""
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"cellView": "form",
|
||||
"id": "8MTGQCZTxDbN"
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# @title Validate Dataset with Template\n",
|
||||
"\n",
|
||||
"# @markdown This section validates the train and eval datasets with the template before starting the fine tuning process.\n",
|
||||
"\n",
|
||||
"import transformers\n",
|
||||
"\n",
|
||||
"dataset_validation_util = importlib.import_module(\n",
|
||||
" \"vertex-ai-samples.community-content.vertex_model_garden.model_oss.notebook_util.dataset_validation_util\"\n",
|
||||
")\n",
|
||||
"\n",
|
||||
"if dataset_validation_util.is_gcs_path(pretrained_model_id):\n",
|
||||
" # Download tokenizer.\n",
|
||||
" ! mkdir tokenizer\n",
|
||||
" ! gsutil cp {pretrained_model_id}/tokenizer.json ./tokenizer\n",
|
||||
" ! gsutil cp {pretrained_model_id}/config.json ./tokenizer\n",
|
||||
" tokenizer_path = \"./tokenizer\"\n",
|
||||
" access_token = \"\"\n",
|
||||
"else:\n",
|
||||
" tokenizer_path = pretrained_model_id\n",
|
||||
" access_token = HF_TOKEN\n",
|
||||
"\n",
|
||||
"tokenizer = transformers.AutoTokenizer.from_pretrained(\n",
|
||||
" tokenizer_path,\n",
|
||||
" trust_remote_code=False,\n",
|
||||
" use_fast=True,\n",
|
||||
" token=access_token,\n",
|
||||
")\n",
|
||||
"\n",
|
||||
"# Validate the train dataset.\n",
|
||||
"dataset_validation_util.validate_dataset_with_template(\n",
|
||||
" dataset_name=train_dataset_name,\n",
|
||||
" split=train_split_name,\n",
|
||||
" input_column=instruct_column_in_dataset,\n",
|
||||
" template=template,\n",
|
||||
" use_multiprocessing=False,\n",
|
||||
" tokenizer=tokenizer,\n",
|
||||
")\n",
|
||||
"\n",
|
||||
"# Validate the eval dataset.\n",
|
||||
"dataset_validation_util.validate_dataset_with_template(\n",
|
||||
" dataset_name=eval_dataset_name,\n",
|
||||
" split=eval_split_name,\n",
|
||||
" input_column=instruct_column_in_dataset,\n",
|
||||
" template=template,\n",
|
||||
" use_multiprocessing=False,\n",
|
||||
" tokenizer=tokenizer,\n",
|
||||
")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"cellView": "form",
|
||||
"id": "885Vf4o8hbbo"
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# @title Finetune\n",
|
||||
"\n",
|
||||
"# @markdown This section demonstrates how to finetune the Mistral-7B model and merge the finetuned LoRA adapter with the base model on Vertex AI. It uses the Vertex AI SDK to create and run the custom training jobs.\n",
|
||||
"\n",
|
||||
"# @markdown The training job takes approximately between 10 to 20 mins to set-up. Once done, the training job is expected to take around 20 mins with the default configurations. To find the training time, throughput, and memory usage of your training job, you can go to the training logs and check the log line of the last training epoch.\n",
|
||||
"\n",
|
||||
"# @markdown **Note**:\n",
|
||||
"# @markdown 1. We recommend setting `finetuning_precision_mode` to `4bit` because it enables using fewer hardware resources for finetuning.\n",
|
||||
"# @markdown 1. If `max_steps > 0`, it takes precedence over `epochs`. One can set a small `max_steps` value to quickly check the pipeline.\n",
|
||||
"\n",
|
||||
"# @markdown Acceletor type to use for training.\n",
|
||||
"accelerator_type = \"NVIDIA_A100_80GB\" # @param [\"NVIDIA_A100_80GB\", \"NVIDIA_H100_80GB\"]\n",
|
||||
"\n",
|
||||
"# The pre-built training docker image.\n",
|
||||
"if accelerator_type == \"NVIDIA_A100_80GB\":\n",
|
||||
" repo = \"us-docker.pkg.dev/vertex-ai-restricted\"\n",
|
||||
" is_restricted_image = True\n",
|
||||
" is_dynamic_workload_scheduler = False\n",
|
||||
" dws_kwargs = {}\n",
|
||||
"else:\n",
|
||||
" repo = \"us-docker.pkg.dev/vertex-ai\"\n",
|
||||
" is_restricted_image = False\n",
|
||||
" is_dynamic_workload_scheduler = True\n",
|
||||
" dws_kwargs = {\n",
|
||||
" \"max_wait_duration\": 1800, # 30 minutes\n",
|
||||
" \"scheduling_strategy\": gca_custom_job_compat.Scheduling.Strategy.FLEX_START,\n",
|
||||
" }\n",
|
||||
"\n",
|
||||
"TRAIN_DOCKER_URI = (\n",
|
||||
" f\"{repo}/vertex-vision-model-garden-dockers/pytorch-peft-train:stable_20240909\"\n",
|
||||
")\n",
|
||||
"\n",
|
||||
"# Worker pool spec.\n",
|
||||
"if accelerator_type == \"NVIDIA_A100_80GB\":\n",
|
||||
" per_node_accelerator_count = 8\n",
|
||||
" machine_type = \"a2-ultragpu-8g\"\n",
|
||||
"elif accelerator_type == \"NVIDIA_H100_80GB\":\n",
|
||||
" per_node_accelerator_count = 8\n",
|
||||
" machine_type = \"a3-highgpu-8g\"\n",
|
||||
"else:\n",
|
||||
" raise ValueError(\n",
|
||||
" f\"Recommended machine settings not found for: {accelerator_type}. To use another accelerator type, edit this code block to pass in an appropriate `machine_type`, `accelerator_type`, and `per_node_accelerator_count` to the deploy_model_vllm function by clicking `Show Code` and then modifying the code.\"\n",
|
||||
" )\n",
|
||||
"\n",
|
||||
"# @markdown Batch size for finetuning.\n",
|
||||
"per_device_train_batch_size = 1 # @param{type:\"integer\"}\n",
|
||||
"# @markdown Number of updates steps to accumulate the gradients for, before performing a backward/update pass.\n",
|
||||
"gradient_accumulation_steps = 4 # @param{type:\"integer\"}\n",
|
||||
"# @markdown Maximum sequence length.\n",
|
||||
"max_seq_length = 4096 # @param{type:\"integer\"}\n",
|
||||
"# @markdown Setting a positive `max_steps` here will override `num_epochs`.\n",
|
||||
"max_steps = -1 # @param{type:\"integer\"}\n",
|
||||
"num_epochs = 1.0 # @param{type:\"number\"}\n",
|
||||
"# @markdown Precision mode for finetuning.\n",
|
||||
"finetuning_precision_mode = \"4bit\" # @param [\"4bit\", \"8bit\", \"float16\"]\n",
|
||||
"# @markdown Learning rate.\n",
|
||||
"learning_rate = 5e-5 # @param{type:\"number\"}\n",
|
||||
"# @markdown The scheduler type to use.\n",
|
||||
"lr_scheduler_type = \"cosine\" # @param{type:\"string\"}\n",
|
||||
"# @markdown LoRA parameters.\n",
|
||||
"lora_rank = 16 # @param{type:\"integer\"}\n",
|
||||
"lora_alpha = 32 # @param{type:\"integer\"}\n",
|
||||
"lora_dropout = 0.05 # @param{type:\"number\"}\n",
|
||||
"# Activates gradient checkpointing for the current model (may be referred to as activation checkpointing or checkpoint activations in other frameworks).\n",
|
||||
"enable_gradient_checkpointing = True\n",
|
||||
"# Attention implementation to use in the model.\n",
|
||||
"attn_implementation = \"flash_attention_2\"\n",
|
||||
"# The optimizer for which to schedule the learning rate.\n",
|
||||
"optimizer = \"paged_adamw_32bit\"\n",
|
||||
"# Define the proportion of training to be dedicated to a linear warmup where learning rate gradually increases.\n",
|
||||
"warmup_ratio = \"0.01\"\n",
|
||||
"# The list or string of integrations to report the results and logs to.\n",
|
||||
"report_to = \"tensorboard\"\n",
|
||||
"# Number of updates steps before two checkpoint saves.\n",
|
||||
"save_steps = 10\n",
|
||||
"# Number of update steps between two logs.\n",
|
||||
"logging_steps = save_steps\n",
|
||||
"# Train precision of the model.\n",
|
||||
"train_precision = \"float16\"\n",
|
||||
"\n",
|
||||
"replica_count = 1\n",
|
||||
"\n",
|
||||
"common_util.check_quota(\n",
|
||||
" project_id=PROJECT_ID,\n",
|
||||
" region=REGION,\n",
|
||||
" accelerator_type=accelerator_type,\n",
|
||||
" accelerator_count=per_node_accelerator_count * replica_count,\n",
|
||||
" is_for_training=True,\n",
|
||||
" is_restricted_image=is_restricted_image,\n",
|
||||
" is_dynamic_workload_scheduler=is_dynamic_workload_scheduler,\n",
|
||||
")\n",
|
||||
"\n",
|
||||
"# Setup training job.\n",
|
||||
"job_name = common_util.get_job_name_with_datetime(\"mistral-lora-train\")\n",
|
||||
"\n",
|
||||
"base_output_dir = os.path.join(STAGING_BUCKET, job_name)\n",
|
||||
"# Create a GCS folder to store the LORA adapter.\n",
|
||||
"lora_output_dir = os.path.join(base_output_dir, \"adapter\")\n",
|
||||
"# Create a GCS folder to store the merged model with the base model and the\n",
|
||||
"# finetuned LORA adapter.\n",
|
||||
"merged_model_output_dir = os.path.join(base_output_dir, \"merged-model\")\n",
|
||||
"\n",
|
||||
"# Add labels for the finetuning job.\n",
|
||||
"labels = {\n",
|
||||
" \"mg-source\": \"notebook\",\n",
|
||||
" \"mg-notebook-name\": \"model_garden_pytorch_mistral_peft_tuning.ipynb\".split(\".\")[0],\n",
|
||||
"}\n",
|
||||
"\n",
|
||||
"labels[\"mg-tune\"] = \"publishers-mistralai-models-mistral\"\n",
|
||||
"versioned_model_id = base_model_id.split(\"/\")[1].lower().replace(\".\", \"-\")\n",
|
||||
"labels[\"versioned-mg-tune\"] = f\"{labels['mg-tune']}-{versioned_model_id}\"\n",
|
||||
"\n",
|
||||
"eval_args = [\n",
|
||||
" f\"--eval_dataset_path={eval_dataset_name}\",\n",
|
||||
" f\"--eval_column={instruct_column_in_dataset}\",\n",
|
||||
" f\"--eval_template={template}\",\n",
|
||||
" f\"--eval_split={eval_split_name}\",\n",
|
||||
" f\"--eval_steps={save_steps}\",\n",
|
||||
" \"--eval_tasks=builtin_eval\",\n",
|
||||
" \"--eval_metric_name=loss\",\n",
|
||||
"]\n",
|
||||
"\n",
|
||||
"train_job_args = [\n",
|
||||
" \"--config_file=vertex_vision_model_garden_peft/deepspeed_zero2_8gpu.yaml\",\n",
|
||||
" \"--task=instruct-lora\",\n",
|
||||
" \"--completion_only=False\",\n",
|
||||
" f\"--pretrained_model_id={pretrained_model_id}\",\n",
|
||||
" f\"--dataset_name={train_dataset_name}\",\n",
|
||||
" f\"--train_split_name={train_split_name}\",\n",
|
||||
" f\"--instruct_column_in_dataset={instruct_column_in_dataset}\",\n",
|
||||
" f\"--output_dir={lora_output_dir}\",\n",
|
||||
" f\"--merge_base_and_lora_output_dir={merged_model_output_dir}\",\n",
|
||||
" f\"--per_device_train_batch_size={per_device_train_batch_size}\",\n",
|
||||
" f\"--gradient_accumulation_steps={gradient_accumulation_steps}\",\n",
|
||||
" f\"--lora_rank={lora_rank}\",\n",
|
||||
" f\"--lora_alpha={lora_alpha}\",\n",
|
||||
" f\"--lora_dropout={lora_dropout}\",\n",
|
||||
" f\"--max_steps={max_steps}\",\n",
|
||||
" f\"--max_seq_length={max_seq_length}\",\n",
|
||||
" f\"--learning_rate={learning_rate}\",\n",
|
||||
" f\"--lr_scheduler_type={lr_scheduler_type}\",\n",
|
||||
" f\"--precision_mode={finetuning_precision_mode}\",\n",
|
||||
" f\"--train_precision={train_precision}\",\n",
|
||||
" f\"--enable_gradient_checkpointing={enable_gradient_checkpointing}\",\n",
|
||||
" f\"--num_epochs={num_epochs}\",\n",
|
||||
" f\"--attn_implementation={attn_implementation}\",\n",
|
||||
" f\"--optimizer={optimizer}\",\n",
|
||||
" f\"--warmup_ratio={warmup_ratio}\",\n",
|
||||
" f\"--report_to={report_to}\",\n",
|
||||
" f\"--logging_output_dir={base_output_dir}\",\n",
|
||||
" f\"--save_steps={save_steps}\",\n",
|
||||
" f\"--logging_steps={logging_steps}\",\n",
|
||||
" f\"--template={template}\",\n",
|
||||
"] + eval_args\n",
|
||||
"\n",
|
||||
"train_job = aiplatform.CustomContainerTrainingJob(\n",
|
||||
" display_name=job_name,\n",
|
||||
" container_uri=TRAIN_DOCKER_URI,\n",
|
||||
" labels=labels,\n",
|
||||
")\n",
|
||||
"\n",
|
||||
"print(\"Running training job with args:\")\n",
|
||||
"print(\" \\\\\\n\".join(train_job_args))\n",
|
||||
"# Pass training arguments and launch job.\n",
|
||||
"train_job.run(\n",
|
||||
" args=train_job_args,\n",
|
||||
" replica_count=replica_count,\n",
|
||||
" machine_type=machine_type,\n",
|
||||
" accelerator_type=accelerator_type,\n",
|
||||
" accelerator_count=per_node_accelerator_count,\n",
|
||||
" boot_disk_size_gb=500,\n",
|
||||
" service_account=SERVICE_ACCOUNT,\n",
|
||||
" base_output_dir=base_output_dir,\n",
|
||||
" sync=False, # Non-blocking call to run.\n",
|
||||
" **dws_kwargs,\n",
|
||||
")\n",
|
||||
"\n",
|
||||
"# Wait until resource has been created.\n",
|
||||
"train_job.wait_for_resource_creation()\n",
|
||||
"\n",
|
||||
"print(\"LoRA adapter will be saved in:\", lora_output_dir)\n",
|
||||
"print(\"Trained and merged models will be saved in:\", merged_model_output_dir)\n",
|
||||
"\n",
|
||||
"# @markdown Click \"Show Code\" to see more details."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"cellView": "form",
|
||||
"id": "cLNQwLMGmzlR"
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# @title Run TensorBoard\n",
|
||||
"# @markdown This section shows how to launch TensorBoard in a [Cloud Shell](https://cloud.google.com/shell/docs).\n",
|
||||
"# @markdown 1. Click the Cloud Shell icon() on the top right to open the Cloud Shell.\n",
|
||||
"# @markdown 2. Copy the `tensorboard` command shown below by running this cell.\n",
|
||||
"# @markdown 3. Paste and run the command in the Cloud Shell to launch TensorBoard.\n",
|
||||
"# @markdown 4. Once the command runs (You may have to click `Authorize` if prompted), click the link starting with `http://localhost`.\n",
|
||||
"\n",
|
||||
"# @markdown Note: You may need to wait around 10 minutes after the job starts in order for the TensorBoard logs to be written to the GCS bucket.\n",
|
||||
"print(f\"Command to copy: tensorboard --logdir {base_output_dir}/logs\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"cellView": "form",
|
||||
"id": "GyDWPdV1NjMT"
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# @title Deploy\n",
|
||||
"# @markdown This section uploads the model to Model Registry and deploys it on the Endpoint. It takes 15 minutes to 1 hour to finish depending on the size of model.\n",
|
||||
"\n",
|
||||
"if train_job.end_time is None:\n",
|
||||
" print(\"Waiting for the training job to finish...\")\n",
|
||||
" train_job.wait()\n",
|
||||
" print(\"The training job has finished.\")\n",
|
||||
"\n",
|
||||
"print(\"Deploying models in:\", merged_model_output_dir)\n",
|
||||
"\n",
|
||||
"# The pre-built serving docker image for vLLM.\n",
|
||||
"VLLM_DOCKER_URI = \"us-docker.pkg.dev/vertex-ai/vertex-vision-model-garden-dockers/pytorch-vllm-serve:20240721_0916_RC00\"\n",
|
||||
"\n",
|
||||
"# Find Vertex AI prediction supported accelerators and regions [here](https://cloud.google.com/vertex-ai/docs/predictions/configure-compute).\n",
|
||||
"# @markdown Accelerator type to use for serving.\n",
|
||||
"accelerator_type = \"NVIDIA_L4\" # @param [\"NVIDIA_L4\", \"NVIDIA_TESLA_V100\", \"NVIDIA_TESLA_T4\", \"NVIDIA_TESLA_A100\"]\n",
|
||||
"\n",
|
||||
"if accelerator_type == \"NVIDIA_L4\":\n",
|
||||
" machine_type = \"g2-standard-8\"\n",
|
||||
" accelerator_count = 1\n",
|
||||
"elif accelerator_type == \"NVIDIA_TESLA_V100\":\n",
|
||||
" machine_type = \"n1-standard-16\"\n",
|
||||
" accelerator_count = 2\n",
|
||||
"elif accelerator_type == \"NVIDIA_TESLA_T4\":\n",
|
||||
" machine_type = \"n1-standard-16\"\n",
|
||||
" accelerator_count = 2\n",
|
||||
"elif accelerator_type == \"NVIDIA_TESLA_A100\":\n",
|
||||
" machine_type = \"a2-highgpu-1g\"\n",
|
||||
" accelerator_count = 1\n",
|
||||
"\n",
|
||||
"common_util.check_quota(\n",
|
||||
" project_id=PROJECT_ID,\n",
|
||||
" region=REGION,\n",
|
||||
" accelerator_type=accelerator_type,\n",
|
||||
" accelerator_count=accelerator_count,\n",
|
||||
" is_for_training=False,\n",
|
||||
")\n",
|
||||
"\n",
|
||||
"# @markdown Set `use_dedicated_endpoint` to False if you don't want to use [dedicated endpoint](https://cloud.google.com/vertex-ai/docs/general/deployment#create-dedicated-endpoint).\n",
|
||||
"use_dedicated_endpoint = True # @param {type:\"boolean\"}\n",
|
||||
"\n",
|
||||
"gpu_memory_utilization = 0.85\n",
|
||||
"max_model_len = 8192 # Maximum context length.\n",
|
||||
"\n",
|
||||
"# Ensure max_model_len does not exceed the limit\n",
|
||||
"if max_model_len > 8192:\n",
|
||||
" raise ValueError(\"max_model_len cannot exceed 8192\")\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"def get_deploy_source() -> str:\n",
|
||||
" \"\"\"Gets deploy_source string based on running environment.\"\"\"\n",
|
||||
" vertex_product = os.environ.get(\"VERTEX_PRODUCT\", \"\")\n",
|
||||
" if vertex_product == \"COLAB_ENTERPRISE\":\n",
|
||||
" return \"notebook_colab_enterprise\"\n",
|
||||
" elif vertex_product == \"WORKBENCH_INSTANCE\":\n",
|
||||
" return \"notebook_workbench\"\n",
|
||||
" else:\n",
|
||||
" # Legacy workbench, legacy colab, or other custom environments.\n",
|
||||
" return \"notebook_environment_unspecified\"\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"def deploy_model_vllm(\n",
|
||||
" model_name: str,\n",
|
||||
" model_id: str,\n",
|
||||
" publisher: str,\n",
|
||||
" publisher_model_id: str,\n",
|
||||
" service_account: str,\n",
|
||||
" base_model_id: str = None,\n",
|
||||
" machine_type: str = \"g2-standard-8\",\n",
|
||||
" accelerator_type: str = \"NVIDIA_L4\",\n",
|
||||
" accelerator_count: int = 1,\n",
|
||||
" gpu_memory_utilization: float = 0.9,\n",
|
||||
" max_model_len: int = 4096,\n",
|
||||
" dtype: str = \"auto\",\n",
|
||||
" enable_trust_remote_code: bool = False,\n",
|
||||
" enforce_eager: bool = False,\n",
|
||||
" enable_lora: bool = False,\n",
|
||||
" enable_chunked_prefill: bool = False,\n",
|
||||
" enable_prefix_cache: bool = False,\n",
|
||||
" host_prefix_kv_cache_utilization_target: float = 0.0,\n",
|
||||
" max_loras: int = 1,\n",
|
||||
" max_cpu_loras: int = 8,\n",
|
||||
" use_dedicated_endpoint: bool = False,\n",
|
||||
" max_num_seqs: int = 256,\n",
|
||||
" model_type: str = None,\n",
|
||||
" enable_llama_tool_parser: bool = False,\n",
|
||||
" is_spot: bool = False,\n",
|
||||
") -> Tuple[aiplatform.Model, aiplatform.Endpoint]:\n",
|
||||
" \"\"\"Deploys trained models with vLLM into Vertex AI.\"\"\"\n",
|
||||
" endpoint = aiplatform.Endpoint.create(\n",
|
||||
" display_name=f\"{model_name}-endpoint\",\n",
|
||||
" dedicated_endpoint_enabled=use_dedicated_endpoint,\n",
|
||||
" )\n",
|
||||
"\n",
|
||||
" if not base_model_id:\n",
|
||||
" base_model_id = model_id\n",
|
||||
"\n",
|
||||
" # See https://docs.vllm.ai/en/latest/models/engine_args.html for a list of possible arguments with descriptions.\n",
|
||||
" vllm_args = [\n",
|
||||
" \"python\",\n",
|
||||
" \"-m\",\n",
|
||||
" \"vllm.entrypoints.api_server\",\n",
|
||||
" \"--host=0.0.0.0\",\n",
|
||||
" \"--port=8080\",\n",
|
||||
" f\"--model={model_id}\",\n",
|
||||
" f\"--tensor-parallel-size={accelerator_count}\",\n",
|
||||
" \"--swap-space=16\",\n",
|
||||
" f\"--max-model-len={max_model_len}\",\n",
|
||||
" f\"--dtype={dtype}\",\n",
|
||||
" f\"--max-loras={max_loras}\",\n",
|
||||
" f\"--max-cpu-loras={max_cpu_loras}\",\n",
|
||||
" f\"--max-num-seqs={max_num_seqs}\",\n",
|
||||
" \"--disable-log-stats\",\n",
|
||||
" ]\n",
|
||||
"\n",
|
||||
" if gpu_memory_utilization:\n",
|
||||
" vllm_args.append(f\"--gpu-memory-utilization={gpu_memory_utilization}\")\n",
|
||||
"\n",
|
||||
" if enable_trust_remote_code:\n",
|
||||
" vllm_args.append(\"--trust-remote-code\")\n",
|
||||
"\n",
|
||||
" if enforce_eager:\n",
|
||||
" vllm_args.append(\"--enforce-eager\")\n",
|
||||
"\n",
|
||||
" if enable_lora:\n",
|
||||
" vllm_args.append(\"--enable-lora\")\n",
|
||||
"\n",
|
||||
" if enable_chunked_prefill:\n",
|
||||
" vllm_args.append(\"--enable-chunked-prefill\")\n",
|
||||
"\n",
|
||||
" if enable_prefix_cache:\n",
|
||||
" vllm_args.append(\"--enable-prefix-caching\")\n",
|
||||
"\n",
|
||||
" if 0 < host_prefix_kv_cache_utilization_target < 1:\n",
|
||||
" vllm_args.append(\n",
|
||||
" f\"--host-prefix-kv-cache-utilization-target={host_prefix_kv_cache_utilization_target}\"\n",
|
||||
" )\n",
|
||||
"\n",
|
||||
" if model_type:\n",
|
||||
" vllm_args.append(f\"--model-type={model_type}\")\n",
|
||||
"\n",
|
||||
" if enable_llama_tool_parser:\n",
|
||||
" vllm_args.append(\"--enable-auto-tool-choice\")\n",
|
||||
" vllm_args.append(\"--tool-call-parser=vertex-llama-3\")\n",
|
||||
"\n",
|
||||
" env_vars = {\n",
|
||||
" \"MODEL_ID\": base_model_id,\n",
|
||||
" \"DEPLOY_SOURCE\": \"notebook\",\n",
|
||||
" }\n",
|
||||
"\n",
|
||||
" # HF_TOKEN is not a compulsory field and may not be defined.\n",
|
||||
" try:\n",
|
||||
" if HF_TOKEN:\n",
|
||||
" env_vars[\"HF_TOKEN\"] = HF_TOKEN\n",
|
||||
" except NameError:\n",
|
||||
" pass\n",
|
||||
"\n",
|
||||
" model = aiplatform.Model.upload(\n",
|
||||
" display_name=model_name,\n",
|
||||
" serving_container_image_uri=VLLM_DOCKER_URI,\n",
|
||||
" serving_container_args=vllm_args,\n",
|
||||
" serving_container_ports=[8080],\n",
|
||||
" serving_container_predict_route=\"/generate\",\n",
|
||||
" serving_container_health_route=\"/ping\",\n",
|
||||
" serving_container_environment_variables=env_vars,\n",
|
||||
" serving_container_shared_memory_size_mb=(16 * 1024), # 16 GB\n",
|
||||
" serving_container_deployment_timeout=7200,\n",
|
||||
" model_garden_source_model_name=(\n",
|
||||
" f\"publishers/{publisher}/models/{publisher_model_id}\"\n",
|
||||
" ),\n",
|
||||
" )\n",
|
||||
" print(\n",
|
||||
" f\"Deploying {model_name} on {machine_type} with {accelerator_count} {accelerator_type} GPU(s).\"\n",
|
||||
" )\n",
|
||||
" model.deploy(\n",
|
||||
" endpoint=endpoint,\n",
|
||||
" machine_type=machine_type,\n",
|
||||
" accelerator_type=accelerator_type,\n",
|
||||
" accelerator_count=accelerator_count,\n",
|
||||
" deploy_request_timeout=1800,\n",
|
||||
" service_account=service_account,\n",
|
||||
" spot=is_spot,\n",
|
||||
" system_labels={\n",
|
||||
" \"NOTEBOOK_NAME\": \"model_garden_pytorch_mistral_peft_tuning.ipynb\",\n",
|
||||
" \"NOTEBOOK_ENVIRONMENT\": get_deploy_source(),\n",
|
||||
" },\n",
|
||||
" )\n",
|
||||
" print(\"endpoint_name:\", endpoint.name)\n",
|
||||
"\n",
|
||||
" return model, endpoint\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"models[\"vllm_gpu\"], endpoints[\"vllm_gpu\"] = deploy_model_vllm(\n",
|
||||
" model_name=common_util.get_job_name_with_datetime(prefix=\"mistral-vllm-serve\"),\n",
|
||||
" model_id=merged_model_output_dir,\n",
|
||||
" publisher=\"mistral-ai\",\n",
|
||||
" publisher_model_id=\"mistral\",\n",
|
||||
" service_account=SERVICE_ACCOUNT,\n",
|
||||
" machine_type=machine_type,\n",
|
||||
" accelerator_type=accelerator_type,\n",
|
||||
" accelerator_count=accelerator_count,\n",
|
||||
" gpu_memory_utilization=gpu_memory_utilization,\n",
|
||||
" max_model_len=max_model_len,\n",
|
||||
" use_dedicated_endpoint=use_dedicated_endpoint,\n",
|
||||
")\n",
|
||||
"\n",
|
||||
"# @markdown Click \"Show code\" to see more details."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"cellView": "form",
|
||||
"id": "4v2Mnui4tH1X"
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# @title Predict\n",
|
||||
"\n",
|
||||
"# @markdown Once deployment succeeds, you can send requests to the endpoint with text prompts. Sampling parameters supported by vLLM can be found [here](https://docs.vllm.ai/en/latest/dev/sampling_params.html).\n",
|
||||
"\n",
|
||||
"# @markdown Example:\n",
|
||||
"\n",
|
||||
"# @markdown ```\n",
|
||||
"# @markdown Human: What is a car?\n",
|
||||
"# @markdown Assistant: A car, or a motor car, is a road-connected human-transportation system used to move people or goods from one place to another. The term also encompasses a wide range of vehicles, including motorboats, trains, and aircrafts. Cars typically have four wheels, a cabin for passengers, and an engine or motor. They have been around since the early 19th century and are now one of the most popular forms of transportation, used for daily commuting, shopping, and other purposes.\n",
|
||||
"# @markdown ```\n",
|
||||
"# @markdown Additionally, you can moderate the generated text with Vertex AI. See [Moderate text documentation](https://cloud.google.com/natural-language/docs/moderating-text) for more details.\n",
|
||||
"\n",
|
||||
"# Loads an existing endpoint instance using the endpoint name:\n",
|
||||
"# - Using `endpoint_name = endpoint.name` allows us to get the\n",
|
||||
"# endpoint name of the endpoint `endpoint` created in the cell\n",
|
||||
"# above.\n",
|
||||
"# - Alternatively, you can set `endpoint_name = \"1234567890123456789\"` to load\n",
|
||||
"# an existing endpoint with the ID 1234567890123456789.\n",
|
||||
"# You may uncomment the code below to load an existing endpoint.\n",
|
||||
"\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",
|
||||
"\n",
|
||||
"prompt = \"What is a car?\" # @param {type: \"string\"}\n",
|
||||
"# @markdown If you encounter an issue like `ServiceUnavailable: 503 Took too long to respond when processing`, you can reduce the maximum number of output tokens, by lowering `max_tokens`.\n",
|
||||
"max_tokens = 50 # @param {type:\"integer\"}\n",
|
||||
"temperature = 1.0 # @param {type:\"number\"}\n",
|
||||
"top_p = 1.0 # @param {type:\"number\"}\n",
|
||||
"top_k = 1 # @param {type:\"integer\"}\n",
|
||||
"# @markdown Set `raw_response` to `True` to obtain the raw model output. Set `raw_response` to `False` to apply additional formatting in the structure of `\"Prompt:\\n{prompt.strip()}\\nOutput:\\n{output}\"`.\n",
|
||||
"raw_response = False # @param {type:\"boolean\"}\n",
|
||||
"\n",
|
||||
"# Overrides parameters for inferences.\n",
|
||||
"instances = [\n",
|
||||
" {\n",
|
||||
" \"prompt\": prompt,\n",
|
||||
" \"max_tokens\": max_tokens,\n",
|
||||
" \"temperature\": temperature,\n",
|
||||
" \"top_p\": top_p,\n",
|
||||
" \"top_k\": top_k,\n",
|
||||
" \"raw_response\": raw_response,\n",
|
||||
" },\n",
|
||||
"]\n",
|
||||
"response = endpoints[\"vllm_gpu\"].predict(\n",
|
||||
" instances=instances, use_dedicated_endpoint=use_dedicated_endpoint\n",
|
||||
")\n",
|
||||
"\n",
|
||||
"for prediction in response.predictions:\n",
|
||||
" print(prediction)\n",
|
||||
"\n",
|
||||
"# @markdown Click \"Show Code\" to see more details."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"cellView": "form",
|
||||
"id": "x9EMCOUJ6-ji"
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# @title Delete the model and endpoint\n",
|
||||
"\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",
|
||||
"for endpoint in endpoints.values():\n",
|
||||
" endpoint.delete(force=True)\n",
|
||||
"\n",
|
||||
"# Delete models.\n",
|
||||
"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"
|
||||
]
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"accelerator": "GPU",
|
||||
"colab": {
|
||||
"name": "model_garden_pytorch_mistral_peft_tuning.ipynb",
|
||||
"toc_visible": true
|
||||
},
|
||||
"kernelspec": {
|
||||
"display_name": "Python 3",
|
||||
"name": "python3"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 0
|
||||
}
|
||||
@@ -1,919 +0,0 @@
|
||||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"cellView": "form",
|
||||
"id": "iJc36RtD90jd"
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Copyright 2026 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": "b9EezHSo90jf"
|
||||
},
|
||||
"source": [
|
||||
"# Vertex AI Model Garden - Mixtral-8x7B (PEFT)\n",
|
||||
"\n",
|
||||
"<table><tbody><tr>\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%2Fcommunity%2Fmodel_garden%2Fmodel_garden_pytorch_mixtral_peft_tuning.ipynb\">\n",
|
||||
" <img alt=\"Google Cloud Colab Enterprise logo\" src=\"https://lh3.googleusercontent.com/JmcxdQi-qOpctIvWKgPtrzZdJJK-J3sWE1RsfjZNwshCFgE_9fULcNpuXYTilIR2hjwN\" width=\"32px\"><br> Run in Colab Enterprise\n",
|
||||
" </a>\n",
|
||||
" </td>\n",
|
||||
" <td style=\"text-align: center\">\n",
|
||||
" <a href=\"https://github.com/GoogleCloudPlatform/vertex-ai-samples/blob/main/notebooks/community/model_garden/model_garden_pytorch_mixtral_peft_tuning.ipynb\">\n",
|
||||
" <img alt=\"GitHub logo\" src=\"https://github.githubassets.com/assets/GitHub-Mark-ea2971cee799.png\" width=\"32px\"><br> View on GitHub\n",
|
||||
" </a>\n",
|
||||
" </td>\n",
|
||||
"</tr></tbody></table>"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "ybMCVFh0_5R8"
|
||||
},
|
||||
"source": [
|
||||
"## Overview\n",
|
||||
"In this notebook you will learn how to fine tune Mixtral-8x7B with QLoRa and\n",
|
||||
"deploy to Vertex AI endpoint.\n",
|
||||
"\n",
|
||||
"### Objective\n",
|
||||
"\n",
|
||||
"* Finetune and merge Mixtral-8x7B model with PEFT training docker image.\n",
|
||||
"* Deploy the finetuned model with vLLM docker image on a Vertex AI Endpoint.\n",
|
||||
"* Run inference on the deployed Vertex AI Endpoint.\n",
|
||||
"\n",
|
||||
"### File a bug\n",
|
||||
"\n",
|
||||
"File a bug on [GitHub](https://github.com/GoogleCloudPlatform/vertex-ai-samples/issues/new) if you encounter any issue with the notebook.\n",
|
||||
"\n",
|
||||
"### Costs\n",
|
||||
"\n",
|
||||
"This tutorial uses billable components of Google Cloud:\n",
|
||||
"\n",
|
||||
"* Vertex AI\n",
|
||||
"* Cloud Storage\n",
|
||||
"\n",
|
||||
"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."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "vzvFJU27a8si"
|
||||
},
|
||||
"source": [
|
||||
"## Run the notebook"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"cellView": "form",
|
||||
"id": "DzESmydvgME9"
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# @title Install Python Packages for Finetuning\n",
|
||||
"\n",
|
||||
"# @markdown 1. Install google-cloud-aiplatform package and restart the session if instructed.\n",
|
||||
"! pip install --upgrade --quiet google-cloud-aiplatform==1.130.0\n",
|
||||
"\n",
|
||||
"# @markdown 2. Install packages to validate dataset with template.\n",
|
||||
"! pip install --upgrade --quiet gcsfs==2024.3.1\n",
|
||||
"! pip install --upgrade --quiet accelerate==0.31.0\n",
|
||||
"! pip install --upgrade --quiet transformers==4.43.1\n",
|
||||
"! pip install --upgrade --quiet datasets==2.19.2\n",
|
||||
"\n",
|
||||
"# Load local tensorboard.\n",
|
||||
"%load_ext tensorboard"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"cellView": "form",
|
||||
"id": "I-OjzhpyMHsu"
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# @title Setup Google Cloud project\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. For finetuning, **[click here](https://console.cloud.google.com/iam-admin/quotas?location=us-central1&metric=aiplatform.googleapis.com%2Frestricted_image_training_nvidia_a100_80gb_gpus)** to check if your project already has the required 8 Nvidia A100 80 GB GPUs in the us-central1 region. If yes, then run this notebook in the us-central1 region. If you do not have 8 Nvidia A100 80 GPUs or have more GPU requirements than this, then schedule your job with Nvidia H100 GPUs via Dynamic Workload Scheduler using [these instructions](https://cloud.google.com/vertex-ai/docs/training/schedule-jobs-dws). For Dynamic Workload Scheduler, check the [us-central1](https://console.cloud.google.com/iam-admin/quotas?location=us-central1&metric=aiplatform.googleapis.com%2Fcustom_model_training_preemptible_nvidia_h100_gpus) or [europe-west4](https://console.cloud.google.com/iam-admin/quotas?location=europe-west4&metric=aiplatform.googleapis.com%2Fcustom_model_training_preemptible_nvidia_h100_gpus) quota for Nvidia H100 GPUs. If you do not have enough GPUs, then you can follow [these instructions](https://cloud.google.com/docs/quotas/view-manage#viewing_your_quota_console) to request quota.\n",
|
||||
"\n",
|
||||
"# @markdown 3. For serving, **[click here](https://console.cloud.google.com/iam-admin/quotas?location=us-central1&metric=aiplatform.googleapis.com%2Fcustom_model_serving_nvidia_l4_gpus)** to check if your project already has the required 1 L4 GPU in the us-central1 region. If yes, then run this notebook in the us-central1 region. If you need more L4 GPUs for your project, then you can follow [these instructions](https://cloud.google.com/docs/quotas/view-manage#viewing_your_quota_console) to request more. Alternatively, 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).\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",
|
||||
"# @markdown 4. **[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",
|
||||
"BUCKET_URI = \"gs://\" # @param {type:\"string\"}\n",
|
||||
"\n",
|
||||
"# @markdown 5. **[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",
|
||||
"# Import the necessary packages\n",
|
||||
"! rm -rf vertex-ai-samples && git clone https://github.com/GoogleCloudPlatform/vertex-ai-samples.git\n",
|
||||
"! cd vertex-ai-samples && git reset --hard 0727e19520cf7957bceb701c248221bd3dbe4f1f\n",
|
||||
"\n",
|
||||
"import datetime\n",
|
||||
"import importlib\n",
|
||||
"import os\n",
|
||||
"import uuid\n",
|
||||
"from typing import Tuple\n",
|
||||
"\n",
|
||||
"from google.cloud import aiplatform\n",
|
||||
"from google.cloud.aiplatform.compat.types import \\\n",
|
||||
" custom_job as gca_custom_job_compat\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",
|
||||
"models, endpoints = {}, {}\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",
|
||||
" if not os.environ.get(\"GOOGLE_CLOUD_REGION\"):\n",
|
||||
" raise ValueError(\n",
|
||||
" \"REGION must be set. See\"\n",
|
||||
" \" https://cloud.google.com/vertex-ai/docs/general/locations for\"\n",
|
||||
" \" available cloud locations.\"\n",
|
||||
" )\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",
|
||||
"# 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.datetime.now().strftime(\"%Y%m%d%H%M%S\")\n",
|
||||
"BUCKET_NAME = \"/\".join(BUCKET_URI.split(\"/\")[:3])\n",
|
||||
"\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, \"mixtral\")\n",
|
||||
"\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",
|
||||
"# 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",
|
||||
"# 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",
|
||||
"! gcloud projects add-iam-policy-binding --no-user-output-enabled {PROJECT_ID} --member=serviceAccount:{SERVICE_ACCOUNT} --role=\"roles/storage.admin\"\n",
|
||||
"! gcloud projects add-iam-policy-binding --no-user-output-enabled {PROJECT_ID} --member=serviceAccount:{SERVICE_ACCOUNT} --role=\"roles/aiplatform.user\""
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"cellView": "form",
|
||||
"id": "rwP8nr8jnNdt"
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# @title Set dataset\n",
|
||||
"\n",
|
||||
"# @markdown Use the Vertex AI SDK to create and run the custom training jobs.\n",
|
||||
"\n",
|
||||
"# @markdown This notebook uses [timdettmers/openassistant-guanaco](https://huggingface.co/datasets/timdettmers/openassistant-guanaco) dataset as an example.\n",
|
||||
"# @markdown You can set `dataset_name` to any existing [Hugging Face dataset](https://huggingface.co/datasets) name, and set `instruct_column_in_dataset` to the name of the dataset column containing training data. The [timdettmers/openassistant-guanaco](https://huggingface.co/datasets/timdettmers/openassistant-guanaco) has only one column `text`, and therefore we set `instruct_column_in_dataset` to `text` in this notebook.\n",
|
||||
"\n",
|
||||
"# @markdown ### (Optional) Prepare a custom JSONL dataset for finetuning\n",
|
||||
"\n",
|
||||
"# @markdown You can prepare a JSONL file where each line is a valid JSON string as your custom training dataset. For example, here is one line from the [timdettmers/openassistant-guanaco](https://huggingface.co/datasets/timdettmers/openassistant-guanaco) dataset:\n",
|
||||
"# @markdown ```\n",
|
||||
"# @markdown {\"text\": \"### Human: Hola### Assistant: \\u00a1Hola! \\u00bfEn qu\\u00e9 puedo ayudarte hoy?\"}\n",
|
||||
"# @markdown ```\n",
|
||||
"\n",
|
||||
"# @markdown The JSON object has a key `text`, which should match `instruct_column_in_dataset`; The value should be one training data point, i.e. a string. After you prepared your JSONL file, you can either upload it to [Hugging Face datasets](https://huggingface.co/datasets) or [Google Cloud Storage](https://cloud.google.com/storage).\n",
|
||||
"\n",
|
||||
"# @markdown - To upload a JSONL dataset to [Hugging Face datasets](https://huggingface.co/datasets), follow the instructions on [Uploading Datasets](https://huggingface.co/docs/hub/en/datasets-adding). Then, set `dataset_name` to the name of your newly created dataset on Hugging Face.\n",
|
||||
"\n",
|
||||
"# @markdown - To upload a JSONL dataset to [Google Cloud Storage](https://cloud.google.com/storage), follow the instructions on [Upload objects from a filesystem](https://cloud.google.com/storage/docs/uploading-objects). Then, set `dataset_name` to the `gs://` URI to your JSONL file. For example: `gs://cloud-samples-data/vertex-ai/model-evaluation/peft_train_sample.jsonl`.\n",
|
||||
"\n",
|
||||
"# @markdown Optionally update the `instruct_column_in_dataset` field below if your JSON objects use a key other than the default `text`.\n",
|
||||
"\n",
|
||||
"# @markdown ### (Optional) Format your data with custom JSON template\n",
|
||||
"\n",
|
||||
"# @markdown Sometimes, your dataset might have multiple text columns and you want to construct the training data with a template. You can prepare a JSON template in the following format:\n",
|
||||
"\n",
|
||||
"# @markdown ```\n",
|
||||
"# @markdown {\n",
|
||||
"# @markdown \"description\": \"Template that accepts text-bison format.\",\n",
|
||||
"# @markdown \"source\": \"https://cloud.google.com/vertex-ai/generative-ai/docs/models/tune-text-models-supervised#dataset-format\",\n",
|
||||
"# @markdown \"prompt_input\": \"\\n\\n<|start_header_id|>user<|end_header_id|>\\n\\n{input_text}<|eot_id|>\\n\\n<|start_header_id|>assistant<|end_header_id|>\\n\\n{output_text}<|eot_id|>\",\n",
|
||||
"# @markdown \"instruction_separator\": \"<|start_header_id|>user<|end_header_id|>\\n\\n\",\n",
|
||||
"# @markdown \"response_separator\": \"<|start_header_id|>assistant<|end_header_id|>\\n\\n\"\n",
|
||||
"# @markdown }\n",
|
||||
"# @markdown ```\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"# @markdown As an example, the template above can be used to format the following training data (this line comes from `gs://cloud-samples-data/vertex-ai/model-evaluation/peft_train_sample.jsonl`):\n",
|
||||
"\n",
|
||||
"# @markdown ```\n",
|
||||
"# @markdown {\"input_text\":\"TRANSCRIPT: \\nREASON FOR EVALUATION:,\\n\\n LABEL:\",\"output_text\":\"Chiropractic\"}\n",
|
||||
"# @markdown ```\n",
|
||||
"\n",
|
||||
"# @markdown This example template simply concatenates `input_text` with `output_text` with some special tokens in between.\n",
|
||||
"# @markdown\n",
|
||||
"# @markdown To try such custom dataset, you can make the following changes:\n",
|
||||
"# @markdown 1. Set `template` to `llama3-text-bison`\n",
|
||||
"# @markdown 1. Set `train_dataset_name` to `gs://cloud-samples-data/vertex-ai/model-evaluation/peft_train_sample.jsonl`\n",
|
||||
"# @markdown 1. Set `train_split_name` to `train`\n",
|
||||
"# @markdown 1. Set `eval_dataset_name` to `gs://cloud-samples-data/vertex-ai/model-evaluation/peft_eval_sample.jsonl`\n",
|
||||
"# @markdown 1. Set `eval_split_name` to `train` (**NOT** `test`)\n",
|
||||
"# @markdown 1. Set `instruct_column_in_dataset` as `input_text`.\n",
|
||||
"\n",
|
||||
"# Template name or gs:// URI to a custom template.\n",
|
||||
"template = \"openassistant-guanaco\" # @param {type:\"string\"}\n",
|
||||
"\n",
|
||||
"# Hugging Face dataset name or gs:// URI to a custom JSONL dataset.\n",
|
||||
"train_dataset_name = \"timdettmers/openassistant-guanaco\" # @param {type:\"string\"}\n",
|
||||
"train_split_name = \"train\" # @param {type:\"string\"}\n",
|
||||
"eval_dataset_name = \"timdettmers/openassistant-guanaco\" # @param {type:\"string\"}\n",
|
||||
"eval_split_name = \"test\" # @param {type:\"string\"}\n",
|
||||
"\n",
|
||||
"# Name of the dataset column containing training text input.\n",
|
||||
"instruct_column_in_dataset = \"text\" # @param {type:\"string\"}"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"cellView": "form",
|
||||
"id": "lkCVPgWl2vxv"
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# @title Set model\n",
|
||||
"\n",
|
||||
"# @markdown Select a model variant of Mixtral.\n",
|
||||
"base_model_id = \"mistralai/Mixtral-8x7B-v0.1\" # @param [\"mistralai/Mixtral-8x7B-v0.1\"] {isTemplate: true}\n",
|
||||
"pretrained_model_id = f\"gs://vertex-model-garden-public-us/{base_model_id}\""
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"cellView": "form",
|
||||
"id": "YZPqfZ-FvPXS"
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# @title Validate Dataset with Template\n",
|
||||
"\n",
|
||||
"# @markdown This section validates the train and eval datasets with the template before starting the fine tuning process.\n",
|
||||
"\n",
|
||||
"import transformers\n",
|
||||
"\n",
|
||||
"dataset_validation_util = importlib.import_module(\n",
|
||||
" \"vertex-ai-samples.community-content.vertex_model_garden.model_oss.notebook_util.dataset_validation_util\"\n",
|
||||
")\n",
|
||||
"\n",
|
||||
"if dataset_validation_util.is_gcs_path(pretrained_model_id):\n",
|
||||
" # Download tokenizer.\n",
|
||||
" ! mkdir tokenizer\n",
|
||||
" ! gsutil cp {pretrained_model_id}/tokenizer.json ./tokenizer\n",
|
||||
" ! gsutil cp {pretrained_model_id}/config.json ./tokenizer\n",
|
||||
" tokenizer_path = \"./tokenizer\"\n",
|
||||
" access_token = \"\"\n",
|
||||
"else:\n",
|
||||
" tokenizer_path = pretrained_model_id\n",
|
||||
" access_token = HF_TOKEN\n",
|
||||
"\n",
|
||||
"tokenizer = transformers.AutoTokenizer.from_pretrained(\n",
|
||||
" tokenizer_path,\n",
|
||||
" trust_remote_code=False,\n",
|
||||
" use_fast=True,\n",
|
||||
" token=access_token,\n",
|
||||
")\n",
|
||||
"\n",
|
||||
"# Validate the train dataset.\n",
|
||||
"dataset_validation_util.validate_dataset_with_template(\n",
|
||||
" dataset_name=train_dataset_name,\n",
|
||||
" split=train_split_name,\n",
|
||||
" input_column=instruct_column_in_dataset,\n",
|
||||
" template=template,\n",
|
||||
" use_multiprocessing=False,\n",
|
||||
" tokenizer=tokenizer,\n",
|
||||
")\n",
|
||||
"\n",
|
||||
"# Validate the eval dataset.\n",
|
||||
"dataset_validation_util.validate_dataset_with_template(\n",
|
||||
" dataset_name=eval_dataset_name,\n",
|
||||
" split=eval_split_name,\n",
|
||||
" input_column=instruct_column_in_dataset,\n",
|
||||
" template=template,\n",
|
||||
" use_multiprocessing=False,\n",
|
||||
" tokenizer=tokenizer,\n",
|
||||
")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"cellView": "form",
|
||||
"id": "885Vf4o8hbbo"
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# @title Finetune\n",
|
||||
"\n",
|
||||
"# @markdown This section demonstrates how to finetune the Mixtral-8x7B model and merge the finetuned LoRA adapter with the base model on Vertex AI. It uses the Vertex AI SDK to create and run the custom training jobs.\n",
|
||||
"\n",
|
||||
"# @markdown The training job takes approximately between 10 to 20 mins to set-up. Once done, the training job is expected to take around 90 mins with the default configurations. To find the training time, throughput, and memory usage of your training job, you can go to the training logs and check the log line of the last training epoch.\n",
|
||||
"\n",
|
||||
"# @markdown **Note**:\n",
|
||||
"# @markdown 1. We recommend setting `finetuning_precision_mode` to `4bit` because it enables using fewer hardware resources for finetuning.\n",
|
||||
"# @markdown 1. If `max_steps > 0`, it takes precedence over `epochs`. One can set a small `max_steps` value to quickly check the pipeline.\n",
|
||||
"\n",
|
||||
"# @markdown Acceletor type to use for training.\n",
|
||||
"accelerator_type = \"NVIDIA_A100_80GB\" # @param [\"NVIDIA_A100_80GB\", \"NVIDIA_H100_80GB\"]\n",
|
||||
"\n",
|
||||
"# The pre-built training docker image.\n",
|
||||
"if accelerator_type == \"NVIDIA_A100_80GB\":\n",
|
||||
" repo = \"us-docker.pkg.dev/vertex-ai-restricted\"\n",
|
||||
" is_restricted_image = True\n",
|
||||
" is_dynamic_workload_scheduler = False\n",
|
||||
" dws_kwargs = {}\n",
|
||||
"else:\n",
|
||||
" repo = \"us-docker.pkg.dev/vertex-ai\"\n",
|
||||
" is_restricted_image = False\n",
|
||||
" is_dynamic_workload_scheduler = True\n",
|
||||
" dws_kwargs = {\n",
|
||||
" \"max_wait_duration\": 1800, # 30 minutes\n",
|
||||
" \"scheduling_strategy\": gca_custom_job_compat.Scheduling.Strategy.FLEX_START,\n",
|
||||
" }\n",
|
||||
"\n",
|
||||
"TRAIN_DOCKER_URI = (\n",
|
||||
" f\"{repo}/vertex-vision-model-garden-dockers/pytorch-peft-train:stable_20240909\"\n",
|
||||
")\n",
|
||||
"\n",
|
||||
"# Worker pool spec.\n",
|
||||
"if accelerator_type == \"NVIDIA_A100_80GB\":\n",
|
||||
" per_node_accelerator_count = 8\n",
|
||||
" machine_type = \"a2-ultragpu-8g\"\n",
|
||||
"elif accelerator_type == \"NVIDIA_H100_80GB\":\n",
|
||||
" per_node_accelerator_count = 8\n",
|
||||
" machine_type = \"a3-highgpu-8g\"\n",
|
||||
"else:\n",
|
||||
" raise ValueError(\n",
|
||||
" f\"Recommended machine settings not found for: {accelerator_type}. To use another accelerator type, edit this code block to pass in an appropriate `machine_type`, `accelerator_type`, and `per_node_accelerator_count` to the deploy_model_vllm function by clicking `Show Code` and then modifying the code.\"\n",
|
||||
" )\n",
|
||||
"\n",
|
||||
"# @markdown Batch size for finetuning.\n",
|
||||
"per_device_train_batch_size = 1 # @param{type:\"integer\"}\n",
|
||||
"# @markdown Number of updates steps to accumulate the gradients for, before performing a backward/update pass.\n",
|
||||
"gradient_accumulation_steps = 4 # @param{type:\"integer\"}\n",
|
||||
"# @markdown Maximum sequence length.\n",
|
||||
"max_seq_length = 4096 # @param{type:\"integer\"}\n",
|
||||
"# @markdown Setting a positive `max_steps` here will override `num_epochs`.\n",
|
||||
"max_steps = -1 # @param{type:\"integer\"}\n",
|
||||
"num_epochs = 1.0 # @param{type:\"number\"}\n",
|
||||
"# @markdown Precision mode for finetuning.\n",
|
||||
"finetuning_precision_mode = \"4bit\" # @param [\"4bit\"]\n",
|
||||
"# @markdown Learning rate.\n",
|
||||
"learning_rate = 5e-5 # @param{type:\"number\"}\n",
|
||||
"# @markdown The scheduler type to use.\n",
|
||||
"lr_scheduler_type = \"cosine\" # @param{type:\"string\"}\n",
|
||||
"# @markdown LoRA parameters.\n",
|
||||
"lora_rank = 16 # @param{type:\"integer\"}\n",
|
||||
"lora_alpha = 32 # @param{type:\"integer\"}\n",
|
||||
"lora_dropout = 0.05 # @param{type:\"number\"}\n",
|
||||
"# Activates gradient checkpointing for the current model (may be referred to as activation checkpointing or checkpoint activations in other frameworks).\n",
|
||||
"enable_gradient_checkpointing = True\n",
|
||||
"# Attention implementation to use in the model.\n",
|
||||
"attn_implementation = \"flash_attention_2\"\n",
|
||||
"# The optimizer for which to schedule the learning rate.\n",
|
||||
"optimizer = \"paged_adamw_32bit\"\n",
|
||||
"# Define the proportion of training to be dedicated to a linear warmup where learning rate gradually increases.\n",
|
||||
"warmup_ratio = \"0.01\"\n",
|
||||
"# The list or string of integrations to report the results and logs to.\n",
|
||||
"report_to = \"tensorboard\"\n",
|
||||
"# Number of updates steps before two checkpoint saves.\n",
|
||||
"save_steps = 10\n",
|
||||
"# Number of update steps between two logs.\n",
|
||||
"logging_steps = save_steps\n",
|
||||
"# Train precision of the model.\n",
|
||||
"train_precision = \"float16\"\n",
|
||||
"\n",
|
||||
"replica_count = 1\n",
|
||||
"\n",
|
||||
"common_util.check_quota(\n",
|
||||
" project_id=PROJECT_ID,\n",
|
||||
" region=REGION,\n",
|
||||
" accelerator_type=accelerator_type,\n",
|
||||
" accelerator_count=per_node_accelerator_count * replica_count,\n",
|
||||
" is_for_training=True,\n",
|
||||
" is_restricted_image=is_restricted_image,\n",
|
||||
" is_dynamic_workload_scheduler=is_dynamic_workload_scheduler,\n",
|
||||
")\n",
|
||||
"\n",
|
||||
"# Setup training job.\n",
|
||||
"job_name = common_util.get_job_name_with_datetime(\"mixtral-lora-train\")\n",
|
||||
"\n",
|
||||
"base_output_dir = os.path.join(STAGING_BUCKET, job_name)\n",
|
||||
"# Create a GCS folder to store the LORA adapter.\n",
|
||||
"lora_output_dir = os.path.join(base_output_dir, \"adapter\")\n",
|
||||
"# Create a GCS folder to store the merged model with the base model and the\n",
|
||||
"# finetuned LORA adapter.\n",
|
||||
"merged_model_output_dir = os.path.join(base_output_dir, \"merged-model\")\n",
|
||||
"\n",
|
||||
"# Add labels for the finetuning job.\n",
|
||||
"labels = {\n",
|
||||
" \"mg-source\": \"notebook\",\n",
|
||||
" \"mg-notebook-name\": \"model_garden_pytorch_mixtral_peft_tuning.ipynb\".split(\".\")[0],\n",
|
||||
"}\n",
|
||||
"\n",
|
||||
"labels[\"mg-tune\"] = \"publishers-mistralai-models-mixtral\"\n",
|
||||
"versioned_model_id = base_model_id.split(\"/\")[1].lower().replace(\".\", \"-\")\n",
|
||||
"labels[\"versioned-mg-tune\"] = f\"{labels['mg-tune']}-{versioned_model_id}\"\n",
|
||||
"\n",
|
||||
"eval_args = [\n",
|
||||
" f\"--eval_dataset_path={eval_dataset_name}\",\n",
|
||||
" f\"--eval_column={instruct_column_in_dataset}\",\n",
|
||||
" f\"--eval_template={template}\",\n",
|
||||
" f\"--eval_split={eval_split_name}\",\n",
|
||||
" f\"--eval_steps={save_steps}\",\n",
|
||||
" \"--eval_tasks=builtin_eval\",\n",
|
||||
" \"--eval_metric_name=loss\",\n",
|
||||
"]\n",
|
||||
"\n",
|
||||
"train_job_args = [\n",
|
||||
" \"--config_file=vertex_vision_model_garden_peft/deepspeed_zero2_8gpu.yaml\",\n",
|
||||
" \"--task=instruct-lora\",\n",
|
||||
" \"--completion_only=False\",\n",
|
||||
" f\"--pretrained_model_id={pretrained_model_id}\",\n",
|
||||
" f\"--dataset_name={train_dataset_name}\",\n",
|
||||
" f\"--train_split_name={train_split_name}\",\n",
|
||||
" f\"--instruct_column_in_dataset={instruct_column_in_dataset}\",\n",
|
||||
" f\"--output_dir={lora_output_dir}\",\n",
|
||||
" f\"--merge_base_and_lora_output_dir={merged_model_output_dir}\",\n",
|
||||
" f\"--per_device_train_batch_size={per_device_train_batch_size}\",\n",
|
||||
" f\"--gradient_accumulation_steps={gradient_accumulation_steps}\",\n",
|
||||
" f\"--lora_rank={lora_rank}\",\n",
|
||||
" f\"--lora_alpha={lora_alpha}\",\n",
|
||||
" f\"--lora_dropout={lora_dropout}\",\n",
|
||||
" f\"--max_steps={max_steps}\",\n",
|
||||
" f\"--max_seq_length={max_seq_length}\",\n",
|
||||
" f\"--learning_rate={learning_rate}\",\n",
|
||||
" f\"--lr_scheduler_type={lr_scheduler_type}\",\n",
|
||||
" f\"--precision_mode={finetuning_precision_mode}\",\n",
|
||||
" f\"--train_precision={train_precision}\",\n",
|
||||
" f\"--enable_gradient_checkpointing={enable_gradient_checkpointing}\",\n",
|
||||
" f\"--num_epochs={num_epochs}\",\n",
|
||||
" f\"--attn_implementation={attn_implementation}\",\n",
|
||||
" f\"--optimizer={optimizer}\",\n",
|
||||
" f\"--warmup_ratio={warmup_ratio}\",\n",
|
||||
" f\"--report_to={report_to}\",\n",
|
||||
" f\"--logging_output_dir={base_output_dir}\",\n",
|
||||
" f\"--save_steps={save_steps}\",\n",
|
||||
" f\"--logging_steps={logging_steps}\",\n",
|
||||
" f\"--template={template}\",\n",
|
||||
"] + eval_args\n",
|
||||
"\n",
|
||||
"train_job = aiplatform.CustomContainerTrainingJob(\n",
|
||||
" display_name=job_name,\n",
|
||||
" container_uri=TRAIN_DOCKER_URI,\n",
|
||||
" labels=labels,\n",
|
||||
")\n",
|
||||
"\n",
|
||||
"print(\"Running training job with args:\")\n",
|
||||
"print(\" \\\\\\n\".join(train_job_args))\n",
|
||||
"# Pass training arguments and launch job.\n",
|
||||
"train_job.run(\n",
|
||||
" args=train_job_args,\n",
|
||||
" replica_count=replica_count,\n",
|
||||
" machine_type=machine_type,\n",
|
||||
" accelerator_type=accelerator_type,\n",
|
||||
" accelerator_count=per_node_accelerator_count,\n",
|
||||
" boot_disk_size_gb=500,\n",
|
||||
" service_account=SERVICE_ACCOUNT,\n",
|
||||
" base_output_dir=base_output_dir,\n",
|
||||
" sync=False, # Non-blocking call to run.\n",
|
||||
" **dws_kwargs,\n",
|
||||
")\n",
|
||||
"\n",
|
||||
"# Wait until resource has been created.\n",
|
||||
"train_job.wait_for_resource_creation()\n",
|
||||
"\n",
|
||||
"print(\"LoRA adapter will be saved in:\", lora_output_dir)\n",
|
||||
"print(\"Trained and merged models will be saved in:\", merged_model_output_dir)\n",
|
||||
"\n",
|
||||
"# @markdown Click \"Show Code\" to see more details."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"cellView": "form",
|
||||
"id": "gLzO6p0Gm2BM"
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# @title Run TensorBoard\n",
|
||||
"# @markdown This section shows how to launch TensorBoard in a [Cloud Shell](https://cloud.google.com/shell/docs).\n",
|
||||
"# @markdown 1. Click the Cloud Shell icon() on the top right to open the Cloud Shell.\n",
|
||||
"# @markdown 2. Copy the `tensorboard` command shown below by running this cell.\n",
|
||||
"# @markdown 3. Paste and run the command in the Cloud Shell to launch TensorBoard.\n",
|
||||
"# @markdown 4. Once the command runs (You may have to click `Authorize` if prompted), click the link starting with `http://localhost`.\n",
|
||||
"\n",
|
||||
"# @markdown Note: You may need to wait around 10 minutes after the job starts in order for the TensorBoard logs to be written to the GCS bucket.\n",
|
||||
"print(f\"Command to copy: tensorboard --logdir {base_output_dir}/logs\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"cellView": "form",
|
||||
"id": "GyDWPdV1NjMT"
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# @title Deploy\n",
|
||||
"# @markdown This section uploads the model to Model Registry and deploys it on the Endpoint. It takes 15 minutes to 1 hour to finish depending on the size of model.\n",
|
||||
"\n",
|
||||
"if train_job.end_time is None:\n",
|
||||
" print(\"Waiting for the training job to finish...\")\n",
|
||||
" train_job.wait()\n",
|
||||
" print(\"The training job has finished.\")\n",
|
||||
"\n",
|
||||
"print(\"Deploying models in:\", merged_model_output_dir)\n",
|
||||
"\n",
|
||||
"# The pre-built serving docker image for vLLM.\n",
|
||||
"VLLM_DOCKER_URI = \"us-docker.pkg.dev/vertex-ai/vertex-vision-model-garden-dockers/pytorch-vllm-serve:20240721_0916_RC00\"\n",
|
||||
"\n",
|
||||
"dtype = \"auto\"\n",
|
||||
"\n",
|
||||
"# @markdown L4 GPUs are good serving solutions and are more cost effective than V100s for 8x7B models. The 8x22B models only works with A100/H100 GPUs now.\n",
|
||||
"\n",
|
||||
"# Find Vertex AI prediction supported accelerators and regions [here](https://cloud.google.com/vertex-ai/docs/predictions/configure-compute).\n",
|
||||
"# @markdown Accelerator type to use for serving.\n",
|
||||
"accelerator_type = \"NVIDIA_L4\" # @param [\"NVIDIA_L4\", \"NVIDIA_TESLA_V100\", \"NVIDIA_H100_80GB\"]\n",
|
||||
"\n",
|
||||
"if accelerator_type == \"NVIDIA_L4\":\n",
|
||||
" machine_type = \"g2-standard-96\"\n",
|
||||
" accelerator_count = 8\n",
|
||||
"elif accelerator_type == \"NVIDIA_TESLA_V100\":\n",
|
||||
" machine_type = \"n1-highmem-32\"\n",
|
||||
" accelerator_count = 8\n",
|
||||
" dtype = \"float16\"\n",
|
||||
"elif accelerator_type == \"NVIDIA_H100_80GB\":\n",
|
||||
" machine_type = \"a3-highgpu-8g\"\n",
|
||||
" accelerator_count = 8\n",
|
||||
"\n",
|
||||
"if \"22B\" in base_model_id and accelerator_type != \"NVIDIA_H100_80GB\":\n",
|
||||
" raise ValueError(\"8x22B model version only works with H100/A100 GPUs.\")\n",
|
||||
"\n",
|
||||
"common_util.check_quota(\n",
|
||||
" project_id=PROJECT_ID,\n",
|
||||
" region=REGION,\n",
|
||||
" accelerator_type=accelerator_type,\n",
|
||||
" accelerator_count=accelerator_count,\n",
|
||||
" is_for_training=False,\n",
|
||||
")\n",
|
||||
"\n",
|
||||
"# @markdown Set `use_dedicated_endpoint` to False if you don't want to use [dedicated endpoint](https://cloud.google.com/vertex-ai/docs/general/deployment#create-dedicated-endpoint).\n",
|
||||
"use_dedicated_endpoint = True # @param {type:\"boolean\"}\n",
|
||||
"\n",
|
||||
"gpu_memory_utilization = 0.85\n",
|
||||
"max_model_len = 8192 # Maximum context length.\n",
|
||||
"\n",
|
||||
"# Ensure max_model_len does not exceed the limit\n",
|
||||
"if max_model_len > 8192:\n",
|
||||
" raise ValueError(\"max_model_len cannot exceed 8192\")\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"def get_deploy_source() -> str:\n",
|
||||
" \"\"\"Gets deploy_source string based on running environment.\"\"\"\n",
|
||||
" vertex_product = os.environ.get(\"VERTEX_PRODUCT\", \"\")\n",
|
||||
" if vertex_product == \"COLAB_ENTERPRISE\":\n",
|
||||
" return \"notebook_colab_enterprise\"\n",
|
||||
" elif vertex_product == \"WORKBENCH_INSTANCE\":\n",
|
||||
" return \"notebook_workbench\"\n",
|
||||
" else:\n",
|
||||
" # Legacy workbench, legacy colab, or other custom environments.\n",
|
||||
" return \"notebook_environment_unspecified\"\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"def deploy_model_vllm(\n",
|
||||
" model_name: str,\n",
|
||||
" model_id: str,\n",
|
||||
" publisher: str,\n",
|
||||
" publisher_model_id: str,\n",
|
||||
" service_account: str,\n",
|
||||
" base_model_id: str = None,\n",
|
||||
" machine_type: str = \"g2-standard-8\",\n",
|
||||
" accelerator_type: str = \"NVIDIA_L4\",\n",
|
||||
" accelerator_count: int = 1,\n",
|
||||
" gpu_memory_utilization: float = 0.9,\n",
|
||||
" max_model_len: int = 4096,\n",
|
||||
" dtype: str = \"auto\",\n",
|
||||
" enable_trust_remote_code: bool = False,\n",
|
||||
" enforce_eager: bool = False,\n",
|
||||
" enable_lora: bool = False,\n",
|
||||
" enable_chunked_prefill: bool = False,\n",
|
||||
" enable_prefix_cache: bool = False,\n",
|
||||
" host_prefix_kv_cache_utilization_target: float = 0.0,\n",
|
||||
" max_loras: int = 1,\n",
|
||||
" max_cpu_loras: int = 8,\n",
|
||||
" use_dedicated_endpoint: bool = False,\n",
|
||||
" max_num_seqs: int = 256,\n",
|
||||
" model_type: str = None,\n",
|
||||
" enable_llama_tool_parser: bool = False,\n",
|
||||
" is_spot: bool = False,\n",
|
||||
") -> Tuple[aiplatform.Model, aiplatform.Endpoint]:\n",
|
||||
" \"\"\"Deploys trained models with vLLM into Vertex AI.\"\"\"\n",
|
||||
" endpoint = aiplatform.Endpoint.create(\n",
|
||||
" display_name=f\"{model_name}-endpoint\",\n",
|
||||
" dedicated_endpoint_enabled=use_dedicated_endpoint,\n",
|
||||
" )\n",
|
||||
"\n",
|
||||
" if not base_model_id:\n",
|
||||
" base_model_id = model_id\n",
|
||||
"\n",
|
||||
" # See https://docs.vllm.ai/en/latest/models/engine_args.html for a list of possible arguments with descriptions.\n",
|
||||
" vllm_args = [\n",
|
||||
" \"python\",\n",
|
||||
" \"-m\",\n",
|
||||
" \"vllm.entrypoints.api_server\",\n",
|
||||
" \"--host=0.0.0.0\",\n",
|
||||
" \"--port=8080\",\n",
|
||||
" f\"--model={model_id}\",\n",
|
||||
" f\"--tensor-parallel-size={accelerator_count}\",\n",
|
||||
" \"--swap-space=16\",\n",
|
||||
" f\"--max-model-len={max_model_len}\",\n",
|
||||
" f\"--dtype={dtype}\",\n",
|
||||
" f\"--max-loras={max_loras}\",\n",
|
||||
" f\"--max-cpu-loras={max_cpu_loras}\",\n",
|
||||
" f\"--max-num-seqs={max_num_seqs}\",\n",
|
||||
" \"--disable-log-stats\",\n",
|
||||
" ]\n",
|
||||
"\n",
|
||||
" if gpu_memory_utilization:\n",
|
||||
" vllm_args.append(f\"--gpu-memory-utilization={gpu_memory_utilization}\")\n",
|
||||
"\n",
|
||||
" if enable_trust_remote_code:\n",
|
||||
" vllm_args.append(\"--trust-remote-code\")\n",
|
||||
"\n",
|
||||
" if enforce_eager:\n",
|
||||
" vllm_args.append(\"--enforce-eager\")\n",
|
||||
"\n",
|
||||
" if enable_lora:\n",
|
||||
" vllm_args.append(\"--enable-lora\")\n",
|
||||
"\n",
|
||||
" if enable_chunked_prefill:\n",
|
||||
" vllm_args.append(\"--enable-chunked-prefill\")\n",
|
||||
"\n",
|
||||
" if enable_prefix_cache:\n",
|
||||
" vllm_args.append(\"--enable-prefix-caching\")\n",
|
||||
"\n",
|
||||
" if 0 < host_prefix_kv_cache_utilization_target < 1:\n",
|
||||
" vllm_args.append(\n",
|
||||
" f\"--host-prefix-kv-cache-utilization-target={host_prefix_kv_cache_utilization_target}\"\n",
|
||||
" )\n",
|
||||
"\n",
|
||||
" if model_type:\n",
|
||||
" vllm_args.append(f\"--model-type={model_type}\")\n",
|
||||
"\n",
|
||||
" if enable_llama_tool_parser:\n",
|
||||
" vllm_args.append(\"--enable-auto-tool-choice\")\n",
|
||||
" vllm_args.append(\"--tool-call-parser=vertex-llama-3\")\n",
|
||||
"\n",
|
||||
" env_vars = {\n",
|
||||
" \"MODEL_ID\": base_model_id,\n",
|
||||
" \"DEPLOY_SOURCE\": \"notebook\",\n",
|
||||
" }\n",
|
||||
"\n",
|
||||
" # HF_TOKEN is not a compulsory field and may not be defined.\n",
|
||||
" try:\n",
|
||||
" if HF_TOKEN:\n",
|
||||
" env_vars[\"HF_TOKEN\"] = HF_TOKEN\n",
|
||||
" except NameError:\n",
|
||||
" pass\n",
|
||||
"\n",
|
||||
" model = aiplatform.Model.upload(\n",
|
||||
" display_name=model_name,\n",
|
||||
" serving_container_image_uri=VLLM_DOCKER_URI,\n",
|
||||
" serving_container_args=vllm_args,\n",
|
||||
" serving_container_ports=[8080],\n",
|
||||
" serving_container_predict_route=\"/generate\",\n",
|
||||
" serving_container_health_route=\"/ping\",\n",
|
||||
" serving_container_environment_variables=env_vars,\n",
|
||||
" serving_container_shared_memory_size_mb=(16 * 1024), # 16 GB\n",
|
||||
" serving_container_deployment_timeout=7200,\n",
|
||||
" model_garden_source_model_name=(\n",
|
||||
" f\"publishers/{publisher}/models/{publisher_model_id}\"\n",
|
||||
" ),\n",
|
||||
" )\n",
|
||||
" print(\n",
|
||||
" f\"Deploying {model_name} on {machine_type} with {accelerator_count} {accelerator_type} GPU(s).\"\n",
|
||||
" )\n",
|
||||
" model.deploy(\n",
|
||||
" endpoint=endpoint,\n",
|
||||
" machine_type=machine_type,\n",
|
||||
" accelerator_type=accelerator_type,\n",
|
||||
" accelerator_count=accelerator_count,\n",
|
||||
" deploy_request_timeout=1800,\n",
|
||||
" service_account=service_account,\n",
|
||||
" spot=is_spot,\n",
|
||||
" system_labels={\n",
|
||||
" \"NOTEBOOK_NAME\": \"model_garden_pytorch_mixtral_peft_tuning.ipynb\",\n",
|
||||
" \"NOTEBOOK_ENVIRONMENT\": get_deploy_source(),\n",
|
||||
" },\n",
|
||||
" )\n",
|
||||
" print(\"endpoint_name:\", endpoint.name)\n",
|
||||
"\n",
|
||||
" return model, endpoint\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"models[\"vllm_gpu\"], endpoints[\"vllm_gpu\"] = deploy_model_vllm(\n",
|
||||
" model_name=common_util.get_job_name_with_datetime(prefix=\"mixtral-vllm-serve\"),\n",
|
||||
" model_id=merged_model_output_dir,\n",
|
||||
" publisher=\"mistral-ai\",\n",
|
||||
" publisher_model_id=\"mixtral\",\n",
|
||||
" service_account=SERVICE_ACCOUNT,\n",
|
||||
" machine_type=machine_type,\n",
|
||||
" accelerator_type=accelerator_type,\n",
|
||||
" accelerator_count=accelerator_count,\n",
|
||||
" gpu_memory_utilization=gpu_memory_utilization,\n",
|
||||
" max_model_len=max_model_len,\n",
|
||||
" dtype=dtype,\n",
|
||||
" use_dedicated_endpoint=use_dedicated_endpoint,\n",
|
||||
")\n",
|
||||
"\n",
|
||||
"# @markdown Click \"Show code\" to see more details."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"cellView": "form",
|
||||
"id": "4v2Mnui4tH1X"
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# @title Predict\n",
|
||||
"\n",
|
||||
"# @markdown Once deployment succeeds, you can send requests to the endpoint with text prompts. Sampling parameters supported by vLLM can be found [here](https://docs.vllm.ai/en/latest/dev/sampling_params.html).\n",
|
||||
"\n",
|
||||
"# @markdown Example:\n",
|
||||
"\n",
|
||||
"# @markdown ```\n",
|
||||
"# @markdown Human: What is a car?\n",
|
||||
"# @markdown Assistant: A car, or a motor car, is a road-connected human-transportation system used to move people or goods from one place to another. The term also encompasses a wide range of vehicles, including motorboats, trains, and aircrafts. Cars typically have four wheels, a cabin for passengers, and an engine or motor. They have been around since the early 19th century and are now one of the most popular forms of transportation, used for daily commuting, shopping, and other purposes.\n",
|
||||
"# @markdown ```\n",
|
||||
"# @markdown Additionally, you can moderate the generated text with Vertex AI. See [Moderate text documentation](https://cloud.google.com/natural-language/docs/moderating-text) for more details.\n",
|
||||
"\n",
|
||||
"# Loads an existing endpoint instance using the endpoint name:\n",
|
||||
"# - Using `endpoint_name = endpoint.name` allows us to get the\n",
|
||||
"# endpoint name of the endpoint `endpoint` created in the cell\n",
|
||||
"# above.\n",
|
||||
"# - Alternatively, you can set `endpoint_name = \"1234567890123456789\"` to load\n",
|
||||
"# an existing endpoint with the ID 1234567890123456789.\n",
|
||||
"# You may uncomment the code below to load an existing endpoint.\n",
|
||||
"\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",
|
||||
"\n",
|
||||
"prompt = \"What is a car?\" # @param {type: \"string\"}\n",
|
||||
"# @markdown If you encounter an issue like `ServiceUnavailable: 503 Took too long to respond when processing`, you can reduce the maximum number of output tokens, by lowering `max_tokens`.\n",
|
||||
"max_tokens = 50 # @param {type:\"integer\"}\n",
|
||||
"temperature = 1.0 # @param {type:\"number\"}\n",
|
||||
"top_p = 1.0 # @param {type:\"number\"}\n",
|
||||
"top_k = 1 # @param {type:\"integer\"}\n",
|
||||
"# @markdown Set `raw_response` to `True` to obtain the raw model output. Set `raw_response` to `False` to apply additional formatting in the structure of `\"Prompt:\\n{prompt.strip()}\\nOutput:\\n{output}\"`.\n",
|
||||
"raw_response = False # @param {type:\"boolean\"}\n",
|
||||
"\n",
|
||||
"# Overrides parameters for inferences.\n",
|
||||
"instances = [\n",
|
||||
" {\n",
|
||||
" \"prompt\": prompt,\n",
|
||||
" \"max_tokens\": max_tokens,\n",
|
||||
" \"temperature\": temperature,\n",
|
||||
" \"top_p\": top_p,\n",
|
||||
" \"top_k\": top_k,\n",
|
||||
" \"raw_response\": raw_response,\n",
|
||||
" },\n",
|
||||
"]\n",
|
||||
"response = endpoints[\"vllm_gpu\"].predict(\n",
|
||||
" instances=instances, use_dedicated_endpoint=use_dedicated_endpoint\n",
|
||||
")\n",
|
||||
"\n",
|
||||
"for prediction in response.predictions:\n",
|
||||
" print(prediction)\n",
|
||||
"\n",
|
||||
"# @markdown Click \"Show Code\" to see more details."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"cellView": "form",
|
||||
"id": "x9EMCOUJ6-ji"
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# @title Delete the model and endpoint\n",
|
||||
"\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",
|
||||
"for endpoint in endpoints.values():\n",
|
||||
" endpoint.delete(force=True)\n",
|
||||
"\n",
|
||||
"# Delete models.\n",
|
||||
"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"
|
||||
]
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"accelerator": "GPU",
|
||||
"colab": {
|
||||
"name": "model_garden_pytorch_mixtral_peft_tuning.ipynb",
|
||||
"toc_visible": true
|
||||
},
|
||||
"kernelspec": {
|
||||
"display_name": "Python 3",
|
||||
"name": "python3"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 0
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user