mirror of
https://github.com/GoogleCloudPlatform/vertex-ai-samples.git
synced 2026-09-26 14:42:04 +00:00
Compare commits
20
Commits
ci_cd_2
...
reduction_12
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7832abd957 | ||
|
|
447bbbff43 | ||
|
|
5651427a97 | ||
|
|
6195e7bbf9 | ||
|
|
2b4f7834b8 | ||
|
|
6eadb9199d | ||
|
|
cf9ba17c7d | ||
|
|
384fa2c1b6 | ||
|
|
4d24324cc6 | ||
|
|
b1331406a0 | ||
|
|
cf00491bdc | ||
|
|
b24de2c375 | ||
|
|
79d80a1f4f | ||
|
|
de3e31e037 | ||
|
|
d45d5fad51 | ||
|
|
10a9e776b7 | ||
|
|
db80aa4953 | ||
|
|
f4345ed935 | ||
|
|
b191b93c7e | ||
|
|
8acf15cccb |
@@ -17,7 +17,7 @@
|
||||
|
||||
import argparse
|
||||
import pathlib
|
||||
import random
|
||||
import os
|
||||
|
||||
import execute_changed_notebooks_helper
|
||||
|
||||
@@ -47,6 +47,12 @@ parser.add_argument(
|
||||
required=False,
|
||||
default=100,
|
||||
)
|
||||
parser.add_argument(
|
||||
"--build_id",
|
||||
type=str,
|
||||
help="The build id (which may be a Cloud Build job specific or user explicit.",
|
||||
required=True
|
||||
)
|
||||
parser.add_argument(
|
||||
"--base_branch",
|
||||
help="The base git branch to diff against to find changed files.",
|
||||
@@ -129,26 +135,35 @@ changed_notebooks = execute_changed_notebooks_helper.get_changed_notebooks(
|
||||
base_branch=args.base_branch,
|
||||
)
|
||||
|
||||
|
||||
results_bucket = f"{args.artifacts_bucket}"
|
||||
results_file = f"{args.build_id}.json"
|
||||
|
||||
if args.test_percent == 100:
|
||||
notebooks = changed_notebooks
|
||||
accumulative_results = {}
|
||||
else:
|
||||
notebooks = [changed_notebook for changed_notebook in changed_notebooks if random.randint(1, 100) < args.test_percent]
|
||||
accumulative_results = execute_changed_notebooks_helper.load_results(results_bucket, results_file)
|
||||
|
||||
notebooks = [changed_notebook for changed_notebook in changed_notebooks if execute_changed_notebooks_helper.select_notebook(changed_notebook, accumulative_results, args.test_percent)]
|
||||
|
||||
if args.dry_run:
|
||||
print("Dry run ...\n")
|
||||
for notebook in notebooks:
|
||||
print(f"Would execute: {notebook.path}")
|
||||
print(f"Would execute: {notebook}")
|
||||
else:
|
||||
execute_changed_notebooks_helper.process_and_execute_notebooks(
|
||||
notebooks=notebooks,
|
||||
container_uri=args.container_uri,
|
||||
staging_bucket=args.staging_bucket,
|
||||
artifacts_bucket=args.artifacts_bucket,
|
||||
results_file=results_file,
|
||||
accumulative_results=accumulative_results,
|
||||
should_parallelize=args.should_parallelize,
|
||||
timeout=args.timeout,
|
||||
variable_project_id=args.variable_project_id,
|
||||
variable_region=args.variable_region,
|
||||
variable_service_account=args.variable_service_account,
|
||||
variable_vpc_network=args.variable_vpc_network,
|
||||
private_pool_id=args.private_pool_id,
|
||||
private_pool_id=args.private_pool_id
|
||||
)
|
||||
|
||||
@@ -21,11 +21,15 @@ import json
|
||||
import git
|
||||
import operator
|
||||
import os
|
||||
import io
|
||||
import json
|
||||
import pathlib
|
||||
import re
|
||||
import subprocess
|
||||
import random
|
||||
from google.cloud import storage
|
||||
import utils
|
||||
from typing import List, Optional
|
||||
from typing import List, Optional, Dict, Any
|
||||
from utils import util
|
||||
|
||||
import execute_notebook_helper
|
||||
@@ -65,7 +69,9 @@ def format_timedelta(delta: datetime.timedelta) -> str:
|
||||
@dataclasses.dataclass
|
||||
class NotebookExecutionResult:
|
||||
name: str
|
||||
path: str
|
||||
duration: datetime.timedelta
|
||||
start_time: datetime.datetime
|
||||
is_pass: bool
|
||||
log_url: str
|
||||
output_uri: str
|
||||
@@ -80,6 +86,40 @@ class NotebookExecutionResult:
|
||||
else:
|
||||
return None
|
||||
|
||||
def load_results(results_bucket: str,
|
||||
results_file: str) -> Dict[str,Any]:
|
||||
'''
|
||||
Load accumulated notebook test results
|
||||
'''
|
||||
|
||||
print("Loading existing accumulative results ...")
|
||||
accumulative_results = {}
|
||||
try:
|
||||
content = util.download_blob_into_memory(results_bucket, results_file, download_as_text=True)
|
||||
accumulative_results = json.loads(content)
|
||||
print(accumulative_results)
|
||||
except Exception as e:
|
||||
print(e)
|
||||
|
||||
# If there are no accumulative results, an empty dict is returned
|
||||
return accumulative_results
|
||||
|
||||
def select_notebook(changed_notebook: str,
|
||||
accumulative_results: Dict[str, Any],
|
||||
test_percent: int) -> bool:
|
||||
'''
|
||||
Algorithm to randomly select a notebook, but weight the propbability of selected based on past failures
|
||||
'''
|
||||
|
||||
if changed_notebook in accumulative_results:
|
||||
pass_count = accumulative_results[changed_notebook]['passed']
|
||||
fail_count = accumulative_results[changed_notebook]['failed']
|
||||
else:
|
||||
pass_count = 1
|
||||
fail_count = 0
|
||||
|
||||
return (random.randint(1, 100) * (1 + (fail_count / (pass_count + fail_count))) < test_percent)
|
||||
|
||||
|
||||
def _process_notebook(
|
||||
notebook_path: str,
|
||||
@@ -191,7 +231,9 @@ def process_and_execute_notebook(
|
||||
|
||||
result = NotebookExecutionResult(
|
||||
name=tag,
|
||||
path=notebook,
|
||||
duration=datetime.timedelta(seconds=0),
|
||||
start_time=datetime.datetime.now(),
|
||||
is_pass=False,
|
||||
output_uri=notebook_output_uri,
|
||||
log_url="",
|
||||
@@ -201,7 +243,6 @@ def process_and_execute_notebook(
|
||||
)
|
||||
|
||||
# TODO: Handle cases where multiple notebooks have the same name
|
||||
time_start = datetime.datetime.now()
|
||||
operation = None
|
||||
try:
|
||||
# Get the python version for running the notebook if specified
|
||||
@@ -247,9 +288,10 @@ def process_and_execute_notebook(
|
||||
# Block and wait for the result
|
||||
operation_result = operation.result(timeout=timeout_in_seconds)
|
||||
|
||||
result.duration = datetime.datetime.now() - time_start
|
||||
result.duration = datetime.datetime.now() - result.start_time
|
||||
result.is_pass = True
|
||||
print(f"{notebook} PASSED in {format_timedelta(result.duration)}.")
|
||||
|
||||
except Exception as error:
|
||||
result.error_message = str(error)
|
||||
|
||||
@@ -268,7 +310,7 @@ def process_and_execute_notebook(
|
||||
except Exception as error:
|
||||
result.error_message = str(error)
|
||||
|
||||
result.duration = datetime.datetime.now() - time_start
|
||||
result.duration = datetime.datetime.now() - result.start_time
|
||||
result.is_pass = False
|
||||
|
||||
print(
|
||||
@@ -336,12 +378,54 @@ def get_changed_notebooks(
|
||||
|
||||
return notebooks
|
||||
|
||||
def _save_results(results: List[NotebookExecutionResult],
|
||||
accumulative_results: Dict[str,Any],
|
||||
artifacts_bucket: str,
|
||||
results_file: str):
|
||||
|
||||
artifacts_bucket = artifacts_bucket.replace("gs://", "").split('/')[0]
|
||||
|
||||
print("Updating accumulative results ...")
|
||||
for result in results:
|
||||
if result.path in accumulative_results:
|
||||
accumulative_results[result.path]['duration'] = result.duration.total_seconds()
|
||||
accumulative_results[result.path]['start_time'] = str(result.start_time)
|
||||
if result.is_pass:
|
||||
accumulative_results[result.path]['passed'] += 1
|
||||
else:
|
||||
accumulative_results[result.path]['failed'] += 1
|
||||
print(f"updating {result.path}")
|
||||
else:
|
||||
if result.is_pass:
|
||||
pass_count = 1
|
||||
fail_count = 0
|
||||
else:
|
||||
pass_count = 0
|
||||
fail_count = 1
|
||||
accumulative_results[result.path] = {
|
||||
'duration': result.duration.total_seconds(),
|
||||
'start_time': str(result.start_time),
|
||||
'passed': pass_count,
|
||||
'failed': fail_count
|
||||
}
|
||||
print(f"adding {result.path}")
|
||||
|
||||
print("Saving accumulative results ...")
|
||||
content = json.dumps(accumulative_results)
|
||||
|
||||
client = storage.Client()
|
||||
bucket = client.get_bucket(artifacts_bucket)
|
||||
bucket.blob(str(results_file)).upload_from_string(content, 'text/json')
|
||||
|
||||
|
||||
|
||||
def process_and_execute_notebooks(
|
||||
notebooks: List[str],
|
||||
container_uri: str,
|
||||
staging_bucket: str,
|
||||
artifacts_bucket: str,
|
||||
results_file: str,
|
||||
accumulative_results: List[NotebookExecutionResult],
|
||||
should_parallelize: bool,
|
||||
timeout: int,
|
||||
variable_project_id: str,
|
||||
@@ -369,6 +453,10 @@ def process_and_execute_notebooks(
|
||||
Required. The GCS staging bucket to write source code to.
|
||||
artifacts_bucket (str):
|
||||
Required. The GCS staging bucket to write executed notebooks to.
|
||||
results_file (str):
|
||||
Required: The path to the artifacts bucket to save results
|
||||
accumulative_results (List):
|
||||
Required: The in-memory previous accumulative notebook CI/CD test results.
|
||||
variable_project_id (str):
|
||||
Required. The value for PROJECT_ID to inject into notebooks.
|
||||
variable_region (str):
|
||||
@@ -471,7 +559,7 @@ def process_and_execute_notebooks(
|
||||
print("=" * 100)
|
||||
|
||||
build_id = results_sorted[0].build_id
|
||||
logs_bucket_name = (results_sorted[0].logs_bucket).removeprefix("gs://")
|
||||
logs_bucket_name = (results_sorted[0].logs_bucket).replace("gs://", "")
|
||||
log_file_name = f"log-{build_id}.txt"
|
||||
|
||||
log_contents = util.download_blob_into_memory(
|
||||
@@ -489,6 +577,11 @@ def process_and_execute_notebooks(
|
||||
else:
|
||||
print(log_contents)
|
||||
|
||||
_save_results(results_sorted,
|
||||
accumulative_results,
|
||||
artifacts_bucket,
|
||||
results_file)
|
||||
|
||||
print("\n=== END RESULTS===\n")
|
||||
|
||||
total_notebook_duration = functools.reduce(
|
||||
|
||||
@@ -36,7 +36,7 @@ steps:
|
||||
- -c
|
||||
- |
|
||||
. workspace/env/bin/activate &&
|
||||
python3 .cloud-build/execute_changed_notebooks_cli.py --test_paths_file "${_TEST_PATHS_FILE}" --base_branch "${_FORCED_BASE_BRANCH}" --container_uri ${_PYTHON_IMAGE} --staging_bucket ${_GCS_STAGING_BUCKET} --artifacts_bucket ${_GCS_STAGING_BUCKET}/executed_notebooks/PR_${_PR_NUMBER}/BUILD_${BUILD_ID} --variable_project_id ${PROJECT_ID} --variable_region ${_GCP_REGION} --variable_service_account ${_GCP_SERVICE_ACCOUNT} --variable_vpc_network "${_GPC_VPC_NETWORK_NAME}" `if [ ! -z "${_PRIVATE_POOL_NAME}" ]; then echo "--private_pool_id ${_PRIVATE_POOL_NAME}"; fi`
|
||||
python3 .cloud-build/execute_changed_notebooks_cli.py --test_paths_file "${_TEST_PATHS_FILE}" --base_branch "${_FORCED_BASE_BRANCH}" --container_uri ${_PYTHON_IMAGE} --staging_bucket ${_GCS_STAGING_BUCKET} --artifacts_bucket ${_GCS_STAGING_BUCKET}/executed_notebooks/PR_${_PR_NUMBER}/BUILD_${BUILD_ID} --variable_project_id ${PROJECT_ID} --variable_region ${_GCP_REGION} --variable_service_account ${_GCP_SERVICE_ACCOUNT} --variable_vpc_network "${_GPC_VPC_NETWORK_NAME}" `if [ ! -z "${_PRIVATE_POOL_NAME}" ]; then echo "--private_pool_id ${_PRIVATE_POOL_NAME}"; fi` --build_id ${BUILD_ID}
|
||||
env:
|
||||
- 'IS_TESTING=1'
|
||||
timeout: 86400s
|
||||
|
||||
@@ -3,12 +3,15 @@ numpy
|
||||
jupyter
|
||||
nbconvert
|
||||
papermill
|
||||
pandas
|
||||
matplotlib
|
||||
tabulate
|
||||
google-cloud-aiplatform
|
||||
google-cloud-storage
|
||||
google-cloud-build
|
||||
google-cloud-storage
|
||||
ratemate
|
||||
GitPython
|
||||
tqdm
|
||||
tqdm
|
||||
fsspec
|
||||
pandas
|
||||
|
||||
|
||||
+1
-1
@@ -196,7 +196,7 @@
|
||||
" USER_FLAG = \"--user\"\n",
|
||||
"\n",
|
||||
"! pip3 install {USER_FLAG} --upgrade --quiet google-cloud-aiplatform \\\n",
|
||||
" google-cloud-pipeline-components \\\n",
|
||||
" google-cloud-pipeline-components==1.0.25 \\\n",
|
||||
" kfp "
|
||||
]
|
||||
},
|
||||
|
||||
@@ -0,0 +1,852 @@
|
||||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"id": "copyright"
|
||||
},
|
||||
"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": "title:generic,gcp"
|
||||
},
|
||||
"source": [
|
||||
"# Get started with Model Garden Pipeline Templates for BERT models\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"<table align=\"left\">\n",
|
||||
"\n",
|
||||
" <td>\n",
|
||||
" <a href=\"https://colab.research.google.com/github/GoogleCloudPlatform/vertex-ai-samples/blob/main/notebooks/community/model_garden/model_garden_template_pipelines_bert.ipynb\">\n",
|
||||
" <img src=\"https://cloud.google.com/ml-engine/images/colab-logo-32px.png\" alt=\"Colab logo\"> Run in Colab\n",
|
||||
" </a>\n",
|
||||
" </td>\n",
|
||||
" <td>\n",
|
||||
" <a href=\"https://github.com/GoogleCloudPlatform/vertex-ai-samples/blob/main/notebooks/community/model_garden/model_garden_template_pipelines_bert.ipynb\">\n",
|
||||
" <img src=\"https://cloud.google.com/ml-engine/images/github-logo-32px.png\" alt=\"GitHub logo\">\n",
|
||||
" View on GitHub\n",
|
||||
" </a>\n",
|
||||
" </td>\n",
|
||||
" <td>\n",
|
||||
" <a href=\"https://console.cloud.google.com/vertex-ai/workbench/deploy-notebook?download_url=https://raw.githubusercontent.com/GoogleCloudPlatform/vertex-ai-samples/main/notebooks/communitymodel_garden/model_garden_template_pipelines_bert.ipynb\">\n",
|
||||
" <img src=\"https://lh3.googleusercontent.com/UiNooY4LUgW_oTvpsNhPpQzsstV5W8F7rYgxgGBD85cWJoLmrOzhVs_ksK_vgx40SHs7jCqkTkCk=e14-rj-sc0xffffff-h130-w32\" alt=\"Vertex AI logo\">\n",
|
||||
" Open in Vertex AI Workbench\n",
|
||||
" </a>\n",
|
||||
" </td> \n",
|
||||
"</table>"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "overview:mlops"
|
||||
},
|
||||
"source": [
|
||||
"## Overview\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"This tutorial demonstrates how to modify, compile and execute a prebuilt Vertex AI Model Garden pipeline template with Vertex AI Pipelines.\n",
|
||||
"\n",
|
||||
"Learn more about [Create a pipeline template](https://cloud.google.com/vertex-ai/docs/pipelines/create-pipeline-template)."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "objective:mlops,stage4,get_started_vertex_model_evaluation"
|
||||
},
|
||||
"source": [
|
||||
"### Objective\n",
|
||||
"\n",
|
||||
"In this tutorial, you learn how to use a prebuilt pipeline template with `Vertex AI Pipelines` to fine-tune a BERT text classification model, where the model is accessed from `Vertex AI Model Garden`.\n",
|
||||
"\n",
|
||||
"This tutorial uses the following Google Cloud ML services:\n",
|
||||
"\n",
|
||||
"- `Vertex AI Pipelines`\n",
|
||||
"- `Vertex AI Training`\n",
|
||||
"- `Vertex AI Model Garden`\n",
|
||||
"- `Google Cloud Pipeline Components`\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"The steps performed include:\n",
|
||||
"\n",
|
||||
"- Create a user-defined repository in the `Artifact Registry`.\n",
|
||||
"- Upload the prebuilt pipeline template to the `Artifact Registry`.\n",
|
||||
"- Create a pipeline job with the prebuilt pipeline template to fine-tune a BERT model.\n",
|
||||
"- Execute the pipeline using `Vertex AI Pipelines`.\n",
|
||||
" - Load BERT model from Vertex AI Model Garden\n",
|
||||
" - Fine-tune train the model\n",
|
||||
" - Do batch prediction\n",
|
||||
" - Evaluate the model from the batch prediction results\n",
|
||||
"- Obtain the Vertex AI Model resource from the pipeline artifacts.\n",
|
||||
"- Deploy the model to a Vertex AI Endpoint\n",
|
||||
"- Make a prediction"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "dataset:bank,lbn"
|
||||
},
|
||||
"source": [
|
||||
"### Model\n",
|
||||
"\n",
|
||||
"This tutorial uses a pre-trained BERT text classification model from `Vertex AI Model Garden`, which is then fine-tuned (transfer learning) on a dataset of text phrases which are classified as either FirstClass or SecondClass.\n",
|
||||
"\n",
|
||||
"Learn more about [BERT pretrained encoder model]( https://tfhub.dev/tensorflow/bert_en_uncased_L-12_H-768_A-12/3). "
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "costs"
|
||||
},
|
||||
"source": [
|
||||
"### Costs\n",
|
||||
"\n",
|
||||
"This tutorial uses billable components of Google Cloud:\n",
|
||||
"\n",
|
||||
"* Vertex AI\n",
|
||||
"* Cloud Storage\n",
|
||||
"* Dataflow\n",
|
||||
"\n",
|
||||
"Learn about [Vertex AI\n",
|
||||
"pricing](https://cloud.google.com/vertex-ai/pricing), [Cloud Storage\n",
|
||||
"pricing](https://cloud.google.com/storage/pricing), and [Dataflow pricing](https://cloud.google.com/dataflow/pricing)\n",
|
||||
"and use the [Pricing\n",
|
||||
"Calculator](https://cloud.google.com/products/calculator/)\n",
|
||||
"to generate a cost estimate based on your projected usage."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "install_mlops"
|
||||
},
|
||||
"source": [
|
||||
"## Installations\n",
|
||||
"\n",
|
||||
"Install the packages required for executing this notebook.\n",
|
||||
"\n",
|
||||
"*Note:* This tutorial requires KFP 2.x."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"id": "install_mlops"
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"import os\n",
|
||||
"\n",
|
||||
"! pip3 install --upgrade google-cloud-aiplatform \\\n",
|
||||
" google-cloud-pipeline-components \\\n",
|
||||
" kfp==2.0.0b15"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "restart"
|
||||
},
|
||||
"source": [
|
||||
"### Colab only: Uncomment the following cell to restart the kernel"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"id": "D-ZBOjErv5mM"
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Automatically restart kernel after installs so that your environment can access the new packages\n",
|
||||
"# import IPython\n",
|
||||
"\n",
|
||||
"# app = IPython.Application.instance()\n",
|
||||
"# app.kernel.do_shutdown(True)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "before_you_begin"
|
||||
},
|
||||
"source": [
|
||||
"## Before you begin\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "before_you_begin:nogpu"
|
||||
},
|
||||
"source": [
|
||||
"### Set your project ID\n",
|
||||
"\n",
|
||||
"**If you don't know your project ID**, try the following:\n",
|
||||
"* Run `gcloud config list`.\n",
|
||||
"* Run `gcloud projects list`.\n",
|
||||
"* See the support page: [Locate the project ID](https://support.google.com/googleapi/answer/7014113)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"id": "set_project_id"
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"PROJECT_ID = \"[your-project-id]\" # @param {type:\"string\"}\n",
|
||||
"\n",
|
||||
"# Set the project id\n",
|
||||
"! gcloud config set project {PROJECT_ID}"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "region"
|
||||
},
|
||||
"source": [
|
||||
"#### Region\n",
|
||||
"\n",
|
||||
"You can also change the `REGION` variable used by Vertex AI. Learn more about [Vertex AI regions](https://cloud.google.com/vertex-ai/docs/general/locations)."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"id": "region"
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"REGION = \"us-central1\" # @param {type: \"string\"}"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "c4ccf556d4ea"
|
||||
},
|
||||
"source": [
|
||||
"### Enable APIs\n",
|
||||
"\n",
|
||||
"You can enable the required APIs using `gcloud`."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"id": "619529337e6d"
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"! gcloud services enable compute.googleapis.com \\\n",
|
||||
" containerregistry.googleapis.com \\\n",
|
||||
" aiplatform.googleapis.com \\\n",
|
||||
" artifactregistry.googleapis.com"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "gcp_authenticate"
|
||||
},
|
||||
"source": [
|
||||
"### Authenticate your Google Cloud account\n",
|
||||
"\n",
|
||||
"Depending on your Jupyter environment, you may have to manually authenticate. Follow the relevant instructions below."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "FvQeFm3Gv5mR"
|
||||
},
|
||||
"source": [
|
||||
"**1. Vertex AI Workbench**\n",
|
||||
"* Do nothing as you are already authenticated."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"id": "ce6043da7b33"
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# ! gcloud auth login"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "0367eac06a10"
|
||||
},
|
||||
"source": [
|
||||
"**3. Colab, uncomment and run:**"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"id": "21ad4dbb4a61"
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"IS_COLAB = False\n",
|
||||
"# from google.colab import auth\n",
|
||||
"# auth.authenticate_user()\n",
|
||||
"# IS_COLAB=True"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "c13224697bfb"
|
||||
},
|
||||
"source": [
|
||||
"**4. Service account or other**\n",
|
||||
"* See how to grant Cloud Storage permissions to your service account at https://cloud.google.com/storage/docs/gsutil/commands/iam#ch-examples."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "bucket:mbsdk"
|
||||
},
|
||||
"source": [
|
||||
"### Create a Cloud Storage bucket\n",
|
||||
"\n",
|
||||
"Create a storage bucket to store intermediate artifacts such as datasets."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"id": "bucket"
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"BUCKET_URI = f\"gs://your-bucket-name-{PROJECT_ID}-unique\" # @param {type:\"string\"}"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "create_bucket"
|
||||
},
|
||||
"source": [
|
||||
"**Only if your bucket doesn't already exist**: Run the following cell to create your Cloud Storage bucket."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"id": "create_bucket"
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"! gsutil mb -l $REGION $BUCKET_URI"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "set_service_account"
|
||||
},
|
||||
"source": [
|
||||
"#### Service Account\n",
|
||||
"\n",
|
||||
"**If you don't know your service account**, try to get your service account using `gcloud` command by executing the second cell below."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"id": "set_service_account"
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"SERVICE_ACCOUNT = \"[your-service-account]\" # @param {type:\"string\"}"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"id": "autoset_service_account"
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"if (\n",
|
||||
" SERVICE_ACCOUNT == \"\"\n",
|
||||
" or SERVICE_ACCOUNT is None\n",
|
||||
" or SERVICE_ACCOUNT == \"[your-service-account]\"\n",
|
||||
"):\n",
|
||||
" # Get your service account from gcloud\n",
|
||||
" if not IS_COLAB:\n",
|
||||
" shell_output = !gcloud auth list 2>/dev/null\n",
|
||||
" SERVICE_ACCOUNT = shell_output[2].replace(\"*\", \"\").strip()\n",
|
||||
"\n",
|
||||
" if IS_COLAB:\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",
|
||||
"\n",
|
||||
" print(\"Service Account:\", SERVICE_ACCOUNT)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "set_service_account:pipelines"
|
||||
},
|
||||
"source": [
|
||||
"#### Set service account access for Vertex AI Pipelines\n",
|
||||
"\n",
|
||||
"Run the following commands to grant your service account access to read and write pipeline artifacts in the bucket that you created in the previous step -- you only need to run these once per service account."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"id": "set_service_account:pipelines"
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"! gsutil iam ch serviceAccount:{SERVICE_ACCOUNT}:roles/storage.objectCreator \n",
|
||||
"! gsutil iam ch serviceAccount:{SERVICE_ACCOUNT}:roles/storage.objectViewer "
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "setup_vars"
|
||||
},
|
||||
"source": [
|
||||
"### Set up variables\n",
|
||||
"\n",
|
||||
"Next, set up some variables used throughout the tutorial.\n",
|
||||
"### Import libraries and define constants"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"id": "import_kfp"
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"import json\n",
|
||||
"\n",
|
||||
"import google.cloud.aiplatform as aiplatform\n",
|
||||
"from kfp.registry import RegistryClient"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "init_aip:mbsdk,all"
|
||||
},
|
||||
"source": [
|
||||
"### Initialize Vertex AI SDK for Python\n",
|
||||
"\n",
|
||||
"Initialize the Vertex AI SDK for Python for your project and corresponding bucket."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"id": "init_aip:mbsdk,all"
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"aiplatform.init(project=PROJECT_ID, location=REGION, staging_bucket=BUCKET_URI)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "9b773e8d2bd2"
|
||||
},
|
||||
"source": [
|
||||
"## Create repo in Artifact Registry\n",
|
||||
"\n",
|
||||
"First, you create your own (user-defined) repository in the `Artifact Registry`. You use this repository to upload and retrieve your pipeline templates.\n",
|
||||
"\n",
|
||||
"The name of your repo is `quickstart-kfp-repo`"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"id": "520de849cee2"
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"REPO_NAME = \"quickstart-kfp-repo\"\n",
|
||||
"\n",
|
||||
"! gcloud artifacts repositories create {REPO_NAME} --location={REGION} --repository-format=KFP"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "1611d3517c0f"
|
||||
},
|
||||
"source": [
|
||||
"### Upload the pipeline template\n",
|
||||
"\n",
|
||||
"Next, you instantiate a client interface to the Artifact Registry. Then with the `upload_pipeline()` method you upload your pipeline template."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"id": "72db37f6d67c"
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"BERT_YAML = \"gs://cloud-samples-data/vertex-ai/dataset-management/datasets/bert_finetuning/pipeline.yaml\"\n",
|
||||
"\n",
|
||||
"! gsutil cp {BERT_YAML} pipeline.yaml\n",
|
||||
"\n",
|
||||
"client = RegistryClient(\n",
|
||||
" host=f\"https://{REGION}-kfp.pkg.dev/{PROJECT_ID}/quickstart-kfp-repo\"\n",
|
||||
")\n",
|
||||
"\n",
|
||||
"templateName, versionName = client.upload_pipeline(\n",
|
||||
" file_name=\"pipeline.yaml\",\n",
|
||||
" tags=[\"v1\", \"latest\"],\n",
|
||||
" extra_headers={\n",
|
||||
" \"description\": \"This is a pipeline template for fine-tuning a BERT model.\"\n",
|
||||
" },\n",
|
||||
")\n",
|
||||
"\n",
|
||||
"! rm pipeline.yaml"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "02f82754fc0d"
|
||||
},
|
||||
"source": [
|
||||
"### View your artifacts in your registry\n",
|
||||
"\n",
|
||||
"Next, using the `gcloud artifacts files` command you view the artifacts, inclusive of the pipeline template, in your artifacts repository."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"id": "b2f641eb2056"
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"! gcloud artifacts files list --repository={REPO_NAME} --location={REGION}"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "9d5296831cfb"
|
||||
},
|
||||
"source": [
|
||||
"## Load and execute the pipeline job\n",
|
||||
"\n",
|
||||
"Next, you create a Vertex AI Pipeline job from your BERT pipeline template by instantiating a PipelineJob(), with the following parameters:\n",
|
||||
"\n",
|
||||
"- `display_name`: The human readable name for the pipeline job.\n",
|
||||
"- `template_path`: The path to the pipeline template in the Artifact Registry.\n",
|
||||
"- `enable_caching`: On re-runs, use the results from previous successful and unchanged steps.\n",
|
||||
"- `pipeline_root`: A Cloud storage location for storing pipeline results.\n",
|
||||
"- `parameter_values`: The parameters and values that are input to the template pipeline. In this example, they are:\n",
|
||||
" - `project`: Your project ID.\n",
|
||||
" - `class_labels`: A list of valid class labels, in cardinal order.\n",
|
||||
" - `root_dir`: A Cloud Storage scratch area.\n",
|
||||
" - `training_data_path`: A Cloud Storage location to the training data.\n",
|
||||
" - `ground_truth_gcs_source_uris`: A Cloud Storage location to evaluation data."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"id": "a3c502fc7e41"
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"PIPELINE_ROOT = f\"{BUCKET_URI}/pipeline_root/bert-finetuning\"\n",
|
||||
"\n",
|
||||
"job = aiplatform.PipelineJob(\n",
|
||||
" display_name=\"bert-finetuning\",\n",
|
||||
" template_path=f\"https://{REGION}-kfp.pkg.dev/{PROJECT_ID}/quickstart-kfp-repo/{templateName}/{versionName}\",\n",
|
||||
" pipeline_root=PIPELINE_ROOT,\n",
|
||||
" enable_caching=False,\n",
|
||||
" parameter_values={\n",
|
||||
" \"project\": PROJECT_ID,\n",
|
||||
" \"class_labels\": [\"FirstClass\", \"SecondClass\", \"[UNK]\"],\n",
|
||||
" \"root_dir\": BUCKET_URI,\n",
|
||||
" \"ground_truth_gcs_source_uris\": [\n",
|
||||
" \"gs://cloud-samples-data/vertex-ai/dataset-management/datasets/bert_finetuning/wide_and_deep_trainer_container_tests_input.jsonl\"\n",
|
||||
" ],\n",
|
||||
" \"training_data_path\": \"gs://cloud-samples-data/vertex-ai/dataset-management/datasets/bert_finetuning/wide_and_deep_trainer_container_tests_input.jsonl\",\n",
|
||||
" },\n",
|
||||
")\n",
|
||||
"\n",
|
||||
"job.run()"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "view_pipleline_results:bqml"
|
||||
},
|
||||
"source": [
|
||||
"### View the pipeline results"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"id": "view_pipleline_results:bqml"
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"PROJECT_NUMBER = job.gca_resource.name.split(\"/\")[1]\n",
|
||||
"print(PROJECT_NUMBER)\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"def print_pipeline_output(job, output_task_name):\n",
|
||||
" JOB_ID = job.name\n",
|
||||
" print(JOB_ID)\n",
|
||||
" artifact = \"\"\n",
|
||||
" for _ in range(len(job.gca_resource.job_detail.task_details)):\n",
|
||||
" TASK_ID = job.gca_resource.job_detail.task_details[_].task_id\n",
|
||||
" EXECUTE_OUTPUT = (\n",
|
||||
" PIPELINE_ROOT\n",
|
||||
" + \"/\"\n",
|
||||
" + PROJECT_NUMBER\n",
|
||||
" + \"/\"\n",
|
||||
" + JOB_ID\n",
|
||||
" + \"/\"\n",
|
||||
" + output_task_name\n",
|
||||
" + \"_\"\n",
|
||||
" + str(TASK_ID)\n",
|
||||
" + \"/executor_output.json\"\n",
|
||||
" )\n",
|
||||
" GCP_RESOURCES = (\n",
|
||||
" PIPELINE_ROOT\n",
|
||||
" + \"/\"\n",
|
||||
" + PROJECT_NUMBER\n",
|
||||
" + \"/\"\n",
|
||||
" + JOB_ID\n",
|
||||
" + \"/\"\n",
|
||||
" + output_task_name\n",
|
||||
" + \"_\"\n",
|
||||
" + str(TASK_ID)\n",
|
||||
" + \"/gcp_resources\"\n",
|
||||
" )\n",
|
||||
" EVALUATION_METRICS = (\n",
|
||||
" PIPELINE_ROOT\n",
|
||||
" + \"/\"\n",
|
||||
" + PROJECT_NUMBER\n",
|
||||
" + \"/\"\n",
|
||||
" + JOB_ID\n",
|
||||
" + \"/\"\n",
|
||||
" + output_task_name\n",
|
||||
" + \"_\"\n",
|
||||
" + str(TASK_ID)\n",
|
||||
" + \"/evaluation_metrics\"\n",
|
||||
" )\n",
|
||||
" # Check if file exists, 0 is success\n",
|
||||
" !gsutil -q stat $EXECUTE_OUTPUT\n",
|
||||
" if _exit_code == 0:\n",
|
||||
" ! gsutil cat $EXECUTE_OUTPUT\n",
|
||||
" artifact = EXECUTE_OUTPUT\n",
|
||||
" break\n",
|
||||
" !gsutil -q stat $GCP_RESOURCES\n",
|
||||
" if _exit_code == 0:\n",
|
||||
" ! gsutil cat $GCP_RESOURCES\n",
|
||||
" artifact = GCP_RESOURCES\n",
|
||||
" break\n",
|
||||
" !gsutil -q stat $EVALUATION_METRICS\n",
|
||||
" if _exit_code == 0:\n",
|
||||
" ! gsutil cat $EVALUATION_METRICS\n",
|
||||
" artifact = EVALUATION_METRICS\n",
|
||||
" break\n",
|
||||
"\n",
|
||||
" return artifact\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"print(\"get-vertex-model\")\n",
|
||||
"artifacts = print_pipeline_output(job, \"get-vertex-model\")\n",
|
||||
"output = !gsutil cat $artifacts\n",
|
||||
"print(output)\n",
|
||||
"output = json.loads(output[0])\n",
|
||||
"model_id = output[\"artifacts\"][\"model\"][\"artifacts\"][0][\"metadata\"][\"resourceName\"]\n",
|
||||
"print(\"\\n\\n\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "f431a9e6f025"
|
||||
},
|
||||
"source": [
|
||||
"### Delete the pipeline job\n",
|
||||
"\n",
|
||||
"The method 'delete()' will delete the pipeline job."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"id": "00bf554abbc6"
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"job.delete()"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "3d183db57ae2"
|
||||
},
|
||||
"source": [
|
||||
"### Deploy the model\n",
|
||||
"\n",
|
||||
"Next, you deploy the model to an endpoint:\n",
|
||||
"\n",
|
||||
"- Use the `model_id` obtained from the pipeline artifacts to instaniate a Vertex AI Model resource instance.\n",
|
||||
"- Deploy the Vertex AI Model resource to a Vertex AI Endpoint resource.\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"id": "591ccc049ce5"
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"model = aiplatform.Model(model_id)\n",
|
||||
"endpoint = model.deploy(\n",
|
||||
" accelerator_count=1,\n",
|
||||
" accelerator_type=aiplatform.gapic.AcceleratorType.NVIDIA_TESLA_T4.name,\n",
|
||||
" machine_type=\"n1-standard-4\",\n",
|
||||
")\n",
|
||||
"print(endpoint)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "edb781a92864"
|
||||
},
|
||||
"source": [
|
||||
"### Make a prediction\n",
|
||||
"\n",
|
||||
"Finally, you make a prediction with the deployed model."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"id": "72d94012a987"
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"endpoint.predict([\"this is a test\"])"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "cleanup:mbsdk"
|
||||
},
|
||||
"source": [
|
||||
"# Cleaning up\n",
|
||||
"\n",
|
||||
"To clean up all Google Cloud resources used in this project, you can [delete the Google Cloud\n",
|
||||
"project](https://cloud.google.com/resource-manager/docs/creating-managing-projects#shutting_down_projects) you used for the tutorial.\n",
|
||||
"\n",
|
||||
"Otherwise, you can delete the individual resources you created in this tutorial."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"id": "cleanup:mbsdk"
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"delete_bucket = False\n",
|
||||
"\n",
|
||||
"endpoint.undeploy_all()\n",
|
||||
"endpoint.delete()\n",
|
||||
"model.delete()\n",
|
||||
"\n",
|
||||
"if delete_bucket or os.getenv(\"IS_TESTING\"):\n",
|
||||
" ! gsutil rm -r $BUCKET_URI\n",
|
||||
"\n",
|
||||
"! rm -rf custom custom.tar.gz"
|
||||
]
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"colab": {
|
||||
"name": "model_garden_pipeline_templates_bert.ipynb",
|
||||
"toc_visible": true
|
||||
},
|
||||
"kernelspec": {
|
||||
"display_name": "Python 3",
|
||||
"name": "python3"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 0
|
||||
}
|
||||
@@ -0,0 +1,850 @@
|
||||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"id": "copyright"
|
||||
},
|
||||
"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": "title:generic,gcp"
|
||||
},
|
||||
"source": [
|
||||
"# Get started with Model Garden Pipeline Templates for T5X models\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"<table align=\"left\">\n",
|
||||
"\n",
|
||||
" <td>\n",
|
||||
" <a href=\"https://colab.research.google.com/github/GoogleCloudPlatform/vertex-ai-samples/blob/main/notebooks/community/model_garden/model_garden_template_pipelines_t5x.ipynb\">\n",
|
||||
" <img src=\"https://cloud.google.com/ml-engine/images/colab-logo-32px.png\" alt=\"Colab logo\"> Run in Colab\n",
|
||||
" </a>\n",
|
||||
" </td>\n",
|
||||
" <td>\n",
|
||||
" <a href=\"https://github.com/GoogleCloudPlatform/vertex-ai-samples/blob/main/notebooks/community/model_garden/model_garden_template_pipelines_t5x.ipynb\">\n",
|
||||
" <img src=\"https://cloud.google.com/ml-engine/images/github-logo-32px.png\" alt=\"GitHub logo\">\n",
|
||||
" View on GitHub\n",
|
||||
" </a>\n",
|
||||
" </td>\n",
|
||||
" <td>\n",
|
||||
" <a href=\"https://console.cloud.google.com/vertex-ai/workbench/deploy-notebook?download_url=https://raw.githubusercontent.com/GoogleCloudPlatform/vertex-ai-samples/main/notebooks/communitymodel_garden/model_garden_template_pipelines_t5x.ipynb\">\n",
|
||||
" <img src=\"https://lh3.googleusercontent.com/UiNooY4LUgW_oTvpsNhPpQzsstV5W8F7rYgxgGBD85cWJoLmrOzhVs_ksK_vgx40SHs7jCqkTkCk=e14-rj-sc0xffffff-h130-w32\" alt=\"Vertex AI logo\">\n",
|
||||
" Open in Vertex AI Workbench\n",
|
||||
" </a>\n",
|
||||
" </td> \n",
|
||||
"</table>"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "overview:mlops"
|
||||
},
|
||||
"source": [
|
||||
"## Overview\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"This tutorial demonstrates how to modify, compile and execute a prebuilt Vertex AI Model Garden pipeline template with Vertex AI Pipelines.\n",
|
||||
"\n",
|
||||
"Learn more about [Create a pipeline template](https://cloud.google.com/vertex-ai/docs/pipelines/create-pipeline-template)."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "objective:mlops,stage4,get_started_vertex_model_evaluation"
|
||||
},
|
||||
"source": [
|
||||
"### Objective\n",
|
||||
"\n",
|
||||
"In this tutorial, you learn how to use a prebuilt pipeline template with `Vertex AI Pipelines` to fine-tune a T5X text classification model, where the model is accessed from `Vertex AI Model Garden`.\n",
|
||||
"\n",
|
||||
"This tutorial uses the following Google Cloud ML services:\n",
|
||||
"\n",
|
||||
"- `Vertex AI Pipelines`\n",
|
||||
"- `Vertex AI Training`\n",
|
||||
"- `Vertex AI Model Garden`\n",
|
||||
"- `Google Cloud Pipeline Components`\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"The steps performed include:\n",
|
||||
"\n",
|
||||
"- Create a user-defined repository in the `Artifact Registry`.\n",
|
||||
"- Upload the prebuilt pipeline template to the `Artifact Registry`.\n",
|
||||
"- Create a pipeline job with the prebuilt pipeline template to fine-tune a T5X model.\n",
|
||||
"- Execute the pipeline using `Vertex AI Pipelines`.\n",
|
||||
" - Load T5X model from Vertex AI Model Garden\n",
|
||||
" - Fine-tune train the model\n",
|
||||
"- Obtain the Vertex AI Model resource from the pipeline artifacts.\n",
|
||||
"- Deploy the model to a Vertex AI Endpoint\n",
|
||||
"- Make a prediction"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "dataset:bank,lbn"
|
||||
},
|
||||
"source": [
|
||||
"### Model\n",
|
||||
"\n",
|
||||
"This tutorial uses a pre-trained T5 text classification model from `Vertex AI Model Garden`, which is then fine-tuned (transfer learning) on a dataset of text phrases which are classified as either FirstClass or SecondClass.\n",
|
||||
"\n",
|
||||
"Learn more about [Text-to-text transfer transformer](https://github.com/google-research/text-to-text-transfer-transformer). "
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "costs"
|
||||
},
|
||||
"source": [
|
||||
"### Costs\n",
|
||||
"\n",
|
||||
"This tutorial uses billable components of Google Cloud:\n",
|
||||
"\n",
|
||||
"* Vertex AI\n",
|
||||
"* Cloud Storage\n",
|
||||
"* Dataflow\n",
|
||||
"\n",
|
||||
"Learn about [Vertex AI\n",
|
||||
"pricing](https://cloud.google.com/vertex-ai/pricing), [Cloud Storage\n",
|
||||
"pricing](https://cloud.google.com/storage/pricing), and [Dataflow pricing](https://cloud.google.com/dataflow/pricing)\n",
|
||||
"and use the [Pricing\n",
|
||||
"Calculator](https://cloud.google.com/products/calculator/)\n",
|
||||
"to generate a cost estimate based on your projected usage."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "install_mlops"
|
||||
},
|
||||
"source": [
|
||||
"## Installations\n",
|
||||
"\n",
|
||||
"Install the packages required for executing this notebook.\n",
|
||||
"\n",
|
||||
"*Note:* This tutorial requires KFP 2.x."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"id": "install_mlops"
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"import os\n",
|
||||
"\n",
|
||||
"! pip3 install --upgrade google-cloud-aiplatform \\\n",
|
||||
" google-cloud-pipeline-components \\\n",
|
||||
" kfp==2.0.0b15"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "restart"
|
||||
},
|
||||
"source": [
|
||||
"### Colab only: Uncomment the following cell to restart the kernel"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"id": "D-ZBOjErv5mM"
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Automatically restart kernel after installs so that your environment can access the new packages\n",
|
||||
"# import IPython\n",
|
||||
"\n",
|
||||
"# app = IPython.Application.instance()\n",
|
||||
"# app.kernel.do_shutdown(True)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "before_you_begin"
|
||||
},
|
||||
"source": [
|
||||
"## Before you begin\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "before_you_begin:nogpu"
|
||||
},
|
||||
"source": [
|
||||
"### Set your project ID\n",
|
||||
"\n",
|
||||
"**If you don't know your project ID**, try the following:\n",
|
||||
"* Run `gcloud config list`.\n",
|
||||
"* Run `gcloud projects list`.\n",
|
||||
"* See the support page: [Locate the project ID](https://support.google.com/googleapi/answer/7014113)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"id": "set_project_id"
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"PROJECT_ID = \"[your-project-id]\" # @param {type:\"string\"}\n",
|
||||
"\n",
|
||||
"# Set the project id\n",
|
||||
"! gcloud config set project {PROJECT_ID}"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "region"
|
||||
},
|
||||
"source": [
|
||||
"#### Region\n",
|
||||
"\n",
|
||||
"You can also change the `REGION` variable used by Vertex AI. Learn more about [Vertex AI regions](https://cloud.google.com/vertex-ai/docs/general/locations)."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"id": "region"
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"REGION = \"us-central1\" # @param {type: \"string\"}"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "c4ccf556d4ea"
|
||||
},
|
||||
"source": [
|
||||
"### Enable APIs\n",
|
||||
"\n",
|
||||
"You can enable the required APIs using `gcloud`."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"id": "619529337e6d"
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"! gcloud services enable compute.googleapis.com \\\n",
|
||||
" containerregistry.googleapis.com \\\n",
|
||||
" aiplatform.googleapis.com \\\n",
|
||||
" artifactregistry.googleapis.com"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "gcp_authenticate"
|
||||
},
|
||||
"source": [
|
||||
"### Authenticate your Google Cloud account\n",
|
||||
"\n",
|
||||
"Depending on your Jupyter environment, you may have to manually authenticate. Follow the relevant instructions below."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "FvQeFm3Gv5mR"
|
||||
},
|
||||
"source": [
|
||||
"**1. Vertex AI Workbench**\n",
|
||||
"* Do nothing as you are already authenticated."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"id": "ce6043da7b33"
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# ! gcloud auth login"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "0367eac06a10"
|
||||
},
|
||||
"source": [
|
||||
"**3. Colab, uncomment and run:**"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"id": "21ad4dbb4a61"
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"IS_COLAB = False\n",
|
||||
"# from google.colab import auth\n",
|
||||
"# auth.authenticate_user()\n",
|
||||
"# IS_COLAB=True"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "c13224697bfb"
|
||||
},
|
||||
"source": [
|
||||
"**4. Service account or other**\n",
|
||||
"* See how to grant Cloud Storage permissions to your service account at https://cloud.google.com/storage/docs/gsutil/commands/iam#ch-examples."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "bucket:mbsdk"
|
||||
},
|
||||
"source": [
|
||||
"### Create a Cloud Storage bucket\n",
|
||||
"\n",
|
||||
"Create a storage bucket to store intermediate artifacts such as datasets."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"id": "bucket"
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"BUCKET_URI = f\"gs://your-bucket-name-{PROJECT_ID}-unique\" # @param {type:\"string\"}"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "create_bucket"
|
||||
},
|
||||
"source": [
|
||||
"**Only if your bucket doesn't already exist**: Run the following cell to create your Cloud Storage bucket."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"id": "create_bucket"
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"! gsutil mb -l $REGION $BUCKET_URI"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "set_service_account"
|
||||
},
|
||||
"source": [
|
||||
"#### Service Account\n",
|
||||
"\n",
|
||||
"**If you don't know your service account**, try to get your service account using `gcloud` command by executing the second cell below."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"id": "set_service_account"
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"SERVICE_ACCOUNT = \"[your-service-account]\" # @param {type:\"string\"}"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"id": "autoset_service_account"
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"if (\n",
|
||||
" SERVICE_ACCOUNT == \"\"\n",
|
||||
" or SERVICE_ACCOUNT is None\n",
|
||||
" or SERVICE_ACCOUNT == \"[your-service-account]\"\n",
|
||||
"):\n",
|
||||
" # Get your service account from gcloud\n",
|
||||
" if not IS_COLAB:\n",
|
||||
" shell_output = !gcloud auth list 2>/dev/null\n",
|
||||
" SERVICE_ACCOUNT = shell_output[2].replace(\"*\", \"\").strip()\n",
|
||||
"\n",
|
||||
" if IS_COLAB:\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",
|
||||
"\n",
|
||||
" print(\"Service Account:\", SERVICE_ACCOUNT)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "set_service_account:pipelines"
|
||||
},
|
||||
"source": [
|
||||
"#### Set service account access for Vertex AI Pipelines\n",
|
||||
"\n",
|
||||
"Run the following commands to grant your service account access to read and write pipeline artifacts in the bucket that you created in the previous step -- you only need to run these once per service account."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"id": "set_service_account:pipelines"
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"! gsutil iam ch serviceAccount:{SERVICE_ACCOUNT}:roles/storage.objectCreator \n",
|
||||
"! gsutil iam ch serviceAccount:{SERVICE_ACCOUNT}:roles/storage.objectViewer "
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "setup_vars"
|
||||
},
|
||||
"source": [
|
||||
"### Set up variables\n",
|
||||
"\n",
|
||||
"Next, set up some variables used throughout the tutorial.\n",
|
||||
"### Import libraries and define constants"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"id": "import_kfp"
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"import json\n",
|
||||
"\n",
|
||||
"import google.cloud.aiplatform as aiplatform\n",
|
||||
"from kfp.registry import RegistryClient"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "init_aip:mbsdk,all"
|
||||
},
|
||||
"source": [
|
||||
"### Initialize Vertex AI SDK for Python\n",
|
||||
"\n",
|
||||
"Initialize the Vertex AI SDK for Python for your project and corresponding bucket."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"id": "init_aip:mbsdk,all"
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"aiplatform.init(project=PROJECT_ID, location=REGION, staging_bucket=BUCKET_URI)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "9b773e8d2bd2"
|
||||
},
|
||||
"source": [
|
||||
"## Create repo in Artifact Registry\n",
|
||||
"\n",
|
||||
"First, you create your own (user-defined) repository in the `Artifact Registry`. You use this repository to upload and retreive your pipeline templates.\n",
|
||||
"\n",
|
||||
"The name of your repo is `quickstart-kfp-repo`"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"id": "520de849cee2"
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"REPO_NAME = \"quickstart-kfp-repo\"\n",
|
||||
"\n",
|
||||
"! gcloud artifacts repositories create {REPO_NAME} --location={REGION} --repository-format=KFP"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "1611d3517c0f"
|
||||
},
|
||||
"source": [
|
||||
"### Upload the pipeline template\n",
|
||||
"\n",
|
||||
"Next, you instantiate a client interface to the Artifact Registry. Then with the `upload_pipeline()` method you upload your pipeline template."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"id": "7f002e57998a"
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"T5X_YAML = \"gs://cloud-samples-data/vertex-ai/dataset-management/datasets/t5_finetuning/pipeline.yaml\"\n",
|
||||
"\n",
|
||||
"! gsutil cp {T5X_YAML} pipeline.yaml\n",
|
||||
"\n",
|
||||
"client = RegistryClient(\n",
|
||||
" host=f\"https://{REGION}-kfp.pkg.dev/{PROJECT_ID}/quickstart-kfp-repo\"\n",
|
||||
")\n",
|
||||
"\n",
|
||||
"templateName, versionName = client.upload_pipeline(\n",
|
||||
" file_name=\"pipeline.yaml\",\n",
|
||||
" tags=[\"v1\", \"latest\"],\n",
|
||||
" extra_headers={\n",
|
||||
" \"description\": \"This is a pipeline template for fine-tuning a T5 model.\"\n",
|
||||
" },\n",
|
||||
")\n",
|
||||
"\n",
|
||||
"! rm pipeline.yaml"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "02f82754fc0d"
|
||||
},
|
||||
"source": [
|
||||
"### View your artifacts in your registry\n",
|
||||
"\n",
|
||||
"Next, using the `gcloud artifacts files` command you view the artifacts, inclusive of the pipeline template, in your artifacts repository."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"id": "b2f641eb2056"
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"! gcloud artifacts files list --repository={REPO_NAME} --location={REGION}"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "968a46a3cb6d"
|
||||
},
|
||||
"source": [
|
||||
"## Load and execute the pipeline job\n",
|
||||
"\n",
|
||||
"Next, you create a Vertex AI Pipeline job from your T5 pipeline template by instantiating a PipelineJob(), with the following parameters:\n",
|
||||
"\n",
|
||||
"- `display_name`: The human readable name for the pipeline job.\n",
|
||||
"- `template_path`: The path to the pipeline template in the Artifact Registry.\n",
|
||||
"- `enable_caching`: On re-runs, use the results from previous successful and unchanged steps.\n",
|
||||
"- `pipeline_root`: A Cloud storage location for storing pipeline results.\n",
|
||||
"- `parameter_values`: The parameters and values that are input to the template pipeline. In this example, they are:\n",
|
||||
"TODO\n",
|
||||
" - `project`: Your project ID.\n",
|
||||
" - `class_labels`: A list of valid class labels, in cardinal order.\n",
|
||||
" - `root_dir`: A Cloud Storage scratch area.\n",
|
||||
" - `training_data_path`: A Cloud Storage location to the training data.\n",
|
||||
" - `ground_truth_gcs_source_uris`: A Cloud Storage location to evaluation data."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"id": "a3c502fc7e41"
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"PIPELINE_ROOT = f\"{BUCKET_URI}/pipeline_root/t5_finetuning\"\n",
|
||||
"\n",
|
||||
"job = aiplatform.PipelineJob(\n",
|
||||
" display_name=\"t5x-finetuning\",\n",
|
||||
" template_path=f\"https://{REGION}-kfp.pkg.dev/{PROJECT_ID}/quickstart-kfp-repo/{templateName}/{versionName}\",\n",
|
||||
" pipeline_root=PIPELINE_ROOT,\n",
|
||||
" enable_caching=False,\n",
|
||||
" parameter_values={\n",
|
||||
" \"project_id\": PROJECT_ID,\n",
|
||||
" \"accelerator_count\": 32,\n",
|
||||
" \"feature_keys\": \"question\",\n",
|
||||
" \"label_key\": \"answer\",\n",
|
||||
" \"training_data_path\": \"gs://cloud-llm-public/tfds/natural_questions_open/1.0.0_shortened/natural_questions_open-train.tfrecord-00000-of-00001\",\n",
|
||||
" \"validation_data_path\": \"gs://cloud-llm-public/tfds/natural_questions_open/1.0.0_shortened/natural_questions_open-validation.tfrecord-00000-of-00001\",\n",
|
||||
" },\n",
|
||||
")\n",
|
||||
"\n",
|
||||
"job.run()"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "view_pipleline_results:bqml"
|
||||
},
|
||||
"source": [
|
||||
"### View the pipeline results"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"id": "view_pipleline_results:bqml"
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"PROJECT_NUMBER = job.gca_resource.name.split(\"/\")[1]\n",
|
||||
"print(PROJECT_NUMBER)\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"def print_pipeline_output(job, output_task_name):\n",
|
||||
" JOB_ID = job.name\n",
|
||||
" print(JOB_ID)\n",
|
||||
" artifact = \"\"\n",
|
||||
" for _ in range(len(job.gca_resource.job_detail.task_details)):\n",
|
||||
" TASK_ID = job.gca_resource.job_detail.task_details[_].task_id\n",
|
||||
" EXECUTE_OUTPUT = (\n",
|
||||
" PIPELINE_ROOT\n",
|
||||
" + \"/\"\n",
|
||||
" + PROJECT_NUMBER\n",
|
||||
" + \"/\"\n",
|
||||
" + JOB_ID\n",
|
||||
" + \"/\"\n",
|
||||
" + output_task_name\n",
|
||||
" + \"_\"\n",
|
||||
" + str(TASK_ID)\n",
|
||||
" + \"/executor_output.json\"\n",
|
||||
" )\n",
|
||||
" GCP_RESOURCES = (\n",
|
||||
" PIPELINE_ROOT\n",
|
||||
" + \"/\"\n",
|
||||
" + PROJECT_NUMBER\n",
|
||||
" + \"/\"\n",
|
||||
" + JOB_ID\n",
|
||||
" + \"/\"\n",
|
||||
" + output_task_name\n",
|
||||
" + \"_\"\n",
|
||||
" + str(TASK_ID)\n",
|
||||
" + \"/gcp_resources\"\n",
|
||||
" )\n",
|
||||
" EVALUATION_METRICS = (\n",
|
||||
" PIPELINE_ROOT\n",
|
||||
" + \"/\"\n",
|
||||
" + PROJECT_NUMBER\n",
|
||||
" + \"/\"\n",
|
||||
" + JOB_ID\n",
|
||||
" + \"/\"\n",
|
||||
" + output_task_name\n",
|
||||
" + \"_\"\n",
|
||||
" + str(TASK_ID)\n",
|
||||
" + \"/evaluation_metrics\"\n",
|
||||
" )\n",
|
||||
" # Check if file exists, 0 is success\n",
|
||||
" !gsutil -q stat $EXECUTE_OUTPUT\n",
|
||||
" if _exit_code == 0:\n",
|
||||
" ! gsutil cat $EXECUTE_OUTPUT\n",
|
||||
" artifact = EXECUTE_OUTPUT\n",
|
||||
" break\n",
|
||||
" !gsutil -q stat $GCP_RESOURCES\n",
|
||||
" if _exit_code == 0:\n",
|
||||
" ! gsutil cat $GCP_RESOURCES\n",
|
||||
" artifact = GCP_RESOURCES\n",
|
||||
" break\n",
|
||||
" !gsutil -q stat $EVALUATION_METRICS\n",
|
||||
" if _exit_code == 0:\n",
|
||||
" ! gsutil cat $EVALUATION_METRICS\n",
|
||||
" artifact = EVALUATION_METRICS\n",
|
||||
" break\n",
|
||||
"\n",
|
||||
" return artifact\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"print(\"model-upload\")\n",
|
||||
"artifacts = print_pipeline_output(job, \"model-upload\")\n",
|
||||
"output = !gsutil cat $artifacts\n",
|
||||
"print(output)\n",
|
||||
"output = json.loads(output[0])\n",
|
||||
"model_id = output[\"artifacts\"][\"model\"][\"artifacts\"][0][\"metadata\"][\"resourceName\"]\n",
|
||||
"print(\"\\n\\n\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "f431a9e6f025"
|
||||
},
|
||||
"source": [
|
||||
"### Delete the pipeline job\n",
|
||||
"\n",
|
||||
"The method 'delete()' will delete the pipeline job."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"id": "00bf554abbc6"
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"job.delete()"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "3d183db57ae2"
|
||||
},
|
||||
"source": [
|
||||
"### Deploy the model\n",
|
||||
"\n",
|
||||
"Next, you deploy the model to an endpoint:\n",
|
||||
"\n",
|
||||
"- Use the `model_id` obtained from the pipeline artifacts to instantiate a Vertex AI Model resource instance.\n",
|
||||
"- Deploy the Vertex AI Model resource to a Vertex AI Endpoint resource.\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"id": "591ccc049ce5"
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"model = aiplatform.Model(model_id)\n",
|
||||
"endpoint = model.deploy(\n",
|
||||
" accelerator_count=1,\n",
|
||||
" accelerator_type=aiplatform.gapic.AcceleratorType.NVIDIA_TESLA_T4.name,\n",
|
||||
" machine_type=\"n1-standard-4\",\n",
|
||||
")\n",
|
||||
"print(endpoint)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "edb781a92864"
|
||||
},
|
||||
"source": [
|
||||
"### Make a prediction\n",
|
||||
"\n",
|
||||
"Finally, you make a prediction with the deployed model."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"id": "72d94012a987"
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"endpoint.predict([\"this is a test\"])"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "cleanup:mbsdk"
|
||||
},
|
||||
"source": [
|
||||
"# Cleaning up\n",
|
||||
"\n",
|
||||
"To clean up all Google Cloud resources used in this project, you can [delete the Google Cloud\n",
|
||||
"project](https://cloud.google.com/resource-manager/docs/creating-managing-projects#shutting_down_projects) you used for the tutorial.\n",
|
||||
"\n",
|
||||
"Otherwise, you can delete the individual resources you created in this tutorial."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"id": "cleanup:mbsdk"
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"delete_bucket = True\n",
|
||||
"\n",
|
||||
"endpoint.undeploy_all()\n",
|
||||
"endpoint.delete()\n",
|
||||
"model.delete()\n",
|
||||
"\n",
|
||||
"if delete_bucket or os.getenv(\"IS_TESTING\"):\n",
|
||||
" ! gsutil rm -r $BUCKET_URI\n",
|
||||
"\n",
|
||||
"! rm -rf custom custom.tar.gz"
|
||||
]
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"colab": {
|
||||
"name": "model_garden_pipeline_templates_t5x.ipynb",
|
||||
"toc_visible": true
|
||||
},
|
||||
"kernelspec": {
|
||||
"display_name": "Python 3",
|
||||
"name": "python3"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 0
|
||||
}
|
||||
+1487
File diff suppressed because it is too large
Load Diff
@@ -184,7 +184,9 @@
|
||||
"\n",
|
||||
"1. [Enable the Vertex AI API and Compute Engine API](https://console.cloud.google.com/flows/enableapi?apiid=aiplatform.googleapis.com,compute_component).\n",
|
||||
"\n",
|
||||
"1. [Create a Cloud Storage bucket](https://cloud.google.com/storage/docs/creating-buckets) for storing experiment outputs."
|
||||
"1. [Create a Cloud Storage bucket](https://cloud.google.com/storage/docs/creating-buckets) for storing experiment outputs.\n",
|
||||
"\n",
|
||||
"1. [Create a service account](https://cloud.google.com/iam/docs/service-accounts-create#iam-service-accounts-create-console) with `Vertex AI User` and `Storage Object Admin` roles for deploying fine tuned model to Vertex AI endpoint."
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -211,7 +213,10 @@
|
||||
"REGION = \"us-central1\" # @param {type:\"string\"}\n",
|
||||
"\n",
|
||||
"# The Cloud Storage bucket for storing experiments output. Fill it without the 'gs://' prefix.\n",
|
||||
"GCS_BUCKET = \"\" # @param {type:\"string\"}"
|
||||
"GCS_BUCKET = \"\" # @param {type:\"string\"}\n",
|
||||
"\n",
|
||||
"# The service account you created in step-5 above, it's like \"<account_name>@<project>.iam.gserviceaccount.com\"\n",
|
||||
"SERVICE_ACCOUNT = \"\" # @param {type:\"string\"}"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -271,7 +276,7 @@
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 1,
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"id": "354da31189dc"
|
||||
},
|
||||
@@ -336,8 +341,6 @@
|
||||
" \"MODEL_ID\": model_id,\n",
|
||||
" \"TASK\": task,\n",
|
||||
" }\n",
|
||||
" # If the model_id is a GCS path, use artifact_uri to pass it to serving docker.\n",
|
||||
" artifact_uri = model_id if model_id.startswith(\"gs://\") else None\n",
|
||||
" model = aiplatform.Model.upload(\n",
|
||||
" display_name=model_name,\n",
|
||||
" serving_container_image_uri=SERVE_DOCKER_URI,\n",
|
||||
@@ -345,7 +348,6 @@
|
||||
" serving_container_predict_route=\"/predictions/diffusers_serving\",\n",
|
||||
" serving_container_health_route=\"/ping\",\n",
|
||||
" serving_container_environment_variables=serving_env,\n",
|
||||
" artifact_uri=artifact_uri,\n",
|
||||
" )\n",
|
||||
" model.deploy(\n",
|
||||
" endpoint=endpoint,\n",
|
||||
@@ -353,6 +355,7 @@
|
||||
" accelerator_type=\"NVIDIA_TESLA_V100\",\n",
|
||||
" accelerator_count=1,\n",
|
||||
" deploy_request_timeout=1800,\n",
|
||||
" service_account=SERVICE_ACCOUNT,\n",
|
||||
" )\n",
|
||||
" return model, endpoint"
|
||||
]
|
||||
@@ -427,6 +430,8 @@
|
||||
" \"--resolution=512\",\n",
|
||||
" \"--learning_rate=1e-5\",\n",
|
||||
" \"--train_batch_size=2\",\n",
|
||||
" \"--checkpointing_steps=50000\",\n",
|
||||
" \"--checkpoints_total_limit=1\",\n",
|
||||
" ],\n",
|
||||
" replica_count=num_nodes,\n",
|
||||
" machine_type=machine_type,\n",
|
||||
@@ -572,7 +577,7 @@
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"model, endpoint = deploy_model(\n",
|
||||
" model_id=f\"gs://{GCS_BUCKET}/controlnet/output\", task=\"image-to-image\"\n",
|
||||
" model_id=f\"gs://{GCS_BUCKET}/controlnet/output\", task=\"controlnet\"\n",
|
||||
")"
|
||||
]
|
||||
},
|
||||
|
||||
@@ -45,7 +45,7 @@
|
||||
" </a>\n",
|
||||
" </td>\n",
|
||||
" <td> <td>\n",
|
||||
" <a href=\"https://console.cloud.google.com/vertex-ai/notebooks/deploy-notebook?download_url=https://raw.githubusercontent.com/GoogleCloudPlatform/vertex-ai-samples/blob/main/notebooks/community/model_garden/model_garden_pytorch_detectron2.ipynb\">\n",
|
||||
" <a href=\"https://console.cloud.google.com/vertex-ai/notebooks/deploy-notebook?download_url=https://raw.githubusercontent.com/GoogleCloudPlatform/vertex-ai-samples/main/notebooks/community/model_garden/model_garden_pytorch_detectron2.ipynb\">\n",
|
||||
" <img src=\"https://lh3.googleusercontent.com/UiNooY4LUgW_oTvpsNhPpQzsstV5W8F7rYgxgGBD85cWJoLmrOzhVs_ksK_vgx40SHs7jCqkTkCk=e14-rj-sc0xffffff-h130-w32\" alt=\"Vertex AI logo\">\n",
|
||||
"Open in Vertex AI Workbench\n",
|
||||
" </a>\n",
|
||||
@@ -189,7 +189,9 @@
|
||||
"\n",
|
||||
"1. [Enable the Vertex AI API and Compute Engine API](https://console.cloud.google.com/flows/enableapi?apiid=aiplatform.googleapis.com,compute_component).\n",
|
||||
"\n",
|
||||
"1. [Create a Cloud Storage bucket](https://cloud.google.com/storage/docs/creating-buckets) for storing experiment outputs."
|
||||
"1. [Create a Cloud Storage bucket](https://cloud.google.com/storage/docs/creating-buckets) for storing experiment outputs.\n",
|
||||
"\n",
|
||||
"1. [Create a service account](https://cloud.google.com/iam/docs/service-accounts-create#iam-service-accounts-create-console) with `Vertex AI User`, `Storage Object Admin`, and `GCS Storage Bucket Owner` roles for deploying fine tuned model to Vertex AI endpoint."
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -213,10 +215,16 @@
|
||||
"PROJECT_ID = \"\" # @param {type:\"string\"}\n",
|
||||
"\n",
|
||||
"# The region you want to launch jobs in.\n",
|
||||
"REGION = \"\" # @param {type:\"string\"}\n",
|
||||
"REGION = \"us-central1\" # @param {type:\"string\"}\n",
|
||||
"\n",
|
||||
"# The Cloud Storage bucket for storing experiments output. For example 'gs://my_bucket'.\n",
|
||||
"BUCKET_URI = \"\" # @param {type:\"string\"}"
|
||||
"BUCKET_URI = \"\" # @param {type:\"string\"}\n",
|
||||
"\n",
|
||||
"# The service account for deploying fine tuned model.\n",
|
||||
"# The service account looks like:\n",
|
||||
"# '<account_name>@<project>.iam.gserviceaccount.com'\n",
|
||||
"# Follow step 5 above to create this account.\n",
|
||||
"SERVICE_ACCOUNT = \"\" # @param {type:\"string\"}"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -814,7 +822,8 @@
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"local_balloon_data_directory = \"balloon\" # @param {type:\"string\"}"
|
||||
"local_balloon_data_directory = \"balloon\" # @param {type:\"string\"}\n",
|
||||
"BALLOON_DATA_GCS_PATH = os.path.join(BUCKET_URI, \"balloon_dataset\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -902,14 +911,47 @@
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"id": "oOfgze5RpJQ8"
|
||||
"id": "0OykIZen9gCC"
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Move Balloon data from local directory to Cloud Storage.\n",
|
||||
"BALLOON_DATA_GCS_PATH = os.path.join(BUCKET_URI, \"balloon_dataset\")\n",
|
||||
"!gsutil -m cp -r $local_balloon_data_directory/* $BALLOON_DATA_GCS_PATH/\n",
|
||||
"!gsutil ls $BALLOON_DATA_GCS_PATH"
|
||||
"\n",
|
||||
"import glob\n",
|
||||
"\n",
|
||||
"from google.cloud import storage\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"def get_bucket_and_blob_name(filepath):\n",
|
||||
" # The gcs path is of the form gs://<bucket-name>/<blob-name>\n",
|
||||
" gs_suffix = filepath.split(\"gs://\", 1)[1]\n",
|
||||
" return tuple(gs_suffix.split(\"/\", 1))\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"def upload_local_dir_to_gcs(local_dir_path, gcs_dir_path):\n",
|
||||
" \"\"\"Uploads files in a local directory to a GCS directory.\"\"\"\n",
|
||||
" client = storage.Client()\n",
|
||||
" bucket_name = gcs_dir_path.split(\"/\")[2]\n",
|
||||
" bucket = client.get_bucket(bucket_name)\n",
|
||||
" for local_file in glob.glob(local_dir_path + \"/**\"):\n",
|
||||
" if not os.path.isfile(local_file):\n",
|
||||
" continue\n",
|
||||
" filename = local_file[1 + len(local_dir_path) :]\n",
|
||||
" gcs_file_path = os.path.join(gcs_dir_path, filename)\n",
|
||||
" _, blob_name = get_bucket_and_blob_name(gcs_file_path)\n",
|
||||
" blob = bucket.blob(blob_name)\n",
|
||||
" blob.upload_from_filename(local_file)\n",
|
||||
" print(\"Copied {} to {}.\".format(local_file, gcs_file_path))\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"upload_local_dir_to_gcs(\n",
|
||||
" os.path.join(local_balloon_data_directory, \"train\"),\n",
|
||||
" os.path.join(BALLOON_DATA_GCS_PATH, \"train\"),\n",
|
||||
")\n",
|
||||
"upload_local_dir_to_gcs(\n",
|
||||
" os.path.join(local_balloon_data_directory, \"val\"),\n",
|
||||
" os.path.join(BALLOON_DATA_GCS_PATH, \"val\"),\n",
|
||||
")"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -944,26 +986,22 @@
|
||||
"train_dataset_name = \"balloon_train\" # @param {type:\"string\"}\n",
|
||||
"train_coco_json_file = os.path.join(\n",
|
||||
" BALLOON_DATA_GCS_PATH, \"train/balloon_train_coco_format.json\"\n",
|
||||
") # @param {type:\"string\"}\n",
|
||||
")\n",
|
||||
"train_coco_json_file = gcs_fuse_path(train_coco_json_file)\n",
|
||||
"train_image_root = os.path.join(\n",
|
||||
" BALLOON_DATA_GCS_PATH, \"train\"\n",
|
||||
") # @param {type:\"string\"}\n",
|
||||
"train_image_root = os.path.join(BALLOON_DATA_GCS_PATH, \"train\")\n",
|
||||
"train_image_root = gcs_fuse_path(train_image_root)\n",
|
||||
"val_dataset_name = \"balloon_val\" # @param {type:\"string\"}\n",
|
||||
"val_coco_json_file = os.path.join(\n",
|
||||
" BALLOON_DATA_GCS_PATH, \"val/balloon_val_coco_format.json\"\n",
|
||||
") # @param {type:\"string\"}\n",
|
||||
")\n",
|
||||
"val_coco_json_file = gcs_fuse_path(val_coco_json_file)\n",
|
||||
"val_image_root = os.path.join(BALLOON_DATA_GCS_PATH, \"val\") # @param {type:\"string\"}\n",
|
||||
"val_image_root = os.path.join(BALLOON_DATA_GCS_PATH, \"val\")\n",
|
||||
"val_image_root = gcs_fuse_path(val_image_root)\n",
|
||||
"output_dir = os.path.join(BUCKET_URI, JOB_NAME)\n",
|
||||
"\n",
|
||||
"#################################################\n",
|
||||
"# Model and dataset related parameters for Mask R-CNN.\n",
|
||||
"config_file = (\n",
|
||||
" \"COCO-InstanceSegmentation/mask_rcnn_R_50_FPN_3x.yaml\" # @param {type:\"string\"}\n",
|
||||
")\n",
|
||||
"config_file = \"COCO-InstanceSegmentation/mask_rcnn_R_50_FPN_3x.yaml\"\n",
|
||||
"config_file = gcs_fuse_path(config_file)\n",
|
||||
"remainder_args_list = []\n",
|
||||
"remainder_args_list += [\"DATASETS.TRAIN\"] + [\n",
|
||||
@@ -982,7 +1020,7 @@
|
||||
"\n",
|
||||
"# #################################################\n",
|
||||
"# # Model and dataset related parameters for RetinaNet.\n",
|
||||
"# config_file='COCO-Detection/retinanet_R_50_FPN_3x.yaml' # @param {type:\"string\"}\n",
|
||||
"# config_file='COCO-Detection/retinanet_R_50_FPN_3x.yaml'\n",
|
||||
"# config_file = gcs_fuse_path(config_file)\n",
|
||||
"# remainder_args_list = []\n",
|
||||
"# remainder_args_list += ['DATASETS.TRAIN'] + ['(\"{train_dataset_name}\",)'.format(train_dataset_name=train_dataset_name)]\n",
|
||||
@@ -998,7 +1036,7 @@
|
||||
"\n",
|
||||
"# #################################################\n",
|
||||
"# # Model and dataset related parameters for Faster R-CNN.\n",
|
||||
"# config_file='COCO-Detection/faster_rcnn_X_101_32x8d_FPN_3x.yaml' # @param {type:\"string\"}\n",
|
||||
"# config_file='COCO-Detection/faster_rcnn_X_101_32x8d_FPN_3x.yaml'\n",
|
||||
"# config_file = gcs_fuse_path(config_file)\n",
|
||||
"# remainder_args_list = []\n",
|
||||
"# remainder_args_list += ['DATASETS.TRAIN'] + ['(\"{train_dataset_name}\",)'.format(train_dataset_name=train_dataset_name)]\n",
|
||||
@@ -1054,7 +1092,6 @@
|
||||
"job = aiplatform.CustomContainerTrainingJob(\n",
|
||||
" display_name=JOB_NAME,\n",
|
||||
" container_uri=container_uri,\n",
|
||||
" command=[\"python\", \"-m\", \"trainer.task\"],\n",
|
||||
")\n",
|
||||
"model = job.run(\n",
|
||||
" args=docker_args_list,\n",
|
||||
@@ -1088,17 +1125,13 @@
|
||||
"# Upload models to model registry\n",
|
||||
"from datetime import datetime\n",
|
||||
"\n",
|
||||
"PRETRAINED_MODEL_PTH_FILE = os.path.join(\n",
|
||||
" output_dir, \"model_final.pth\"\n",
|
||||
") # @param {type:\"string\"}\n",
|
||||
"PRETRAINED_MODEL_CFG_YAML_FILE = os.path.join(\n",
|
||||
" output_dir, \"config.yaml\"\n",
|
||||
") # @param {type:\"string\"}\n",
|
||||
"PRETRAINED_MODEL_PTH_FILE = os.path.join(output_dir, \"model_final.pth\")\n",
|
||||
"PRETRAINED_MODEL_CFG_YAML_FILE = os.path.join(output_dir, \"config.yaml\")\n",
|
||||
"TEST_THRESHOLD = 0.7\n",
|
||||
"PREDICTION_CONTAINER_URI = SERVE_DOCKER_URI\n",
|
||||
"PREDICTION_DISPLAY_NAME = \"upload_detectron2_\" + datetime.now().strftime(\n",
|
||||
" \"%Y%m%d_%H%M%S\"\n",
|
||||
") # @param {type:\"string\"}\n",
|
||||
")\n",
|
||||
"\n",
|
||||
"model = upload_model(\n",
|
||||
" project=PROJECT_ID,\n",
|
||||
@@ -1123,9 +1156,7 @@
|
||||
"# Deploy uploaded models\n",
|
||||
"from datetime import datetime\n",
|
||||
"\n",
|
||||
"DEPLOYED_NAME = \"deploy_iod_\" + datetime.now().strftime(\n",
|
||||
" \"%Y%m%d_%H%M%S\"\n",
|
||||
") # @param {type:\"string\"}\n",
|
||||
"DEPLOYED_NAME = \"deploy_iod_\" + datetime.now().strftime(\"%Y%m%d_%H%M%S\")\n",
|
||||
"MACHINE_TYPE = \"n1-highmem-16\" # @param {type:\"string\"}\n",
|
||||
"\n",
|
||||
"TRAFFIC_SPLIT = {\"0\": 100}\n",
|
||||
@@ -1133,13 +1164,13 @@
|
||||
"MIN_NODES = 1\n",
|
||||
"MAX_NODES = 1\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"endpoint = model.deploy(\n",
|
||||
" deployed_model_display_name=DEPLOYED_NAME,\n",
|
||||
" traffic_split=TRAFFIC_SPLIT,\n",
|
||||
" machine_type=MACHINE_TYPE,\n",
|
||||
" min_replica_count=MIN_NODES,\n",
|
||||
" max_replica_count=MAX_NODES,\n",
|
||||
" service_account=SERVICE_ACCOUNT,\n",
|
||||
")\n",
|
||||
"\n",
|
||||
"print(\"endpoint id is: \", endpoint.name)"
|
||||
@@ -1155,11 +1186,12 @@
|
||||
"source": [
|
||||
"# Run predictions\n",
|
||||
"# Fill the \"endpoint_id\" from previous step below.\n",
|
||||
"# For example 'endpoint_id = \"8211918096324100096\"'.\n",
|
||||
"\n",
|
||||
"endpoint_id = \"1218390824971141120\" # @param {type:\"string\"}\n",
|
||||
"endpoint_id = \"\" # @param {type:\"string\"}\n",
|
||||
"local_test_filepath = os.path.join(\n",
|
||||
" local_balloon_data_directory, \"val/410488422_5f8991f26e_b.jpg\"\n",
|
||||
") # @param {type:\"string\"}\n",
|
||||
")\n",
|
||||
"instances = get_prediction_instances(local_test_filepath)\n",
|
||||
"api_endpoint = REGION + \"-aiplatform.googleapis.com\"\n",
|
||||
"\n",
|
||||
@@ -1182,7 +1214,7 @@
|
||||
"boxes = prediction[\"boxes\"]\n",
|
||||
"classes = prediction[\"classes\"]\n",
|
||||
"scores = prediction[\"scores\"]\n",
|
||||
"if \"masks_rle\" in prediction:\n",
|
||||
"if prediction[\"masks_rle\"]:\n",
|
||||
" masks_numpy = decode_rle_masks(prediction[\"masks_rle\"])\n",
|
||||
"else:\n",
|
||||
" masks_numpy = None\n",
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
]
|
||||
},
|
||||
{
|
||||
"attachments": {},
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "99c1c3fc2ca5"
|
||||
@@ -48,12 +49,13 @@
|
||||
" <img src=\"https://lh3.googleusercontent.com/UiNooY4LUgW_oTvpsNhPpQzsstV5W8F7rYgxgGBD85cWJoLmrOzhVs_ksK_vgx40SHs7jCqkTkCk=e14-rj-sc0xffffff-h130-w32\" alt=\"Vertex AI logo\">\n",
|
||||
"Open in Vertex AI Workbench\n",
|
||||
" </a>\n",
|
||||
" (a Python-3 CPU notebook is recommended)\n",
|
||||
" (a Python-3 GPU notebook with preinstalled HuggingFace/transformer libraries is recommended)\n",
|
||||
" </td>\n",
|
||||
"</table>"
|
||||
]
|
||||
},
|
||||
{
|
||||
"attachments": {},
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "3de7470326a2"
|
||||
@@ -61,13 +63,15 @@
|
||||
"source": [
|
||||
"## Overview\n",
|
||||
"\n",
|
||||
"This notebook demonstrates finetuning [runwayml/stable-diffusion-v1-5](https://huggingface.co/runwayml/stable-diffusion-v1-5) with [Dreambooth](https://huggingface.co/docs/diffusers/training/dreambooth) and deploying it on Vertex AI for online prediction.\n",
|
||||
"This notebook demonstrates running local inference on [Vertex AI Workbench](https://cloud.google.com/vertex-ai-workbench).\n",
|
||||
"This notebook also demonstrates finetuning [runwayml/stable-diffusion-v1-5](https://huggingface.co/runwayml/stable-diffusion-v1-5) with [Dreambooth](https://huggingface.co/docs/diffusers/training/dreambooth) and deploying it on Vertex AI for online prediction.\n",
|
||||
"\n",
|
||||
"### Objective\n",
|
||||
"\n",
|
||||
"- Run local predictions for text-to-image and text-guided-image-to-image with serving dockers.\n",
|
||||
"- Finetune the stable-diffusion-v1.5 model with [Dreambooth](https://huggingface.co/docs/diffusers/training/dreambooth).\n",
|
||||
"- Upload the model to [Model Registry](https://cloud.google.com/vertex-ai/docs/model-registry/introduction).\n",
|
||||
"- Deploy the model on [Endpoint](https://cloud.google.com/vertex-ai/docs/predictions/using-private-endpoints).\n",
|
||||
"- Upload the model to [Vertex AI Model Registry](https://cloud.google.com/vertex-ai/docs/model-registry/introduction).\n",
|
||||
"- Deploy the model to a [Vertex AI Endpoint resource](https://cloud.google.com/vertex-ai/docs/predictions/using-private-endpoints).\n",
|
||||
"- Run online predictions for text-to-image and text-guided-image-to-image.\n",
|
||||
"\n",
|
||||
"### Costs\n",
|
||||
@@ -81,6 +85,114 @@
|
||||
]
|
||||
},
|
||||
{
|
||||
"attachments": {},
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "e8a42fa49305"
|
||||
},
|
||||
"source": [
|
||||
"## Local inference (Workbench only)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"attachments": {},
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "1169c41b76b3"
|
||||
},
|
||||
"source": [
|
||||
"The quickest and easiest way to use this model locally is by using Vertex AI Workbench with a pre-built custom container that has the necessary packages installed.\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"1. Follow [this link](https://console.cloud.google.com/vertex-ai/notebooks/deploy-notebook?download_url=https://raw.githubusercontent.com/GoogleCloudPlatform/vertex-ai-samples/main/notebooks/community/model_garden/model_garden_pytorch_stable_diffusion.ipynb) to deploy the notebook to a Vertex AI Workbench Instance.\n",
|
||||
"2. Select `Create a new Notebook`.\n",
|
||||
"3. Click `Advanced Options`.\n",
|
||||
"4. Under **Environment**, select `Custom Container` for `Environment`. \n",
|
||||
"5. Set `Docker container image` to `us-docker.pkg.dev/vertex-ai/vertex-vision-model-garden-dockers/transformers-notebook`.\n",
|
||||
"6. Under **Machine configuration**, select a GPU and select `Install NVIDIA GPU driver automatically for me`.\n",
|
||||
"7. Click `Create` to create the Vertex AI Workbench instance. \n",
|
||||
"\n",
|
||||
"Once the notebook is ready, simply execute the code block(s) below in the Workbench instance."
|
||||
]
|
||||
},
|
||||
{
|
||||
"attachments": {},
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "1d5ebc91c786"
|
||||
},
|
||||
"source": [
|
||||
"### Text-to-image"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"id": "d39ed8c97cc5"
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"import torch\n",
|
||||
"from diffusers import StableDiffusionPipeline\n",
|
||||
"\n",
|
||||
"model_id = \"runwayml/stable-diffusion-v1-5\"\n",
|
||||
"pipe = StableDiffusionPipeline.from_pretrained(model_id, torch_dtype=torch.float16)\n",
|
||||
"pipe = pipe.to(\"cuda\")\n",
|
||||
"\n",
|
||||
"prompt = \"a photo of an astronaut riding a horse on mars\"\n",
|
||||
"image = pipe(prompt).images[0]\n",
|
||||
"\n",
|
||||
"display(image)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"attachments": {},
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "5aed5ed7b6f6"
|
||||
},
|
||||
"source": [
|
||||
"### Text-guided image-to-image"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"id": "faadabb7728f"
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"from io import BytesIO\n",
|
||||
"\n",
|
||||
"import requests\n",
|
||||
"import torch\n",
|
||||
"from diffusers import StableDiffusionImg2ImgPipeline\n",
|
||||
"from PIL import Image\n",
|
||||
"\n",
|
||||
"device = \"cuda\"\n",
|
||||
"model_id_or_path = \"runwayml/stable-diffusion-v1-5\"\n",
|
||||
"pipe = StableDiffusionImg2ImgPipeline.from_pretrained(\n",
|
||||
" model_id_or_path, torch_dtype=torch.float16\n",
|
||||
")\n",
|
||||
"pipe = pipe.to(device)\n",
|
||||
"\n",
|
||||
"url = \"https://raw.githubusercontent.com/CompVis/stable-diffusion/main/assets/stable-samples/img2img/sketch-mountains-input.jpg\"\n",
|
||||
"\n",
|
||||
"response = requests.get(url)\n",
|
||||
"init_image = Image.open(BytesIO(response.content)).convert(\"RGB\")\n",
|
||||
"init_image = init_image.resize((768, 512))\n",
|
||||
"\n",
|
||||
"prompt = \"A fantasy landscape, trending on artstation\"\n",
|
||||
"\n",
|
||||
"images = pipe(prompt=prompt, image=init_image, strength=0.75, guidance_scale=7.5).images\n",
|
||||
"display(images[0])"
|
||||
]
|
||||
},
|
||||
{
|
||||
"attachments": {},
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "264c07757582"
|
||||
@@ -92,6 +204,7 @@
|
||||
]
|
||||
},
|
||||
{
|
||||
"attachments": {},
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "d73ffa0c0b83"
|
||||
@@ -125,6 +238,7 @@
|
||||
]
|
||||
},
|
||||
{
|
||||
"attachments": {},
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "fb671e75ca7b"
|
||||
@@ -142,12 +256,11 @@
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Install gdown for downloading example training images.\n",
|
||||
"!pip install gdown\n",
|
||||
"# Install gsutil for downloading/uploading data from/to Cloud Storage buckets.\n",
|
||||
"!pip install gsutil"
|
||||
"!pip install gdown"
|
||||
]
|
||||
},
|
||||
{
|
||||
"attachments": {},
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "5244aac3d929"
|
||||
@@ -171,6 +284,7 @@
|
||||
]
|
||||
},
|
||||
{
|
||||
"attachments": {},
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "bb7adab99e41"
|
||||
@@ -184,10 +298,13 @@
|
||||
"\n",
|
||||
"1. [Enable the Vertex AI API and Compute Engine API](https://console.cloud.google.com/flows/enableapi?apiid=aiplatform.googleapis.com,compute_component).\n",
|
||||
"\n",
|
||||
"1. [Create a Cloud Storage bucket](https://cloud.google.com/storage/docs/creating-buckets) for storing experiment outputs."
|
||||
"1. [Create a Cloud Storage bucket](https://cloud.google.com/storage/docs/creating-buckets) for storing experiment outputs.\n",
|
||||
"\n",
|
||||
"1. [Create a service account](https://cloud.google.com/iam/docs/service-accounts-create#iam-service-accounts-create-console) with `Vertex AI User` and `Storage Object Admin` roles for deploying fine tuned model to Vertex AI endpoint."
|
||||
]
|
||||
},
|
||||
{
|
||||
"attachments": {},
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "6c460088b873"
|
||||
@@ -211,10 +328,14 @@
|
||||
"REGION = \"us-central1\" # @param {type:\"string\"}\n",
|
||||
"\n",
|
||||
"# The Cloud Storage bucket for storing experiments output. Fill it without the 'gs://' prefix.\n",
|
||||
"GCS_BUCKET = \"\" # @param {type:\"string\"}"
|
||||
"GCS_BUCKET = \"\" # @param {type:\"string\"}\n",
|
||||
"\n",
|
||||
"# The service account for deploying fine tuned model.\n",
|
||||
"SERVICE_ACCOUNT = \"\" # @param {type:\"string\"}"
|
||||
]
|
||||
},
|
||||
{
|
||||
"attachments": {},
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "e828eb320337"
|
||||
@@ -237,6 +358,7 @@
|
||||
]
|
||||
},
|
||||
{
|
||||
"attachments": {},
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "2cc825514deb"
|
||||
@@ -261,6 +383,7 @@
|
||||
]
|
||||
},
|
||||
{
|
||||
"attachments": {},
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "0c250872074f"
|
||||
@@ -278,12 +401,13 @@
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"import base64\n",
|
||||
"import glob\n",
|
||||
"import os\n",
|
||||
"from datetime import datetime\n",
|
||||
"from io import BytesIO\n",
|
||||
"\n",
|
||||
"import requests\n",
|
||||
"from google.cloud import aiplatform\n",
|
||||
"from google.cloud import aiplatform, storage\n",
|
||||
"from PIL import Image\n",
|
||||
"\n",
|
||||
"\n",
|
||||
@@ -326,8 +450,6 @@
|
||||
" \"MODEL_ID\": model_id,\n",
|
||||
" \"TASK\": task,\n",
|
||||
" }\n",
|
||||
" # If the model_id is a GCS path, use artifact_uri to pass it to serving docker.\n",
|
||||
" artifact_uri = model_id if model_id.startswith(\"gs://\") else None\n",
|
||||
" model = aiplatform.Model.upload(\n",
|
||||
" display_name=model_name,\n",
|
||||
" serving_container_image_uri=SERVE_DOCKER_URI,\n",
|
||||
@@ -335,7 +457,6 @@
|
||||
" serving_container_predict_route=\"/predictions/diffusers_serving\",\n",
|
||||
" serving_container_health_route=\"/ping\",\n",
|
||||
" serving_container_environment_variables=serving_env,\n",
|
||||
" artifact_uri=artifact_uri,\n",
|
||||
" )\n",
|
||||
" model.deploy(\n",
|
||||
" endpoint=endpoint,\n",
|
||||
@@ -343,11 +464,35 @@
|
||||
" accelerator_type=\"NVIDIA_TESLA_V100\",\n",
|
||||
" accelerator_count=1,\n",
|
||||
" deploy_request_timeout=1800,\n",
|
||||
" service_account=SERVICE_ACCOUNT,\n",
|
||||
" )\n",
|
||||
" return model, endpoint"
|
||||
" return model, endpoint\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"def get_bucket_and_blob_name(filepath):\n",
|
||||
" # The gcs path is of the form gs://<bucket-name>/<blob-name>\n",
|
||||
" gs_suffix = filepath.split(\"gs://\", 1)[1]\n",
|
||||
" return tuple(gs_suffix.split(\"/\", 1))\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"def upload_local_dir_to_gcs(local_dir_path, gcs_dir_path):\n",
|
||||
" \"\"\"Uploads files in a local directory to a GCS directory.\"\"\"\n",
|
||||
" client = storage.Client()\n",
|
||||
" bucket_name = gcs_dir_path.split(\"/\")[2]\n",
|
||||
" bucket = client.get_bucket(bucket_name)\n",
|
||||
" for local_file in glob.glob(local_dir_path + \"/**\"):\n",
|
||||
" if not os.path.isfile(local_file):\n",
|
||||
" continue\n",
|
||||
" filename = local_file[1 + len(local_dir_path) :]\n",
|
||||
" gcs_file_path = os.path.join(gcs_dir_path, filename)\n",
|
||||
" _, blob_name = get_bucket_and_blob_name(gcs_file_path)\n",
|
||||
" blob = bucket.blob(blob_name)\n",
|
||||
" blob.upload_from_filename(local_file)\n",
|
||||
" print(\"Copied {} to {}.\".format(local_file, gcs_file_path))"
|
||||
]
|
||||
},
|
||||
{
|
||||
"attachments": {},
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "e70e3519ff8b"
|
||||
@@ -357,6 +502,7 @@
|
||||
]
|
||||
},
|
||||
{
|
||||
"attachments": {},
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "0dc65d8f0689"
|
||||
@@ -381,11 +527,12 @@
|
||||
"!gdown --folder https://drive.google.com/drive/folders/1BO_dyz-p65qhBRRMRA4TbZ8qW4rB99JZ\n",
|
||||
"\n",
|
||||
"# Upload data to Cloud Storage bucket.\n",
|
||||
"!gsutil -m cp -r dog/* gs://{GCS_BUCKET}/dreambooth/dog/\n",
|
||||
"!gsutil -m cp -r dog/* gs://{GCS_BUCKET}/dreambooth/dog_class/"
|
||||
"upload_local_dir_to_gcs(\"dog\", f\"gs://{GCS_BUCKET}/dreambooth/dog\")\n",
|
||||
"upload_local_dir_to_gcs(\"dog\", f\"gs://{GCS_BUCKET}/dreambooth/dog_class\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"attachments": {},
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "969cfeb79317"
|
||||
@@ -455,6 +602,7 @@
|
||||
]
|
||||
},
|
||||
{
|
||||
"attachments": {},
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "bf7f82732e61"
|
||||
@@ -464,6 +612,7 @@
|
||||
]
|
||||
},
|
||||
{
|
||||
"attachments": {},
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "1cc26e68d7b0"
|
||||
@@ -475,6 +624,7 @@
|
||||
]
|
||||
},
|
||||
{
|
||||
"attachments": {},
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "cd7b56421392"
|
||||
@@ -484,6 +634,7 @@
|
||||
]
|
||||
},
|
||||
{
|
||||
"attachments": {},
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "6d331b1ea337"
|
||||
@@ -504,13 +655,14 @@
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Set the model_id to a GCS path, like \"gs://GCS_BUCKET/dreambooth/output\", to load the dreambooth finetuned model above.\n",
|
||||
"# Set the model_id to \"runwayml/stable-diffusion-v1-5\" to load the OSS pre-trained model.\n",
|
||||
"model, endpoint = deploy_model(\n",
|
||||
" model_id=\"runwayml/stable-diffusion-v1-5\", task=\"text-to-image\"\n",
|
||||
" model_id=f\"gs://{GCS_BUCKET}/dreambooth/output\", task=\"text-to-image\"\n",
|
||||
")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"attachments": {},
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "80b3fd2ace09"
|
||||
@@ -539,6 +691,7 @@
|
||||
]
|
||||
},
|
||||
{
|
||||
"attachments": {},
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "af21a3cff1e0"
|
||||
@@ -563,6 +716,7 @@
|
||||
]
|
||||
},
|
||||
{
|
||||
"attachments": {},
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "c1e51f764a60"
|
||||
@@ -572,6 +726,7 @@
|
||||
]
|
||||
},
|
||||
{
|
||||
"attachments": {},
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "fa686a54047c"
|
||||
@@ -595,6 +750,7 @@
|
||||
]
|
||||
},
|
||||
{
|
||||
"attachments": {},
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "80b3fd2ace09"
|
||||
@@ -627,6 +783,7 @@
|
||||
]
|
||||
},
|
||||
{
|
||||
"attachments": {},
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "ed3795d474b9"
|
||||
|
||||
+43
-25
@@ -142,9 +142,7 @@
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Install gdown for downloading example training images.\n",
|
||||
"!pip install gdown\n",
|
||||
"# Install gsutil for downloading/uploading data from/to Cloud Storage buckets.\n",
|
||||
"!pip install gsutil"
|
||||
"!pip install gdown"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -184,7 +182,9 @@
|
||||
"\n",
|
||||
"1. [Enable the Vertex AI API and Compute Engine API](https://console.cloud.google.com/flows/enableapi?apiid=aiplatform.googleapis.com,compute_component).\n",
|
||||
"\n",
|
||||
"1. [Create a Cloud Storage bucket](https://cloud.google.com/storage/docs/creating-buckets) for storing experiment outputs."
|
||||
"1. [Create a Cloud Storage bucket](https://cloud.google.com/storage/docs/creating-buckets) for storing experiment outputs.\n",
|
||||
"\n",
|
||||
"1. [Create a service account](https://cloud.google.com/iam/docs/service-accounts-create#iam-service-accounts-create-console) with `Vertex AI User` and `Storage Object Admin` roles for deploying fine tuned model to Vertex AI endpoint."
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -210,8 +210,14 @@
|
||||
"# The region you want to launch jobs in.\n",
|
||||
"REGION = \"us-central1\" # @param {type:\"string\"}\n",
|
||||
"\n",
|
||||
"# The Cloud Storage bucket for storing experiments output. Fill it without the 'gs://' prefix.\n",
|
||||
"GCS_BUCKET = \"\" # @param {type:\"string\"}"
|
||||
"# The Cloud Storage bucket for storing experiments output.\n",
|
||||
"# Fill it without the 'gs://' prefix.\n",
|
||||
"GCS_BUCKET = \"\" # @param {type:\"string\"}\n",
|
||||
"\n",
|
||||
"# The service account for deploying fine tuned model.\n",
|
||||
"# The service account looks like:\n",
|
||||
"# '<account_name>@<project>.iam.gserviceaccount.com'\n",
|
||||
"SERVICE_ACCOUNT = \"\" # @param {type:\"string\"}"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -271,19 +277,20 @@
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 2,
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"id": "8759e624ebc0"
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"import base64\n",
|
||||
"import glob\n",
|
||||
"import os\n",
|
||||
"from datetime import datetime\n",
|
||||
"from io import BytesIO\n",
|
||||
"\n",
|
||||
"import requests\n",
|
||||
"from google.cloud import aiplatform\n",
|
||||
"from google.cloud import aiplatform, storage\n",
|
||||
"from PIL import Image\n",
|
||||
"\n",
|
||||
"\n",
|
||||
@@ -326,8 +333,6 @@
|
||||
" \"MODEL_ID\": model_id,\n",
|
||||
" \"TASK\": task,\n",
|
||||
" }\n",
|
||||
" # If the model_id is a GCS path, use artifact_uri to pass it to serving docker.\n",
|
||||
" artifact_uri = model_id if model_id.startswith(\"gs://\") else None\n",
|
||||
" model = aiplatform.Model.upload(\n",
|
||||
" display_name=model_name,\n",
|
||||
" serving_container_image_uri=SERVE_DOCKER_URI,\n",
|
||||
@@ -335,7 +340,6 @@
|
||||
" serving_container_predict_route=\"/predictions/diffusers_serving\",\n",
|
||||
" serving_container_health_route=\"/ping\",\n",
|
||||
" serving_container_environment_variables=serving_env,\n",
|
||||
" artifact_uri=artifact_uri,\n",
|
||||
" )\n",
|
||||
" model.deploy(\n",
|
||||
" endpoint=endpoint,\n",
|
||||
@@ -343,8 +347,31 @@
|
||||
" accelerator_type=\"NVIDIA_TESLA_V100\",\n",
|
||||
" accelerator_count=1,\n",
|
||||
" deploy_request_timeout=1800,\n",
|
||||
" service_account=SERVICE_ACCOUNT,\n",
|
||||
" )\n",
|
||||
" return model, endpoint"
|
||||
" return model, endpoint\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"def get_bucket_and_blob_name(filepath):\n",
|
||||
" # The gcs path is of the form gs://<bucket-name>/<blob-name>\n",
|
||||
" gs_suffix = filepath.split(\"gs://\", 1)[1]\n",
|
||||
" return tuple(gs_suffix.split(\"/\", 1))\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"def upload_local_dir_to_gcs(local_dir_path, gcs_dir_path):\n",
|
||||
" \"\"\"Uploads files in a local directory to a GCS directory.\"\"\"\n",
|
||||
" client = storage.Client()\n",
|
||||
" bucket_name = gcs_dir_path.split(\"/\")[2]\n",
|
||||
" bucket = client.get_bucket(bucket_name)\n",
|
||||
" for local_file in glob.glob(local_dir_path + \"/**\"):\n",
|
||||
" if not os.path.isfile(local_file):\n",
|
||||
" continue\n",
|
||||
" filename = local_file[1 + len(local_dir_path) :]\n",
|
||||
" gcs_file_path = os.path.join(gcs_dir_path, filename)\n",
|
||||
" _, blob_name = get_bucket_and_blob_name(gcs_file_path)\n",
|
||||
" blob = bucket.blob(blob_name)\n",
|
||||
" blob.upload_from_filename(local_file)\n",
|
||||
" print(\"Copied {} to {}.\".format(local_file, gcs_file_path))"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -381,17 +408,8 @@
|
||||
"!gdown --folder https://drive.google.com/drive/folders/1BO_dyz-p65qhBRRMRA4TbZ8qW4rB99JZ\n",
|
||||
"\n",
|
||||
"# Upload data to Cloud Storage bucket.\n",
|
||||
"!gsutil -m cp -r dog/* gs://{GCS_BUCKET}/dreambooth/dog/\n",
|
||||
"!gsutil -m cp -r dog/* gs://{GCS_BUCKET}/dreambooth/dog_class/"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "969cfeb79317"
|
||||
},
|
||||
"source": [
|
||||
"**NOTE**: If the upload step fails due to lacking of permission, you need to [grant the Storage Object Admin role](https://cloud.google.com/storage/docs/access-control/using-iam-permissions) for the Cloud account of the notebook."
|
||||
"upload_local_dir_to_gcs(\"dog\", f\"gs://{GCS_BUCKET}/dreambooth/dog\")\n",
|
||||
"upload_local_dir_to_gcs(\"dog\", f\"gs://{GCS_BUCKET}/dreambooth/dog_class\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -504,9 +522,9 @@
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Set the model_id to a GCS path, like \"gs://GCS_BUCKET/dreambooth/output\", to load the dreambooth finetuned model above.\n",
|
||||
"# Set the model_id to \"runwayml/stable-diffusion-inpainting\" to load the OSS pre-trained model.\n",
|
||||
"model, endpoint = deploy_model(\n",
|
||||
" model_id=\"runwayml/stable-diffusion-inpainting\", task=\"image-inpainting\"\n",
|
||||
" model_id=f\"gs://{GCS_BUCKET}/dreambooth/output\", task=\"image-inpainting\"\n",
|
||||
")"
|
||||
]
|
||||
},
|
||||
|
||||
@@ -104,7 +104,9 @@
|
||||
"\n",
|
||||
"1. [Create a Cloud Storage bucket](https://cloud.google.com/storage/docs/creating-buckets) for storing experiment outputs.\n",
|
||||
"\n",
|
||||
"1. [Enable the Vertex AI API and Compute Engine API](https://console.cloud.google.com/flows/enableapi?apiid=aiplatform.googleapis.com,compute_component)."
|
||||
"1. [Enable the Vertex AI API and Compute Engine API](https://console.cloud.google.com/flows/enableapi?apiid=aiplatform.googleapis.com,compute_component).\n",
|
||||
"\n",
|
||||
"1. [Create a service account](https://cloud.google.com/iam/docs/service-accounts-create#iam-service-accounts-create-console) with `Vertex AI User` and `Storage Object Admin` roles for deploying fine tuned model to Vertex AI endpoint."
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -193,13 +195,18 @@
|
||||
"# The region for running jobs.\n",
|
||||
"REGION = \"us-central1\" # @param {type:\"string\"}\n",
|
||||
"\n",
|
||||
"# The model you want to train and serve.\n",
|
||||
"# The model you want to train and serve. Please select a model from the verified model list above.\n",
|
||||
"# We use a ViT model as the example.\n",
|
||||
"MODEL_NAME = \"vit_tiny_patch16_224\" # @param {type:\"string\"}\n",
|
||||
"\n",
|
||||
"# The Cloud Storage bucket name without gs:// prefix for training outputs.\n",
|
||||
"# For example: test_bucket\n",
|
||||
"GCS_BUCKET = \"\" # @param {type:\"string\"}"
|
||||
"GCS_BUCKET = \"\" # @param {type:\"string\"}\n",
|
||||
"\n",
|
||||
"# The service account for deploying fine tuned model. It looks like:\n",
|
||||
"# '<account_name>@<project>.iam.gserviceaccount.com'\n",
|
||||
"# Follow step 6 above to create this account.\n",
|
||||
"SERVICE_ACCOUNT = \"\" # @param {type:\"string\"}"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -225,7 +232,7 @@
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# The training docker uri.\n",
|
||||
"# The prebuilt training docker uri.\n",
|
||||
"TRAIN_DOCKER_URI = \"us-docker.pkg.dev/vertex-ai-restricted/vertex-vision-model-garden-dockers/pytorch-timm-train\"\n",
|
||||
"\n",
|
||||
"# The path to data directory on Cloud Storage without gs:// prefix.\n",
|
||||
@@ -265,8 +272,8 @@
|
||||
"# Single node with multiple GPUs.\n",
|
||||
"machine_type = \"n1-highmem-32\"\n",
|
||||
"num_nodes = 1\n",
|
||||
"gpu_type = \"NVIDIA_TESLA_P100\"\n",
|
||||
"num_gpus = 4\n",
|
||||
"gpu_type = \"NVIDIA_TESLA_P100\" # @param {type:\"string\"}\n",
|
||||
"num_gpus = 4 # @param {type:\"integer\"}\n",
|
||||
"\n",
|
||||
"# Model specific config.\n",
|
||||
"job_name = f\"pytorch-{MODEL_NAME}\"\n",
|
||||
@@ -336,8 +343,8 @@
|
||||
"# Worker pool spec.\n",
|
||||
"machine_type = \"n1-highmem-16\"\n",
|
||||
"num_nodes = 1\n",
|
||||
"gpu_type = \"NVIDIA_TESLA_V100\"\n",
|
||||
"num_gpus = 2\n",
|
||||
"gpu_type = \"NVIDIA_TESLA_V100\" # @param {type:\"string\"}\n",
|
||||
"num_gpus = 2 # @param {type:\"integer\"}\n",
|
||||
"worker_pool_specs = [\n",
|
||||
" {\n",
|
||||
" \"machine_spec\": {\n",
|
||||
@@ -408,19 +415,14 @@
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# The serve docker uri.\n",
|
||||
"# The prebuilt serving docker uri.\n",
|
||||
"SERVE_DOCKER_URI = \"us-docker.pkg.dev/vertex-ai-restricted/vertex-vision-model-garden-dockers/pytorch-timm-serve\"\n",
|
||||
"# The port number used by torchserve traffic.\n",
|
||||
"SERVE_PORT = 7080\n",
|
||||
"# The path to model checkpoint file, including gs:// prefix.\n",
|
||||
"MODEL_PT_PATH = \"gs://path_to_model_best.pth.tar\" # @param {type:\"string\"}\n",
|
||||
"# [Optional] the path to index_to_name.json, including gs:// prefix.\n",
|
||||
"INDEX_TO_NAME_FILE = \"gs://path_to_index_to_name.json\" # @param {type:\"string\"}\n",
|
||||
"\n",
|
||||
"# Converts gs:// uris to /gcs/ to use GCS Fuse.\n",
|
||||
"# See https://github.com/GoogleCloudPlatform/gcsfuse.\n",
|
||||
"MODEL_PT_PATH = MODEL_PT_PATH.replace(\"gs://\", \"/gcs/\")\n",
|
||||
"INDEX_TO_NAME_FILE = INDEX_TO_NAME_FILE.replace(\"gs://\", \"/gcs/\")"
|
||||
"INDEX_TO_NAME_FILE = \"gs://path_to_index_to_name.json\" # @param {type:\"string\"}"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -469,6 +471,7 @@
|
||||
" accelerator_type=\"NVIDIA_TESLA_T4\",\n",
|
||||
" accelerator_count=1,\n",
|
||||
" traffic_percentage=100,\n",
|
||||
" service_account=SERVICE_ACCOUNT,\n",
|
||||
")"
|
||||
]
|
||||
},
|
||||
@@ -506,10 +509,10 @@
|
||||
"# endpoint = aiplatform.Endpoint('projects/816369962409/locations/us-central1/endpoints/8809168414485512192')\n",
|
||||
"\n",
|
||||
"# Please upload an image and enter its filename below.\n",
|
||||
"IMAGE_FILENAME = \"cat.jpg\" # @param {type:\"string\"}\n",
|
||||
"IMAGE_FILENAME = \"test.jpg\" # @param {type:\"string\"}\n",
|
||||
"\n",
|
||||
"# Alternatively, uncomment the follow line to download a cat image for demonstration.\n",
|
||||
"# ! wget http://images.cocodataset.org/val2017/000000039769.jpg -O cat.jpg\n",
|
||||
"# Alternatively, uncomment the following line to download a cat image for demonstration.\n",
|
||||
"# ! wget http://images.cocodataset.org/val2017/000000039769.jpg -O test.jpg\n",
|
||||
"\n",
|
||||
"with open(IMAGE_FILENAME, \"rb\") as f:\n",
|
||||
" image_b64 = base64.b64encode(f.read()).decode(\"utf-8\")\n",
|
||||
|
||||
@@ -118,7 +118,7 @@
|
||||
},
|
||||
"source": [
|
||||
"### Colab Only\n",
|
||||
"Run the following commands for colab and skip this section if you use workbench."
|
||||
"Run the following commands for Colab and skip this section if you use Workbench."
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -181,7 +181,16 @@
|
||||
"# The project and bucket are for experiments below.\n",
|
||||
"PROJECT_ID = \"\" # @param {type:\"string\"}\n",
|
||||
"BUCKET_URI = \"\" # @param {type:\"string\"}\n",
|
||||
"REGION = \"us-central1\"\n",
|
||||
"\n",
|
||||
"# You can choose a region from https://cloud.google.com/about/locations.\n",
|
||||
"# Only regions prefixed by \"us\", \"asia\", or \"europe\" are supported.\n",
|
||||
"REGION = \"us-central1\" # @param {type:\"string\"}\n",
|
||||
"REGION_PREFIX = REGION.split(\"-\")[0]\n",
|
||||
"assert REGION_PREFIX in (\n",
|
||||
" \"us\",\n",
|
||||
" \"europe\",\n",
|
||||
" \"asia\",\n",
|
||||
"), f'{REGION} is not supported. It must be prefixed by \"us\", \"asia\", or \"europe\".'\n",
|
||||
"\n",
|
||||
"! gcloud config set project $PROJECT_ID\n",
|
||||
"\n",
|
||||
@@ -231,13 +240,13 @@
|
||||
"\n",
|
||||
"# Data converter constants.\n",
|
||||
"DATA_CONVERTER_JOB_PREFIX = \"data_converter\"\n",
|
||||
"DATA_CONVERTER_CONTAINER = \"us-docker.pkg.dev/vertex-ai-restricted/vertex-vision-model-garden-dockers/data-converter:latest\"\n",
|
||||
"DATA_CONVERTER_CONTAINER = f\"{REGION_PREFIX}-docker.pkg.dev/vertex-ai-restricted/vertex-vision-model-garden-dockers/data-converter\"\n",
|
||||
"DATA_CONVERTER_MACHINE_TYPE = \"n1-highmem-8\"\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"# Training constants.\n",
|
||||
"TRAINING_JOB_PREFIX = \"train\"\n",
|
||||
"TRAIN_CONTAINER_URI = \"us-docker.pkg.dev/vertex-ai-restricted/vertex-vision-model-garden-dockers/tfvision-oss:latest\"\n",
|
||||
"TRAIN_CONTAINER_URI = f\"{REGION_PREFIX}-docker.pkg.dev/vertex-ai-restricted/vertex-vision-model-garden-dockers/tfvision-oss\"\n",
|
||||
"TRAIN_MACHINE_TYPE = \"n1-highmem-16\"\n",
|
||||
"TRAIN_ACCELERATOR_TYPE = \"NVIDIA_TESLA_P100\"\n",
|
||||
"TRAIN_NUM_GPU = 1\n",
|
||||
@@ -247,7 +256,7 @@
|
||||
"\n",
|
||||
"# Export constants.\n",
|
||||
"EXPORT_JOB_PREFIX = \"export\"\n",
|
||||
"EXPORT_CONTAINER_URI = \"us-docker.pkg.dev/vertex-ai-restricted/vertex-vision-model-garden-dockers/tfvision-serving:latest\"\n",
|
||||
"EXPORT_CONTAINER_URI = f\"{REGION_PREFIX}-docker.pkg.dev/vertex-ai-restricted/vertex-vision-model-garden-dockers/tfvision-serving\"\n",
|
||||
"EXPORT_MACHINE_TYPE = \"n1-highmem-8\"\n",
|
||||
"\n",
|
||||
"# Prediction constants.\n",
|
||||
@@ -256,9 +265,7 @@
|
||||
"# and optimized tensorflow runtime dockers: https://cloud.google.com/vertex-ai/docs/predictions/optimized-tensorflow-runtime.\n",
|
||||
"# The example in this notebook uses optimized tensorflow runtime dockers.\n",
|
||||
"# You can adjust accelerator types and machine types to get faster predictions.\n",
|
||||
"PREDICTION_CONTAINER_URI = (\n",
|
||||
" \"us-docker.pkg.dev/vertex-ai-restricted/prediction/tf_opt-gpu.2-11:latest\"\n",
|
||||
")\n",
|
||||
"PREDICTION_CONTAINER_URI = f\"{REGION_PREFIX}-docker.pkg.dev/vertex-ai-restricted/prediction/tf_opt-gpu.2-11:latest\"\n",
|
||||
"SERVING_CONTAINER_ARGS = [\"--allow_precompilation\", \"--allow_compression\"]\n",
|
||||
"PREDICTION_ACCELERATOR_TYPE = \"NVIDIA_TESLA_T4\"\n",
|
||||
"PREDICTION_MACHINE_TYPE = \"n1-standard-4\"\n",
|
||||
@@ -307,10 +314,9 @@
|
||||
" endpoint_id: str,\n",
|
||||
" instances: Union[Dict, List[Dict]],\n",
|
||||
" location: str = \"us-central1\",\n",
|
||||
" api_endpoint: str = \"us-central1-aiplatform.googleapis.com\",\n",
|
||||
"):\n",
|
||||
" # The AI Platform services require regional API endpoints.\n",
|
||||
" client_options = {\"api_endpoint\": api_endpoint}\n",
|
||||
" client_options = {\"api_endpoint\": f\"{location}-aiplatform.googleapis.com\"}\n",
|
||||
" # Initialize client that will be used to create and send requests.\n",
|
||||
" # This client only needs to be created once, and can be reused for multiple requests.\n",
|
||||
" client = aiplatform.gapic.PredictionServiceClient(client_options=client_options)\n",
|
||||
@@ -536,7 +542,7 @@
|
||||
"# input_train_data_path = ''\n",
|
||||
"# input_validation_data_path = ''\n",
|
||||
"\n",
|
||||
"experiment = \"ViT-s16\" # @param [\"ResNet-50\",\"ResNet-RS-50\",\"Efficientnetv2-m\",\"ViT-ti16\",\"ViT-s16\",\"ViT-b16\",\"ViT-l16\"]\n",
|
||||
"experiment = \"ResNet-50\" # @param [\"ResNet-50\",\"ResNet-RS-50\",\"Efficientnetv2-m\",\"ViT-ti16\",\"ViT-s16\",\"ViT-b16\",\"ViT-l16\"]\n",
|
||||
"\n",
|
||||
"train_job_name = get_job_name_with_datetime(TRAINING_JOB_PREFIX + \"_\" + OBJECTIVE)\n",
|
||||
"model_dir = os.path.join(BUCKET_URI, train_job_name)\n",
|
||||
@@ -562,6 +568,7 @@
|
||||
" **{\n",
|
||||
" \"experiment\": \"resnet_imagenet\",\n",
|
||||
" \"config_file\": os.path.join(CONFIG_DIR, \"imagenet_resnet50_gpu.yaml\"),\n",
|
||||
" \"init_checkpoint\": \"https://storage.googleapis.com/tf_model_garden/vision/resnet/resnet-50-i224.tar.gz\",\n",
|
||||
" },\n",
|
||||
" ),\n",
|
||||
" \"ResNet-RS-50\": dict(\n",
|
||||
|
||||
+60
-27
@@ -118,7 +118,7 @@
|
||||
},
|
||||
"source": [
|
||||
"### Colab Only\n",
|
||||
"Run the following commands for colab and skip this section if you use workbench."
|
||||
"Run the following commands for Colab and skip this section if you are using Workbench."
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -181,27 +181,37 @@
|
||||
"# The project and bucket are for experiments below.\n",
|
||||
"PROJECT_ID = \"\" # @param {type:\"string\"}\n",
|
||||
"BUCKET_URI = \"\" # @param {type:\"string\"}\n",
|
||||
"REGION = \"us-central1\"\n",
|
||||
"\n",
|
||||
"# You can choose a region from https://cloud.google.com/about/locations.\n",
|
||||
"# Only regions prefixed by \"us\", \"asia\", or \"europe\" are supported.\n",
|
||||
"REGION = \"us-central1\" # @param {type:\"string\"}\n",
|
||||
"REGION_PREFIX = REGION.split(\"-\")[0]\n",
|
||||
"assert REGION_PREFIX in (\n",
|
||||
" \"us\",\n",
|
||||
" \"europe\",\n",
|
||||
" \"asia\",\n",
|
||||
"), f'{REGION} is not supported. It must be prefixed by \"us\", \"asia\", or \"europe\".'\n",
|
||||
"\n",
|
||||
"! gcloud config set project $PROJECT_ID\n",
|
||||
"\n",
|
||||
"STAGING_BUCKET = os.path.join(BUCKET_URI, \"temporal\")\n",
|
||||
"CHECKPOINT_BUCKET = os.path.join(BUCKET_URI, \"ckpt\")\n",
|
||||
"\n",
|
||||
"aiplatform.init(project=PROJECT_ID, location=REGION, staging_bucket=STAGING_BUCKET)\n",
|
||||
"\n",
|
||||
"# Download config files.\n",
|
||||
"CONFIG_DIR = os.path.join(BUCKET_URI, \"config\")\n",
|
||||
"! wget https://raw.githubusercontent.com/tensorflow/models/master/official/vision/configs/experiments/retinanet/coco_spinenet49_gpu_multiworker_mirrored.yaml\n",
|
||||
"! gsutil cp coco_spinenet49_gpu_multiworker_mirrored.yaml $CONFIG_DIR\n",
|
||||
"! gsutil cp coco_spinenet49_gpu_multiworker_mirrored.yaml $CONFIG_DIR/\n",
|
||||
"\n",
|
||||
"! wget https://raw.githubusercontent.com/tensorflow/models/master/official/vision/configs/experiments/retinanet/coco_spinenet96_gpu_multiworker_mirrored.yaml\n",
|
||||
"! gsutil cp coco_spinenet96_gpu_multiworker_mirrored.yaml $CONFIG_DIR\n",
|
||||
"! gsutil cp coco_spinenet96_gpu_multiworker_mirrored.yaml $CONFIG_DIR/\n",
|
||||
"\n",
|
||||
"! wget https://raw.githubusercontent.com/tensorflow/models/master/official/vision/configs/experiments/retinanet/coco_spinenet143_gpu_multiworker_mirrored.yaml\n",
|
||||
"! gsutil cp coco_spinenet143_gpu_multiworker_mirrored.yaml $CONFIG_DIR\n",
|
||||
"! gsutil cp coco_spinenet143_gpu_multiworker_mirrored.yaml $CONFIG_DIR/\n",
|
||||
"\n",
|
||||
"! wget https://raw.githubusercontent.com/tensorflow/models/master/official/projects/yolo/configs/experiments/yolov4/detection/scaled_yolov4_1280_gpu.yaml\n",
|
||||
"! gsutil cp scaled_yolov4_1280_gpu.yaml $CONFIG_DIR"
|
||||
"! gsutil cp scaled_yolov4_1280_gpu.yaml $CONFIG_DIR/"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -225,13 +235,13 @@
|
||||
"\n",
|
||||
"# Data converter constants.\n",
|
||||
"DATA_CONVERTER_JOB_PREFIX = \"data_converter\"\n",
|
||||
"DATA_CONVERTER_CONTAINER = \"us-docker.pkg.dev/vertex-ai-restricted/vertex-vision-model-garden-dockers/data-converter:latest\"\n",
|
||||
"DATA_CONVERTER_CONTAINER = f\"{REGION_PREFIX}-docker.pkg.dev/vertex-ai-restricted/vertex-vision-model-garden-dockers/data-converter\"\n",
|
||||
"DATA_CONVERTER_MACHINE_TYPE = \"n1-highmem-8\"\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"# Training constants.\n",
|
||||
"TRAINING_JOB_PREFIX = \"train\"\n",
|
||||
"TRAIN_CONTAINER_URI = \"us-docker.pkg.dev/vertex-ai-restricted/vertex-vision-model-garden-dockers/tfvision-oss:latest\"\n",
|
||||
"TRAIN_CONTAINER_URI = f\"{REGION_PREFIX}-docker.pkg.dev/vertex-ai-restricted/vertex-vision-model-garden-dockers/tfvision-oss\"\n",
|
||||
"TRAIN_MACHINE_TYPE = \"n1-highmem-16\"\n",
|
||||
"TRAIN_ACCELERATOR_TYPE = \"NVIDIA_TESLA_V100\"\n",
|
||||
"TRAIN_NUM_GPU = 2\n",
|
||||
@@ -251,7 +261,7 @@
|
||||
"\n",
|
||||
"# Export constants.\n",
|
||||
"EXPORT_JOB_PREFIX = \"export\"\n",
|
||||
"EXPORT_CONTAINER_URI = \"us-docker.pkg.dev/vertex-ai-restricted/vertex-vision-model-garden-dockers/tfvision-serving:latest\"\n",
|
||||
"EXPORT_CONTAINER_URI = f\"{REGION_PREFIX}-docker.pkg.dev/vertex-ai-restricted/vertex-vision-model-garden-dockers/tfvision-serving\"\n",
|
||||
"EXPORT_MACHINE_TYPE = \"n1-highmem-8\"\n",
|
||||
"\n",
|
||||
"# Prediction constants.\n",
|
||||
@@ -260,9 +270,7 @@
|
||||
"# and optimized tensorflow runtime dockers: https://cloud.google.com/vertex-ai/docs/predictions/optimized-tensorflow-runtime.\n",
|
||||
"# The example in this notebook uses optimized tensorflow runtime dockers.\n",
|
||||
"# You can adjust accelerator types and machine types to get faster predictions.\n",
|
||||
"PREDICTION_CONTAINER_URI = (\n",
|
||||
" \"us-docker.pkg.dev/vertex-ai-restricted/prediction/tf_opt-gpu.2-11:latest\"\n",
|
||||
")\n",
|
||||
"PREDICTION_CONTAINER_URI = f\"{REGION_PREFIX}-docker.pkg.dev/vertex-ai-restricted/prediction/tf_opt-gpu.2-11:latest\"\n",
|
||||
"SERVING_CONTAINER_ARGS = [\"--allow_precompilation\", \"--allow_compression\"]\n",
|
||||
"PREDICTION_ACCELERATOR_TYPE = \"NVIDIA_TESLA_T4\"\n",
|
||||
"PREDICTION_MACHINE_TYPE = \"n1-standard-4\"\n",
|
||||
@@ -313,10 +321,9 @@
|
||||
" endpoint_id: str,\n",
|
||||
" instances: Union[Dict, List[Dict]],\n",
|
||||
" location: str = \"us-central1\",\n",
|
||||
" api_endpoint: str = \"us-central1-aiplatform.googleapis.com\",\n",
|
||||
"):\n",
|
||||
" # The AI Platform services require regional API endpoints.\n",
|
||||
" client_options = {\"api_endpoint\": api_endpoint}\n",
|
||||
" client_options = {\"api_endpoint\": f\"{location}-aiplatform.googleapis.com\"}\n",
|
||||
" # Initialize client that will be used to create and send requests.\n",
|
||||
" # This client only needs to be created once, and can be reused for multiple requests.\n",
|
||||
" client = aiplatform.gapic.PredictionServiceClient(client_options=client_options)\n",
|
||||
@@ -469,7 +476,30 @@
|
||||
" font,\n",
|
||||
" display_str_list=[display_str],\n",
|
||||
" )\n",
|
||||
" return image"
|
||||
" return image\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"def upload_checkpoint_to_gcs(checkpoint_url):\n",
|
||||
" filename = os.path.basename(checkpoint_url)\n",
|
||||
" checkpoint_name = filename.replace(\".tar.gz\", \"\")\n",
|
||||
" print(\"Download checkpoint from\", checkpoint_url, \"and store to\", CHECKPOINT_BUCKET)\n",
|
||||
" ! wget $checkpoint_url -O $filename\n",
|
||||
" ! mkdir -p $checkpoint_name\n",
|
||||
" ! tar -xvzf $filename -C $checkpoint_name\n",
|
||||
"\n",
|
||||
" # Search for relative path to the checkpoint.\n",
|
||||
" checkpoint_path = None\n",
|
||||
" for root, dirs, files in os.walk(checkpoint_name):\n",
|
||||
" for file in files:\n",
|
||||
" if file.endswith(\".index\"):\n",
|
||||
" checkpoint_path = os.path.join(root, os.path.splitext(file)[0])\n",
|
||||
" checkpoint_path = os.path.relpath(checkpoint_path, checkpoint_name)\n",
|
||||
" break\n",
|
||||
"\n",
|
||||
" ! gsutil cp -r $checkpoint_name $CHECKPOINT_BUCKET/\n",
|
||||
" checkpoint_uri = os.path.join(CHECKPOINT_BUCKET, checkpoint_name, checkpoint_path)\n",
|
||||
" print(\"Checkpoint uploaded to\", checkpoint_uri)\n",
|
||||
" return checkpoint_uri"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -621,8 +651,8 @@
|
||||
" \"objective\": OBJECTIVE,\n",
|
||||
" \"model_dir\": model_dir,\n",
|
||||
" \"num_classes\": num_classes,\n",
|
||||
" \"global_batch_size\": 4,\n",
|
||||
" \"prefetch_buffer_size\": 12,\n",
|
||||
" \"global_batch_size\": 2,\n",
|
||||
" \"prefetch_buffer_size\": 6,\n",
|
||||
" \"train_steps\": 2000,\n",
|
||||
" \"input_size\": \"1024,1024\",\n",
|
||||
"}\n",
|
||||
@@ -661,9 +691,19 @@
|
||||
" **{\n",
|
||||
" \"experiment\": \"scaled_yolo\",\n",
|
||||
" \"config_file\": TRAIN_YOLOV4_CONFIG,\n",
|
||||
" \"init_checkpoint\": \"https://storage.googleapis.com/tf_model_garden/vision/yolo/scaled-yolov4/scaled-yolov4-l-p6-i1280.tar.gz\",\n",
|
||||
" \"input_size\": \"1280,1280\",\n",
|
||||
" },\n",
|
||||
" ),\n",
|
||||
"}\n",
|
||||
"experiment_container_args = experiment_container_args_dict[experiment]\n",
|
||||
"\n",
|
||||
"# Copy checkpoint to GCS bucket if specified.\n",
|
||||
"init_checkpoint = experiment_container_args.get(\"init_checkpoint\")\n",
|
||||
"if init_checkpoint:\n",
|
||||
" experiment_container_args[\"init_checkpoint\"] = upload_checkpoint_to_gcs(\n",
|
||||
" init_checkpoint\n",
|
||||
" )\n",
|
||||
"\n",
|
||||
"params_override = \"runtime.num_gpus=%s\" % TRAIN_NUM_GPU\n",
|
||||
"eval_params_override = \"runtime.num_gpus=1,runtime.distribution_strategy=mirrored\"\n",
|
||||
@@ -681,10 +721,7 @@
|
||||
" \"--mode=train\",\n",
|
||||
" \"--params_override=%s\" % params_override,\n",
|
||||
" ]\n",
|
||||
" + [\n",
|
||||
" \"--{}={}\".format(k, v)\n",
|
||||
" for k, v in experiment_container_args_dict[experiment].items()\n",
|
||||
" ],\n",
|
||||
" + [\"--{}={}\".format(k, v) for k, v in experiment_container_args.items()],\n",
|
||||
" },\n",
|
||||
" },\n",
|
||||
" {},\n",
|
||||
@@ -702,10 +739,7 @@
|
||||
" \"--mode=continuous_eval\",\n",
|
||||
" \"--params_override=%s\" % eval_params_override,\n",
|
||||
" ]\n",
|
||||
" + [\n",
|
||||
" \"--{}={}\".format(k, v)\n",
|
||||
" for k, v in experiment_container_args_dict[experiment].items()\n",
|
||||
" ],\n",
|
||||
" + [\"--{}={}\".format(k, v) for k, v in experiment_container_args.items()],\n",
|
||||
" },\n",
|
||||
" },\n",
|
||||
"]\n",
|
||||
@@ -807,8 +841,7 @@
|
||||
" \"args\": [\n",
|
||||
" \"--objective=%s\" % OBJECTIVE,\n",
|
||||
" \"--input_image_size=1024,1024\",\n",
|
||||
" \"--experiment=%s\"\n",
|
||||
" % experiment_container_args_dict[experiment][\"experiment\"],\n",
|
||||
" \"--experiment=%s\" % experiment_container_args[\"experiment\"],\n",
|
||||
" \"--config_file=%s/params.yaml\" % best_trial_dir,\n",
|
||||
" \"--checkpoint_path=%s/best_ckpt\" % best_trial_dir,\n",
|
||||
" \"--export_dir=%s/best_model\" % model_dir,\n",
|
||||
|
||||
@@ -119,7 +119,7 @@
|
||||
"source": [
|
||||
"### Colab Only\n",
|
||||
"\n",
|
||||
"Run the following commands for colab and skip this section if you use workbench."
|
||||
"Run the following commands for Colab and skip this section if you use Workbench."
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -182,18 +182,28 @@
|
||||
"# The project and bucket are for experiments below.\n",
|
||||
"PROJECT_ID = \"\" # @param {type:\"string\"}\n",
|
||||
"BUCKET_URI = \"\" # @param {type:\"string\"}\n",
|
||||
"REGION = \"us-central1\"\n",
|
||||
"\n",
|
||||
"# You can choose a region from https://cloud.google.com/about/locations.\n",
|
||||
"# Only regions prefixed by \"us\", \"asia\", or \"europe\" are supported.\n",
|
||||
"REGION = \"europe-west4\" # @param {type:\"string\"}\n",
|
||||
"REGION_PREFIX = REGION.split(\"-\")[0]\n",
|
||||
"assert REGION_PREFIX in (\n",
|
||||
" \"us\",\n",
|
||||
" \"europe\",\n",
|
||||
" \"asia\",\n",
|
||||
"), f'{REGION} is not supported. It must be prefixed by \"us\", \"asia\", or \"europe\".'\n",
|
||||
"\n",
|
||||
"! gcloud config set project $PROJECT_ID\n",
|
||||
"\n",
|
||||
"STAGING_BUCKET = os.path.join(BUCKET_URI, \"temporal\")\n",
|
||||
"CHECKPOINT_BUCKET = os.path.join(BUCKET_URI, \"ckpt\")\n",
|
||||
"\n",
|
||||
"aiplatform.init(project=PROJECT_ID, location=REGION, staging_bucket=STAGING_BUCKET)\n",
|
||||
"\n",
|
||||
"# Download config files.\n",
|
||||
"CONFIG_DIR = os.path.join(BUCKET_URI, \"config\")\n",
|
||||
"! wget https://raw.githubusercontent.com/tensorflow/models/master/official/vision/configs/experiments/semantic_segmentation/deeplabv3plus_resnet101_cityscapes_gpu_multiworker_mirrored.yaml\n",
|
||||
"! gsutil cp deeplabv3plus_resnet101_cityscapes_gpu_multiworker_mirrored.yaml $CONFIG_DIR"
|
||||
"! gsutil cp deeplabv3plus_resnet101_cityscapes_gpu_multiworker_mirrored.yaml $CONFIG_DIR/"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -217,13 +227,13 @@
|
||||
"\n",
|
||||
"# Data converter constants.\n",
|
||||
"DATA_CONVERTER_JOB_PREFIX = \"data_converter\"\n",
|
||||
"DATA_CONVERTER_CONTAINER = \"us-docker.pkg.dev/vertex-ai-restricted/vertex-vision-model-garden-dockers/data-converter:latest\"\n",
|
||||
"DATA_CONVERTER_CONTAINER = f\"{REGION_PREFIX}-docker.pkg.dev/vertex-ai-restricted/vertex-vision-model-garden-dockers/data-converter\"\n",
|
||||
"DATA_CONVERTER_MACHINE_TYPE = \"n1-highmem-8\"\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"# Training constants.\n",
|
||||
"TRAINING_JOB_PREFIX = \"train\"\n",
|
||||
"TRAIN_CONTAINER_URI = \"us-docker.pkg.dev/vertex-ai-restricted/vertex-vision-model-garden-dockers/tfvision-oss:latest\"\n",
|
||||
"TRAIN_CONTAINER_URI = f\"{REGION_PREFIX}-docker.pkg.dev/vertex-ai-restricted/vertex-vision-model-garden-dockers/tfvision-oss\"\n",
|
||||
"TRAIN_MACHINE_TYPE = \"n1-highmem-16\"\n",
|
||||
"TRAIN_ACCELERATOR_TYPE = \"NVIDIA_TESLA_V100\"\n",
|
||||
"TRAIN_NUM_GPU = 2\n",
|
||||
@@ -236,7 +246,7 @@
|
||||
"\n",
|
||||
"# Export constants.\n",
|
||||
"EXPORT_JOB_PREFIX = \"export\"\n",
|
||||
"EXPORT_CONTAINER_URI = \"us-docker.pkg.dev/vertex-ai-restricted/vertex-vision-model-garden-dockers/tfvision-serving:latest\"\n",
|
||||
"EXPORT_CONTAINER_URI = f\"{REGION_PREFIX}-docker.pkg.dev/vertex-ai-restricted/vertex-vision-model-garden-dockers/tfvision-serving\"\n",
|
||||
"EXPORT_MACHINE_TYPE = \"n1-highmem-8\"\n",
|
||||
"\n",
|
||||
"# Prediction constants.\n",
|
||||
@@ -245,9 +255,7 @@
|
||||
"# and optimized tensorflow runtime dockers: https://cloud.google.com/vertex-ai/docs/predictions/optimized-tensorflow-runtime.\n",
|
||||
"# The example in this notebook uses optimized tensorflow runtime dockers.\n",
|
||||
"# You can adjust accelerator types and machine types to get faster predictions.\n",
|
||||
"PREDICTION_CONTAINER_URI = (\n",
|
||||
" \"us-docker.pkg.dev/vertex-ai-restricted/prediction/tf_opt-gpu.2-11:latest\"\n",
|
||||
")\n",
|
||||
"PREDICTION_CONTAINER_URI = f\"{REGION_PREFIX}-docker.pkg.dev/vertex-ai-restricted/prediction/tf_opt-gpu.2-11:latest\"\n",
|
||||
"SERVING_CONTAINER_ARGS = [\"--allow_precompilation\", \"--allow_compression\"]\n",
|
||||
"PREDICTION_ACCELERATOR_TYPE = \"NVIDIA_TESLA_T4\"\n",
|
||||
"PREDICTION_MACHINE_TYPE = \"n1-standard-4\"\n",
|
||||
@@ -298,10 +306,9 @@
|
||||
" endpoint_id: str,\n",
|
||||
" instances: Union[Dict, List[Dict]],\n",
|
||||
" location: str = \"us-central1\",\n",
|
||||
" api_endpoint: str = \"us-central1-aiplatform.googleapis.com\",\n",
|
||||
"):\n",
|
||||
" # The AI Platform services require regional API endpoints.\n",
|
||||
" client_options = {\"api_endpoint\": api_endpoint}\n",
|
||||
" client_options = {\"api_endpoint\": f\"{location}-aiplatform.googleapis.com\"}\n",
|
||||
" # Initialize client that will be used to create and send requests.\n",
|
||||
" # This client only needs to be created once, and can be reused for multiple requests.\n",
|
||||
" client = aiplatform.gapic.PredictionServiceClient(client_options=client_options)\n",
|
||||
@@ -508,7 +515,30 @@
|
||||
" ]\n",
|
||||
" category_image_color = Image.fromarray(category_image_color_np)\n",
|
||||
"\n",
|
||||
" return score_image_grayscale, category_image_color"
|
||||
" return score_image_grayscale, category_image_color\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"def upload_checkpoint_to_gcs(checkpoint_url):\n",
|
||||
" filename = os.path.basename(checkpoint_url)\n",
|
||||
" checkpoint_name = filename.replace(\".tar.gz\", \"\")\n",
|
||||
" print(\"Download checkpoint from\", checkpoint_url, \"and store to\", CHECKPOINT_BUCKET)\n",
|
||||
" ! wget $checkpoint_url -O $filename\n",
|
||||
" ! mkdir -p $checkpoint_name\n",
|
||||
" ! tar -xvzf $filename -C $checkpoint_name\n",
|
||||
"\n",
|
||||
" # Search for relative path to the checkpoint.\n",
|
||||
" checkpoint_path = None\n",
|
||||
" for root, dirs, files in os.walk(checkpoint_name):\n",
|
||||
" for file in files:\n",
|
||||
" if file.endswith(\".index\"):\n",
|
||||
" checkpoint_path = os.path.join(root, os.path.splitext(file)[0])\n",
|
||||
" checkpoint_path = os.path.relpath(checkpoint_path, checkpoint_name)\n",
|
||||
" break\n",
|
||||
"\n",
|
||||
" ! gsutil cp -r $checkpoint_name $CHECKPOINT_BUCKET/\n",
|
||||
" checkpoint_uri = os.path.join(CHECKPOINT_BUCKET, checkpoint_name, checkpoint_path)\n",
|
||||
" print(\"Checkpoint uploaded to\", checkpoint_uri)\n",
|
||||
" return checkpoint_uri"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -665,8 +695,17 @@
|
||||
" \"prefetch_buffer_size\": 12,\n",
|
||||
" \"train_steps\": 500,\n",
|
||||
" \"output_size\": \"1024,2048\",\n",
|
||||
" \"init_checkpoint\": \"https://storage.googleapis.com/tf_model_garden/vision/deeplabv3plus/dilated-resnet-101-deeplabv3plus.tar.gz\",\n",
|
||||
" }\n",
|
||||
"}\n",
|
||||
"experiment_container_args = experiment_container_args_dict[experiment]\n",
|
||||
"\n",
|
||||
"# Copy checkpoint to GCS bucket if specified.\n",
|
||||
"init_checkpoint = experiment_container_args.get(\"init_checkpoint\")\n",
|
||||
"if init_checkpoint:\n",
|
||||
" experiment_container_args[\"init_checkpoint\"] = upload_checkpoint_to_gcs(\n",
|
||||
" init_checkpoint\n",
|
||||
" )\n",
|
||||
"\n",
|
||||
"worker_pool_specs = [\n",
|
||||
" {\n",
|
||||
@@ -681,10 +720,7 @@
|
||||
" \"args\": [\n",
|
||||
" \"--mode=train_and_eval\",\n",
|
||||
" ]\n",
|
||||
" + [\n",
|
||||
" \"--{}={}\".format(k, v)\n",
|
||||
" for k, v in experiment_container_args_dict[experiment].items()\n",
|
||||
" ],\n",
|
||||
" + [\"--{}={}\".format(k, v) for k, v in experiment_container_args.items()],\n",
|
||||
" },\n",
|
||||
" },\n",
|
||||
"]\n",
|
||||
@@ -787,13 +823,11 @@
|
||||
" \"command\": [],\n",
|
||||
" \"args\": [\n",
|
||||
" \"--objective=%s\" % OBJECTIVE,\n",
|
||||
" \"--experiment=%s\"\n",
|
||||
" % experiment_container_args_dict[experiment][\"experiment\"],\n",
|
||||
" \"--experiment=%s\" % experiment_container_args[\"experiment\"],\n",
|
||||
" \"--config_file=%s/params.yaml\" % best_trial_dir,\n",
|
||||
" \"--checkpoint_path=%s/best_ckpt\" % best_trial_dir,\n",
|
||||
" \"--export_dir=%s/best_model\" % model_dir,\n",
|
||||
" \"--input_image_size=%s\"\n",
|
||||
" % experiment_container_args_dict[experiment][\"output_size\"],\n",
|
||||
" \"--input_image_size=%s\" % experiment_container_args[\"output_size\"],\n",
|
||||
" ],\n",
|
||||
" },\n",
|
||||
" }\n",
|
||||
|
||||
+1
-1
@@ -1479,7 +1479,7 @@
|
||||
"source": [
|
||||
"For more information about VPC peering in Vertex AI, see https://cloud.google.com/vertex-ai/docs/general/vpc-peering.\n",
|
||||
"\n",
|
||||
"**IMPORTANT: you can only setup one VPC peering to servicenetworking.googleapis.com per project.**"
|
||||
"**IMPORTANT: you can only setup one VPC peering to servicenetworking.googleapis.com per VPC network.**"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
||||
@@ -130,48 +130,6 @@
|
||||
"to generate a cost estimate based on your projected usage."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "setup_local"
|
||||
},
|
||||
"source": [
|
||||
"### Set up your local development environment\n",
|
||||
"\n",
|
||||
"**If you are using Colab or Vertex AI Workbench Notebooks**, your environment already meets\n",
|
||||
"all the requirements to run this notebook.\n",
|
||||
"\n",
|
||||
"**Otherwise**, make sure your environment meets this notebook's requirements.\n",
|
||||
"You need the following:\n",
|
||||
"\n",
|
||||
"* The Google Cloud SDK\n",
|
||||
"* Git\n",
|
||||
"* Python 3\n",
|
||||
"* virtualenv\n",
|
||||
"* Jupyter notebook running in a virtual environment with Python 3\n",
|
||||
"\n",
|
||||
"The Google Cloud guide to [Setting up a Python development\n",
|
||||
"environment](https://cloud.google.com/python/setup) and the [Jupyter\n",
|
||||
"installation guide](https://jupyter.org/install) provide detailed instructions\n",
|
||||
"for meeting these requirements. The following steps provide a condensed set of\n",
|
||||
"instructions:\n",
|
||||
"\n",
|
||||
"1. [Install and initialize the Cloud SDK.](https://cloud.google.com/sdk/docs/)\n",
|
||||
"\n",
|
||||
"1. [Install Python 3.](https://cloud.google.com/python/setup#installing_python)\n",
|
||||
"\n",
|
||||
"1. [Install\n",
|
||||
" virtualenv](https://cloud.google.com/python/setup#installing_and_using_virtualenv)\n",
|
||||
" and create a virtual environment that uses Python 3. Activate the virtual environment.\n",
|
||||
"\n",
|
||||
"1. To install Jupyter, run `pip3 install jupyter` on the\n",
|
||||
"command-line in a terminal shell.\n",
|
||||
"\n",
|
||||
"1. To launch Jupyter, run `jupyter notebook` on the command-line in a terminal shell.\n",
|
||||
"\n",
|
||||
"1. Open this notebook in the Jupyter Notebook Dashboard."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
@@ -193,17 +151,8 @@
|
||||
"source": [
|
||||
"import os\n",
|
||||
"\n",
|
||||
"# The Vertex AI Workbench Notebook product has specific requirements\n",
|
||||
"IS_WORKBENCH_NOTEBOOK = os.getenv(\"DL_ANACONDA_HOME\")\n",
|
||||
"IS_USER_MANAGED_WORKBENCH_NOTEBOOK = os.path.exists(\n",
|
||||
" \"/opt/deeplearning/metadata/env_version\"\n",
|
||||
")\n",
|
||||
"# Vertex AI Notebook requires dependencies to be installed with '--user'\n",
|
||||
"USER_FLAG = \"\"\n",
|
||||
"if IS_WORKBENCH_NOTEBOOK:\n",
|
||||
" USER_FLAG = \"--user\"\n",
|
||||
"\n",
|
||||
"! pip3 install --upgrade --quiet {USER_FLAG} google-cloud-aiplatform google-cloud-storage"
|
||||
"! pip3 install --upgrade --quiet google-cloud-aiplatform \\\n",
|
||||
" google-cloud-storage"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -212,65 +161,38 @@
|
||||
"id": "restart"
|
||||
},
|
||||
"source": [
|
||||
"### Restart the kernel\n",
|
||||
"\n",
|
||||
"After you install the additional packages, you need to restart the notebook kernel so it can find the packages."
|
||||
"### Colab only: Uncomment the following cell to restart the kernel"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"id": "restart"
|
||||
"id": "D-ZBOjErv5mM"
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Automatically restart kernel after installs\n",
|
||||
"import os\n",
|
||||
"# Automatically restart kernel after installs so that your environment can access the new packages\n",
|
||||
"# import IPython\n",
|
||||
"\n",
|
||||
"if not os.getenv(\"IS_TESTING\"):\n",
|
||||
" # Automatically restart kernel after installs\n",
|
||||
" import IPython\n",
|
||||
"\n",
|
||||
" app = IPython.Application.instance()\n",
|
||||
" app.kernel.do_shutdown(True)"
|
||||
"# app = IPython.Application.instance()\n",
|
||||
"# app.kernel.do_shutdown(True)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "before_you_begin:nogpu"
|
||||
"id": "yfEglUHQk9S3"
|
||||
},
|
||||
"source": [
|
||||
"## Before you begin\n",
|
||||
"\n",
|
||||
"### Set up your Google Cloud project\n",
|
||||
"### Set your project ID\n",
|
||||
"\n",
|
||||
"**The following steps are required, regardless of your notebook environment.**\n",
|
||||
"\n",
|
||||
"1. [Select or create a Google Cloud project](https://console.cloud.google.com/cloud-resource-manager). When you first create an account, you get a $300 free credit towards your compute/storage costs.\n",
|
||||
"\n",
|
||||
"1. [Make sure that billing is enabled for your project](https://cloud.google.com/billing/docs/how-to/modify-project).\n",
|
||||
"\n",
|
||||
"1. [Enable the Vertex AI API](https://console.cloud.google.com/flows/enableapi?apiid=aiplatform.googleapis.com). \n",
|
||||
"\n",
|
||||
"1. If you are running this notebook locally, you need to install the [Cloud SDK](https://cloud.google.com/sdk).\n",
|
||||
"\n",
|
||||
"1. Enter your project ID in the cell below. Then run the cell to make sure the\n",
|
||||
"Cloud SDK uses the right project for all the commands in this notebook.\n",
|
||||
"\n",
|
||||
"**Note**: Jupyter runs lines prefixed with `!` as shell commands, and it interpolates Python variables prefixed with `$` into these commands.\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "5aee4379e8e5"
|
||||
},
|
||||
"source": [
|
||||
"#### Set your project ID\n",
|
||||
"\n",
|
||||
"**If you don't know your project ID**, you may be able to get your project ID using `gcloud`."
|
||||
"**If you don't know your project ID**, try the following:\n",
|
||||
"* Run `gcloud config list`.\n",
|
||||
"* Run `gcloud projects list`.\n",
|
||||
"* See the support page: [Locate the project ID](https://support.google.com/googleapi/answer/7014113)"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -281,33 +203,10 @@
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"PROJECT_ID = \"[your-project-id]\" # @param {type:\"string\"}"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"id": "autoset_project_id"
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"if PROJECT_ID == \"\" or PROJECT_ID is None or PROJECT_ID == \"[your-project-id]\":\n",
|
||||
" # Get your GCP project id from gcloud\n",
|
||||
" shell_output = ! gcloud config list --format 'value(core.project)' 2>/dev/null\n",
|
||||
" PROJECT_ID = shell_output[0]\n",
|
||||
" print(\"Project ID:\", PROJECT_ID)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"id": "set_gcloud_project_id"
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"! gcloud config set project $PROJECT_ID"
|
||||
"PROJECT_ID = \"[your-project-id]\" # @param {type:\"string\"}\n",
|
||||
"\n",
|
||||
"# Set the project id\n",
|
||||
"! gcloud config set project {PROJECT_ID}"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -318,16 +217,7 @@
|
||||
"source": [
|
||||
"#### Region\n",
|
||||
"\n",
|
||||
"You can also change the `REGION` variable, which is used for operations\n",
|
||||
"throughout the rest of this notebook. Below are regions supported for Vertex AI. It is recommended that you choose the region closest to you.\n",
|
||||
"\n",
|
||||
"- Americas: `us-central1`\n",
|
||||
"- Europe: `europe-west4`\n",
|
||||
"- Asia Pacific: `asia-east1`\n",
|
||||
"\n",
|
||||
"You may not use a multi-regional bucket for training with Vertex AI. Not all regions provide support for all Vertex AI services.\n",
|
||||
"\n",
|
||||
"Learn more about [Vertex AI regions](https://cloud.google.com/vertex-ai/docs/general/locations)."
|
||||
"You can also change the `REGION` variable used by Vertex AI. Learn more about [Vertex AI regions](https://cloud.google.com/vertex-ai/docs/general/locations)."
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -338,41 +228,7 @@
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"REGION = \"[your-region]\" # @param {type: \"string\"}\n",
|
||||
"\n",
|
||||
"if REGION == \"[your-region]\":\n",
|
||||
" REGION = \"us-central1\""
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "timestamp"
|
||||
},
|
||||
"source": [
|
||||
"#### UUID\n",
|
||||
"\n",
|
||||
"If you are in a live tutorial session, you might be using a shared test account or project. To avoid name collisions between users on resources created, you create a uuid for each instance session, and append it onto the name of resources you create in this tutorial.\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"id": "timestamp"
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"import random\n",
|
||||
"import string\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"# Generate a uuid of a specifed length(default=8)\n",
|
||||
"def generate_uuid(length: int = 8) -> str:\n",
|
||||
" return \"\".join(random.choices(string.ascii_lowercase + string.digits, k=length))\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"UUID = generate_uuid()"
|
||||
"REGION = \"us-central1\" # @param {type: \"string\"}"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -383,64 +239,54 @@
|
||||
"source": [
|
||||
"### Authenticate your Google Cloud account\n",
|
||||
"\n",
|
||||
"**If you are using Vertex AI Workbench Notebooks**, your environment is already\n",
|
||||
"authenticated. \n",
|
||||
"Depending on your Jupyter environment, you may have to manually authenticate. Follow the relevant instructions below.\n",
|
||||
"\n",
|
||||
"**If you are using Colab**, run the cell below and follow the instructions\n",
|
||||
"when prompted to authenticate your account via oAuth.\n",
|
||||
"**1. Vertex AI Workbench**\n",
|
||||
"* Do nothing as you are already authenticated.\n",
|
||||
"\n",
|
||||
"**Otherwise**, follow these steps:\n",
|
||||
"\n",
|
||||
"1. In the Cloud Console, go to the [**Create service account key**\n",
|
||||
" page](https://console.cloud.google.com/apis/credentials/serviceaccountkey).\n",
|
||||
"\n",
|
||||
"2. Click **Create service account**.\n",
|
||||
"\n",
|
||||
"3. In the **Service account name** field, enter a name, and\n",
|
||||
" click **Create**.\n",
|
||||
"\n",
|
||||
"4. In the **Grant this service account access to project** section, click the **Role** drop-down list. Type \"Vertex AI\"\n",
|
||||
"into the filter box, and select\n",
|
||||
" **Vertex AI Administrator**. Type \"Storage Object Admin\" into the filter box, and select **Storage Object Admin**.\n",
|
||||
"\n",
|
||||
"5. Click *Create*. A JSON file that contains your key downloads to your\n",
|
||||
"local environment.\n",
|
||||
"\n",
|
||||
"6. Enter the path to your service account key as the\n",
|
||||
"`GOOGLE_APPLICATION_CREDENTIALS` variable in the cell below and run the cell."
|
||||
"**2. Local JupyterLab instance, uncomment and run:**"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"id": "gcp_authenticate"
|
||||
"id": "ce6043da7b33"
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# If you are running this notebook in Colab, run this cell and follow the\n",
|
||||
"# instructions to authenticate your GCP account. This provides access to your\n",
|
||||
"# Cloud Storage bucket and lets you submit training jobs and prediction\n",
|
||||
"# requests.\n",
|
||||
"\n",
|
||||
"import os\n",
|
||||
"import sys\n",
|
||||
"\n",
|
||||
"# If on Vertex AI Workbench, then don't execute this code\n",
|
||||
"IS_COLAB = \"google.colab\" in sys.modules\n",
|
||||
"if not os.path.exists(\"/opt/deeplearning/metadata/env_version\") and not os.getenv(\n",
|
||||
" \"DL_ANACONDA_HOME\"\n",
|
||||
"):\n",
|
||||
" if \"google.colab\" in sys.modules:\n",
|
||||
" from google.colab import auth as google_auth\n",
|
||||
"\n",
|
||||
" google_auth.authenticate_user()\n",
|
||||
"\n",
|
||||
" # If you are running this notebook locally, replace the string below with the\n",
|
||||
" # path to your service account key and run this cell to authenticate your GCP\n",
|
||||
" # account.\n",
|
||||
" elif not os.getenv(\"IS_TESTING\"):\n",
|
||||
" %env GOOGLE_APPLICATION_CREDENTIALS ''"
|
||||
"# ! gcloud auth login"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "0367eac06a10"
|
||||
},
|
||||
"source": [
|
||||
"**3. Colab, uncomment and run:**"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"id": "21ad4dbb4a61"
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# from google.colab import auth\n",
|
||||
"# auth.authenticate_user()"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "c13224697bfb"
|
||||
},
|
||||
"source": [
|
||||
"**4. Service account or other**\n",
|
||||
"* See how to grant Cloud Storage permissions to your service account at https://cloud.google.com/storage/docs/gsutil/commands/iam#ch-examples."
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -451,11 +297,7 @@
|
||||
"source": [
|
||||
"### Create a Cloud Storage bucket\n",
|
||||
"\n",
|
||||
"**The following steps are required, regardless of your notebook environment.**\n",
|
||||
"\n",
|
||||
"When you run a Vertex AI pipeline job using the Cloud SDK, your job stores the pipeline artifacts to a Cloud Storage bucket. In this tutorial, you create a Vertex AI Pipeline job that saves the artifacts like evaluation metrics and feature attributes to a Cloud Storage bucket.\n",
|
||||
"\n",
|
||||
"Set the name of your Cloud Storage bucket below. It must be unique across all Cloud Storage buckets."
|
||||
"Create a storage bucket to store intermediate artifacts such as datasets."
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -466,27 +308,13 @@
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"BUCKET_NAME = \"[your-bucket-name]\" # @param {type:\"string\"}\n",
|
||||
"BUCKET_URI = f\"gs://{BUCKET_NAME}\""
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"id": "autoset_bucket"
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"if BUCKET_NAME == \"\" or BUCKET_NAME is None or BUCKET_NAME == \"[your-bucket-name]\":\n",
|
||||
" BUCKET_NAME = PROJECT_ID + \"aip-\" + UUID\n",
|
||||
" BUCKET_URI = f\"gs://{BUCKET_NAME}\""
|
||||
"BUCKET_URI = f\"gs://your-bucket-name-{PROJECT_ID}-unique\" # @param {type:\"string\"}"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "create_bucket"
|
||||
"id": "autoset_bucket"
|
||||
},
|
||||
"source": [
|
||||
"**Only if your bucket doesn't already exist**: Run the following cell to create your Cloud Storage bucket."
|
||||
@@ -496,33 +324,13 @@
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"id": "create_bucket"
|
||||
"id": "91c46850b49b"
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"! gsutil mb -l $REGION -p $PROJECT_ID $BUCKET_URI"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "validate_bucket"
|
||||
},
|
||||
"source": [
|
||||
"Finally, validate access to your Cloud Storage bucket by examining its contents:"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"id": "validate_bucket"
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"! gsutil ls -al $BUCKET_URI"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
@@ -653,7 +461,7 @@
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"dataset = aiplatform.VideoDataset.create(\n",
|
||||
" display_name=\"Golf Swings\" + \"_\" + UUID,\n",
|
||||
" display_name=\"Golf Swings\",\n",
|
||||
" gcs_source=IMPORT_FILES,\n",
|
||||
" import_schema_uri=aiplatform.schema.dataset.ioformat.video.action_recognition,\n",
|
||||
")\n",
|
||||
@@ -693,7 +501,7 @@
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"job = aiplatform.AutoMLVideoTrainingJob(\n",
|
||||
" display_name=\"golf_\" + UUID,\n",
|
||||
" display_name=\"golf\",\n",
|
||||
" prediction_type=\"action_recognition\",\n",
|
||||
")\n",
|
||||
"\n",
|
||||
@@ -730,7 +538,7 @@
|
||||
"source": [
|
||||
"model = job.run(\n",
|
||||
" dataset=dataset,\n",
|
||||
" model_display_name=\"golf_\" + UUID,\n",
|
||||
" model_display_name=\"golf\",\n",
|
||||
" training_fraction_split=0.8,\n",
|
||||
" test_fraction_split=0.2,\n",
|
||||
")"
|
||||
@@ -876,7 +684,7 @@
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"batch_predict_job = model.batch_predict(\n",
|
||||
" job_display_name=\"golf_\" + UUID,\n",
|
||||
" job_display_name=\"golf\",\n",
|
||||
" gcs_source=gcs_input_uri,\n",
|
||||
" gcs_destination_prefix=BUCKET_URI,\n",
|
||||
" sync=False,\n",
|
||||
|
||||
@@ -0,0 +1,669 @@
|
||||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"id": "ur8xi4C7S06n"
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Copyright 2022 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": "JAPoU8Sm5E6e"
|
||||
},
|
||||
"source": [
|
||||
"# Delete Outdated Experiments in Vertex AI TensorBoard\n",
|
||||
"\n",
|
||||
"<table align=\"left\">\n",
|
||||
"\n",
|
||||
" <td>\n",
|
||||
" <a href=\"https://colab.research.google.com/github/GoogleCloudPlatform/vertex-ai-samples/blob/main/notebooks/official/experiments/delete_outdated_tensorboard_experiments.ipynb\">\n",
|
||||
" <img src=\"https://cloud.google.com/ml-engine/images/colab-logo-32px.png\" alt=\"Colab logo\"> Run in Colab\n",
|
||||
" </a>\n",
|
||||
" </td>\n",
|
||||
" <td>\n",
|
||||
" <a href=\"https://github.com/GoogleCloudPlatform/vertex-ai-samples/blob/main/notebooks/official/experiments/delete_outdated_tensorboard_experiments.ipynb\">\n",
|
||||
" <img src=\"https://cloud.google.com/ml-engine/images/github-logo-32px.png\" alt=\"GitHub logo\">\n",
|
||||
" View on GitHub\n",
|
||||
" </a>\n",
|
||||
" </td>\n",
|
||||
" <td>\n",
|
||||
" <a href=\"https://console.cloud.google.com/vertex-ai/workbench/deploy-notebook?download_url=https://raw.githubusercontent.com/vertex-ai-samples/main/notebooks/official/experiments/delete_outdated_tensorboard_experiments.ipynb\">\n",
|
||||
" <img src=\"https://lh3.googleusercontent.com/UiNooY4LUgW_oTvpsNhPpQzsstV5W8F7rYgxgGBD85cWJoLmrOzhVs_ksK_vgx40SHs7jCqkTkCk=e14-rj-sc0xffffff-h130-w32\" alt=\"Vertex AI logo\">\n",
|
||||
" Open in Vertex AI Workbench\n",
|
||||
" </a>\n",
|
||||
" </td>\n",
|
||||
"</table>"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "24743cf4a1e1"
|
||||
},
|
||||
"source": [
|
||||
"**_NOTE_**: This notebook has been tested in the following environment:\n",
|
||||
"\n",
|
||||
"* Python version = 3.9"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "tvgnzT1CKxrO"
|
||||
},
|
||||
"source": [
|
||||
"## Overview\n",
|
||||
"\n",
|
||||
"Vertex AI will have a new Vertex AI TensorBoard billing model. From August 2023, it will change from monthly `$300/user` to monthly `$10/GB`. In preparation for this change, users need to delete old Vertex AI TensorBoard Experiments to avoid unnecessary storage costs when the pricing change takes place.\n",
|
||||
"\n",
|
||||
"Learn more about [Vertex AI TensorBoard](https://cloud.google.com/vertex-ai/docs/experiments/tensorboard-overview)."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "d975e698c9a4"
|
||||
},
|
||||
"source": [
|
||||
"### Objective\n",
|
||||
"\n",
|
||||
"In this tutorial, you learn how to delete outdated TensorBoard Experiments to avoid unnecessary storage costs.\n",
|
||||
"\n",
|
||||
"This tutorial uses the following Google Cloud ML services and resources:\n",
|
||||
"\n",
|
||||
"- Vertex AI Tensorboard\n",
|
||||
"\n",
|
||||
"The steps performed include:\n",
|
||||
"\n",
|
||||
"- How to delete the TB Experiment with a predefined key-value label pair `<label_key, label_value>`\n",
|
||||
"\n",
|
||||
"- How to delete the TB Experiments created before the `create_time`\n",
|
||||
"\n",
|
||||
"- How to delete the TB Experiments created before the `update_time`"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "08d289fa873f"
|
||||
},
|
||||
"source": [
|
||||
"### Dataset\n",
|
||||
"\n",
|
||||
"No dataset is used."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "aed92deeb4a0"
|
||||
},
|
||||
"source": [
|
||||
"### 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),\n",
|
||||
"and use the [Pricing Calculator](https://cloud.google.com/products/calculator/)\n",
|
||||
"to generate a cost estimate based on your projected usage."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "i7EUnXsZhAGF"
|
||||
},
|
||||
"source": [
|
||||
"## Installation\n",
|
||||
"\n",
|
||||
"Install the following packages required to execute this notebook."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"id": "2b4ef9b72d43"
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Install the packages\n",
|
||||
"import os\n",
|
||||
"\n",
|
||||
"if not os.getenv(\"IS_TESTING\"):\n",
|
||||
" USER = \"--user\"\n",
|
||||
"else:\n",
|
||||
" USER = \"\"\n",
|
||||
"! pip3 install {USER} --upgrade google-cloud-aiplatform"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "58707a750154"
|
||||
},
|
||||
"source": [
|
||||
"### Colab only: Uncomment the following cell to restart the kernel."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"id": "f200f10a1da3"
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Automatically restart kernel after installs so that your environment can access the new packages\n",
|
||||
"# import IPython\n",
|
||||
"\n",
|
||||
"# app = IPython.Application.instance()\n",
|
||||
"# app.kernel.do_shutdown(True)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "BF1j6f9HApxa"
|
||||
},
|
||||
"source": [
|
||||
"## Before you begin\n",
|
||||
"\n",
|
||||
"### Set up your Google Cloud project\n",
|
||||
"\n",
|
||||
"**The following steps are required, regardless of your notebook environment.**\n",
|
||||
"\n",
|
||||
"1. [Select or create a Google Cloud project](https://console.cloud.google.com/cloud-resource-manager). When you first create an account, you get a $300 free credit towards your compute/storage costs.\n",
|
||||
"\n",
|
||||
"2. [Make sure that billing is enabled for your project](https://cloud.google.com/billing/docs/how-to/modify-project).\n",
|
||||
"\n",
|
||||
"3. [Enable the Vertex AI API](https://console.cloud.google.com/flows/enableapi?apiid=aiplatform.googleapis.com).\n",
|
||||
"\n",
|
||||
"4. If you are running this notebook locally, you need to install the [Cloud SDK](https://cloud.google.com/sdk)."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "WReHDGG5g0XY"
|
||||
},
|
||||
"source": [
|
||||
"#### Set your project ID\n",
|
||||
"\n",
|
||||
"**If you don't know your project ID**, try the following:\n",
|
||||
"* Run `gcloud config list`.\n",
|
||||
"* Run `gcloud projects list`.\n",
|
||||
"* See the support page: [Locate the project ID](https://support.google.com/googleapi/answer/7014113)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"id": "oM1iC_MfAts1"
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"PROJECT_ID = \"[your-project-id]\" # @param {type:\"string\"}\n",
|
||||
"\n",
|
||||
"# Set the project id\n",
|
||||
"! gcloud config set project {PROJECT_ID}"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "region"
|
||||
},
|
||||
"source": [
|
||||
"#### Region\n",
|
||||
"\n",
|
||||
"You can also change the `REGION` variable used by Vertex AI. Learn more about [Vertex AI regions](https://cloud.google.com/vertex-ai/docs/general/locations)."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"id": "QAup21nz6LHk"
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"REGION = \"us-central1\" # @param {type: \"string\"}"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "sBCra4QMA2wR"
|
||||
},
|
||||
"source": [
|
||||
"### Authenticate your Google Cloud account\n",
|
||||
"\n",
|
||||
"Depending on your Jupyter environment, you may have to manually authenticate. Follow the relevant instructions below."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "74ccc9e52986"
|
||||
},
|
||||
"source": [
|
||||
"**1. Vertex AI Workbench**\n",
|
||||
"* Do nothing as you are already authenticated."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "de775a3773ba"
|
||||
},
|
||||
"source": [
|
||||
"**2. Local JupyterLab instance, uncomment and run:**"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"id": "254614fa0c46"
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# ! gcloud auth login"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "ef21552ccea8"
|
||||
},
|
||||
"source": [
|
||||
"**3. Colab, uncomment and run:**"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"id": "603adbbf0532"
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# from google.colab import auth\n",
|
||||
"# auth.authenticate_user()"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "f6b2ccc891ed"
|
||||
},
|
||||
"source": [
|
||||
"**4. Service account or other**\n",
|
||||
"* See how to grant permissions to your service account at https://cloud.google.com/marketplace/docs/grant-service-account-access."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "960505627ddf"
|
||||
},
|
||||
"source": [
|
||||
"### Import libraries"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"id": "PyQmSRbKA8r-"
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"from google.cloud import aiplatform"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "NUJOpq7_-nt6"
|
||||
},
|
||||
"source": [
|
||||
"### Define constants\n",
|
||||
"\n",
|
||||
"Define variables you use in this tutorial. In particular, you set\n",
|
||||
"\n",
|
||||
"- `CREATE_TIME_CUT` : delete tensorboard experiments that were created before CREATE_TIME_CUT. For example, `2022-12-31`.\n",
|
||||
"\n",
|
||||
"- `UPDATE_TIME_CUT` : delete tensorboard experiments that were created before UPDATE_TIME_CUT. For example, `2022-12-31`.\n",
|
||||
"\n",
|
||||
"- `DETAILED_LOG` : a booled variable to see Tensorboard deletion progress. If True, it shows progress by experiments. Otherwise, it reports progress per 100 experiments."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"id": "0AkyoMre-qe5"
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"CREATE_TIME_CUT = \"\" # @param {type:\"string\"}\n",
|
||||
"\n",
|
||||
"UPDATE_TIME_CUT = \"\" # @param {type:\"string\"}\n",
|
||||
"\n",
|
||||
"DETAILED_LOG = True # @param {type: \"boolean\"}"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "n68J5KJ4ERbF"
|
||||
},
|
||||
"source": [
|
||||
"### Define Helpers"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"id": "JIXC-tVrETET"
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"def clean_up_by_label(tensorboard_instance, label_key, label_value):\n",
|
||||
" \"\"\"Delete the TB Experiment with the key-value label pair <label_key, label_value>\"\"\"\n",
|
||||
" # List tensorboard experiments\n",
|
||||
" tensorboard_experiments = aiplatform.TensorboardExperiment.list(\n",
|
||||
" tensorboard_name=tensorboard_instance.resource_name\n",
|
||||
" )\n",
|
||||
" # Get the number of tensorboard experiments\n",
|
||||
" num_tensorboard_experiments = len(tensorboard_experiments)\n",
|
||||
" # For each experiment\n",
|
||||
" for i in range(num_tensorboard_experiments):\n",
|
||||
" tensorboard_experiment = tensorboard_experiments[i]\n",
|
||||
" if detailed_log or (i % 100 == 0):\n",
|
||||
" print(\n",
|
||||
" f\">>>checking TB experiment [{i + 1}/{num_tensorboard_experiments}]: {tensorboard_experiment.resource_name}\"\n",
|
||||
" )\n",
|
||||
" # Get experiment labels\n",
|
||||
" labels = tensorboard_experiment.labels\n",
|
||||
" # Filter by label\n",
|
||||
" if label_key in labels and labels[label_key] == label_value:\n",
|
||||
" # Delete experiment\n",
|
||||
" tensorboard_experiment.delete()\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"def clean_up_by_create_time(tensorboard_instance, create_time_cut):\n",
|
||||
" \"\"\"Delete the TB Experiment with the `create_time`\"\"\"\n",
|
||||
" # List tensorboard experiments\n",
|
||||
" tensorboard_experiments = aiplatform.TensorboardExperiment.list(\n",
|
||||
" tensorboard_name=tensorboard_instance.resource_name, order_by=\"create_time\"\n",
|
||||
" )\n",
|
||||
" # Get the number of tensorboard experiments\n",
|
||||
" num_tensorboard_experiments = len(tensorboard_experiments)\n",
|
||||
" # For each experiment\n",
|
||||
" for i in range(num_tensorboard_experiments):\n",
|
||||
" tensorboard_experiment = tensorboard_experiments[i]\n",
|
||||
" if detailed_log or (i % 100 == 0):\n",
|
||||
" print(\n",
|
||||
" f\">>> checking TB experiment [{i + 1}/{num_tensorboard_experiments}]: {tensorboard_experiment.resource_name}\"\n",
|
||||
" )\n",
|
||||
" # Filter by create_time\n",
|
||||
" if str(tensorboard_experiment.create_time) < create_time_cut:\n",
|
||||
" # Delete experiment\n",
|
||||
" tensorboard_experiment.delete()\n",
|
||||
" else:\n",
|
||||
" break\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"def clean_up_by_update_time(tensorboard_instance, update_time_cut):\n",
|
||||
" \"\"\"Delete the TB Experiment with with the `update_time`\"\"\"\n",
|
||||
" # List tensorboard experiments\n",
|
||||
" tensorboard_experiments = aiplatform.TensorboardExperiment.list(\n",
|
||||
" tensorboard_name=tensorboard_instance.resource_name, order_by=\"update_time\"\n",
|
||||
" )\n",
|
||||
" # Get the number of tensorboard experiments\n",
|
||||
" num_tensorboard_experiments = len(tensorboard_experiments)\n",
|
||||
" # For each experiment\n",
|
||||
" for i in range(num_tensorboard_experiments):\n",
|
||||
" tensorboard_experiment = tensorboard_experiments[i]\n",
|
||||
" if detailed_log or (i % 100 == 0):\n",
|
||||
" print(\n",
|
||||
" f\">>> checking TB experiment [{i + 1}/{num_tensorboard_experiments}]: {tensorboard_experiment.resource_name}\"\n",
|
||||
" )\n",
|
||||
" # Filter by update_time\n",
|
||||
" if str(tensorboard_experiment.update_time) < update_time_cut:\n",
|
||||
" tensorboard_experiment.delete()\n",
|
||||
" else:\n",
|
||||
" break"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "UCUOlTLYCT0B"
|
||||
},
|
||||
"source": [
|
||||
"## Delete outdated Vertex AI TensorBoard Experiments"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "EGfFVHhWDjkl"
|
||||
},
|
||||
"source": [
|
||||
"### Initialize Vertex AI SDK for Python\n",
|
||||
"\n",
|
||||
"Initialize the Vertex AI SDK for Python for your project."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"id": "G1l-7Wft3jb6"
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"aiplatform.init(project=PROJECT_ID, location=REGION)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "e4672ef33691"
|
||||
},
|
||||
"source": [
|
||||
"### Set delete outdated TensorBoard experiments \n",
|
||||
"\n",
|
||||
"Initialize a flag variable to start deleting outdated TensorBoard experiments and a flag variable to choose the deleting method. "
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"id": "8cdc326c9823"
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"delete_tb_experiments = False # @param {type: \"boolean\"}\n",
|
||||
"\n",
|
||||
"delete_method = \"\" # @param [\"by_label\", \"by_create_time\", \"by_update_time\"]"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "JjJVARe5V-MG"
|
||||
},
|
||||
"source": [
|
||||
"### Delete an TensorBoard instance\n",
|
||||
"\n",
|
||||
"To delete a Tensorboard instance, you need `TENSORBOARD_INSTANCE` ID which uniquely identifies the Tensorboard instance where you run experiments.\n",
|
||||
"\n",
|
||||
"To get the Tensorboard instance ID, you can either\n",
|
||||
"\n",
|
||||
"- go to the cloud console UI, Vertex AI > Experiments > Tensorboard Instances, or\n",
|
||||
"- use the list command below to list all TensorBoard instances for your project and region.\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"id": "eqM2pIO8_4Y7"
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"tensorboard_instances = aiplatform.Tensorboard.list(project=PROJECT_ID, location=REGION)\n",
|
||||
"print(tensorboard_instances)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "wT_uPArACMPX"
|
||||
},
|
||||
"source": [
|
||||
"Set the tensorboard instance id for which you want to delete experiments."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"id": "hUync8E9CLcm"
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"if delete_tb_experiments:\n",
|
||||
"\n",
|
||||
" TENSORBOARD_INSTANCE_ID = \"\" # @param {type:\"string\"}\n",
|
||||
"\n",
|
||||
" TENSORBOARD_INSTANCE = aiplatform.Tensorboard(\n",
|
||||
" project=PROJECT_ID, location=REGION, tensorboard_name=TENSORBOARD_INSTANCE_ID\n",
|
||||
" )\n",
|
||||
" print(TENSORBOARD_INSTANCE)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "OOp22fxdHqmT"
|
||||
},
|
||||
"source": [
|
||||
"### Delete a TensorBoard Experiment with the key-value label pair\n",
|
||||
"\n",
|
||||
"You delete a TensorBoard experiment using a predefined `label_key` and `label_value`. For example, you may have assigned `delete` label key and `true` label value to indicate all Tensorboard experiments you want to delete.\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"id": "N7KajCsjij1g"
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"LABEL_KEY = \"delete\" # @param {type:\"string\"}\n",
|
||||
"LABEL_VALUE = \"true\" # @param {type:\"string\"}"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"id": "N45samDzWBO2"
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"if delete_tb_experiments and delete_method == \"by_label\":\n",
|
||||
" clean_up_by_label(TENSORBOARD_INSTANCE, LABEL_KEY, LABEL_VALUE)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "XrEVqlgSIL6K"
|
||||
},
|
||||
"source": [
|
||||
"### Delete a TensorBoard Experiment with `create_time`\n",
|
||||
"\n",
|
||||
"You delete a TensorBoard experiment using `create_time` field"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"id": "4_bjNeQ7p87A"
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"if delete_tb_experiments and delete_method == \"by_create_time\":\n",
|
||||
" clean_up_by_create_time(TENSORBOARD_INSTANCE, CREATE_TIME_CUT)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "ZGNlSbIrIP_o"
|
||||
},
|
||||
"source": [
|
||||
"### Delete a TensorBoard Experiment with `update_time`\n",
|
||||
"\n",
|
||||
"You delete a TensorBoard Experiment using a predefined `update_time` field"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"id": "SDyc_a8XwEve"
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"if delete_tb_experiments and delete_method == \"by_update_time\":\n",
|
||||
" clean_up_by_update_time(TENSORBOARD_INSTANCE, UPDATE_TIME_CUT)"
|
||||
]
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"colab": {
|
||||
"name": "delete_outdated_tensorboard_experiments.ipynb",
|
||||
"toc_visible": true
|
||||
},
|
||||
"kernelspec": {
|
||||
"display_name": "Python 3",
|
||||
"name": "python3"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 0
|
||||
}
|
||||
+3
-3
@@ -34,18 +34,18 @@
|
||||
"<table align=\"left\">\n",
|
||||
"\n",
|
||||
" <td>\n",
|
||||
" <a href=\"https://colab.research.google.com/github/GoogleCloudPlatform/vertex-ai-samples/blob/main/notebooks/official/experiments/autologging.ipynb\">\n",
|
||||
" <a href=\"https://colab.research.google.com/github/GoogleCloudPlatform/vertex-ai-samples/blob/main/notebooks/official/experiments/get_started_with_vertex_experiments_autologging.ipynb\">\n",
|
||||
" <img src=\"https://cloud.google.com/ml-engine/images/colab-logo-32px.png\" alt=\"Colab logo\"> Run in Colab\n",
|
||||
" </a>\n",
|
||||
" </td>\n",
|
||||
" <td>\n",
|
||||
" <a href=\"https://github.com/GoogleCloudPlatform/vertex-ai-samples/blob/main/notebooks/official/experiments/autologging.ipynb\">\n",
|
||||
" <a href=\"https://github.com/GoogleCloudPlatform/vertex-ai-samples/blob/main/notebooks/official/experiments/get_started_with_vertex_experiments_autologging.ipynb\">\n",
|
||||
" <img src=\"https://cloud.google.com/ml-engine/images/github-logo-32px.png\" alt=\"GitHub logo\">\n",
|
||||
" View on GitHub\n",
|
||||
" </a>\n",
|
||||
" </td>\n",
|
||||
" <td>\n",
|
||||
" <a href=\"https://console.cloud.google.com/vertex-ai/workbench/deploy-notebook?download_url=https://raw.githubusercontent.com/GoogleCloudPlatform/vertex-ai-samples/main/notebooks/official/experiments/autologging.ipynb\">\n",
|
||||
" <a href=\"https://console.cloud.google.com/vertex-ai/workbench/deploy-notebook?download_url=https://raw.githubusercontent.com/GoogleCloudPlatform/vertex-ai-samples/main/notebooks/official/experiments/get_started_with_vertex_experiments_autologging.ipynb\">\n",
|
||||
" <img src=\"https://lh3.googleusercontent.com/UiNooY4LUgW_oTvpsNhPpQzsstV5W8F7rYgxgGBD85cWJoLmrOzhVs_ksK_vgx40SHs7jCqkTkCk=e14-rj-sc0xffffff-h130-w32\" alt=\"Vertex AI logo\">\n",
|
||||
" Open in Vertex AI Workbench\n",
|
||||
" </a>\n",
|
||||
|
||||
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user