mirror of
https://github.com/GoogleCloudPlatform/vertex-ai-samples.git
synced 2026-09-26 14:42:04 +00:00
Compare commits
364
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
95d442694c | ||
|
|
7d74bc3caa | ||
|
|
b5b65198a6 | ||
|
|
3a5a14f1d8 | ||
|
|
157f8538ed | ||
|
|
532bf04933 | ||
|
|
99547ccb73 | ||
|
|
2e0cd74533 | ||
|
|
b9a9d76e8b | ||
|
|
fb61e0631c | ||
|
|
16c38c8fbf | ||
|
|
8888e8ad7f | ||
|
|
c787a0e99e | ||
|
|
8ea77a7cb0 | ||
|
|
2bb6d6deb2 | ||
|
|
7b235c935a | ||
|
|
3c88e9284c | ||
|
|
e967b02a22 | ||
|
|
aeb87cbc44 | ||
|
|
1f39a8f892 | ||
|
|
d2a6508379 | ||
|
|
39d1646b3c | ||
|
|
4c5ede0130 | ||
|
|
7c8eeeb1d1 | ||
|
|
99929ca018 | ||
|
|
6aadabd967 | ||
|
|
9b5be742c1 | ||
|
|
63d5b5e3bf | ||
|
|
1448645ba4 | ||
|
|
3d19ffb131 | ||
|
|
b6018551a5 | ||
|
|
65fbf0ee0b | ||
|
|
427bd3d5ea | ||
|
|
5f41599745 | ||
|
|
67fbd84832 | ||
|
|
9b427b6a1f | ||
|
|
37d5d5b992 | ||
|
|
287911b681 | ||
|
|
c83387181a | ||
|
|
236d45b87e | ||
|
|
4eb7b3ce39 | ||
|
|
d74554f641 | ||
|
|
3e70c63899 | ||
|
|
4c79ab91e2 | ||
|
|
dd8a7ad325 | ||
|
|
a3bb273e78 | ||
|
|
1ff0872546 | ||
|
|
91144b8476 | ||
|
|
9822bd64a1 | ||
|
|
f14ff50d2b | ||
|
|
fdc30dab67 | ||
|
|
93229f62c9 | ||
|
|
b37f474255 | ||
|
|
344b0dd6d7 | ||
|
|
48b7cdb21d | ||
|
|
cefdc32d5f | ||
|
|
7558411fbc | ||
|
|
1c0487c459 | ||
|
|
6b7bb867ab | ||
|
|
8c7363c2b0 | ||
|
|
2ea22da2bf | ||
|
|
1d96584421 | ||
|
|
06d57da90c | ||
|
|
355105218d | ||
|
|
3090a312c0 | ||
|
|
8c265ee1ef | ||
|
|
fdbfecda04 | ||
|
|
7050730b6a | ||
|
|
4ec962d277 | ||
|
|
3185ca7d48 | ||
|
|
32ac97982c | ||
|
|
1aa94377f5 | ||
|
|
7271fde2d7 | ||
|
|
71431d5520 | ||
|
|
0f58771ecd | ||
|
|
05c5b68db1 | ||
|
|
ee2744a7de | ||
|
|
a32db129ea | ||
|
|
c9aff9a5d9 | ||
|
|
7324b084ee | ||
|
|
095b0bd628 | ||
|
|
7a1b262154 | ||
|
|
ad1a827824 | ||
|
|
1ff7fc70ed | ||
|
|
b45e17efc0 | ||
|
|
98ad1655a7 | ||
|
|
19d56c0fa0 | ||
|
|
a3ee3687da | ||
|
|
ff1b9ad8ef | ||
|
|
64b4f5103c | ||
|
|
a2e8f933dc | ||
|
|
5cb368585c | ||
|
|
db96de8266 | ||
|
|
18440f5c0c | ||
|
|
95d44d0cf5 | ||
|
|
fc2e91d050 | ||
|
|
b8872c1e03 | ||
|
|
b21ec83ba3 | ||
|
|
d42cc4fbc9 | ||
|
|
28ceb8085e | ||
|
|
a460dcbdd8 | ||
|
|
a76ffe0103 | ||
|
|
168c5c2f15 | ||
|
|
d45bbb36df | ||
|
|
a83ee780f1 | ||
|
|
6011ca5127 | ||
|
|
d53ebed734 | ||
|
|
38f29064a0 | ||
|
|
6ccad69a18 | ||
|
|
0ca86220f8 | ||
|
|
25e004b60e | ||
|
|
871288ac1a | ||
|
|
753bb0e120 | ||
|
|
3893b76486 | ||
|
|
ee805e7846 | ||
|
|
eb605b7943 | ||
|
|
6f0cab7bbb | ||
|
|
eb9b6552d8 | ||
|
|
35d71b410e | ||
|
|
b7d98d6f9a | ||
|
|
a421dc1354 | ||
|
|
a4a72c8b22 | ||
|
|
5c403dde3d | ||
|
|
a85753e1b7 | ||
|
|
2f54cf23cc | ||
|
|
ffc7427265 | ||
|
|
0e738b506f | ||
|
|
fdeaaa37fb | ||
|
|
fed7df10ac | ||
|
|
725b2fdd32 | ||
|
|
a70f93fe0a | ||
|
|
d03697cf73 | ||
|
|
191f2a11bc | ||
|
|
1b692bc330 | ||
|
|
edfd7727d3 | ||
|
|
5d32bd8835 | ||
|
|
8b188a11b2 | ||
|
|
83546a8e7b | ||
|
|
c9aa6df17b | ||
|
|
b4955b28a2 | ||
|
|
f33d9eb6d1 | ||
|
|
1bdbb7921a | ||
|
|
7154a722ba | ||
|
|
99d4a8c31a | ||
|
|
f9cedf2850 | ||
|
|
f4f0112a6a | ||
|
|
e441568c38 | ||
|
|
fee8c969e4 | ||
|
|
bdac091e3f | ||
|
|
ff9338ed3c | ||
|
|
1a538fd249 | ||
|
|
4f09c94b5f | ||
|
|
bcf3e6b0f5 | ||
|
|
fbcf783064 | ||
|
|
2f5fe80f34 | ||
|
|
a850f3a88a | ||
|
|
de91feaca1 | ||
|
|
a7fd0734dc | ||
|
|
ce1b167f08 | ||
|
|
65ff3cab60 | ||
|
|
c7ef72f1d3 | ||
|
|
bd58428857 | ||
|
|
a4a6ed848b | ||
|
|
b753bc58d3 | ||
|
|
6279e12eea | ||
|
|
fc0c34c905 | ||
|
|
ef388ecf30 | ||
|
|
bafb2c6f59 | ||
|
|
f2d431c182 | ||
|
|
2e4b6a1b1b | ||
|
|
95cebcbf8f | ||
|
|
08f1b659c5 | ||
|
|
86ba71931d | ||
|
|
d811306fb9 | ||
|
|
4173e6d561 | ||
|
|
499d25055a | ||
|
|
60776de953 | ||
|
|
182ebcf285 | ||
|
|
39359a5b21 | ||
|
|
0d72cfe070 | ||
|
|
64fef140a2 | ||
|
|
015809b948 | ||
|
|
faccdd081f | ||
|
|
3e8a3cf28e | ||
|
|
821bba2776 | ||
|
|
c82bdee299 | ||
|
|
c27381139b | ||
|
|
01236836f2 | ||
|
|
b8380650bd | ||
|
|
69d266cb90 | ||
|
|
530524ac6e | ||
|
|
ba66961fce | ||
|
|
aca7035482 | ||
|
|
3d270cde69 | ||
|
|
9754c265ff | ||
|
|
f5d730c9f1 | ||
|
|
acd42a3a1b | ||
|
|
eb7cf4b6bc | ||
|
|
34b1011ac9 | ||
|
|
239d664990 | ||
|
|
920c771238 | ||
|
|
e7c68ecb78 | ||
|
|
cfeb118d8b | ||
|
|
2c9c8db15c | ||
|
|
6778a2cfbf | ||
|
|
26c5d56e6d | ||
|
|
527fe79f15 | ||
|
|
2a003fa9c3 | ||
|
|
03b9b6026f | ||
|
|
ff8d6a9d56 | ||
|
|
874c881ad6 | ||
|
|
f484429a89 | ||
|
|
7fa2502c09 | ||
|
|
056791fadd | ||
|
|
154be75dce | ||
|
|
ed7e900a02 | ||
|
|
f109fefbfa | ||
|
|
6f9c99d1df | ||
|
|
ed39d78005 | ||
|
|
d6466ab1a6 | ||
|
|
65e310e4e6 | ||
|
|
0e773ba90f | ||
|
|
0747f9efb8 | ||
|
|
53785fb812 | ||
|
|
b85c24dca5 | ||
|
|
ea5c12c22a | ||
|
|
392c1b7361 | ||
|
|
c5980e636e | ||
|
|
8859e9426d | ||
|
|
db7cc9000a | ||
|
|
d1fe50a1d9 | ||
|
|
9e3597692f | ||
|
|
45c8deebe5 | ||
|
|
6705c4e4ee | ||
|
|
b7f06d948a | ||
|
|
7f3c1a9a36 | ||
|
|
2e991c5b9d | ||
|
|
f8ac68ec10 | ||
|
|
a591c39367 | ||
|
|
d938982aae | ||
|
|
1397c9a64a | ||
|
|
da97ec2244 | ||
|
|
c3f1f8239b | ||
|
|
73878dcc01 | ||
|
|
13bad2e6a3 | ||
|
|
0172f2b11b | ||
|
|
1ba0c17555 | ||
|
|
399c961074 | ||
|
|
d44836db9d | ||
|
|
4e236fd553 | ||
|
|
352b1e2710 | ||
|
|
13cc94d3b7 | ||
|
|
632362ed80 | ||
|
|
90b5575b0c | ||
|
|
2d96cc0af1 | ||
|
|
aadc80752b | ||
|
|
e8745a750b | ||
|
|
67b54685be | ||
|
|
738dc1e01c | ||
|
|
3b481a43a9 | ||
|
|
35d0dee5a0 | ||
|
|
90a0bb9b4c | ||
|
|
e59d5462b4 | ||
|
|
f94bf3c7e1 | ||
|
|
dd215b8cf0 | ||
|
|
784c94a72f | ||
|
|
dccfed9743 | ||
|
|
8346855cfe | ||
|
|
64ad5123d0 | ||
|
|
0025e56323 | ||
|
|
8fd9f35aca | ||
|
|
658abd6d5b | ||
|
|
1243f736e2 | ||
|
|
dd0b07163f | ||
|
|
c6b268ba89 | ||
|
|
fd4f7d2641 | ||
|
|
5c513e20c9 | ||
|
|
d78dba7941 | ||
|
|
42fa88547b | ||
|
|
c4cda29095 | ||
|
|
47725449b5 | ||
|
|
2eba462437 | ||
|
|
97a3f4d3dd | ||
|
|
531e567358 | ||
|
|
1f7c7105bb | ||
|
|
b109183d52 | ||
|
|
72ed00fe0f | ||
|
|
e8d9137a50 | ||
|
|
872e98c544 | ||
|
|
0966fc56a4 | ||
|
|
e8d1e58fc6 | ||
|
|
f73ff8a44f | ||
|
|
48c5810bd7 | ||
|
|
9821d8986c | ||
|
|
207d5db3e9 | ||
|
|
9deb05e3e7 | ||
|
|
8dafc25aab | ||
|
|
ef10e7db53 | ||
|
|
cba907ddf8 | ||
|
|
16c3d7fe25 | ||
|
|
60e1f92ef4 | ||
|
|
fb392c6375 | ||
|
|
b4d10bc5aa | ||
|
|
4049250bad | ||
|
|
923db816e1 | ||
|
|
872f1561cd | ||
|
|
8d7832de6e | ||
|
|
f840017cda | ||
|
|
de3f35b8a6 | ||
|
|
b746bc80d4 | ||
|
|
2001604d37 | ||
|
|
faa148f66e | ||
|
|
f184411666 | ||
|
|
bdad774100 | ||
|
|
9abe9a643b | ||
|
|
ab230ca06f | ||
|
|
dcbd3702d2 | ||
|
|
0505d0c04c | ||
|
|
a47e0aacbb | ||
|
|
15912adeaf | ||
|
|
35fdba7e1c | ||
|
|
f403fa9051 | ||
|
|
0d346b136e | ||
|
|
60d71d29cc | ||
|
|
28c872f4b6 | ||
|
|
c637d693b7 | ||
|
|
5c3a216eb7 | ||
|
|
0b7831b0f4 | ||
|
|
6a6f077ae4 | ||
|
|
27f0a4bb63 | ||
|
|
1476453603 | ||
|
|
dbafcb47ea | ||
|
|
f20700f25a | ||
|
|
d1ca1cd7f8 | ||
|
|
9b03fb7f8e | ||
|
|
aac271eacc | ||
|
|
68b53e0d32 | ||
|
|
bf354adfd3 | ||
|
|
55ad5701e4 | ||
|
|
918564dcc7 | ||
|
|
19b3b5da0f | ||
|
|
2bdab9a9b8 | ||
|
|
88e5d5d236 | ||
|
|
79730d191f | ||
|
|
019040e4cb | ||
|
|
4fd3514d6d | ||
|
|
bb17381b03 | ||
|
|
3f06f48282 | ||
|
|
33abd1e427 | ||
|
|
1d9bfe9934 | ||
|
|
fb9defa985 | ||
|
|
824fb689e4 | ||
|
|
c48dd8662b | ||
|
|
f251721d23 | ||
|
|
e949eb128f | ||
|
|
df48e74f59 | ||
|
|
ce9e6ecf62 | ||
|
|
9ab5f4274a | ||
|
|
29e584a422 | ||
|
|
beabb87cff | ||
|
|
e3f6717ff6 | ||
|
|
fd30c4014a | ||
|
|
4be8b0a59a | ||
|
|
aa09d46265 |
@@ -5,6 +5,8 @@ from resource_cleanup_manager import (
|
||||
ModelResourceCleanupManager,
|
||||
EndpointResourceCleanupManager,
|
||||
ResourceCleanupManager,
|
||||
MatchingEngineIndexEndpointResourceCleanupManager,
|
||||
MatchingEngineIndexResourceCleanupManager,
|
||||
)
|
||||
|
||||
rate_limit = RateLimit(max_count=25, per=60, greedy=False)
|
||||
@@ -40,10 +42,12 @@ if is_dry_run:
|
||||
print("Starting cleanup in dry run mode...")
|
||||
|
||||
# List of all cleanup managers
|
||||
managers = [
|
||||
managers: List[ResourceCleanupManager] = [
|
||||
DatasetResourceCleanupManager(),
|
||||
EndpointResourceCleanupManager(),
|
||||
ModelResourceCleanupManager(), # ModelResourceCleanupManager must follow EndpointResourceCleanupManager due to deployed models blocking model deletion.
|
||||
MatchingEngineIndexEndpointResourceCleanupManager(),
|
||||
MatchingEngineIndexResourceCleanupManager(),
|
||||
]
|
||||
|
||||
run_cleanup_managers(managers=managers, is_dry_run=is_dry_run)
|
||||
|
||||
@@ -109,3 +109,11 @@ class EndpointResourceCleanupManager(VertexAIResourceCleanupManager):
|
||||
|
||||
class ModelResourceCleanupManager(VertexAIResourceCleanupManager):
|
||||
vertex_ai_resource = aiplatform.Model
|
||||
|
||||
|
||||
class MatchingEngineIndexResourceCleanupManager(VertexAIResourceCleanupManager):
|
||||
vertex_ai_resource = aiplatform.MatchingEngineIndex
|
||||
|
||||
|
||||
class MatchingEngineIndexEndpointResourceCleanupManager(VertexAIResourceCleanupManager):
|
||||
vertex_ai_resource = aiplatform.MatchingEngineIndexEndpoint
|
||||
|
||||
@@ -17,13 +17,16 @@ import concurrent
|
||||
import dataclasses
|
||||
import datetime
|
||||
import functools
|
||||
import json
|
||||
import git
|
||||
import operator
|
||||
import os
|
||||
import pathlib
|
||||
import re
|
||||
import subprocess
|
||||
import utils
|
||||
from typing import List, Optional
|
||||
from utils import util
|
||||
|
||||
import execute_notebook_helper
|
||||
import execute_notebook_remote
|
||||
@@ -35,6 +38,7 @@ from utils import NotebookProcessors, util
|
||||
|
||||
# A buffer so that workers finish before the orchestrating job
|
||||
WORKER_TIMEOUT_BUFFER_IN_SECONDS: int = 60 * 60
|
||||
PYTHON_VERSION = "3.9" # Set default python version
|
||||
|
||||
|
||||
def format_timedelta(delta: datetime.timedelta) -> str:
|
||||
@@ -66,6 +70,7 @@ class NotebookExecutionResult:
|
||||
log_url: str
|
||||
output_uri: str
|
||||
build_id: str
|
||||
logs_bucket: str
|
||||
error_message: Optional[str]
|
||||
|
||||
@property
|
||||
@@ -97,6 +102,7 @@ def _process_notebook(
|
||||
"VPC_NETWORK": variable_vpc_network,
|
||||
},
|
||||
)
|
||||
unique_strings_preprocessor = NotebookProcessors.UniqueStringsPreprocessor()
|
||||
|
||||
# Use no-execute preprocessor
|
||||
(
|
||||
@@ -105,11 +111,41 @@ def _process_notebook(
|
||||
) = remove_no_execute_cells_preprocessor.preprocess(nb)
|
||||
|
||||
(nb, resources) = update_variables_preprocessor.preprocess(nb, resources)
|
||||
(nb, resources) = unique_strings_preprocessor.preprocess(nb, resources)
|
||||
|
||||
with open(notebook_path, mode="w", encoding="utf-8") as new_file:
|
||||
nbformat.write(nb, new_file)
|
||||
|
||||
|
||||
def _get_notebook_python_version(notebook_path: str) -> str:
|
||||
"""
|
||||
Get the python version for running the notebook if it is specified in
|
||||
the notebook.
|
||||
"""
|
||||
python_version = PYTHON_VERSION
|
||||
|
||||
# Load the notebook
|
||||
file = open(notebook_path)
|
||||
src = file.read()
|
||||
nb_json = json.loads(src)
|
||||
|
||||
# Iterate over the cells in the ipynb
|
||||
for cell in nb_json["cells"]:
|
||||
if cell["cell_type"] == "markdown":
|
||||
markdown = str.join("", cell["source"])
|
||||
|
||||
# Look for the python version specification pattern
|
||||
re_match = re.search(
|
||||
"python version = (\d\.\d)", markdown, flags=re.IGNORECASE
|
||||
)
|
||||
if re_match:
|
||||
# get the version number
|
||||
python_version = re_match.group(1)
|
||||
break
|
||||
|
||||
return python_version
|
||||
|
||||
|
||||
def _create_tag(filepath: str) -> str:
|
||||
tag = os.path.basename(os.path.normpath(filepath))
|
||||
tag = re.sub("[^0-9a-zA-Z_.-]+", "-", tag)
|
||||
@@ -160,6 +196,7 @@ def process_and_execute_notebook(
|
||||
output_uri=notebook_output_uri,
|
||||
log_url="",
|
||||
build_id="",
|
||||
logs_bucket="",
|
||||
error_message=None,
|
||||
)
|
||||
|
||||
@@ -167,6 +204,12 @@ def process_and_execute_notebook(
|
||||
time_start = datetime.datetime.now()
|
||||
operation = None
|
||||
try:
|
||||
# Get the python version for running the notebook if specified
|
||||
notebook_exec_python_version = _get_notebook_python_version(
|
||||
notebook_path=notebook
|
||||
)
|
||||
print(f"Running notebook with python {notebook_exec_python_version}")
|
||||
|
||||
# Pre-process notebook by substituting variable names
|
||||
_process_notebook(
|
||||
notebook_path=notebook,
|
||||
@@ -193,14 +236,16 @@ def process_and_execute_notebook(
|
||||
private_pool_id=private_pool_id,
|
||||
private_pool_region=variable_region,
|
||||
timeout_in_seconds=timeout_in_seconds,
|
||||
python_version=notebook_exec_python_version,
|
||||
)
|
||||
|
||||
operation_metadata = BuildOperationMetadata(mapping=operation.metadata)
|
||||
result.build_id = operation_metadata.build.id
|
||||
result.log_url = operation_metadata.build.log_url
|
||||
result.logs_bucket = operation_metadata.build.logs_bucket
|
||||
|
||||
# Block and wait for the result
|
||||
operation_result = operation.result()
|
||||
operation_result = operation.result(timeout=timeout_in_seconds)
|
||||
|
||||
result.duration = datetime.datetime.now() - time_start
|
||||
result.is_pass = True
|
||||
@@ -339,7 +384,7 @@ def process_and_execute_notebooks(
|
||||
seconds=max(timeout - WORKER_TIMEOUT_BUFFER_IN_SECONDS, 0)
|
||||
)
|
||||
|
||||
if len(notebooks) > 1:
|
||||
if len(notebooks) >= 1:
|
||||
notebook_execution_results: List[NotebookExecutionResult] = []
|
||||
|
||||
print(f"Found {len(notebooks)} modified notebooks: {notebooks}")
|
||||
@@ -404,6 +449,7 @@ def process_and_execute_notebooks(
|
||||
result.log_url,
|
||||
result.output_uri,
|
||||
result.output_uri_web,
|
||||
result.logs_bucket,
|
||||
]
|
||||
for result in results_sorted
|
||||
],
|
||||
@@ -414,10 +460,35 @@ def process_and_execute_notebooks(
|
||||
"log_url",
|
||||
"output_uri",
|
||||
"output_uri_web",
|
||||
"logs_bucket",
|
||||
],
|
||||
)
|
||||
)
|
||||
|
||||
if len(notebooks) == 1:
|
||||
print("=" * 100)
|
||||
print("The notebook execution build log:\n")
|
||||
print("=" * 100)
|
||||
|
||||
build_id = results_sorted[0].build_id
|
||||
logs_bucket_name = (results_sorted[0].logs_bucket).removeprefix("gs://")
|
||||
log_file_name = f"log-{build_id}.txt"
|
||||
|
||||
log_contents = util.download_blob_into_memory(
|
||||
bucket_name=logs_bucket_name,
|
||||
blob_name=log_file_name,
|
||||
download_as_text=True,
|
||||
)
|
||||
|
||||
# Remove extra steps from the log
|
||||
match = re.search("starting Step #4", log_contents, flags=re.IGNORECASE)
|
||||
|
||||
if match is not None:
|
||||
match_index = match.span()[0]
|
||||
print(log_contents[match_index:])
|
||||
else:
|
||||
print(log_contents)
|
||||
|
||||
print("\n=== END RESULTS===\n")
|
||||
|
||||
total_notebook_duration = functools.reduce(
|
||||
@@ -433,25 +504,5 @@ def process_and_execute_notebooks(
|
||||
# Raise error if any notebooks failed
|
||||
if not all([result.is_pass for result in results_sorted]):
|
||||
raise RuntimeError("Notebook failures detected. See logs for details")
|
||||
|
||||
elif len(notebooks) == 1:
|
||||
notebook = notebooks[0]
|
||||
|
||||
# Pre-process notebook by substituting variable names
|
||||
_process_notebook(
|
||||
notebook_path=notebook,
|
||||
variable_project_id=variable_project_id,
|
||||
variable_region=variable_region,
|
||||
variable_service_account=variable_service_account,
|
||||
variable_vpc_network=variable_vpc_network,
|
||||
)
|
||||
|
||||
execute_notebook_helper.execute_notebook(
|
||||
notebook_source=notebook,
|
||||
output_file_or_uri="/".join(
|
||||
[artifacts_bucket, pathlib.Path(notebook).name]
|
||||
),
|
||||
should_log_output=True,
|
||||
)
|
||||
else:
|
||||
print("No notebooks modified in this pull request.")
|
||||
|
||||
@@ -40,6 +40,7 @@ def execute_notebook_remote(
|
||||
private_pool_region: Optional[str],
|
||||
tag: Optional[str],
|
||||
timeout_in_seconds: Optional[int] = None,
|
||||
python_version: Optional[str] = None
|
||||
) -> operation.Operation:
|
||||
"""Create and execute a single notebook on Google Cloud Build"""
|
||||
# Load build steps from YAML
|
||||
@@ -50,8 +51,12 @@ def execute_notebook_remote(
|
||||
"_PYTHON_IMAGE": container_uri,
|
||||
"_NOTEBOOK_GCS_URI": notebook_uri,
|
||||
"_NOTEBOOK_OUTPUT_GCS_URI": notebook_output_uri,
|
||||
"_PYTHON_VERSION" : f"python{python_version}"
|
||||
}
|
||||
|
||||
if python_version is not None:
|
||||
substitutions["_PYTHON_VERSION"] = "python" + python_version
|
||||
|
||||
build = cloudbuild_v1.Build()
|
||||
|
||||
options: Optional[client_options.ClientOptions] = None
|
||||
|
||||
@@ -10,21 +10,21 @@ steps:
|
||||
entrypoint: /bin/sh
|
||||
args:
|
||||
- -c
|
||||
- python3 .cloud-build/CheckPythonVersion.py -q
|
||||
- ${_PYTHON_VERSION} .cloud-build/CheckPythonVersion.py -q
|
||||
# Create a virtual environment
|
||||
- name: ${_PYTHON_IMAGE}
|
||||
entrypoint: /bin/sh
|
||||
args:
|
||||
- -c
|
||||
- python3 -m venv workspace/env
|
||||
- ${_PYTHON_VERSION} -m venv workspace/env
|
||||
# Install Python dependencies
|
||||
- name: ${_PYTHON_IMAGE}
|
||||
entrypoint: /bin/sh
|
||||
args:
|
||||
- -c
|
||||
- . workspace/env/bin/activate &&
|
||||
python3 -m pip -q install -U pip &&
|
||||
python3 -m pip -q install -U -r .cloud-build/requirements.txt
|
||||
python -m pip -q install -U pip &&
|
||||
python -m pip -q install -U -r .cloud-build/requirements.txt
|
||||
# Install Python dependencies and run testing script
|
||||
- name: ${_PYTHON_IMAGE}
|
||||
entrypoint: /bin/sh
|
||||
@@ -32,7 +32,7 @@ steps:
|
||||
- -c
|
||||
- |
|
||||
. workspace/env/bin/activate &&
|
||||
python3 .cloud-build/execute_notebook_cli.py --notebook_source "${_NOTEBOOK_GCS_URI}" --output_file_or_uri "${_NOTEBOOK_OUTPUT_GCS_URI}"
|
||||
python .cloud-build/execute_notebook_cli.py --notebook_source "${_NOTEBOOK_GCS_URI}" --output_file_or_uri "${_NOTEBOOK_OUTPUT_GCS_URI}"
|
||||
env:
|
||||
- 'IS_TESTING=1'
|
||||
timeout: 86400s
|
||||
|
||||
@@ -10,4 +10,5 @@ google-cloud-aiplatform
|
||||
google-cloud-storage
|
||||
google-cloud-build
|
||||
ratemate
|
||||
GitPython
|
||||
GitPython
|
||||
google-api-core<2.11.0
|
||||
@@ -1,5 +1,5 @@
|
||||
notebooks/official/vizier/gapic-vizier-multi-objective-optimization.ipynb
|
||||
notebooks/official/pipelines/lightweight_functions_component_io_kfp.ipynb
|
||||
notebooks/official/ml_metadata/sdk-metric-parameter-tracking-for-locally-trained-models.ipynb
|
||||
notebooks/official/pipelines/metrics_viz_run_compare_kfp.ipynb
|
||||
notebooks/official/matching_engine/sdk_matching_engine_for_indexing.ipynb
|
||||
notebooks/official/custom/custom-tabular-bq-managed-dataset.ipynb
|
||||
.cloud-build/tests/python_version_test.ipynb
|
||||
|
||||
@@ -1 +1 @@
|
||||
notebooks/official/pipelines/metrics_viz_run_compare_kfp.ipynb
|
||||
notebooks/official/custom/custom-tabular-bq-managed-dataset.ipynb
|
||||
|
||||
@@ -0,0 +1,61 @@
|
||||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "57a3d44ed8a8"
|
||||
},
|
||||
"source": [
|
||||
"### Set up your Google Cloud project\n",
|
||||
"\n",
|
||||
"**_NOTE_**: This notebook has been tested in the following environment:\n",
|
||||
"\n",
|
||||
"* Python version = 3.7\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 and Compute Engine API](https://console.cloud.google.com/flows/enableapi?apiid=aiplatform.googleapis.com,compute_component).\n",
|
||||
"\n",
|
||||
"1. If you are running this notebook locally, you will 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."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"id": "c6516f90311b"
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# test if the right python version is being used\n",
|
||||
"import sys\n",
|
||||
"\n",
|
||||
"actual_python_version = f\"{sys.version_info.major}.{sys.version_info.minor}\"\n",
|
||||
"print(f\"Runtime python version: {actual_python_version}\")\n",
|
||||
"\n",
|
||||
"assert actual_python_version == \"3.7\", \"Wrong python version!\""
|
||||
]
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"colab": {
|
||||
"name": "python_version_test.ipynb",
|
||||
"toc_visible": true
|
||||
},
|
||||
"kernelspec": {
|
||||
"display_name": "Python 3",
|
||||
"name": "python3"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 0
|
||||
}
|
||||
@@ -14,6 +14,8 @@
|
||||
# limitations under the License.
|
||||
|
||||
from typing import Dict
|
||||
import random
|
||||
import string
|
||||
|
||||
from nbconvert.preprocessors import Preprocessor
|
||||
|
||||
@@ -63,3 +65,36 @@ class UpdateVariablesPreprocessor(Preprocessor):
|
||||
executable_cells.append(cell)
|
||||
notebook.cells = executable_cells
|
||||
return notebook, resources
|
||||
|
||||
|
||||
# Generate a uuid of a specifed length
|
||||
def generate_uuid(length: int = 8) -> str:
|
||||
return "".join(random.choices(string.ascii_lowercase + string.digits, k=length))
|
||||
|
||||
|
||||
class UniqueStringsPreprocessor(Preprocessor):
|
||||
# A preprocessor that replaces strings that end with "-unique" or "_unique" with a uuid.
|
||||
|
||||
@staticmethod
|
||||
def update_unique_strings(content: str):
|
||||
# Replace strings that end with "-unique" or "_unique" with a uuid.
|
||||
|
||||
unique_id = generate_uuid()
|
||||
return (
|
||||
content.replace('-unique"', f'-{unique_id}"')
|
||||
.replace("-unique'", f'-{unique_id}"')
|
||||
.replace('_unique"', f'_{unique_id}"')
|
||||
.replace("_unique'", f'_{unique_id}"')
|
||||
)
|
||||
|
||||
def preprocess(self, notebook, resources=None):
|
||||
executable_cells = []
|
||||
for cell in notebook.cells:
|
||||
if cell.cell_type == "code":
|
||||
cell.source = self.update_unique_strings(
|
||||
content=cell.source,
|
||||
)
|
||||
|
||||
executable_cells.append(cell)
|
||||
notebook.cells = executable_cells
|
||||
return notebook, resources
|
||||
|
||||
@@ -40,65 +40,3 @@ def get_updated_value(content: str, variable_name: str, variable_value: str) ->
|
||||
content,
|
||||
flags=re.M,
|
||||
)
|
||||
|
||||
|
||||
def test_update_value():
|
||||
new_content = get_updated_value(
|
||||
content='asdf\nPROJECT_ID = "[your-project-id]" #@param {type:"string"} \nasdf',
|
||||
variable_name="PROJECT_ID",
|
||||
variable_value="sample-project",
|
||||
)
|
||||
assert (
|
||||
new_content
|
||||
== 'asdf\nPROJECT_ID = "sample-project" #@param {type:"string"} \nasdf'
|
||||
)
|
||||
|
||||
|
||||
def test_update_value_single_quotes():
|
||||
new_content = get_updated_value(
|
||||
content="PROJECT_ID = '[your-project-id]'",
|
||||
variable_name="PROJECT_ID",
|
||||
variable_value="sample-project",
|
||||
)
|
||||
assert new_content == "PROJECT_ID = 'sample-project'"
|
||||
|
||||
|
||||
def test_update_value_avoidance():
|
||||
new_content = get_updated_value(
|
||||
content="PROJECT_ID = shell_output[0] ",
|
||||
variable_name="PROJECT_ID",
|
||||
variable_value="sample-project",
|
||||
)
|
||||
assert new_content == "PROJECT_ID = shell_output[0] "
|
||||
|
||||
|
||||
def test_region():
|
||||
new_content = get_updated_value(
|
||||
content='REGION = "[your-region]" # @param {type:"string"}',
|
||||
variable_name="REGION",
|
||||
variable_value="us-central1",
|
||||
)
|
||||
assert new_content == 'REGION = "us-central1" # @param {type:"string"}'
|
||||
|
||||
|
||||
def test_region_equal_equals_ignore():
|
||||
# Tests that == is ignored
|
||||
new_content = get_updated_value(
|
||||
content='REGION == "[your-region]" # @param {type:"string"}',
|
||||
variable_name="REGION",
|
||||
variable_value="us-central1",
|
||||
)
|
||||
assert new_content == 'REGION == "[your-region]" # @param {type:"string"}'
|
||||
|
||||
|
||||
def test_service_account():
|
||||
# Tests that == is ignored
|
||||
new_content = get_updated_value(
|
||||
content='SERVICE_ACCOUNT = "[your-service-account]" # @param {type:"string"}',
|
||||
variable_name="SERVICE_ACCOUNT",
|
||||
variable_value="12345-compute@developer.gserviceaccount.com",
|
||||
)
|
||||
assert (
|
||||
new_content
|
||||
== 'SERVICE_ACCOUNT = "12345-compute@developer.gserviceaccount.com" # @param {type:"string"}'
|
||||
)
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
from utils import NotebookProcessors
|
||||
|
||||
|
||||
def test_update_value():
|
||||
# Test that the content was updated
|
||||
preprocessor = NotebookProcessors.UniqueStringsPreprocessor()
|
||||
|
||||
content = 'PROJECT_ID = "your-project-id-unique"'
|
||||
|
||||
new_content = preprocessor.update_unique_strings(content)
|
||||
|
||||
assert new_content != content
|
||||
assert new_content.startswith('PROJECT_ID = "your-project-id-')
|
||||
assert new_content.endswith('"')
|
||||
@@ -0,0 +1,63 @@
|
||||
from utils import UpdateNotebookVariables
|
||||
|
||||
|
||||
def test_update_value():
|
||||
new_content = UpdateNotebookVariables.get_updated_value(
|
||||
content='asdf\nPROJECT_ID = "[your-project-id]" #@param {type:"string"} \nasdf',
|
||||
variable_name="PROJECT_ID",
|
||||
variable_value="sample-project",
|
||||
)
|
||||
assert (
|
||||
new_content
|
||||
== 'asdf\nPROJECT_ID = "sample-project" #@param {type:"string"} \nasdf'
|
||||
)
|
||||
|
||||
|
||||
def test_update_value_single_quotes():
|
||||
new_content = UpdateNotebookVariables.get_updated_value(
|
||||
content="PROJECT_ID = '[your-project-id]'",
|
||||
variable_name="PROJECT_ID",
|
||||
variable_value="sample-project",
|
||||
)
|
||||
assert new_content == "PROJECT_ID = 'sample-project'"
|
||||
|
||||
|
||||
def test_update_value_avoidance():
|
||||
new_content = UpdateNotebookVariables.get_updated_value(
|
||||
content="PROJECT_ID = shell_output[0] ",
|
||||
variable_name="PROJECT_ID",
|
||||
variable_value="sample-project",
|
||||
)
|
||||
assert new_content == "PROJECT_ID = shell_output[0] "
|
||||
|
||||
|
||||
def test_region():
|
||||
new_content = UpdateNotebookVariables.get_updated_value(
|
||||
content='REGION = "[your-region]" # @param {type:"string"}',
|
||||
variable_name="REGION",
|
||||
variable_value="us-central1",
|
||||
)
|
||||
assert new_content == 'REGION = "us-central1" # @param {type:"string"}'
|
||||
|
||||
|
||||
def test_region_equal_equals_ignore():
|
||||
# Tests that == is ignored
|
||||
new_content = UpdateNotebookVariables.get_updated_value(
|
||||
content='REGION == "[your-region]" # @param {type:"string"}',
|
||||
variable_name="REGION",
|
||||
variable_value="us-central1",
|
||||
)
|
||||
assert new_content == 'REGION == "[your-region]" # @param {type:"string"}'
|
||||
|
||||
|
||||
def test_service_account():
|
||||
# Tests that == is ignored
|
||||
new_content = UpdateNotebookVariables.get_updated_value(
|
||||
content='SERVICE_ACCOUNT = "[your-service-account]" # @param {type:"string"}',
|
||||
variable_name="SERVICE_ACCOUNT",
|
||||
variable_value="12345-compute@developer.gserviceaccount.com",
|
||||
)
|
||||
assert (
|
||||
new_content
|
||||
== 'SERVICE_ACCOUNT = "12345-compute@developer.gserviceaccount.com" # @param {type:"string"}'
|
||||
)
|
||||
@@ -3,7 +3,7 @@ import subprocess
|
||||
import tarfile
|
||||
import uuid
|
||||
from datetime import datetime
|
||||
from typing import Optional
|
||||
from typing import Optional, Union
|
||||
|
||||
from google.auth import credentials as auth_credentials
|
||||
from google.cloud import storage
|
||||
@@ -58,3 +58,29 @@ def archive_code_and_upload(staging_bucket: str):
|
||||
print(f"Uploaded source code archive to {source_archived_file_gcs}")
|
||||
|
||||
return source_archived_file_gcs
|
||||
|
||||
|
||||
def download_blob_into_memory(
|
||||
bucket_name: str, blob_name: str, download_as_text: Optional[bool] = False
|
||||
) -> Union[bytes, str]:
|
||||
"""
|
||||
Downloads a blob into memory as byte or as text if
|
||||
download_as_text is set to True.
|
||||
"""
|
||||
|
||||
storage_client = storage.Client()
|
||||
|
||||
bucket = storage_client.bucket(bucket_name)
|
||||
|
||||
# Construct a client side representation of a blob.
|
||||
blob = bucket.blob(blob_name)
|
||||
|
||||
# Download the blob content
|
||||
if download_as_text:
|
||||
contents = blob.download_as_text()
|
||||
else:
|
||||
contents = blob.download_as_bytes()
|
||||
|
||||
print(f"Downloaded storage object {blob_name} from bucket {bucket_name}.")
|
||||
|
||||
return contents
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
# To use this image, run this command with the desired notebook args from the top-level vertex-ai-samples directory:
|
||||
# 1. To lint all changed notebooks:
|
||||
# docker run -v ${PWD}:/setup/app gcr.io/python-docs-samples-tests/notebook_linter:latest
|
||||
# 2. To lint specific notebooks:
|
||||
# docker run -v ${PWD}:/setup/app gcr.io/python-docs-samples-tests/notebook_linter:latest notebooks/1.ipynb notebooks/2.ipynb
|
||||
|
||||
FROM python:3.10
|
||||
|
||||
WORKDIR setup
|
||||
|
||||
COPY ./requirements.txt .
|
||||
COPY ./run_linter.sh .
|
||||
|
||||
# Install dependencies.
|
||||
RUN pip install --upgrade pip
|
||||
RUN pip install -r requirements.txt
|
||||
|
||||
WORKDIR app
|
||||
|
||||
ENTRYPOINT ["/setup/run_linter.sh"]
|
||||
@@ -2,9 +2,9 @@ git+https://github.com/tensorflow/docs
|
||||
ipython
|
||||
jupyter
|
||||
nbconvert
|
||||
black==22.6.0
|
||||
pyupgrade==2.34.0
|
||||
black==22.10.0
|
||||
pyupgrade==2.38.4
|
||||
isort==5.10.1
|
||||
flake8==4.0.1
|
||||
nbqa==1.4.0
|
||||
nbqa==1.5.3
|
||||
|
||||
|
||||
@@ -47,12 +47,22 @@ done
|
||||
|
||||
echo "Test mode: $is_test"
|
||||
|
||||
# Read in user-provided notebooks
|
||||
notebooks=()
|
||||
for arg in "$@"; do
|
||||
if [[ $arg == *.ipynb ]]; then
|
||||
notebooks+=("$arg")
|
||||
fi
|
||||
done
|
||||
|
||||
# Only check notebooks in test folders modified in this pull request.
|
||||
# Note: Use process substitution to persist the data in the array
|
||||
notebooks=()
|
||||
while read -r file || [ -n "$line" ]; do
|
||||
notebooks+=("$file")
|
||||
done < <(git diff --name-only main... | grep '\.ipynb$')
|
||||
if [ ${#notebooks[@]} -eq 0 ]; then
|
||||
echo "Checking for changed notebooked using git"
|
||||
while read -r file || [ -n "$line" ]; do
|
||||
notebooks+=("$file")
|
||||
done < <(git diff --name-only main... | grep '\.ipynb$')
|
||||
fi
|
||||
|
||||
problematic_notebooks=()
|
||||
if [ ${#notebooks[@]} -gt 0 ]; then
|
||||
|
||||
@@ -6,3 +6,6 @@
|
||||
/sklearn_text_classification_from_script_using_vertex_sdk @maxhardt
|
||||
/pluto_on_workbench @wkharold
|
||||
/cpr-examples @samthrasher
|
||||
/Train_tabular_models_with_many_frameworks_and_import_to_Vertex_AI_using_Pipelines @Ark-kun
|
||||
/pipeline_components @Ark-kun
|
||||
/pipeline_components/image_ml_model_training @lakeyk
|
||||
|
||||
+83
@@ -0,0 +1,83 @@
|
||||
name: Train tabular classification logistic regression model using Scikit learn pipeline
|
||||
metadata:
|
||||
annotations:
|
||||
author: Alexey Volkov <alexey.volkov@ark-kun.com>
|
||||
canonical_location: https://raw.githubusercontent.com/Ark-kun/pipeline_components/master/samples/Google_Cloud_Vertex_AI/Train_tabular_classification_logistic_regression_model_using_Scikit_learn_and_import_to_Vertex_AI/pipeline.component.yaml
|
||||
sdk: https://cloud-pipelines.net/pipeline-editor/
|
||||
implementation:
|
||||
graph:
|
||||
tasks:
|
||||
Download from GCS:
|
||||
componentRef:
|
||||
digest: 4175c9ff143cb8cc75d05451c0a0ebdf5a0d6d020816e29f5e9cefbb7d56f241
|
||||
url: https://raw.githubusercontent.com/Ark-kun/pipeline_components/27a5ea25e849c9e8c0cb6ed65518bc3ece259aaf/components/google-cloud/storage/download/workaround_for_buggy_KFPv2_compiler/component.yaml
|
||||
arguments:
|
||||
GCS path: gs://ml-pipeline-dataset/Chicago_taxi_trips/chicago_taxi_trips_2019-01-01_-_2019-02-01_limit=10000.csv
|
||||
annotations:
|
||||
editor.position: '{"x":40,"y":40,"width":180,"height":40}'
|
||||
Select columns using Pandas on CSV data:
|
||||
componentRef:
|
||||
digest: 9b9500f461c1d04f1e48992de9138db14a6800f23649d73048673d5ea6dc56ad
|
||||
url: https://raw.githubusercontent.com/Ark-kun/pipeline_components/8c78aae096806cff3bc331a40566f42f5c3e9d4b/components/pandas/Select_columns/in_CSV_format/component.yaml
|
||||
arguments:
|
||||
table:
|
||||
taskOutput:
|
||||
outputName: Data
|
||||
taskId: Download from GCS
|
||||
column_names: '["tips", "trip_seconds", "trip_miles", "pickup_community_area", "dropoff_community_area", "fare", "tolls", "extras"]'
|
||||
annotations:
|
||||
editor.position: '{"x":40,"y":140,"width":180,"height":54}'
|
||||
Fill all missing values using Pandas on CSV data:
|
||||
componentRef:
|
||||
digest: a1b0c29a4615f2e3652aa5d31b9255fa15700e146627c755f8fc172f82e71af7
|
||||
url: https://raw.githubusercontent.com/Ark-kun/pipeline_components/23405971f5f16a41b16c343129b893c52e4d1d48/components/pandas/Fill_all_missing_values/in_CSV_format/component.yaml
|
||||
arguments:
|
||||
table:
|
||||
taskOutput:
|
||||
outputName: transformed_table
|
||||
taskId: Select columns using Pandas on CSV data
|
||||
type: CSV
|
||||
replacement_value: '0'
|
||||
annotations:
|
||||
editor.position: '{"x":40,"y":250,"width":180,"height":54}'
|
||||
Binarize column using Pandas on CSV data:
|
||||
componentRef:
|
||||
digest: d699afd4d7cae862708717cc160f4394ed0c04e536e9515923ef1e8865f01d44
|
||||
url: https://raw.githubusercontent.com/Ark-kun/pipeline_components/1e2558325f4c708aca75827c8acc13d230ee7e9f/components/pandas/Binarize_column/in_CSV_format/component.yaml
|
||||
arguments:
|
||||
table:
|
||||
taskOutput:
|
||||
outputName: transformed_table
|
||||
taskId: Fill all missing values using Pandas on CSV data
|
||||
type: CSV
|
||||
column_name: tips
|
||||
predicate: '> 0'
|
||||
new_column_name: class
|
||||
annotations:
|
||||
editor.position: '{"x":40,"y":380,"width":180,"height":54}'
|
||||
Train logistic regression model using scikit learn from CSV:
|
||||
componentRef:
|
||||
digest: a864625a822e4b1c8ef6fe4ae1454fd90f15438f70a6712bb4c30e0dda4d35b7
|
||||
url: https://raw.githubusercontent.com/Ark-kun/pipeline_components/cb44b75c9c062fcc40c2b905b2024b4493dbc62b/components/ML_frameworks/Scikit_learn/Train_logistic_regression_model/from_CSV/component.yaml
|
||||
arguments:
|
||||
dataset:
|
||||
taskOutput:
|
||||
outputName: transformed_table
|
||||
taskId: Binarize column using Pandas on CSV data
|
||||
type: CSV
|
||||
label_column_name: class
|
||||
annotations:
|
||||
editor.position: '{"x":40,"y":510,"width":180,"height":70}'
|
||||
Upload Scikit learn pickle model to Google Cloud Vertex AI:
|
||||
componentRef:
|
||||
digest: 81c91c8d7d21ec97e0872f669d68bd89edea87279d703685db54aa94743bebcd
|
||||
url: https://raw.githubusercontent.com/Ark-kun/pipeline_components/c6a8b67d1ada2cc17665c99ff6b410df588bee28/components/google-cloud/Vertex_AI/Models/Upload_Scikit-learn_pickle_model/workaround_for_buggy_KFPv2_compiler/component.yaml
|
||||
arguments:
|
||||
model:
|
||||
taskOutput:
|
||||
outputName: model
|
||||
taskId: Train logistic regression model using scikit learn from CSV
|
||||
type: ScikitLearnPickleModel
|
||||
annotations:
|
||||
editor.position: '{"x":40,"y":660,"width":180,"height":70}'
|
||||
outputValues: {}
|
||||
+73
@@ -0,0 +1,73 @@
|
||||
# python3 -m pip install "kfp<2.0.0" "google-cloud-aiplatform>=1.16.0" --upgrade --quiet
|
||||
from kfp import components
|
||||
|
||||
# %% Loading components
|
||||
download_from_gcs_op = components.load_component_from_url("https://raw.githubusercontent.com/GoogleCloudPlatform/vertex-ai-samples/399405402d95f4a011e2d2e967c96f8508ba5688/community-content/pipeline_components/google-cloud/storage/download/component.yaml")
|
||||
select_columns_using_Pandas_on_CSV_data_op = components.load_component_from_url("https://raw.githubusercontent.com/GoogleCloudPlatform/vertex-ai-samples/399405402d95f4a011e2d2e967c96f8508ba5688/community-content/pipeline_components/pandas/Select_columns/in_CSV_format/component.yaml")
|
||||
fill_all_missing_values_using_Pandas_on_CSV_data_op = components.load_component_from_url("https://raw.githubusercontent.com/GoogleCloudPlatform/vertex-ai-samples/399405402d95f4a011e2d2e967c96f8508ba5688/community-content/pipeline_components/pandas/Fill_all_missing_values/in_CSV_format/component.yaml")
|
||||
binarize_column_using_Pandas_on_CSV_data_op = components.load_component_from_url("https://raw.githubusercontent.com/GoogleCloudPlatform/vertex-ai-samples/399405402d95f4a011e2d2e967c96f8508ba5688/community-content/pipeline_components/pandas/Binarize_column/in_CSV_format/component.yaml")
|
||||
train_logistic_regression_model_using_scikit_learn_from_CSV_op = components.load_component_from_url("https://raw.githubusercontent.com/GoogleCloudPlatform/vertex-ai-samples/1f5cf6e06409b704064b2086c0a705e4e6b4fcde/community-content/pipeline_components/ML_frameworks/Scikit_learn/Train_logistic_regression_model/from_CSV/component.yaml")
|
||||
upload_Scikit_learn_pickle_model_to_Google_Cloud_Vertex_AI_op = components.load_component_from_url("https://raw.githubusercontent.com/GoogleCloudPlatform/vertex-ai-samples/399405402d95f4a011e2d2e967c96f8508ba5688/community-content/pipeline_components/google-cloud/Vertex_AI/Models/Upload_Scikit-learn_pickle_model/component.yaml")
|
||||
deploy_model_to_endpoint_op = components.load_component_from_url("https://raw.githubusercontent.com/GoogleCloudPlatform/vertex-ai-samples/399405402d95f4a011e2d2e967c96f8508ba5688/community-content/pipeline_components/google-cloud/Vertex_AI/Models/Deploy_to_endpoint/component.yaml")
|
||||
|
||||
# %% Pipeline definition
|
||||
def train_tabular_classification_logistic_regression_model_using_Scikit_learn_pipeline():
|
||||
dataset_gcs_uri = "gs://ml-pipeline-dataset/Chicago_taxi_trips/chicago_taxi_trips_2019-01-01_-_2019-02-01_limit=10000.csv"
|
||||
feature_columns = ["trip_seconds", "trip_miles", "pickup_community_area", "dropoff_community_area", "fare", "tolls", "extras"] # Excluded "trip_total"
|
||||
label_column = "tips"
|
||||
# Deploying the model might incur additional costs over time
|
||||
deploy_model = False
|
||||
|
||||
classification_label_column = "class"
|
||||
all_columns = [label_column] + feature_columns
|
||||
|
||||
training_data = download_from_gcs_op(
|
||||
gcs_path=dataset_gcs_uri
|
||||
).outputs["Data"]
|
||||
|
||||
training_data = select_columns_using_Pandas_on_CSV_data_op(
|
||||
table=training_data,
|
||||
column_names=all_columns,
|
||||
).outputs["transformed_table"]
|
||||
|
||||
# Cleaning the NaN values.
|
||||
training_data = fill_all_missing_values_using_Pandas_on_CSV_data_op(
|
||||
table=training_data,
|
||||
replacement_value="0",
|
||||
#replacement_type_name="float",
|
||||
).outputs["transformed_table"]
|
||||
|
||||
classification_training_data = binarize_column_using_Pandas_on_CSV_data_op(
|
||||
table=training_data,
|
||||
column_name=label_column,
|
||||
predicate="> 0",
|
||||
new_column_name=classification_label_column,
|
||||
).outputs["transformed_table"]
|
||||
|
||||
model = train_logistic_regression_model_using_scikit_learn_from_CSV_op(
|
||||
dataset=classification_training_data,
|
||||
label_column_name=classification_label_column,
|
||||
# Optional:
|
||||
#penalty="l2",
|
||||
#solver="lbfgs",
|
||||
#max_iterations=100,
|
||||
#multi_class_mode="auto",
|
||||
#random_seed=0,
|
||||
).outputs["model"]
|
||||
|
||||
vertex_model_name = upload_Scikit_learn_pickle_model_to_Google_Cloud_Vertex_AI_op(
|
||||
model=model,
|
||||
).outputs["model_name"]
|
||||
|
||||
# Deploying the model might incur additional costs over time
|
||||
if deploy_model:
|
||||
sklearn_vertex_endpoint_name = deploy_model_to_endpoint_op(
|
||||
model_name=vertex_model_name,
|
||||
).outputs["endpoint_name"]
|
||||
|
||||
pipeline_func = train_tabular_classification_logistic_regression_model_using_Scikit_learn_pipeline
|
||||
|
||||
# %% Pipeline submission
|
||||
if __name__ == '__main__':
|
||||
from google.cloud import aiplatform
|
||||
aiplatform.PipelineJob.from_pipeline_func(pipeline_func=pipeline_func).submit()
|
||||
+114
@@ -0,0 +1,114 @@
|
||||
name: Train tabular classification model using PyTorch pipeline
|
||||
metadata:
|
||||
annotations:
|
||||
author: Alexey Volkov <alexey.volkov@ark-kun.com>
|
||||
canonical_location: https://raw.githubusercontent.com/Ark-kun/pipeline_components/master/samples/Google_Cloud_Vertex_AI/Train_tabular_classification_model_using_PyTorch_and_import_to_Vertex_AI/pipeline.component.yaml
|
||||
sdk: https://cloud-pipelines.net/pipeline-editor/
|
||||
implementation:
|
||||
graph:
|
||||
tasks:
|
||||
Download from GCS:
|
||||
componentRef:
|
||||
digest: 4175c9ff143cb8cc75d05451c0a0ebdf5a0d6d020816e29f5e9cefbb7d56f241
|
||||
url: https://raw.githubusercontent.com/Ark-kun/pipeline_components/27a5ea25e849c9e8c0cb6ed65518bc3ece259aaf/components/google-cloud/storage/download/workaround_for_buggy_KFPv2_compiler/component.yaml
|
||||
arguments:
|
||||
GCS path: gs://ml-pipeline-dataset/Chicago_taxi_trips/chicago_taxi_trips_2019-01-01_-_2019-02-01_limit=10000.csv
|
||||
annotations:
|
||||
editor.position: '{"x":240,"y":40,"width":180,"height":40}'
|
||||
Select columns using Pandas on CSV data:
|
||||
componentRef:
|
||||
digest: 9b9500f461c1d04f1e48992de9138db14a6800f23649d73048673d5ea6dc56ad
|
||||
url: https://raw.githubusercontent.com/Ark-kun/pipeline_components/8c78aae096806cff3bc331a40566f42f5c3e9d4b/components/pandas/Select_columns/in_CSV_format/component.yaml
|
||||
arguments:
|
||||
table:
|
||||
taskOutput:
|
||||
outputName: Data
|
||||
taskId: Download from GCS
|
||||
column_names: '["tips", "trip_seconds", "trip_miles", "pickup_community_area", "dropoff_community_area", "fare", "tolls", "extras"]'
|
||||
annotations:
|
||||
editor.position: '{"x":240,"y":140,"width":180,"height":54}'
|
||||
Fill all missing values using Pandas on CSV data:
|
||||
componentRef:
|
||||
digest: a1b0c29a4615f2e3652aa5d31b9255fa15700e146627c755f8fc172f82e71af7
|
||||
url: https://raw.githubusercontent.com/Ark-kun/pipeline_components/23405971f5f16a41b16c343129b893c52e4d1d48/components/pandas/Fill_all_missing_values/in_CSV_format/component.yaml
|
||||
arguments:
|
||||
table:
|
||||
taskOutput:
|
||||
outputName: transformed_table
|
||||
taskId: Select columns using Pandas on CSV data
|
||||
type: CSV
|
||||
replacement_value: '0'
|
||||
annotations:
|
||||
editor.position: '{"x":240,"y":250,"width":180,"height":54}'
|
||||
Create fully connected pytorch network:
|
||||
componentRef:
|
||||
digest: d03d8248fd358a0275ec33568ee7dd7dce576cc112b09dfafe2651e4d97e04a9
|
||||
url: https://raw.githubusercontent.com/Ark-kun/pipeline_components/1a2ef3eeb77bc278f33cad0dd29008ea2431e191/components/PyTorch/Create_fully_connected_network/component.yaml
|
||||
arguments:
|
||||
input_size: '7'
|
||||
hidden_layer_sizes: '[10]'
|
||||
activation_name: elu
|
||||
output_activation_name: sigmoid
|
||||
annotations:
|
||||
editor.position: '{"x":40,"y":360,"width":180,"height":54}'
|
||||
Binarize column using Pandas on CSV data:
|
||||
componentRef:
|
||||
digest: d699afd4d7cae862708717cc160f4394ed0c04e536e9515923ef1e8865f01d44
|
||||
url: https://raw.githubusercontent.com/Ark-kun/pipeline_components/1e2558325f4c708aca75827c8acc13d230ee7e9f/components/pandas/Binarize_column/in_CSV_format/component.yaml
|
||||
arguments:
|
||||
table:
|
||||
taskOutput:
|
||||
outputName: transformed_table
|
||||
taskId: Fill all missing values using Pandas on CSV data
|
||||
type: CSV
|
||||
column_name: tips
|
||||
predicate: ' > 0'
|
||||
new_column_name: class
|
||||
annotations:
|
||||
editor.position: '{"x":240,"y":360,"width":180,"height":54}'
|
||||
Train pytorch model from csv:
|
||||
componentRef:
|
||||
digest: 40f3185eb61e9727f41a4e0c05dd3d3b44bd802aa0f378cfc31756560033949a
|
||||
url: https://raw.githubusercontent.com/Ark-kun/pipeline_components/d8c4cf5e6403bc65bcf8d606e6baf87e2528a3dc/components/PyTorch/Train_PyTorch_model/from_CSV/component.yaml
|
||||
arguments:
|
||||
model:
|
||||
taskOutput:
|
||||
outputName: model
|
||||
taskId: Create fully connected pytorch network
|
||||
type: PyTorchScriptModule
|
||||
training_data:
|
||||
taskOutput:
|
||||
outputName: transformed_table
|
||||
taskId: Binarize column using Pandas on CSV data
|
||||
type: CSV
|
||||
label_column_name: class
|
||||
loss_function_name: binary_cross_entropy
|
||||
annotations:
|
||||
editor.position: '{"x":240,"y":490,"width":180,"height":40}'
|
||||
Create PyTorch Model Archive with base handler:
|
||||
componentRef:
|
||||
digest: 8298b5ee1b0f0879f893add4cf352c8dec7cf9e21bb9db134c91a2d046cdb0ec
|
||||
url: https://raw.githubusercontent.com/Ark-kun/pipeline_components/46d51383e6554b7f3ab4fd8cf614d8c2b422fb22/components/PyTorch/Create_PyTorch_Model_Archive/with_base_handler/component.yaml
|
||||
arguments:
|
||||
Model:
|
||||
taskOutput:
|
||||
outputName: trained_model
|
||||
taskId: Train pytorch model from csv
|
||||
type: PyTorchScriptModule
|
||||
Model name: model
|
||||
Model version: '1.0'
|
||||
annotations:
|
||||
editor.position: '{"x":240,"y":590,"width":180,"height":54}'
|
||||
Upload PyTorch model archive to Google Cloud Vertex AI:
|
||||
componentRef:
|
||||
digest: 4450212fae7b9001482aca7eb78b28413c205506eccf08a04e7754a8dfa99004
|
||||
url: https://raw.githubusercontent.com/Ark-kun/pipeline_components/c6a8b67d1ada2cc17665c99ff6b410df588bee28/components/google-cloud/Vertex_AI/Models/Upload_PyTorch_model_archive/workaround_for_buggy_KFPv2_compiler/component.yaml
|
||||
arguments:
|
||||
model_archive:
|
||||
taskOutput:
|
||||
outputName: Model archive
|
||||
taskId: Create PyTorch Model Archive with base handler
|
||||
type: PyTorchModelArchive
|
||||
annotations:
|
||||
editor.position: '{"x":240,"y":720,"width":180,"height":70}'
|
||||
outputValues: {}
|
||||
+95
@@ -0,0 +1,95 @@
|
||||
# python3 -m pip install "kfp<2.0.0" "google-cloud-aiplatform>=1.16.0" --upgrade --quiet
|
||||
from kfp import components
|
||||
|
||||
# %% Loading components
|
||||
download_from_gcs_op = components.load_component_from_url("https://raw.githubusercontent.com/GoogleCloudPlatform/vertex-ai-samples/399405402d95f4a011e2d2e967c96f8508ba5688/community-content/pipeline_components/google-cloud/storage/download/component.yaml")
|
||||
select_columns_using_Pandas_on_CSV_data_op = components.load_component_from_url("https://raw.githubusercontent.com/GoogleCloudPlatform/vertex-ai-samples/399405402d95f4a011e2d2e967c96f8508ba5688/community-content/pipeline_components/pandas/Select_columns/in_CSV_format/component.yaml")
|
||||
fill_all_missing_values_using_Pandas_on_CSV_data_op = components.load_component_from_url("https://raw.githubusercontent.com/GoogleCloudPlatform/vertex-ai-samples/399405402d95f4a011e2d2e967c96f8508ba5688/community-content/pipeline_components/pandas/Fill_all_missing_values/in_CSV_format/component.yaml")
|
||||
binarize_column_using_Pandas_on_CSV_data_op = components.load_component_from_url("https://raw.githubusercontent.com/GoogleCloudPlatform/vertex-ai-samples/399405402d95f4a011e2d2e967c96f8508ba5688/community-content/pipeline_components/pandas/Binarize_column/in_CSV_format/component.yaml")
|
||||
create_fully_connected_pytorch_network_op = components.load_component_from_url("https://raw.githubusercontent.com/GoogleCloudPlatform/vertex-ai-samples/399405402d95f4a011e2d2e967c96f8508ba5688/community-content/pipeline_components/PyTorch/Create_fully_connected_network/component.yaml")
|
||||
train_pytorch_model_from_csv_op = components.load_component_from_url("https://raw.githubusercontent.com/GoogleCloudPlatform/vertex-ai-samples/399405402d95f4a011e2d2e967c96f8508ba5688/community-content/pipeline_components/PyTorch/Train_PyTorch_model/from_CSV/component.yaml")
|
||||
create_pytorch_model_archive_with_base_handler_op = components.load_component_from_url("https://raw.githubusercontent.com/GoogleCloudPlatform/vertex-ai-samples/399405402d95f4a011e2d2e967c96f8508ba5688/community-content/pipeline_components/PyTorch/Create_PyTorch_Model_Archive/with_base_handler/component.yaml")
|
||||
upload_PyTorch_model_archive_to_Google_Cloud_Vertex_AI_op = components.load_component_from_url("https://raw.githubusercontent.com/GoogleCloudPlatform/vertex-ai-samples/399405402d95f4a011e2d2e967c96f8508ba5688/community-content/pipeline_components/google-cloud/Vertex_AI/Models/Upload_PyTorch_model_archive/component.yaml")
|
||||
deploy_model_to_endpoint_op = components.load_component_from_url("https://raw.githubusercontent.com/GoogleCloudPlatform/vertex-ai-samples/399405402d95f4a011e2d2e967c96f8508ba5688/community-content/pipeline_components/google-cloud/Vertex_AI/Models/Deploy_to_endpoint/component.yaml")
|
||||
|
||||
# %% Pipeline definition
|
||||
def train_tabular_classification_model_using_PyTorch_pipeline():
|
||||
dataset_gcs_uri = "gs://ml-pipeline-dataset/Chicago_taxi_trips/chicago_taxi_trips_2019-01-01_-_2019-02-01_limit=10000.csv"
|
||||
feature_columns = ["trip_seconds", "trip_miles", "pickup_community_area", "dropoff_community_area", "fare", "tolls", "extras"] # Excluded "trip_total"
|
||||
label_column = "tips"
|
||||
# Deploying the model might incur additional costs over time
|
||||
deploy_model = False
|
||||
|
||||
classification_label_column = "class"
|
||||
all_columns = [label_column] + feature_columns
|
||||
|
||||
training_data = download_from_gcs_op(
|
||||
gcs_path=dataset_gcs_uri
|
||||
).outputs["Data"]
|
||||
|
||||
training_data = select_columns_using_Pandas_on_CSV_data_op(
|
||||
table=training_data,
|
||||
column_names=all_columns,
|
||||
).outputs["transformed_table"]
|
||||
|
||||
# Cleaning the NaN values.
|
||||
training_data = fill_all_missing_values_using_Pandas_on_CSV_data_op(
|
||||
table=training_data,
|
||||
replacement_value="0",
|
||||
#replacement_type_name="float",
|
||||
).outputs["transformed_table"]
|
||||
|
||||
classification_training_data = binarize_column_using_Pandas_on_CSV_data_op(
|
||||
table=training_data,
|
||||
column_name=label_column,
|
||||
predicate=" > 0",
|
||||
new_column_name=classification_label_column,
|
||||
).outputs["transformed_table"]
|
||||
|
||||
network = create_fully_connected_pytorch_network_op(
|
||||
input_size=len(feature_columns),
|
||||
# Optional:
|
||||
hidden_layer_sizes=[10],
|
||||
activation_name="elu",
|
||||
output_activation_name="sigmoid",
|
||||
# output_size=1,
|
||||
).outputs["model"]
|
||||
|
||||
model = train_pytorch_model_from_csv_op(
|
||||
model=network,
|
||||
training_data=classification_training_data,
|
||||
label_column_name=classification_label_column,
|
||||
loss_function_name="binary_cross_entropy",
|
||||
# Optional:
|
||||
#number_of_epochs=1,
|
||||
#learning_rate=0.1,
|
||||
#optimizer_name="Adadelta",
|
||||
#optimizer_parameters={},
|
||||
#batch_size=32,
|
||||
#batch_log_interval=100,
|
||||
#random_seed=0,
|
||||
).outputs["trained_model"]
|
||||
|
||||
model_archive = create_pytorch_model_archive_with_base_handler_op(
|
||||
model=model,
|
||||
# Optional:
|
||||
# model_name="model",
|
||||
# model_version="1.0",
|
||||
).outputs["Model archive"]
|
||||
|
||||
vertex_model_name = upload_PyTorch_model_archive_to_Google_Cloud_Vertex_AI_op(
|
||||
model_archive=model_archive,
|
||||
).outputs["model_name"]
|
||||
|
||||
# Deploying the model might incur additional costs over time
|
||||
if deploy_model:
|
||||
vertex_endpoint_name = deploy_model_to_endpoint_op(
|
||||
model_name=vertex_model_name,
|
||||
).outputs["endpoint_name"]
|
||||
|
||||
pipeline_func=train_tabular_classification_model_using_PyTorch_pipeline
|
||||
|
||||
# %% Pipeline submission
|
||||
if __name__ == '__main__':
|
||||
from google.cloud import aiplatform
|
||||
aiplatform.PipelineJob.from_pipeline_func(pipeline_func=pipeline_func).submit()
|
||||
+132
@@ -0,0 +1,132 @@
|
||||
name: Train tabular classification model using TensorFlow pipeline
|
||||
metadata:
|
||||
annotations:
|
||||
author: Alexey Volkov <alexey.volkov@ark-kun.com>
|
||||
canonical_location: https://raw.githubusercontent.com/Ark-kun/pipeline_components/master/samples/Google_Cloud_Vertex_AI/Train_tabular_classification_model_using_TensorFlow_and_import_to_Vertex_AI/pipeline.component.yaml
|
||||
sdk: https://cloud-pipelines.net/pipeline-editor/
|
||||
implementation:
|
||||
graph:
|
||||
tasks:
|
||||
Download from GCS:
|
||||
componentRef:
|
||||
digest: 4175c9ff143cb8cc75d05451c0a0ebdf5a0d6d020816e29f5e9cefbb7d56f241
|
||||
url: https://raw.githubusercontent.com/Ark-kun/pipeline_components/27a5ea25e849c9e8c0cb6ed65518bc3ece259aaf/components/google-cloud/storage/download/workaround_for_buggy_KFPv2_compiler/component.yaml
|
||||
arguments:
|
||||
GCS path: gs://ml-pipeline-dataset/Chicago_taxi_trips/chicago_taxi_trips_2019-01-01_-_2019-02-01_limit=10000.csv
|
||||
annotations:
|
||||
editor.position: '{"x":40,"y":40,"width":180,"height":40}'
|
||||
Select columns using Pandas on CSV data:
|
||||
componentRef:
|
||||
digest: 9b9500f461c1d04f1e48992de9138db14a6800f23649d73048673d5ea6dc56ad
|
||||
url: https://raw.githubusercontent.com/Ark-kun/pipeline_components/8c78aae096806cff3bc331a40566f42f5c3e9d4b/components/pandas/Select_columns/in_CSV_format/component.yaml
|
||||
arguments:
|
||||
table:
|
||||
taskOutput:
|
||||
outputName: Data
|
||||
taskId: Download from GCS
|
||||
column_names: '["tips", "trip_seconds", "trip_miles", "pickup_community_area", "dropoff_community_area", "fare", "tolls", "extras"]'
|
||||
annotations:
|
||||
editor.position: '{"x":40,"y":140,"width":180,"height":54}'
|
||||
Fill all missing values using Pandas on CSV data:
|
||||
componentRef:
|
||||
digest: a1b0c29a4615f2e3652aa5d31b9255fa15700e146627c755f8fc172f82e71af7
|
||||
url: https://raw.githubusercontent.com/Ark-kun/pipeline_components/23405971f5f16a41b16c343129b893c52e4d1d48/components/pandas/Fill_all_missing_values/in_CSV_format/component.yaml
|
||||
arguments:
|
||||
table:
|
||||
taskOutput:
|
||||
outputName: transformed_table
|
||||
taskId: Select columns using Pandas on CSV data
|
||||
type: CSV
|
||||
replacement_value: '0'
|
||||
annotations:
|
||||
editor.position: '{"x":40,"y":250,"width":180,"height":54}'
|
||||
Binarize column using Pandas on CSV data:
|
||||
componentRef:
|
||||
digest: d699afd4d7cae862708717cc160f4394ed0c04e536e9515923ef1e8865f01d44
|
||||
url: https://raw.githubusercontent.com/Ark-kun/pipeline_components/1e2558325f4c708aca75827c8acc13d230ee7e9f/components/pandas/Binarize_column/in_CSV_format/component.yaml
|
||||
arguments:
|
||||
table:
|
||||
taskOutput:
|
||||
outputName: transformed_table
|
||||
taskId: Fill all missing values using Pandas on CSV data
|
||||
type: CSV
|
||||
column_name: tips
|
||||
predicate: ' > 0'
|
||||
new_column_name: class
|
||||
annotations:
|
||||
editor.position: '{"x":40,"y":370,"width":180,"height":54}'
|
||||
Split rows into subsets:
|
||||
componentRef:
|
||||
digest: a609c3c9196484290f24a1174955f95b27f07a7b458aa5cb8cde28866cb2cb46
|
||||
url: https://raw.githubusercontent.com/Ark-kun/pipeline_components/daae5a4abaa35e44501818b1534ed7827d7da073/components/dataset_manipulation/Split_rows_into_subsets/in_CSV/component.yaml
|
||||
arguments:
|
||||
table:
|
||||
taskOutput:
|
||||
outputName: transformed_table
|
||||
taskId: Binarize column using Pandas on CSV data
|
||||
type: CSV
|
||||
fraction_1: '0.8'
|
||||
annotations:
|
||||
editor.position: '{"x":170,"y":500,"width":180,"height":40}'
|
||||
Create fully connected tensorflow network:
|
||||
componentRef:
|
||||
digest: bfcafbc5ce711b1f69cabf1338212d10d50136a73db9f9f7c984de7b80b4bfb0
|
||||
url: https://raw.githubusercontent.com/Ark-kun/pipeline_components/9ca0f9eecf5f896f65b8538bbd809747052617d1/components/tensorflow/Create_fully_connected_network/component.yaml
|
||||
arguments:
|
||||
input_size: '7'
|
||||
hidden_layer_sizes: '[10]'
|
||||
activation_name: elu
|
||||
output_activation_name: sigmoid
|
||||
annotations:
|
||||
editor.position: '{"x":370,"y":500,"width":180,"height":54}'
|
||||
Train model using Keras on CSV:
|
||||
componentRef:
|
||||
digest: 42ae60c889034dbad74815653e95b4f7d576b5f47f803173e8679c7b54984609
|
||||
url: https://raw.githubusercontent.com/Ark-kun/pipeline_components/c504a4010348c50eaaf6d4337586ccc008f4dcef/components/tensorflow/Train_model_using_Keras/on_CSV/component.yaml
|
||||
arguments:
|
||||
training_data:
|
||||
taskOutput:
|
||||
outputName: split_1
|
||||
taskId: Split rows into subsets
|
||||
type: CSV
|
||||
model:
|
||||
taskOutput:
|
||||
outputName: model
|
||||
taskId: Create fully connected tensorflow network
|
||||
type: TensorflowSavedModel
|
||||
label_column_name: class
|
||||
loss_function_name: binary_crossentropy
|
||||
number_of_epochs: '10'
|
||||
annotations:
|
||||
editor.position: '{"x":40,"y":620,"width":180,"height":54}'
|
||||
Upload Tensorflow model to Google Cloud Vertex AI:
|
||||
componentRef:
|
||||
digest: 2e45263ff640b1a688e359b6936e27a81b2407749a84f340af2aa5547e0cb92c
|
||||
url: https://raw.githubusercontent.com/Ark-kun/pipeline_components/c6a8b67d1ada2cc17665c99ff6b410df588bee28/components/google-cloud/Vertex_AI/Models/Upload_Tensorflow_model/workaround_for_buggy_KFPv2_compiler/component.yaml
|
||||
arguments:
|
||||
model:
|
||||
taskOutput:
|
||||
outputName: trained_model
|
||||
taskId: Train model using Keras on CSV
|
||||
type: TensorflowSavedModel
|
||||
annotations:
|
||||
editor.position: '{"x":40,"y":750,"width":180,"height":54}'
|
||||
Predict with TensorFlow model on CSV data:
|
||||
componentRef:
|
||||
digest: 921bb1563e93a78233b8acceab87055b9154ccf5595d056028cf0396ca224cd4
|
||||
url: https://raw.githubusercontent.com/Ark-kun/pipeline_components/59c759ce6f543184e30db6817d2a703879bc0f39/components/tensorflow/Predict/on_CSV/component.yaml
|
||||
arguments:
|
||||
dataset:
|
||||
taskOutput:
|
||||
outputName: split_2
|
||||
taskId: Split rows into subsets
|
||||
type: CSV
|
||||
model:
|
||||
taskOutput:
|
||||
outputName: trained_model
|
||||
taskId: Train model using Keras on CSV
|
||||
type: TensorflowSavedModel
|
||||
label_column_name: class
|
||||
annotations:
|
||||
editor.position: '{"x":240,"y":750,"width":180,"height":54}'
|
||||
outputValues: {}
|
||||
+106
@@ -0,0 +1,106 @@
|
||||
# python3 -m pip install "kfp<2.0.0" "google-cloud-aiplatform>=1.16.0" --upgrade --quiet
|
||||
from kfp import components
|
||||
|
||||
# %% Loading components
|
||||
download_from_gcs_op = components.load_component_from_url("https://raw.githubusercontent.com/GoogleCloudPlatform/vertex-ai-samples/399405402d95f4a011e2d2e967c96f8508ba5688/community-content/pipeline_components/google-cloud/storage/download/component.yaml")
|
||||
select_columns_using_Pandas_on_CSV_data_op = components.load_component_from_url("https://raw.githubusercontent.com/GoogleCloudPlatform/vertex-ai-samples/399405402d95f4a011e2d2e967c96f8508ba5688/community-content/pipeline_components/pandas/Select_columns/in_CSV_format/component.yaml")
|
||||
fill_all_missing_values_using_Pandas_on_CSV_data_op = components.load_component_from_url("https://raw.githubusercontent.com/GoogleCloudPlatform/vertex-ai-samples/399405402d95f4a011e2d2e967c96f8508ba5688/community-content/pipeline_components/pandas/Fill_all_missing_values/in_CSV_format/component.yaml")
|
||||
binarize_column_using_Pandas_on_CSV_data_op = components.load_component_from_url("https://raw.githubusercontent.com/GoogleCloudPlatform/vertex-ai-samples/399405402d95f4a011e2d2e967c96f8508ba5688/community-content/pipeline_components/pandas/Binarize_column/in_CSV_format/component.yaml")
|
||||
split_rows_into_subsets_op = components.load_component_from_url("https://raw.githubusercontent.com/GoogleCloudPlatform/vertex-ai-samples/399405402d95f4a011e2d2e967c96f8508ba5688/community-content/pipeline_components/dataset_manipulation/Split_rows_into_subsets/in_CSV/component.yaml")
|
||||
create_fully_connected_tensorflow_network_op = components.load_component_from_url("https://raw.githubusercontent.com/GoogleCloudPlatform/vertex-ai-samples/399405402d95f4a011e2d2e967c96f8508ba5688/community-content/pipeline_components/tensorflow/Create_fully_connected_network/component.yaml")
|
||||
train_model_using_Keras_on_CSV_op = components.load_component_from_url("https://raw.githubusercontent.com/GoogleCloudPlatform/vertex-ai-samples/399405402d95f4a011e2d2e967c96f8508ba5688/community-content/pipeline_components/tensorflow/Train_model_using_Keras/on_CSV/component.yaml")
|
||||
predict_with_TensorFlow_model_on_CSV_data_op = components.load_component_from_url("https://raw.githubusercontent.com/GoogleCloudPlatform/vertex-ai-samples/399405402d95f4a011e2d2e967c96f8508ba5688/community-content/pipeline_components/tensorflow/Predict/on_CSV/component.yaml")
|
||||
upload_Tensorflow_model_to_Google_Cloud_Vertex_AI_op = components.load_component_from_url("https://raw.githubusercontent.com/GoogleCloudPlatform/vertex-ai-samples/399405402d95f4a011e2d2e967c96f8508ba5688/community-content/pipeline_components/google-cloud/Vertex_AI/Models/Upload_Tensorflow_model/component.yaml")
|
||||
deploy_model_to_endpoint_op = components.load_component_from_url("https://raw.githubusercontent.com/GoogleCloudPlatform/vertex-ai-samples/399405402d95f4a011e2d2e967c96f8508ba5688/community-content/pipeline_components/google-cloud/Vertex_AI/Models/Deploy_to_endpoint/component.yaml")
|
||||
|
||||
# %% Pipeline definition
|
||||
def train_tabular_classification_model_using_TensorFlow_pipeline():
|
||||
dataset_gcs_uri = "gs://ml-pipeline-dataset/Chicago_taxi_trips/chicago_taxi_trips_2019-01-01_-_2019-02-01_limit=10000.csv"
|
||||
feature_columns = ["trip_seconds", "trip_miles", "pickup_community_area", "dropoff_community_area", "fare", "tolls", "extras"] # Excluded "trip_total"
|
||||
label_column = "tips"
|
||||
training_set_fraction = 0.8
|
||||
# Deploying the model might incur additional costs over time
|
||||
deploy_model = False
|
||||
|
||||
classification_label_column = "class"
|
||||
all_columns = [label_column] + feature_columns
|
||||
|
||||
dataset = download_from_gcs_op(
|
||||
gcs_path=dataset_gcs_uri
|
||||
).outputs["Data"]
|
||||
|
||||
dataset = select_columns_using_Pandas_on_CSV_data_op(
|
||||
table=dataset,
|
||||
column_names=all_columns,
|
||||
).outputs["transformed_table"]
|
||||
|
||||
dataset = fill_all_missing_values_using_Pandas_on_CSV_data_op(
|
||||
table=dataset,
|
||||
replacement_value="0",
|
||||
# # Optional:
|
||||
# column_names=None, # =[...]
|
||||
).outputs["transformed_table"]
|
||||
|
||||
classification_dataset = binarize_column_using_Pandas_on_CSV_data_op(
|
||||
table=dataset,
|
||||
column_name=label_column,
|
||||
predicate=" > 0",
|
||||
new_column_name=classification_label_column,
|
||||
).outputs["transformed_table"]
|
||||
|
||||
split_task = split_rows_into_subsets_op(
|
||||
table=classification_dataset,
|
||||
fraction_1=training_set_fraction,
|
||||
)
|
||||
classification_training_data = split_task.outputs["split_1"]
|
||||
classification_testing_data = split_task.outputs["split_2"]
|
||||
|
||||
network = create_fully_connected_tensorflow_network_op(
|
||||
input_size=len(feature_columns),
|
||||
# Optional:
|
||||
hidden_layer_sizes=[10],
|
||||
activation_name="elu",
|
||||
output_activation_name="sigmoid",
|
||||
# output_size=1,
|
||||
).outputs["model"]
|
||||
|
||||
model = train_model_using_Keras_on_CSV_op(
|
||||
training_data=classification_training_data,
|
||||
model=network,
|
||||
label_column_name=classification_label_column,
|
||||
# Optional:
|
||||
loss_function_name="binary_crossentropy",
|
||||
number_of_epochs=10,
|
||||
#learning_rate=0.1,
|
||||
#optimizer_name="Adadelta",
|
||||
#optimizer_parameters={},
|
||||
#batch_size=32,
|
||||
#metric_names=["mean_absolute_error"],
|
||||
#random_seed=0,
|
||||
).outputs["trained_model"]
|
||||
|
||||
predictions = predict_with_TensorFlow_model_on_CSV_data_op(
|
||||
dataset=classification_testing_data,
|
||||
model=model,
|
||||
# label_column_name needs to be set when doing prediction on a dataset that has labels
|
||||
label_column_name=classification_label_column,
|
||||
# Optional:
|
||||
# batch_size=1000,
|
||||
).outputs["predictions"]
|
||||
|
||||
vertex_model_name = upload_Tensorflow_model_to_Google_Cloud_Vertex_AI_op(
|
||||
model=model,
|
||||
).outputs["model_name"]
|
||||
|
||||
# Deploying the model might incur additional costs over time
|
||||
if deploy_model:
|
||||
vertex_endpoint_name = deploy_model_to_endpoint_op(
|
||||
model_name=vertex_model_name,
|
||||
).outputs["endpoint_name"]
|
||||
|
||||
pipeline_func = train_tabular_classification_model_using_TensorFlow_pipeline
|
||||
|
||||
# %% Pipeline submission
|
||||
if __name__ == '__main__':
|
||||
from google.cloud import aiplatform
|
||||
aiplatform.PipelineJob.from_pipeline_func(pipeline_func=pipeline_func).submit()
|
||||
+115
@@ -0,0 +1,115 @@
|
||||
name: Train tabular classification model using XGBoost pipeline
|
||||
metadata:
|
||||
annotations:
|
||||
author: Alexey Volkov <alexey.volkov@ark-kun.com>
|
||||
canonical_location: https://raw.githubusercontent.com/Ark-kun/pipeline_components/master/samples/Google_Cloud_Vertex_AI/Train_tabular_classification_model_using_XGBoost_and_import_to_Vertex_AI/pipeline.component.yaml
|
||||
sdk: https://cloud-pipelines.net/pipeline-editor/
|
||||
implementation:
|
||||
graph:
|
||||
tasks:
|
||||
Download from GCS:
|
||||
componentRef:
|
||||
digest: 4175c9ff143cb8cc75d05451c0a0ebdf5a0d6d020816e29f5e9cefbb7d56f241
|
||||
url: https://raw.githubusercontent.com/Ark-kun/pipeline_components/27a5ea25e849c9e8c0cb6ed65518bc3ece259aaf/components/google-cloud/storage/download/workaround_for_buggy_KFPv2_compiler/component.yaml
|
||||
arguments:
|
||||
GCS path: gs://ml-pipeline-dataset/Chicago_taxi_trips/chicago_taxi_trips_2019-01-01_-_2019-02-01_limit=10000.csv
|
||||
annotations:
|
||||
editor.position: '{"x":40,"y":40,"width":180,"height":40}'
|
||||
Select columns using Pandas on CSV data:
|
||||
componentRef:
|
||||
digest: 9b9500f461c1d04f1e48992de9138db14a6800f23649d73048673d5ea6dc56ad
|
||||
url: https://raw.githubusercontent.com/Ark-kun/pipeline_components/8c78aae096806cff3bc331a40566f42f5c3e9d4b/components/pandas/Select_columns/in_CSV_format/component.yaml
|
||||
arguments:
|
||||
table:
|
||||
taskOutput:
|
||||
outputName: Data
|
||||
taskId: Download from GCS
|
||||
column_names: '["tips", "trip_seconds", "trip_miles", "pickup_community_area", "dropoff_community_area", "fare", "tolls", "extras"]'
|
||||
annotations:
|
||||
editor.position: '{"x":40,"y":140,"width":180,"height":54}'
|
||||
Fill all missing values using Pandas on CSV data:
|
||||
componentRef:
|
||||
digest: a1b0c29a4615f2e3652aa5d31b9255fa15700e146627c755f8fc172f82e71af7
|
||||
url: https://raw.githubusercontent.com/Ark-kun/pipeline_components/23405971f5f16a41b16c343129b893c52e4d1d48/components/pandas/Fill_all_missing_values/in_CSV_format/component.yaml
|
||||
arguments:
|
||||
table:
|
||||
taskOutput:
|
||||
outputName: transformed_table
|
||||
taskId: Select columns using Pandas on CSV data
|
||||
type: CSV
|
||||
replacement_value: '0'
|
||||
annotations:
|
||||
editor.position: '{"x":40,"y":250,"width":180,"height":54}'
|
||||
Binarize column using Pandas on CSV data:
|
||||
componentRef:
|
||||
digest: d699afd4d7cae862708717cc160f4394ed0c04e536e9515923ef1e8865f01d44
|
||||
url: https://raw.githubusercontent.com/Ark-kun/pipeline_components/1e2558325f4c708aca75827c8acc13d230ee7e9f/components/pandas/Binarize_column/in_CSV_format/component.yaml
|
||||
arguments:
|
||||
table:
|
||||
taskOutput:
|
||||
outputName: transformed_table
|
||||
taskId: Fill all missing values using Pandas on CSV data
|
||||
type: CSV
|
||||
column_name: tips
|
||||
predicate: '> 0'
|
||||
new_column_name: class
|
||||
annotations:
|
||||
editor.position: '{"x":40,"y":380,"width":180,"height":54}'
|
||||
Split rows into subsets:
|
||||
componentRef:
|
||||
digest: a609c3c9196484290f24a1174955f95b27f07a7b458aa5cb8cde28866cb2cb46
|
||||
url: https://raw.githubusercontent.com/Ark-kun/pipeline_components/daae5a4abaa35e44501818b1534ed7827d7da073/components/dataset_manipulation/Split_rows_into_subsets/in_CSV/component.yaml
|
||||
arguments:
|
||||
table:
|
||||
taskOutput:
|
||||
outputName: transformed_table
|
||||
taskId: Binarize column using Pandas on CSV data
|
||||
type: CSV
|
||||
fraction_1: '0.8'
|
||||
annotations:
|
||||
editor.position: '{"x":170,"y":510,"width":180,"height":40}'
|
||||
Train XGBoost model on CSV:
|
||||
componentRef:
|
||||
digest: 538c5a01eb38deaf532d619f0bbeaff4efc550fe1f0f776fc06791097b68ceac
|
||||
url: https://raw.githubusercontent.com/Ark-kun/pipeline_components/58d3a47f904f32a64af8403330ba7e2134cae46d/components/XGBoost/Train/component.yaml
|
||||
arguments:
|
||||
training_data:
|
||||
taskOutput:
|
||||
outputName: split_1
|
||||
taskId: Split rows into subsets
|
||||
type: CSV
|
||||
label_column_name: class
|
||||
objective: binary:logistic
|
||||
annotations:
|
||||
editor.position: '{"x":40,"y":630,"width":180,"height":40}'
|
||||
Upload XGBoost model to Google Cloud Vertex AI:
|
||||
componentRef:
|
||||
digest: 5a5a273c403670743820986c03a4175b7cb4595a556524fefcce403656286977
|
||||
url: https://raw.githubusercontent.com/Ark-kun/pipeline_components/c6a8b67d1ada2cc17665c99ff6b410df588bee28/components/google-cloud/Vertex_AI/Models/Upload_XGBoost_model/workaround_for_buggy_KFPv2_compiler/component.yaml
|
||||
arguments:
|
||||
model:
|
||||
taskOutput:
|
||||
outputName: model
|
||||
taskId: Train XGBoost model on CSV
|
||||
type: XGBoostModel
|
||||
annotations:
|
||||
editor.position: '{"x":40,"y":750,"width":180,"height":54}'
|
||||
Xgboost predict on CSV:
|
||||
componentRef:
|
||||
digest: 0876233a0c7306fefec188bd70f059b46d1fb5aa57be231799570e3bbbdd0d95
|
||||
url: https://raw.githubusercontent.com/Ark-kun/pipeline_components/4694ec97baccf59284c2a1db4aa2250c22291eab/components/XGBoost/Predict/component.yaml
|
||||
arguments:
|
||||
data:
|
||||
taskOutput:
|
||||
outputName: split_2
|
||||
taskId: Split rows into subsets
|
||||
type: CSV
|
||||
model:
|
||||
taskOutput:
|
||||
outputName: model
|
||||
taskId: Train XGBoost model on CSV
|
||||
type: XGBoostModel
|
||||
label_column_name: class
|
||||
annotations:
|
||||
editor.position: '{"x":240,"y":750,"width":180,"height":40}'
|
||||
outputValues: {}
|
||||
+94
@@ -0,0 +1,94 @@
|
||||
# python3 -m pip install "kfp<2.0.0" "google-cloud-aiplatform>=1.16.0" --upgrade --quiet
|
||||
from kfp import components
|
||||
|
||||
# %% Loading components
|
||||
download_from_gcs_op = components.load_component_from_url("https://raw.githubusercontent.com/GoogleCloudPlatform/vertex-ai-samples/399405402d95f4a011e2d2e967c96f8508ba5688/community-content/pipeline_components/google-cloud/storage/download/component.yaml")
|
||||
select_columns_using_Pandas_on_CSV_data_op = components.load_component_from_url("https://raw.githubusercontent.com/GoogleCloudPlatform/vertex-ai-samples/399405402d95f4a011e2d2e967c96f8508ba5688/community-content/pipeline_components/pandas/Select_columns/in_CSV_format/component.yaml")
|
||||
fill_all_missing_values_using_Pandas_on_CSV_data_op = components.load_component_from_url("https://raw.githubusercontent.com/GoogleCloudPlatform/vertex-ai-samples/399405402d95f4a011e2d2e967c96f8508ba5688/community-content/pipeline_components/pandas/Fill_all_missing_values/in_CSV_format/component.yaml")
|
||||
binarize_column_using_Pandas_on_CSV_data_op = components.load_component_from_url("https://raw.githubusercontent.com/GoogleCloudPlatform/vertex-ai-samples/399405402d95f4a011e2d2e967c96f8508ba5688/community-content/pipeline_components/pandas/Binarize_column/in_CSV_format/component.yaml")
|
||||
split_rows_into_subsets_op = components.load_component_from_url("https://raw.githubusercontent.com/GoogleCloudPlatform/vertex-ai-samples/399405402d95f4a011e2d2e967c96f8508ba5688/community-content/pipeline_components/dataset_manipulation/Split_rows_into_subsets/in_CSV/component.yaml")
|
||||
train_XGBoost_model_on_CSV_op = components.load_component_from_url("https://raw.githubusercontent.com/GoogleCloudPlatform/vertex-ai-samples/399405402d95f4a011e2d2e967c96f8508ba5688/community-content/pipeline_components/XGBoost/Train/component.yaml")
|
||||
xgboost_predict_on_CSV_op = components.load_component_from_url("https://raw.githubusercontent.com/GoogleCloudPlatform/vertex-ai-samples/399405402d95f4a011e2d2e967c96f8508ba5688/community-content/pipeline_components/XGBoost/Predict/component.yaml")
|
||||
upload_XGBoost_model_to_Google_Cloud_Vertex_AI_op = components.load_component_from_url("https://raw.githubusercontent.com/GoogleCloudPlatform/vertex-ai-samples/399405402d95f4a011e2d2e967c96f8508ba5688/community-content/pipeline_components/google-cloud/Vertex_AI/Models/Upload_XGBoost_model/component.yaml")
|
||||
deploy_model_to_endpoint_op = components.load_component_from_url("https://raw.githubusercontent.com/GoogleCloudPlatform/vertex-ai-samples/399405402d95f4a011e2d2e967c96f8508ba5688/community-content/pipeline_components/google-cloud/Vertex_AI/Models/Deploy_to_endpoint/component.yaml")
|
||||
|
||||
# %% Pipeline definition
|
||||
def train_tabular_classification_model_using_XGBoost_pipeline():
|
||||
dataset_gcs_uri = "gs://ml-pipeline-dataset/Chicago_taxi_trips/chicago_taxi_trips_2019-01-01_-_2019-02-01_limit=10000.csv"
|
||||
feature_columns = ["trip_seconds", "trip_miles", "pickup_community_area", "dropoff_community_area", "fare", "tolls", "extras"] # Excluded "trip_total"
|
||||
label_column = "tips"
|
||||
training_set_fraction = 0.8
|
||||
# Deploying the model might incur additional costs over time
|
||||
deploy_model = False
|
||||
|
||||
classification_label_column = "class"
|
||||
all_columns = [label_column] + feature_columns
|
||||
|
||||
dataset = download_from_gcs_op(
|
||||
gcs_path=dataset_gcs_uri
|
||||
).outputs["Data"]
|
||||
|
||||
dataset = select_columns_using_Pandas_on_CSV_data_op(
|
||||
table=dataset,
|
||||
column_names=all_columns,
|
||||
).outputs["transformed_table"]
|
||||
|
||||
dataset = fill_all_missing_values_using_Pandas_on_CSV_data_op(
|
||||
table=dataset,
|
||||
replacement_value="0",
|
||||
# # Optional:
|
||||
# column_names=None, # =[...]
|
||||
).outputs["transformed_table"]
|
||||
|
||||
classification_dataset = binarize_column_using_Pandas_on_CSV_data_op(
|
||||
table=dataset,
|
||||
column_name=label_column,
|
||||
predicate="> 0",
|
||||
new_column_name=classification_label_column,
|
||||
).outputs["transformed_table"]
|
||||
|
||||
split_task = split_rows_into_subsets_op(
|
||||
table=classification_dataset,
|
||||
fraction_1=training_set_fraction,
|
||||
)
|
||||
classification_training_data = split_task.outputs["split_1"]
|
||||
classification_testing_data = split_task.outputs["split_2"]
|
||||
|
||||
model = train_XGBoost_model_on_CSV_op(
|
||||
training_data=classification_training_data,
|
||||
label_column_name=classification_label_column,
|
||||
objective="binary:logistic",
|
||||
# Optional:
|
||||
#starting_model=None,
|
||||
#num_iterations=10,
|
||||
#booster_params={},
|
||||
#booster="gbtree",
|
||||
#learning_rate=0.3,
|
||||
#min_split_loss=0,
|
||||
#max_depth=6,
|
||||
).outputs["model"]
|
||||
|
||||
# Predicting on the testing data
|
||||
predictions = xgboost_predict_on_CSV_op(
|
||||
data=classification_testing_data,
|
||||
model=model,
|
||||
# label_column needs to be set when doing prediction on a dataset that has labels
|
||||
label_column_name=classification_label_column,
|
||||
).outputs["predictions"]
|
||||
|
||||
vertex_model_name = upload_XGBoost_model_to_Google_Cloud_Vertex_AI_op(
|
||||
model=model,
|
||||
).outputs["model_name"]
|
||||
|
||||
# Deploying the model might incur additional costs over time
|
||||
if deploy_model:
|
||||
vertex_endpoint_name = deploy_model_to_endpoint_op(
|
||||
model_name=vertex_model_name,
|
||||
).outputs["endpoint_name"]
|
||||
|
||||
pipeline_func = train_tabular_classification_model_using_XGBoost_pipeline
|
||||
|
||||
# %% Pipeline submission
|
||||
if __name__ == '__main__':
|
||||
from google.cloud import aiplatform
|
||||
aiplatform.PipelineJob.from_pipeline_func(pipeline_func=pipeline_func).submit()
|
||||
+257
@@ -0,0 +1,257 @@
|
||||
name: Train tabular classification model using all frameworks pipeline
|
||||
metadata:
|
||||
annotations:
|
||||
author: Alexey Volkov <alexey.volkov@ark-kun.com>
|
||||
canonical_location: https://raw.githubusercontent.com/Ark-kun/pipeline_components/master/samples/Google_Cloud_Vertex_AI/Train_tabular_classification_model_using_all_frameworks_and_import_to_Vertex_AI/pipeline.component.yaml
|
||||
sdk: https://cloud-pipelines.net/pipeline-editor/
|
||||
implementation:
|
||||
graph:
|
||||
tasks:
|
||||
Download from GCS:
|
||||
componentRef:
|
||||
digest: 4175c9ff143cb8cc75d05451c0a0ebdf5a0d6d020816e29f5e9cefbb7d56f241
|
||||
url: https://raw.githubusercontent.com/Ark-kun/pipeline_components/27a5ea25e849c9e8c0cb6ed65518bc3ece259aaf/components/google-cloud/storage/download/workaround_for_buggy_KFPv2_compiler/component.yaml
|
||||
arguments:
|
||||
GCS path: gs://ml-pipeline-dataset/Chicago_taxi_trips/chicago_taxi_trips_2019-01-01_-_2019-02-01_limit=10000.csv
|
||||
annotations:
|
||||
editor.position: '{"x":550,"y":40,"width":180,"height":40}'
|
||||
Select columns using Pandas on CSV data:
|
||||
componentRef:
|
||||
digest: 9b9500f461c1d04f1e48992de9138db14a6800f23649d73048673d5ea6dc56ad
|
||||
url: https://raw.githubusercontent.com/Ark-kun/pipeline_components/8c78aae096806cff3bc331a40566f42f5c3e9d4b/components/pandas/Select_columns/in_CSV_format/component.yaml
|
||||
arguments:
|
||||
table:
|
||||
taskOutput:
|
||||
outputName: Data
|
||||
taskId: Download from GCS
|
||||
column_names: '["tips", "trip_seconds", "trip_miles", "pickup_community_area", "dropoff_community_area", "fare", "tolls", "extras"]'
|
||||
annotations:
|
||||
editor.position: '{"x":550,"y":140,"width":180,"height":54}'
|
||||
Fill all missing values using Pandas on CSV data:
|
||||
componentRef:
|
||||
digest: a1b0c29a4615f2e3652aa5d31b9255fa15700e146627c755f8fc172f82e71af7
|
||||
url: https://raw.githubusercontent.com/Ark-kun/pipeline_components/23405971f5f16a41b16c343129b893c52e4d1d48/components/pandas/Fill_all_missing_values/in_CSV_format/component.yaml
|
||||
arguments:
|
||||
table:
|
||||
taskOutput:
|
||||
outputName: transformed_table
|
||||
taskId: Select columns using Pandas on CSV data
|
||||
type: CSV
|
||||
replacement_value: '0'
|
||||
annotations:
|
||||
editor.position: '{"x":550,"y":250,"width":180,"height":54}'
|
||||
Binarize column using Pandas on CSV data:
|
||||
componentRef:
|
||||
digest: d699afd4d7cae862708717cc160f4394ed0c04e536e9515923ef1e8865f01d44
|
||||
url: https://raw.githubusercontent.com/Ark-kun/pipeline_components/1e2558325f4c708aca75827c8acc13d230ee7e9f/components/pandas/Binarize_column/in_CSV_format/component.yaml
|
||||
arguments:
|
||||
table:
|
||||
taskOutput:
|
||||
outputName: transformed_table
|
||||
taskId: Fill all missing values using Pandas on CSV data
|
||||
type: CSV
|
||||
column_name: tips
|
||||
predicate: ' > 0'
|
||||
new_column_name: class
|
||||
annotations:
|
||||
editor.position: '{"x":550,"y":380,"width":180,"height":54}'
|
||||
Split rows into subsets:
|
||||
componentRef:
|
||||
digest: a609c3c9196484290f24a1174955f95b27f07a7b458aa5cb8cde28866cb2cb46
|
||||
url: https://raw.githubusercontent.com/Ark-kun/pipeline_components/daae5a4abaa35e44501818b1534ed7827d7da073/components/dataset_manipulation/Split_rows_into_subsets/in_CSV/component.yaml
|
||||
arguments:
|
||||
table:
|
||||
taskOutput:
|
||||
outputName: transformed_table
|
||||
taskId: Binarize column using Pandas on CSV data
|
||||
type: CSV
|
||||
fraction_1: '0.8'
|
||||
annotations:
|
||||
editor.position: '{"x":550,"y":490,"width":180,"height":40}'
|
||||
Create fully connected pytorch network:
|
||||
componentRef:
|
||||
digest: d03d8248fd358a0275ec33568ee7dd7dce576cc112b09dfafe2651e4d97e04a9
|
||||
url: https://raw.githubusercontent.com/Ark-kun/pipeline_components/1a2ef3eeb77bc278f33cad0dd29008ea2431e191/components/PyTorch/Create_fully_connected_network/component.yaml
|
||||
arguments:
|
||||
input_size: '7'
|
||||
hidden_layer_sizes: '[10]'
|
||||
activation_name: elu
|
||||
output_activation_name: sigmoid
|
||||
annotations:
|
||||
editor.position: '{"x":380,"y":620,"width":180,"height":54}'
|
||||
Create fully connected tensorflow network:
|
||||
componentRef:
|
||||
digest: bfcafbc5ce711b1f69cabf1338212d10d50136a73db9f9f7c984de7b80b4bfb0
|
||||
url: https://raw.githubusercontent.com/Ark-kun/pipeline_components/9ca0f9eecf5f896f65b8538bbd809747052617d1/components/tensorflow/Create_fully_connected_network/component.yaml
|
||||
arguments:
|
||||
input_size: '7'
|
||||
hidden_layer_sizes: '[10]'
|
||||
activation_name: elu
|
||||
output_activation_name: sigmoid
|
||||
annotations:
|
||||
editor.position: '{"x":40,"y":630,"width":180,"height":54}'
|
||||
Train model using Keras on CSV:
|
||||
componentRef:
|
||||
digest: 42ae60c889034dbad74815653e95b4f7d576b5f47f803173e8679c7b54984609
|
||||
url: https://raw.githubusercontent.com/Ark-kun/pipeline_components/c504a4010348c50eaaf6d4337586ccc008f4dcef/components/tensorflow/Train_model_using_Keras/on_CSV/component.yaml
|
||||
arguments:
|
||||
training_data:
|
||||
taskOutput:
|
||||
outputName: split_1
|
||||
taskId: Split rows into subsets
|
||||
type: CSV
|
||||
model:
|
||||
taskOutput:
|
||||
outputName: model
|
||||
taskId: Create fully connected tensorflow network
|
||||
type: TensorflowSavedModel
|
||||
label_column_name: class
|
||||
loss_function_name: binary_crossentropy
|
||||
number_of_epochs: '10'
|
||||
annotations:
|
||||
editor.position: '{"x":40,"y":750,"width":180,"height":54}'
|
||||
Train pytorch model from csv:
|
||||
componentRef:
|
||||
digest: 40f3185eb61e9727f41a4e0c05dd3d3b44bd802aa0f378cfc31756560033949a
|
||||
url: https://raw.githubusercontent.com/Ark-kun/pipeline_components/d8c4cf5e6403bc65bcf8d606e6baf87e2528a3dc/components/PyTorch/Train_PyTorch_model/from_CSV/component.yaml
|
||||
arguments:
|
||||
model:
|
||||
taskOutput:
|
||||
outputName: model
|
||||
taskId: Create fully connected pytorch network
|
||||
type: PyTorchScriptModule
|
||||
training_data:
|
||||
taskOutput:
|
||||
outputName: split_1
|
||||
taskId: Split rows into subsets
|
||||
type: CSV
|
||||
label_column_name: class
|
||||
loss_function_name: binary_cross_entropy
|
||||
annotations:
|
||||
editor.position: '{"x":380,"y":750,"width":180,"height":40}'
|
||||
Train XGBoost model on CSV:
|
||||
componentRef:
|
||||
digest: 538c5a01eb38deaf532d619f0bbeaff4efc550fe1f0f776fc06791097b68ceac
|
||||
url: https://raw.githubusercontent.com/Ark-kun/pipeline_components/58d3a47f904f32a64af8403330ba7e2134cae46d/components/XGBoost/Train/component.yaml
|
||||
arguments:
|
||||
training_data:
|
||||
taskOutput:
|
||||
outputName: split_1
|
||||
taskId: Split rows into subsets
|
||||
type: CSV
|
||||
label_column_name: class
|
||||
objective: binary:logistic
|
||||
annotations:
|
||||
editor.position: '{"x":720,"y":750,"width":180,"height":40}'
|
||||
Train logistic regression model using scikit learn from CSV:
|
||||
componentRef:
|
||||
digest: a864625a822e4b1c8ef6fe4ae1454fd90f15438f70a6712bb4c30e0dda4d35b7
|
||||
url: https://raw.githubusercontent.com/Ark-kun/pipeline_components/cb44b75c9c062fcc40c2b905b2024b4493dbc62b/components/ML_frameworks/Scikit_learn/Train_logistic_regression_model/from_CSV/component.yaml
|
||||
arguments:
|
||||
dataset:
|
||||
taskOutput:
|
||||
outputName: split_1
|
||||
taskId: Split rows into subsets
|
||||
type: CSV
|
||||
label_column_name: class
|
||||
annotations:
|
||||
editor.position: '{"x":1030,"y":750,"width":180,"height":70}'
|
||||
Predict with TensorFlow model on CSV data:
|
||||
componentRef:
|
||||
digest: 921bb1563e93a78233b8acceab87055b9154ccf5595d056028cf0396ca224cd4
|
||||
url: https://raw.githubusercontent.com/Ark-kun/pipeline_components/59c759ce6f543184e30db6817d2a703879bc0f39/components/tensorflow/Predict/on_CSV/component.yaml
|
||||
arguments:
|
||||
dataset:
|
||||
taskOutput:
|
||||
outputName: split_2
|
||||
taskId: Split rows into subsets
|
||||
type: CSV
|
||||
model:
|
||||
taskOutput:
|
||||
outputName: trained_model
|
||||
taskId: Train model using Keras on CSV
|
||||
type: TensorflowSavedModel
|
||||
label_column_name: class
|
||||
annotations:
|
||||
editor.position: '{"x":160,"y":880,"width":180,"height":54}'
|
||||
Create PyTorch Model Archive with base handler:
|
||||
componentRef:
|
||||
digest: 8298b5ee1b0f0879f893add4cf352c8dec7cf9e21bb9db134c91a2d046cdb0ec
|
||||
url: https://raw.githubusercontent.com/Ark-kun/pipeline_components/46d51383e6554b7f3ab4fd8cf614d8c2b422fb22/components/PyTorch/Create_PyTorch_Model_Archive/with_base_handler/component.yaml
|
||||
arguments:
|
||||
Model:
|
||||
taskOutput:
|
||||
outputName: trained_model
|
||||
taskId: Train pytorch model from csv
|
||||
type: PyTorchScriptModule
|
||||
Model name: model
|
||||
Model version: '1.0'
|
||||
annotations:
|
||||
editor.position: '{"x":380,"y":880,"width":180,"height":54}'
|
||||
Xgboost predict on CSV:
|
||||
componentRef:
|
||||
digest: 0876233a0c7306fefec188bd70f059b46d1fb5aa57be231799570e3bbbdd0d95
|
||||
url: https://raw.githubusercontent.com/Ark-kun/pipeline_components/4694ec97baccf59284c2a1db4aa2250c22291eab/components/XGBoost/Predict/component.yaml
|
||||
arguments:
|
||||
data:
|
||||
taskOutput:
|
||||
outputName: split_2
|
||||
taskId: Split rows into subsets
|
||||
type: CSV
|
||||
model:
|
||||
taskOutput:
|
||||
outputName: model
|
||||
taskId: Train XGBoost model on CSV
|
||||
type: XGBoostModel
|
||||
label_column_name: class
|
||||
annotations:
|
||||
editor.position: '{"x":810,"y":880,"width":180,"height":40}'
|
||||
Upload Scikit learn pickle model to Google Cloud Vertex AI:
|
||||
componentRef:
|
||||
digest: 81c91c8d7d21ec97e0872f669d68bd89edea87279d703685db54aa94743bebcd
|
||||
url: https://raw.githubusercontent.com/Ark-kun/pipeline_components/c6a8b67d1ada2cc17665c99ff6b410df588bee28/components/google-cloud/Vertex_AI/Models/Upload_Scikit-learn_pickle_model/workaround_for_buggy_KFPv2_compiler/component.yaml
|
||||
arguments:
|
||||
model:
|
||||
taskOutput:
|
||||
outputName: model
|
||||
taskId: Train logistic regression model using scikit learn from CSV
|
||||
type: ScikitLearnPickleModel
|
||||
annotations:
|
||||
editor.position: '{"x":1030,"y":880,"width":180,"height":70}'
|
||||
Upload Tensorflow model to Google Cloud Vertex AI:
|
||||
componentRef:
|
||||
digest: 2e45263ff640b1a688e359b6936e27a81b2407749a84f340af2aa5547e0cb92c
|
||||
url: https://raw.githubusercontent.com/Ark-kun/pipeline_components/c6a8b67d1ada2cc17665c99ff6b410df588bee28/components/google-cloud/Vertex_AI/Models/Upload_Tensorflow_model/workaround_for_buggy_KFPv2_compiler/component.yaml
|
||||
arguments:
|
||||
model:
|
||||
taskOutput:
|
||||
outputName: trained_model
|
||||
taskId: Train model using Keras on CSV
|
||||
type: TensorflowSavedModel
|
||||
annotations:
|
||||
editor.position: '{"x":40,"y":1010,"width":180,"height":54}'
|
||||
Upload PyTorch model archive to Google Cloud Vertex AI:
|
||||
componentRef:
|
||||
digest: 4450212fae7b9001482aca7eb78b28413c205506eccf08a04e7754a8dfa99004
|
||||
url: https://raw.githubusercontent.com/Ark-kun/pipeline_components/c6a8b67d1ada2cc17665c99ff6b410df588bee28/components/google-cloud/Vertex_AI/Models/Upload_PyTorch_model_archive/workaround_for_buggy_KFPv2_compiler/component.yaml
|
||||
arguments:
|
||||
model_archive:
|
||||
taskOutput:
|
||||
outputName: Model archive
|
||||
taskId: Create PyTorch Model Archive with base handler
|
||||
type: PyTorchModelArchive
|
||||
annotations:
|
||||
editor.position: '{"x":380,"y":1010,"width":180,"height":70}'
|
||||
Upload XGBoost model to Google Cloud Vertex AI:
|
||||
componentRef:
|
||||
digest: 5a5a273c403670743820986c03a4175b7cb4595a556524fefcce403656286977
|
||||
url: https://raw.githubusercontent.com/Ark-kun/pipeline_components/c6a8b67d1ada2cc17665c99ff6b410df588bee28/components/google-cloud/Vertex_AI/Models/Upload_XGBoost_model/workaround_for_buggy_KFPv2_compiler/component.yaml
|
||||
arguments:
|
||||
model:
|
||||
taskOutput:
|
||||
outputName: model
|
||||
taskId: Train XGBoost model on CSV
|
||||
type: XGBoostModel
|
||||
annotations:
|
||||
editor.position: '{"x":720,"y":1010,"width":180,"height":54}'
|
||||
outputValues: {}
|
||||
+224
@@ -0,0 +1,224 @@
|
||||
# python3 -m pip install "kfp<2.0.0" "google-cloud-aiplatform>=1.16.0" --upgrade --quiet
|
||||
from kfp import components
|
||||
|
||||
# %% Loading components
|
||||
download_from_gcs_op = components.load_component_from_url("https://raw.githubusercontent.com/GoogleCloudPlatform/vertex-ai-samples/399405402d95f4a011e2d2e967c96f8508ba5688/community-content/pipeline_components/google-cloud/storage/download/component.yaml")
|
||||
select_columns_using_Pandas_on_CSV_data_op = components.load_component_from_url("https://raw.githubusercontent.com/GoogleCloudPlatform/vertex-ai-samples/399405402d95f4a011e2d2e967c96f8508ba5688/community-content/pipeline_components/pandas/Select_columns/in_CSV_format/component.yaml")
|
||||
fill_all_missing_values_using_Pandas_on_CSV_data_op = components.load_component_from_url("https://raw.githubusercontent.com/GoogleCloudPlatform/vertex-ai-samples/399405402d95f4a011e2d2e967c96f8508ba5688/community-content/pipeline_components/pandas/Fill_all_missing_values/in_CSV_format/component.yaml")
|
||||
binarize_column_using_Pandas_on_CSV_data_op = components.load_component_from_url("https://raw.githubusercontent.com/GoogleCloudPlatform/vertex-ai-samples/399405402d95f4a011e2d2e967c96f8508ba5688/community-content/pipeline_components/pandas/Binarize_column/in_CSV_format/component.yaml")
|
||||
split_rows_into_subsets_op = components.load_component_from_url("https://raw.githubusercontent.com/GoogleCloudPlatform/vertex-ai-samples/399405402d95f4a011e2d2e967c96f8508ba5688/community-content/pipeline_components/dataset_manipulation/Split_rows_into_subsets/in_CSV/component.yaml")
|
||||
|
||||
# TensorFlow
|
||||
create_fully_connected_tensorflow_network_op = components.load_component_from_url("https://raw.githubusercontent.com/GoogleCloudPlatform/vertex-ai-samples/399405402d95f4a011e2d2e967c96f8508ba5688/community-content/pipeline_components/tensorflow/Create_fully_connected_network/component.yaml")
|
||||
train_model_using_Keras_on_CSV_op = components.load_component_from_url("https://raw.githubusercontent.com/GoogleCloudPlatform/vertex-ai-samples/399405402d95f4a011e2d2e967c96f8508ba5688/community-content/pipeline_components/tensorflow/Train_model_using_Keras/on_CSV/component.yaml")
|
||||
predict_with_TensorFlow_model_on_CSV_data_op = components.load_component_from_url("https://raw.githubusercontent.com/GoogleCloudPlatform/vertex-ai-samples/399405402d95f4a011e2d2e967c96f8508ba5688/community-content/pipeline_components/tensorflow/Predict/on_CSV/component.yaml")
|
||||
upload_Tensorflow_model_to_Google_Cloud_Vertex_AI_op = components.load_component_from_url("https://raw.githubusercontent.com/GoogleCloudPlatform/vertex-ai-samples/399405402d95f4a011e2d2e967c96f8508ba5688/community-content/pipeline_components/google-cloud/Vertex_AI/Models/Upload_Tensorflow_model/component.yaml")
|
||||
|
||||
# PyTorch
|
||||
create_fully_connected_pytorch_network_op = components.load_component_from_url("https://raw.githubusercontent.com/GoogleCloudPlatform/vertex-ai-samples/399405402d95f4a011e2d2e967c96f8508ba5688/community-content/pipeline_components/PyTorch/Create_fully_connected_network/component.yaml")
|
||||
train_pytorch_model_from_csv_op = components.load_component_from_url("https://raw.githubusercontent.com/GoogleCloudPlatform/vertex-ai-samples/399405402d95f4a011e2d2e967c96f8508ba5688/community-content/pipeline_components/PyTorch/Train_PyTorch_model/from_CSV/component.yaml")
|
||||
create_pytorch_model_archive_with_base_handler_op = components.load_component_from_url("https://raw.githubusercontent.com/GoogleCloudPlatform/vertex-ai-samples/399405402d95f4a011e2d2e967c96f8508ba5688/community-content/pipeline_components/PyTorch/Create_PyTorch_Model_Archive/with_base_handler/component.yaml")
|
||||
upload_PyTorch_model_archive_to_Google_Cloud_Vertex_AI_op = components.load_component_from_url("https://raw.githubusercontent.com/GoogleCloudPlatform/vertex-ai-samples/399405402d95f4a011e2d2e967c96f8508ba5688/community-content/pipeline_components/google-cloud/Vertex_AI/Models/Upload_PyTorch_model_archive/component.yaml")
|
||||
|
||||
# XGBoost
|
||||
train_XGBoost_model_on_CSV_op = components.load_component_from_url("https://raw.githubusercontent.com/GoogleCloudPlatform/vertex-ai-samples/399405402d95f4a011e2d2e967c96f8508ba5688/community-content/pipeline_components/XGBoost/Train/component.yaml")
|
||||
xgboost_predict_on_CSV_op = components.load_component_from_url("https://raw.githubusercontent.com/GoogleCloudPlatform/vertex-ai-samples/399405402d95f4a011e2d2e967c96f8508ba5688/community-content/pipeline_components/XGBoost/Predict/component.yaml")
|
||||
upload_XGBoost_model_to_Google_Cloud_Vertex_AI_op = components.load_component_from_url("https://raw.githubusercontent.com/GoogleCloudPlatform/vertex-ai-samples/399405402d95f4a011e2d2e967c96f8508ba5688/community-content/pipeline_components/google-cloud/Vertex_AI/Models/Upload_XGBoost_model/component.yaml")
|
||||
|
||||
# Scikit-learn
|
||||
#train_linear_regression_model_using_scikit_learn_from_CSV_op = components.load_component_from_url("https://raw.githubusercontent.com/GoogleCloudPlatform/vertex-ai-samples/1f5cf6e06409b704064b2086c0a705e4e6b4fcde/community-content/pipeline_components/ML_frameworks/Scikit_learn/Train_linear_regression_model/from_CSV/component.yaml")
|
||||
train_logistic_regression_model_using_scikit_learn_from_CSV_op = components.load_component_from_url("https://raw.githubusercontent.com/GoogleCloudPlatform/vertex-ai-samples/1f5cf6e06409b704064b2086c0a705e4e6b4fcde/community-content/pipeline_components/ML_frameworks/Scikit_learn/Train_logistic_regression_model/from_CSV/component.yaml")
|
||||
upload_Scikit_learn_pickle_model_to_Google_Cloud_Vertex_AI_op = components.load_component_from_url("https://raw.githubusercontent.com/GoogleCloudPlatform/vertex-ai-samples/399405402d95f4a011e2d2e967c96f8508ba5688/community-content/pipeline_components/google-cloud/Vertex_AI/Models/Upload_Scikit-learn_pickle_model/component.yaml")
|
||||
|
||||
# Vertex AI
|
||||
deploy_model_to_endpoint_op = components.load_component_from_url("https://raw.githubusercontent.com/GoogleCloudPlatform/vertex-ai-samples/399405402d95f4a011e2d2e967c96f8508ba5688/community-content/pipeline_components/google-cloud/Vertex_AI/Models/Deploy_to_endpoint/component.yaml")
|
||||
|
||||
# %% Pipeline definition
|
||||
def train_tabular_classification_model_using_all_frameworks_pipeline():
|
||||
dataset_gcs_uri = "gs://ml-pipeline-dataset/Chicago_taxi_trips/chicago_taxi_trips_2019-01-01_-_2019-02-01_limit=10000.csv"
|
||||
feature_columns = ["trip_seconds", "trip_miles", "pickup_community_area", "dropoff_community_area", "fare", "tolls", "extras"] # Excluded "trip_total"
|
||||
label_column = "tips"
|
||||
training_set_fraction = 0.8
|
||||
# Deploying the model might incur additional costs over time
|
||||
deploy_model = False
|
||||
|
||||
classification_label_column = "class"
|
||||
all_columns = [label_column] + feature_columns
|
||||
|
||||
dataset = download_from_gcs_op(
|
||||
gcs_path=dataset_gcs_uri
|
||||
).outputs["Data"]
|
||||
|
||||
dataset = select_columns_using_Pandas_on_CSV_data_op(
|
||||
table=dataset,
|
||||
column_names=all_columns,
|
||||
).outputs["transformed_table"]
|
||||
|
||||
dataset = fill_all_missing_values_using_Pandas_on_CSV_data_op(
|
||||
table=dataset,
|
||||
replacement_value="0",
|
||||
# # Optional:
|
||||
# column_names=None, # =[...]
|
||||
).outputs["transformed_table"]
|
||||
|
||||
classification_dataset = binarize_column_using_Pandas_on_CSV_data_op(
|
||||
table=dataset,
|
||||
column_name=label_column,
|
||||
predicate=" > 0",
|
||||
new_column_name=classification_label_column,
|
||||
).outputs["transformed_table"]
|
||||
|
||||
split_task = split_rows_into_subsets_op(
|
||||
table=classification_dataset,
|
||||
fraction_1=training_set_fraction,
|
||||
)
|
||||
classification_training_data = split_task.outputs["split_1"]
|
||||
classification_testing_data = split_task.outputs["split_2"]
|
||||
|
||||
# TensorFlow
|
||||
tensorflow_network = create_fully_connected_tensorflow_network_op(
|
||||
input_size=len(feature_columns),
|
||||
# Optional:
|
||||
hidden_layer_sizes=[10],
|
||||
activation_name="elu",
|
||||
output_activation_name="sigmoid",
|
||||
# output_size=1,
|
||||
).outputs["model"]
|
||||
|
||||
tensorflow_model = train_model_using_Keras_on_CSV_op(
|
||||
training_data=classification_training_data,
|
||||
model=tensorflow_network,
|
||||
label_column_name=classification_label_column,
|
||||
# Optional:
|
||||
loss_function_name="binary_crossentropy",
|
||||
number_of_epochs=10,
|
||||
#learning_rate=0.1,
|
||||
#optimizer_name="Adadelta",
|
||||
#optimizer_parameters={},
|
||||
#batch_size=32,
|
||||
#metric_names=["mean_absolute_error"],
|
||||
#random_seed=0,
|
||||
).outputs["trained_model"]
|
||||
|
||||
tensorflow_predictions = predict_with_TensorFlow_model_on_CSV_data_op(
|
||||
dataset=classification_testing_data,
|
||||
model=tensorflow_model,
|
||||
# label_column_name needs to be set when doing prediction on a dataset that has labels
|
||||
label_column_name=classification_label_column,
|
||||
# Optional:
|
||||
# batch_size=1000,
|
||||
).outputs["predictions"]
|
||||
|
||||
tensorflow_vertex_model_name = upload_Tensorflow_model_to_Google_Cloud_Vertex_AI_op(
|
||||
model=tensorflow_model,
|
||||
).outputs["model_name"]
|
||||
|
||||
# Deploying the model might incur additional costs over time
|
||||
if deploy_model:
|
||||
tensorflow_vertex_endpoint_name = deploy_model_to_endpoint_op(
|
||||
model_name=tensorflow_vertex_model_name,
|
||||
).outputs["endpoint_name"]
|
||||
|
||||
# PyTorch
|
||||
pytorch_network = create_fully_connected_pytorch_network_op(
|
||||
input_size=len(feature_columns),
|
||||
# Optional:
|
||||
hidden_layer_sizes=[10],
|
||||
activation_name="elu",
|
||||
output_activation_name="sigmoid",
|
||||
# output_size=1,
|
||||
).outputs["model"]
|
||||
|
||||
pytorch_model = train_pytorch_model_from_csv_op(
|
||||
model=pytorch_network,
|
||||
training_data=classification_training_data,
|
||||
label_column_name=classification_label_column,
|
||||
loss_function_name="binary_cross_entropy",
|
||||
# Optional:
|
||||
#number_of_epochs=1,
|
||||
#learning_rate=0.1,
|
||||
#optimizer_name="Adadelta",
|
||||
#optimizer_parameters={},
|
||||
#batch_size=32,
|
||||
#batch_log_interval=100,
|
||||
#random_seed=0,
|
||||
).outputs["trained_model"]
|
||||
|
||||
pytorch_model_archive = create_pytorch_model_archive_with_base_handler_op(
|
||||
model=pytorch_model,
|
||||
# Optional:
|
||||
# model_name="model",
|
||||
# model_version="1.0",
|
||||
).outputs["Model archive"]
|
||||
|
||||
pytorch_vertex_model_name = upload_PyTorch_model_archive_to_Google_Cloud_Vertex_AI_op(
|
||||
model_archive=pytorch_model_archive,
|
||||
).outputs["model_name"]
|
||||
|
||||
# Deploying the model might incur additional costs over time
|
||||
if deploy_model:
|
||||
pytorch_vertex_endpoint_name = deploy_model_to_endpoint_op(
|
||||
model_name=pytorch_vertex_model_name,
|
||||
).outputs["endpoint_name"]
|
||||
|
||||
# XGBoost
|
||||
xgboost_model = train_XGBoost_model_on_CSV_op(
|
||||
training_data=classification_training_data,
|
||||
label_column_name=classification_label_column,
|
||||
objective="binary:logistic",
|
||||
# Optional:
|
||||
#starting_model=None,
|
||||
#num_iterations=10,
|
||||
#booster_params={},
|
||||
#booster="gbtree",
|
||||
#learning_rate=0.3,
|
||||
#min_split_loss=0,
|
||||
#max_depth=6,
|
||||
).outputs["model"]
|
||||
|
||||
# Predicting on the testing data
|
||||
xgboost_predictions = xgboost_predict_on_CSV_op(
|
||||
data=classification_testing_data,
|
||||
model=xgboost_model,
|
||||
# label_column needs to be set when doing prediction on a dataset that has labels
|
||||
label_column_name=classification_label_column,
|
||||
).outputs["predictions"]
|
||||
|
||||
xgboost_vertex_model_name = upload_XGBoost_model_to_Google_Cloud_Vertex_AI_op(
|
||||
model=xgboost_model,
|
||||
).outputs["model_name"]
|
||||
|
||||
# Deploying the model might incur additional costs over time
|
||||
if deploy_model:
|
||||
xgboost_vertex_endpoint_name = deploy_model_to_endpoint_op(
|
||||
model_name=xgboost_vertex_model_name,
|
||||
).outputs["endpoint_name"]
|
||||
|
||||
# Scikit-learn
|
||||
sklearn_model = train_logistic_regression_model_using_scikit_learn_from_CSV_op(
|
||||
dataset=classification_training_data,
|
||||
label_column_name=classification_label_column,
|
||||
# Optional:
|
||||
#penalty="l2",
|
||||
#solver="lbfgs",
|
||||
#max_iterations=100,
|
||||
#multi_class_mode="auto",
|
||||
#random_seed=0,
|
||||
).outputs["model"]
|
||||
|
||||
sklearn_vertex_model_name = upload_Scikit_learn_pickle_model_to_Google_Cloud_Vertex_AI_op(
|
||||
model=sklearn_model,
|
||||
).outputs["model_name"]
|
||||
|
||||
# Deploying the model might incur additional costs over time
|
||||
if deploy_model:
|
||||
sklearn_vertex_endpoint_name = deploy_model_to_endpoint_op(
|
||||
model_name=sklearn_vertex_model_name,
|
||||
).outputs["endpoint_name"]
|
||||
|
||||
pipeline_func=train_tabular_classification_model_using_all_frameworks_pipeline
|
||||
|
||||
# %% Pipeline submission
|
||||
if __name__ == '__main__':
|
||||
from google.cloud import aiplatform
|
||||
aiplatform.PipelineJob.from_pipeline_func(pipeline_func=pipeline_func).submit()
|
||||
+68
@@ -0,0 +1,68 @@
|
||||
name: Train tabular regression linear model using Scikit learn pipeline
|
||||
metadata:
|
||||
annotations:
|
||||
author: Alexey Volkov <alexey.volkov@ark-kun.com>
|
||||
canonical_location: https://raw.githubusercontent.com/Ark-kun/pipeline_components/master/samples/Google_Cloud_Vertex_AI/Train_tabular_regression_linear_model_using_Scikit_learn_and_import_to_Vertex_AI/pipeline.component.yaml
|
||||
sdk: https://cloud-pipelines.net/pipeline-editor/
|
||||
implementation:
|
||||
graph:
|
||||
tasks:
|
||||
Download from GCS:
|
||||
componentRef:
|
||||
digest: 4175c9ff143cb8cc75d05451c0a0ebdf5a0d6d020816e29f5e9cefbb7d56f241
|
||||
url: https://raw.githubusercontent.com/Ark-kun/pipeline_components/27a5ea25e849c9e8c0cb6ed65518bc3ece259aaf/components/google-cloud/storage/download/workaround_for_buggy_KFPv2_compiler/component.yaml
|
||||
arguments:
|
||||
GCS path: gs://ml-pipeline-dataset/Chicago_taxi_trips/chicago_taxi_trips_2019-01-01_-_2019-02-01_limit=10000.csv
|
||||
annotations:
|
||||
editor.position: '{"x":40,"y":40,"width":180,"height":40}'
|
||||
Select columns using Pandas on CSV data:
|
||||
componentRef:
|
||||
digest: 9b9500f461c1d04f1e48992de9138db14a6800f23649d73048673d5ea6dc56ad
|
||||
url: https://raw.githubusercontent.com/Ark-kun/pipeline_components/8c78aae096806cff3bc331a40566f42f5c3e9d4b/components/pandas/Select_columns/in_CSV_format/component.yaml
|
||||
arguments:
|
||||
table:
|
||||
taskOutput:
|
||||
outputName: Data
|
||||
taskId: Download from GCS
|
||||
column_names: '["tips", "trip_seconds", "trip_miles", "pickup_community_area", "dropoff_community_area", "fare", "tolls", "extras"]'
|
||||
annotations:
|
||||
editor.position: '{"x":40,"y":140,"width":180,"height":54}'
|
||||
Fill all missing values using Pandas on CSV data:
|
||||
componentRef:
|
||||
digest: a1b0c29a4615f2e3652aa5d31b9255fa15700e146627c755f8fc172f82e71af7
|
||||
url: https://raw.githubusercontent.com/Ark-kun/pipeline_components/23405971f5f16a41b16c343129b893c52e4d1d48/components/pandas/Fill_all_missing_values/in_CSV_format/component.yaml
|
||||
arguments:
|
||||
table:
|
||||
taskOutput:
|
||||
outputName: transformed_table
|
||||
taskId: Select columns using Pandas on CSV data
|
||||
type: CSV
|
||||
replacement_value: '0'
|
||||
annotations:
|
||||
editor.position: '{"x":40,"y":250,"width":180,"height":54}'
|
||||
Train linear regression model using scikit learn from CSV:
|
||||
componentRef:
|
||||
digest: c7fe7912ab0d1fb45d201d452e9ce6be5544e7d8c6d229db7a4b931ff58560f3
|
||||
url: https://raw.githubusercontent.com/Ark-kun/pipeline_components/f807e02b54d4886c65a05f40848fd51c72407f40/components/ML_frameworks/Scikit_learn/Train_linear_regression_model/from_CSV/component.yaml
|
||||
arguments:
|
||||
dataset:
|
||||
taskOutput:
|
||||
outputName: transformed_table
|
||||
taskId: Fill all missing values using Pandas on CSV data
|
||||
type: CSV
|
||||
label_column_name: tips
|
||||
annotations:
|
||||
editor.position: '{"x":40,"y":360,"width":180,"height":54}'
|
||||
Upload Scikit learn pickle model to Google Cloud Vertex AI:
|
||||
componentRef:
|
||||
digest: 81c91c8d7d21ec97e0872f669d68bd89edea87279d703685db54aa94743bebcd
|
||||
url: https://raw.githubusercontent.com/Ark-kun/pipeline_components/c6a8b67d1ada2cc17665c99ff6b410df588bee28/components/google-cloud/Vertex_AI/Models/Upload_Scikit-learn_pickle_model/workaround_for_buggy_KFPv2_compiler/component.yaml
|
||||
arguments:
|
||||
model:
|
||||
taskOutput:
|
||||
outputName: model
|
||||
taskId: Train linear regression model using scikit learn from CSV
|
||||
type: ScikitLearnPickleModel
|
||||
annotations:
|
||||
editor.position: '{"x":40,"y":490,"width":180,"height":70}'
|
||||
outputValues: {}
|
||||
+57
@@ -0,0 +1,57 @@
|
||||
# python3 -m pip install "kfp<2.0.0" "google-cloud-aiplatform>=1.16.0" --upgrade --quiet
|
||||
from kfp import components
|
||||
|
||||
# %% Loading components
|
||||
download_from_gcs_op = components.load_component_from_url("https://raw.githubusercontent.com/GoogleCloudPlatform/vertex-ai-samples/399405402d95f4a011e2d2e967c96f8508ba5688/community-content/pipeline_components/google-cloud/storage/download/component.yaml")
|
||||
select_columns_using_Pandas_on_CSV_data_op = components.load_component_from_url("https://raw.githubusercontent.com/GoogleCloudPlatform/vertex-ai-samples/399405402d95f4a011e2d2e967c96f8508ba5688/community-content/pipeline_components/pandas/Select_columns/in_CSV_format/component.yaml")
|
||||
fill_all_missing_values_using_Pandas_on_CSV_data_op = components.load_component_from_url("https://raw.githubusercontent.com/GoogleCloudPlatform/vertex-ai-samples/399405402d95f4a011e2d2e967c96f8508ba5688/community-content/pipeline_components/pandas/Fill_all_missing_values/in_CSV_format/component.yaml")
|
||||
train_linear_regression_model_using_scikit_learn_from_CSV_op = components.load_component_from_url("https://raw.githubusercontent.com/GoogleCloudPlatform/vertex-ai-samples/1f5cf6e06409b704064b2086c0a705e4e6b4fcde/community-content/pipeline_components/ML_frameworks/Scikit_learn/Train_linear_regression_model/from_CSV/component.yaml")
|
||||
upload_Scikit_learn_pickle_model_to_Google_Cloud_Vertex_AI_op = components.load_component_from_url("https://raw.githubusercontent.com/GoogleCloudPlatform/vertex-ai-samples/399405402d95f4a011e2d2e967c96f8508ba5688/community-content/pipeline_components/google-cloud/Vertex_AI/Models/Upload_Scikit-learn_pickle_model/component.yaml")
|
||||
deploy_model_to_endpoint_op = components.load_component_from_url("https://raw.githubusercontent.com/GoogleCloudPlatform/vertex-ai-samples/399405402d95f4a011e2d2e967c96f8508ba5688/community-content/pipeline_components/google-cloud/Vertex_AI/Models/Deploy_to_endpoint/component.yaml")
|
||||
|
||||
# %% Pipeline definition
|
||||
def train_tabular_regression_linear_model_using_Scikit_learn_pipeline():
|
||||
dataset_gcs_uri = "gs://ml-pipeline-dataset/Chicago_taxi_trips/chicago_taxi_trips_2019-01-01_-_2019-02-01_limit=10000.csv"
|
||||
feature_columns = ["trip_seconds", "trip_miles", "pickup_community_area", "dropoff_community_area", "fare", "tolls", "extras"] # Excluded "trip_total"
|
||||
label_column = "tips"
|
||||
all_columns = [label_column] + feature_columns
|
||||
# Deploying the model might incur additional costs over time
|
||||
deploy_model = False
|
||||
|
||||
training_data = download_from_gcs_op(
|
||||
gcs_path=dataset_gcs_uri
|
||||
).outputs["Data"]
|
||||
|
||||
training_data = select_columns_using_Pandas_on_CSV_data_op(
|
||||
table=training_data,
|
||||
column_names=all_columns,
|
||||
).outputs["transformed_table"]
|
||||
|
||||
# Cleaning the NaN values.
|
||||
training_data = fill_all_missing_values_using_Pandas_on_CSV_data_op(
|
||||
table=training_data,
|
||||
replacement_value="0",
|
||||
#replacement_type_name="float",
|
||||
).outputs["transformed_table"]
|
||||
|
||||
model = train_linear_regression_model_using_scikit_learn_from_CSV_op(
|
||||
dataset=training_data,
|
||||
label_column_name=label_column,
|
||||
).outputs["model"]
|
||||
|
||||
vertex_model_name = upload_Scikit_learn_pickle_model_to_Google_Cloud_Vertex_AI_op(
|
||||
model=model,
|
||||
).outputs["model_name"]
|
||||
|
||||
# Deploying the model might incur additional costs over time
|
||||
if deploy_model:
|
||||
sklearn_vertex_endpoint_name = deploy_model_to_endpoint_op(
|
||||
model_name=vertex_model_name,
|
||||
).outputs["endpoint_name"]
|
||||
|
||||
pipeline_func = train_tabular_regression_linear_model_using_Scikit_learn_pipeline
|
||||
|
||||
# %% Pipeline submission
|
||||
if __name__ == '__main__':
|
||||
from google.cloud import aiplatform
|
||||
aiplatform.PipelineJob.from_pipeline_func(pipeline_func=pipeline_func).submit()
|
||||
+97
@@ -0,0 +1,97 @@
|
||||
name: Train tabular regression model using PyTorch pipeline
|
||||
metadata:
|
||||
annotations:
|
||||
author: Alexey Volkov <alexey.volkov@ark-kun.com>
|
||||
canonical_location: https://raw.githubusercontent.com/Ark-kun/pipeline_components/master/samples/Google_Cloud_Vertex_AI/Train_tabular_regression_model_using_PyTorch_and_import_to_Vertex_AI/pipeline.component.yaml
|
||||
sdk: https://cloud-pipelines.net/pipeline-editor/
|
||||
implementation:
|
||||
graph:
|
||||
tasks:
|
||||
Download from GCS:
|
||||
componentRef:
|
||||
digest: 4175c9ff143cb8cc75d05451c0a0ebdf5a0d6d020816e29f5e9cefbb7d56f241
|
||||
url: https://raw.githubusercontent.com/Ark-kun/pipeline_components/27a5ea25e849c9e8c0cb6ed65518bc3ece259aaf/components/google-cloud/storage/download/workaround_for_buggy_KFPv2_compiler/component.yaml
|
||||
arguments:
|
||||
GCS path: gs://ml-pipeline-dataset/Chicago_taxi_trips/chicago_taxi_trips_2019-01-01_-_2019-02-01_limit=10000.csv
|
||||
annotations:
|
||||
editor.position: '{"x":240,"y":40,"width":180,"height":40}'
|
||||
Select columns using Pandas on CSV data:
|
||||
componentRef:
|
||||
digest: 9b9500f461c1d04f1e48992de9138db14a6800f23649d73048673d5ea6dc56ad
|
||||
url: https://raw.githubusercontent.com/Ark-kun/pipeline_components/8c78aae096806cff3bc331a40566f42f5c3e9d4b/components/pandas/Select_columns/in_CSV_format/component.yaml
|
||||
arguments:
|
||||
table:
|
||||
taskOutput:
|
||||
outputName: Data
|
||||
taskId: Download from GCS
|
||||
column_names: '["tips", "trip_seconds", "trip_miles", "pickup_community_area", "dropoff_community_area", "fare", "tolls", "extras"]'
|
||||
annotations:
|
||||
editor.position: '{"x":240,"y":130,"width":180,"height":54}'
|
||||
Create fully connected pytorch network:
|
||||
componentRef:
|
||||
digest: d03d8248fd358a0275ec33568ee7dd7dce576cc112b09dfafe2651e4d97e04a9
|
||||
url: https://raw.githubusercontent.com/Ark-kun/pipeline_components/1a2ef3eeb77bc278f33cad0dd29008ea2431e191/components/PyTorch/Create_fully_connected_network/component.yaml
|
||||
arguments:
|
||||
input_size: '7'
|
||||
hidden_layer_sizes: '[10]'
|
||||
activation_name: elu
|
||||
annotations:
|
||||
editor.position: '{"x":40,"y":240,"width":180,"height":54}'
|
||||
Fill all missing values using Pandas on CSV data:
|
||||
componentRef:
|
||||
digest: a1b0c29a4615f2e3652aa5d31b9255fa15700e146627c755f8fc172f82e71af7
|
||||
url: https://raw.githubusercontent.com/Ark-kun/pipeline_components/23405971f5f16a41b16c343129b893c52e4d1d48/components/pandas/Fill_all_missing_values/in_CSV_format/component.yaml
|
||||
arguments:
|
||||
table:
|
||||
taskOutput:
|
||||
outputName: transformed_table
|
||||
taskId: Select columns using Pandas on CSV data
|
||||
type: CSV
|
||||
replacement_value: '0'
|
||||
annotations:
|
||||
editor.position: '{"x":240,"y":240,"width":180,"height":54}'
|
||||
Train pytorch model from csv:
|
||||
componentRef:
|
||||
digest: 40f3185eb61e9727f41a4e0c05dd3d3b44bd802aa0f378cfc31756560033949a
|
||||
url: https://raw.githubusercontent.com/Ark-kun/pipeline_components/d8c4cf5e6403bc65bcf8d606e6baf87e2528a3dc/components/PyTorch/Train_PyTorch_model/from_CSV/component.yaml
|
||||
arguments:
|
||||
model:
|
||||
taskOutput:
|
||||
outputName: model
|
||||
taskId: Create fully connected pytorch network
|
||||
type: PyTorchScriptModule
|
||||
training_data:
|
||||
taskOutput:
|
||||
outputName: transformed_table
|
||||
taskId: Fill all missing values using Pandas on CSV data
|
||||
type: CSV
|
||||
label_column_name: tips
|
||||
annotations:
|
||||
editor.position: '{"x":240,"y":380,"width":180,"height":40}'
|
||||
Create PyTorch Model Archive with base handler:
|
||||
componentRef:
|
||||
digest: 8298b5ee1b0f0879f893add4cf352c8dec7cf9e21bb9db134c91a2d046cdb0ec
|
||||
url: https://raw.githubusercontent.com/Ark-kun/pipeline_components/46d51383e6554b7f3ab4fd8cf614d8c2b422fb22/components/PyTorch/Create_PyTorch_Model_Archive/with_base_handler/component.yaml
|
||||
arguments:
|
||||
Model:
|
||||
taskOutput:
|
||||
outputName: trained_model
|
||||
taskId: Train pytorch model from csv
|
||||
type: PyTorchScriptModule
|
||||
Model name: model
|
||||
Model version: '1.0'
|
||||
annotations:
|
||||
editor.position: '{"x":240,"y":500,"width":180,"height":54}'
|
||||
Upload PyTorch model archive to Google Cloud Vertex AI:
|
||||
componentRef:
|
||||
digest: 4450212fae7b9001482aca7eb78b28413c205506eccf08a04e7754a8dfa99004
|
||||
url: https://raw.githubusercontent.com/Ark-kun/pipeline_components/c6a8b67d1ada2cc17665c99ff6b410df588bee28/components/google-cloud/Vertex_AI/Models/Upload_PyTorch_model_archive/workaround_for_buggy_KFPv2_compiler/component.yaml
|
||||
arguments:
|
||||
model_archive:
|
||||
taskOutput:
|
||||
outputName: Model archive
|
||||
taskId: Create PyTorch Model Archive with base handler
|
||||
type: PyTorchModelArchive
|
||||
annotations:
|
||||
editor.position: '{"x":240,"y":630,"width":180,"height":70}'
|
||||
outputValues: {}
|
||||
+85
@@ -0,0 +1,85 @@
|
||||
# python3 -m pip install "kfp<2.0.0" "google-cloud-aiplatform>=1.16.0" --upgrade --quiet
|
||||
from kfp import components
|
||||
|
||||
# %% Loading components
|
||||
download_from_gcs_op = components.load_component_from_url("https://raw.githubusercontent.com/GoogleCloudPlatform/vertex-ai-samples/399405402d95f4a011e2d2e967c96f8508ba5688/community-content/pipeline_components/google-cloud/storage/download/component.yaml")
|
||||
select_columns_using_Pandas_on_CSV_data_op = components.load_component_from_url("https://raw.githubusercontent.com/GoogleCloudPlatform/vertex-ai-samples/399405402d95f4a011e2d2e967c96f8508ba5688/community-content/pipeline_components/pandas/Select_columns/in_CSV_format/component.yaml")
|
||||
fill_all_missing_values_using_Pandas_on_CSV_data_op = components.load_component_from_url("https://raw.githubusercontent.com/GoogleCloudPlatform/vertex-ai-samples/399405402d95f4a011e2d2e967c96f8508ba5688/community-content/pipeline_components/pandas/Fill_all_missing_values/in_CSV_format/component.yaml")
|
||||
create_fully_connected_pytorch_network_op = components.load_component_from_url("https://raw.githubusercontent.com/GoogleCloudPlatform/vertex-ai-samples/399405402d95f4a011e2d2e967c96f8508ba5688/community-content/pipeline_components/PyTorch/Create_fully_connected_network/component.yaml")
|
||||
train_pytorch_model_from_csv_op = components.load_component_from_url("https://raw.githubusercontent.com/GoogleCloudPlatform/vertex-ai-samples/399405402d95f4a011e2d2e967c96f8508ba5688/community-content/pipeline_components/PyTorch/Train_PyTorch_model/from_CSV/component.yaml")
|
||||
create_pytorch_model_archive_with_base_handler_op = components.load_component_from_url("https://raw.githubusercontent.com/GoogleCloudPlatform/vertex-ai-samples/399405402d95f4a011e2d2e967c96f8508ba5688/community-content/pipeline_components/PyTorch/Create_PyTorch_Model_Archive/with_base_handler/component.yaml")
|
||||
upload_PyTorch_model_archive_to_Google_Cloud_Vertex_AI_op = components.load_component_from_url("https://raw.githubusercontent.com/GoogleCloudPlatform/vertex-ai-samples/399405402d95f4a011e2d2e967c96f8508ba5688/community-content/pipeline_components/google-cloud/Vertex_AI/Models/Upload_PyTorch_model_archive/component.yaml")
|
||||
deploy_model_to_endpoint_op = components.load_component_from_url("https://raw.githubusercontent.com/GoogleCloudPlatform/vertex-ai-samples/399405402d95f4a011e2d2e967c96f8508ba5688/community-content/pipeline_components/google-cloud/Vertex_AI/Models/Deploy_to_endpoint/component.yaml")
|
||||
|
||||
# %% Pipeline definition
|
||||
def train_tabular_regression_model_using_PyTorch_pipeline():
|
||||
dataset_gcs_uri = "gs://ml-pipeline-dataset/Chicago_taxi_trips/chicago_taxi_trips_2019-01-01_-_2019-02-01_limit=10000.csv"
|
||||
feature_columns = ["trip_seconds", "trip_miles", "pickup_community_area", "dropoff_community_area", "fare", "tolls", "extras"] # Excluded "trip_total"
|
||||
label_column = "tips"
|
||||
all_columns = [label_column] + feature_columns
|
||||
# Deploying the model might incur additional costs over time
|
||||
deploy_model = False
|
||||
|
||||
training_data = download_from_gcs_op(
|
||||
gcs_path=dataset_gcs_uri
|
||||
).outputs["Data"]
|
||||
|
||||
training_data = select_columns_using_Pandas_on_CSV_data_op(
|
||||
table=training_data,
|
||||
column_names=all_columns,
|
||||
).outputs["transformed_table"]
|
||||
|
||||
# Cleaning the NaN values.
|
||||
training_data = fill_all_missing_values_using_Pandas_on_CSV_data_op(
|
||||
table=training_data,
|
||||
replacement_value="0",
|
||||
#replacement_type_name="float",
|
||||
).outputs["transformed_table"]
|
||||
|
||||
network = create_fully_connected_pytorch_network_op(
|
||||
input_size=len(feature_columns),
|
||||
# Optional:
|
||||
hidden_layer_sizes=[10],
|
||||
activation_name="elu",
|
||||
# output_activation_name=None,
|
||||
# output_size=1,
|
||||
).outputs["model"]
|
||||
|
||||
model = train_pytorch_model_from_csv_op(
|
||||
model=network,
|
||||
training_data=training_data,
|
||||
label_column_name=label_column,
|
||||
# Optional:
|
||||
#loss_function_name="mse_loss",
|
||||
#number_of_epochs=1,
|
||||
#learning_rate=0.1,
|
||||
#optimizer_name="Adadelta",
|
||||
#optimizer_parameters={},
|
||||
#batch_size=32,
|
||||
#batch_log_interval=100,
|
||||
#random_seed=0,
|
||||
).outputs["trained_model"]
|
||||
|
||||
model_archive = create_pytorch_model_archive_with_base_handler_op(
|
||||
model=model,
|
||||
# Optional:
|
||||
# model_name="model",
|
||||
# model_version="1.0",
|
||||
).outputs["Model archive"]
|
||||
|
||||
vertex_model_name = upload_PyTorch_model_archive_to_Google_Cloud_Vertex_AI_op(
|
||||
model_archive=model_archive,
|
||||
).outputs["model_name"]
|
||||
|
||||
# Deploying the model might incur additional costs over time
|
||||
if deploy_model:
|
||||
vertex_endpoint_name = deploy_model_to_endpoint_op(
|
||||
model_name=vertex_model_name,
|
||||
).outputs["endpoint_name"]
|
||||
|
||||
pipeline_func=train_tabular_regression_model_using_PyTorch_pipeline
|
||||
|
||||
# %% Pipeline submission
|
||||
if __name__ == '__main__':
|
||||
from google.cloud import aiplatform
|
||||
aiplatform.PipelineJob.from_pipeline_func(pipeline_func=pipeline_func).submit()
|
||||
+116
@@ -0,0 +1,116 @@
|
||||
name: Train tabular regression model using Tensorflow pipeline
|
||||
metadata:
|
||||
annotations:
|
||||
author: Alexey Volkov <alexey.volkov@ark-kun.com>
|
||||
canonical_location: https://raw.githubusercontent.com/Ark-kun/pipeline_components/master/samples/Google_Cloud_Vertex_AI/Train_tabular_regression_model_using_TensorFlow_and_import_to_Vertex_AI/pipeline.component.yaml
|
||||
sdk: https://cloud-pipelines.net/pipeline-editor/
|
||||
implementation:
|
||||
graph:
|
||||
tasks:
|
||||
Download from GCS:
|
||||
componentRef:
|
||||
digest: 4175c9ff143cb8cc75d05451c0a0ebdf5a0d6d020816e29f5e9cefbb7d56f241
|
||||
url: https://raw.githubusercontent.com/Ark-kun/pipeline_components/27a5ea25e849c9e8c0cb6ed65518bc3ece259aaf/components/google-cloud/storage/download/workaround_for_buggy_KFPv2_compiler/component.yaml
|
||||
arguments:
|
||||
GCS path: gs://ml-pipeline-dataset/Chicago_taxi_trips/chicago_taxi_trips_2019-01-01_-_2019-02-01_limit=10000.csv
|
||||
annotations:
|
||||
editor.position: '{"x":40,"y":40,"width":180,"height":40}'
|
||||
Select columns using Pandas on CSV data:
|
||||
componentRef:
|
||||
digest: 9b9500f461c1d04f1e48992de9138db14a6800f23649d73048673d5ea6dc56ad
|
||||
url: https://raw.githubusercontent.com/Ark-kun/pipeline_components/8c78aae096806cff3bc331a40566f42f5c3e9d4b/components/pandas/Select_columns/in_CSV_format/component.yaml
|
||||
arguments:
|
||||
table:
|
||||
taskOutput:
|
||||
outputName: Data
|
||||
taskId: Download from GCS
|
||||
column_names: '["tips", "trip_seconds", "trip_miles", "pickup_community_area", "dropoff_community_area", "fare", "tolls", "extras"]'
|
||||
annotations:
|
||||
editor.position: '{"x":40,"y":140,"width":180,"height":54}'
|
||||
Fill all missing values using Pandas on CSV data:
|
||||
componentRef:
|
||||
digest: a1b0c29a4615f2e3652aa5d31b9255fa15700e146627c755f8fc172f82e71af7
|
||||
url: https://raw.githubusercontent.com/Ark-kun/pipeline_components/23405971f5f16a41b16c343129b893c52e4d1d48/components/pandas/Fill_all_missing_values/in_CSV_format/component.yaml
|
||||
arguments:
|
||||
table:
|
||||
taskOutput:
|
||||
outputName: transformed_table
|
||||
taskId: Select columns using Pandas on CSV data
|
||||
type: CSV
|
||||
replacement_value: '0'
|
||||
annotations:
|
||||
editor.position: '{"x":40,"y":250,"width":180,"height":54}'
|
||||
Split rows into subsets:
|
||||
componentRef:
|
||||
digest: a609c3c9196484290f24a1174955f95b27f07a7b458aa5cb8cde28866cb2cb46
|
||||
url: https://raw.githubusercontent.com/Ark-kun/pipeline_components/daae5a4abaa35e44501818b1534ed7827d7da073/components/dataset_manipulation/Split_rows_into_subsets/in_CSV/component.yaml
|
||||
arguments:
|
||||
table:
|
||||
taskOutput:
|
||||
outputName: transformed_table
|
||||
taskId: Fill all missing values using Pandas on CSV data
|
||||
type: CSV
|
||||
fraction_1: '0.8'
|
||||
annotations:
|
||||
editor.position: '{"x":170,"y":380,"width":180,"height":40}'
|
||||
Create fully connected tensorflow network:
|
||||
componentRef:
|
||||
digest: bfcafbc5ce711b1f69cabf1338212d10d50136a73db9f9f7c984de7b80b4bfb0
|
||||
url: https://raw.githubusercontent.com/Ark-kun/pipeline_components/9ca0f9eecf5f896f65b8538bbd809747052617d1/components/tensorflow/Create_fully_connected_network/component.yaml
|
||||
arguments:
|
||||
input_size: '7'
|
||||
hidden_layer_sizes: '[10]'
|
||||
activation_name: elu
|
||||
annotations:
|
||||
editor.position: '{"x":370,"y":380,"width":180,"height":54}'
|
||||
Train model using Keras on CSV:
|
||||
componentRef:
|
||||
digest: 42ae60c889034dbad74815653e95b4f7d576b5f47f803173e8679c7b54984609
|
||||
url: https://raw.githubusercontent.com/Ark-kun/pipeline_components/c504a4010348c50eaaf6d4337586ccc008f4dcef/components/tensorflow/Train_model_using_Keras/on_CSV/component.yaml
|
||||
arguments:
|
||||
training_data:
|
||||
taskOutput:
|
||||
outputName: split_1
|
||||
taskId: Split rows into subsets
|
||||
type: CSV
|
||||
model:
|
||||
taskOutput:
|
||||
outputName: model
|
||||
taskId: Create fully connected tensorflow network
|
||||
type: TensorflowSavedModel
|
||||
label_column_name: tips
|
||||
number_of_epochs: '10'
|
||||
metric_names: '["mean_absolute_error"]'
|
||||
annotations:
|
||||
editor.position: '{"x":40,"y":500,"width":180,"height":54}'
|
||||
Upload Tensorflow model to Google Cloud Vertex AI:
|
||||
componentRef:
|
||||
digest: 2e45263ff640b1a688e359b6936e27a81b2407749a84f340af2aa5547e0cb92c
|
||||
url: https://raw.githubusercontent.com/Ark-kun/pipeline_components/c6a8b67d1ada2cc17665c99ff6b410df588bee28/components/google-cloud/Vertex_AI/Models/Upload_Tensorflow_model/workaround_for_buggy_KFPv2_compiler/component.yaml
|
||||
arguments:
|
||||
model:
|
||||
taskOutput:
|
||||
outputName: trained_model
|
||||
taskId: Train model using Keras on CSV
|
||||
type: TensorflowSavedModel
|
||||
annotations:
|
||||
editor.position: '{"x":40,"y":630,"width":180,"height":54}'
|
||||
Predict with TensorFlow model on CSV data:
|
||||
componentRef:
|
||||
digest: 921bb1563e93a78233b8acceab87055b9154ccf5595d056028cf0396ca224cd4
|
||||
url: https://raw.githubusercontent.com/Ark-kun/pipeline_components/59c759ce6f543184e30db6817d2a703879bc0f39/components/tensorflow/Predict/on_CSV/component.yaml
|
||||
arguments:
|
||||
dataset:
|
||||
taskOutput:
|
||||
outputName: split_2
|
||||
taskId: Split rows into subsets
|
||||
type: CSV
|
||||
model:
|
||||
taskOutput:
|
||||
outputName: trained_model
|
||||
taskId: Train model using Keras on CSV
|
||||
type: TensorflowSavedModel
|
||||
label_column_name: tips
|
||||
annotations:
|
||||
editor.position: '{"x":240,"y":630,"width":180,"height":54}'
|
||||
outputValues: {}
|
||||
+97
@@ -0,0 +1,97 @@
|
||||
# python3 -m pip install "kfp<2.0.0" "google-cloud-aiplatform>=1.16.0" --upgrade --quiet
|
||||
from kfp import components
|
||||
|
||||
# %% Loading components
|
||||
download_from_gcs_op = components.load_component_from_url("https://raw.githubusercontent.com/GoogleCloudPlatform/vertex-ai-samples/399405402d95f4a011e2d2e967c96f8508ba5688/community-content/pipeline_components/google-cloud/storage/download/component.yaml")
|
||||
select_columns_using_Pandas_on_CSV_data_op = components.load_component_from_url("https://raw.githubusercontent.com/GoogleCloudPlatform/vertex-ai-samples/399405402d95f4a011e2d2e967c96f8508ba5688/community-content/pipeline_components/pandas/Select_columns/in_CSV_format/component.yaml")
|
||||
fill_all_missing_values_using_Pandas_on_CSV_data_op = components.load_component_from_url("https://raw.githubusercontent.com/GoogleCloudPlatform/vertex-ai-samples/399405402d95f4a011e2d2e967c96f8508ba5688/community-content/pipeline_components/pandas/Fill_all_missing_values/in_CSV_format/component.yaml")
|
||||
split_rows_into_subsets_op = components.load_component_from_url("https://raw.githubusercontent.com/GoogleCloudPlatform/vertex-ai-samples/399405402d95f4a011e2d2e967c96f8508ba5688/community-content/pipeline_components/dataset_manipulation/Split_rows_into_subsets/in_CSV/component.yaml")
|
||||
create_fully_connected_tensorflow_network_op = components.load_component_from_url("https://raw.githubusercontent.com/GoogleCloudPlatform/vertex-ai-samples/399405402d95f4a011e2d2e967c96f8508ba5688/community-content/pipeline_components/tensorflow/Create_fully_connected_network/component.yaml")
|
||||
train_model_using_Keras_on_CSV_op = components.load_component_from_url("https://raw.githubusercontent.com/GoogleCloudPlatform/vertex-ai-samples/399405402d95f4a011e2d2e967c96f8508ba5688/community-content/pipeline_components/tensorflow/Train_model_using_Keras/on_CSV/component.yaml")
|
||||
predict_with_TensorFlow_model_on_CSV_data_op = components.load_component_from_url("https://raw.githubusercontent.com/GoogleCloudPlatform/vertex-ai-samples/399405402d95f4a011e2d2e967c96f8508ba5688/community-content/pipeline_components/tensorflow/Predict/on_CSV/component.yaml")
|
||||
upload_Tensorflow_model_to_Google_Cloud_Vertex_AI_op = components.load_component_from_url("https://raw.githubusercontent.com/GoogleCloudPlatform/vertex-ai-samples/399405402d95f4a011e2d2e967c96f8508ba5688/community-content/pipeline_components/google-cloud/Vertex_AI/Models/Upload_Tensorflow_model/component.yaml")
|
||||
deploy_model_to_endpoint_op = components.load_component_from_url("https://raw.githubusercontent.com/GoogleCloudPlatform/vertex-ai-samples/399405402d95f4a011e2d2e967c96f8508ba5688/community-content/pipeline_components/google-cloud/Vertex_AI/Models/Deploy_to_endpoint/component.yaml")
|
||||
|
||||
# %% Pipeline definition
|
||||
def train_tabular_regression_model_using_Tensorflow_pipeline():
|
||||
dataset_gcs_uri = "gs://ml-pipeline-dataset/Chicago_taxi_trips/chicago_taxi_trips_2019-01-01_-_2019-02-01_limit=10000.csv"
|
||||
feature_columns = ["trip_seconds", "trip_miles", "pickup_community_area", "dropoff_community_area", "fare", "tolls", "extras"] # Excluded "trip_total"
|
||||
label_column = "tips"
|
||||
training_set_fraction = 0.8
|
||||
# Deploying the model might incur additional costs over time
|
||||
deploy_model = False
|
||||
|
||||
all_columns = [label_column] + feature_columns
|
||||
|
||||
dataset = download_from_gcs_op(
|
||||
gcs_path=dataset_gcs_uri
|
||||
).outputs["Data"]
|
||||
|
||||
dataset = select_columns_using_Pandas_on_CSV_data_op(
|
||||
table=dataset,
|
||||
column_names=all_columns,
|
||||
).outputs["transformed_table"]
|
||||
|
||||
dataset = fill_all_missing_values_using_Pandas_on_CSV_data_op(
|
||||
table=dataset,
|
||||
replacement_value="0",
|
||||
# # Optional:
|
||||
# column_names=None, # =[...]
|
||||
).outputs["transformed_table"]
|
||||
|
||||
split_task = split_rows_into_subsets_op(
|
||||
table=dataset,
|
||||
fraction_1=training_set_fraction,
|
||||
)
|
||||
training_data = split_task.outputs["split_1"]
|
||||
testing_data = split_task.outputs["split_2"]
|
||||
|
||||
network = create_fully_connected_tensorflow_network_op(
|
||||
input_size=len(feature_columns),
|
||||
# Optional:
|
||||
hidden_layer_sizes=[10],
|
||||
activation_name="elu",
|
||||
# output_activation_name=None,
|
||||
# output_size=1,
|
||||
).outputs["model"]
|
||||
|
||||
model = train_model_using_Keras_on_CSV_op(
|
||||
training_data=training_data,
|
||||
model=network,
|
||||
label_column_name=label_column,
|
||||
# Optional:
|
||||
#loss_function_name="mean_squared_error",
|
||||
number_of_epochs=10,
|
||||
#learning_rate=0.1,
|
||||
#optimizer_name="Adadelta",
|
||||
#optimizer_parameters={},
|
||||
#batch_size=32,
|
||||
metric_names=["mean_absolute_error"],
|
||||
#random_seed=0,
|
||||
).outputs["trained_model"]
|
||||
|
||||
predictions = predict_with_TensorFlow_model_on_CSV_data_op(
|
||||
dataset=testing_data,
|
||||
model=model,
|
||||
# label_column_name needs to be set when doing prediction on a dataset that has labels
|
||||
label_column_name=label_column,
|
||||
# Optional:
|
||||
# batch_size=1000,
|
||||
).outputs["predictions"]
|
||||
|
||||
vertex_model_name = upload_Tensorflow_model_to_Google_Cloud_Vertex_AI_op(
|
||||
model=model,
|
||||
).outputs["model_name"]
|
||||
|
||||
# Deploying the model might incur additional costs over time
|
||||
if deploy_model:
|
||||
vertex_endpoint_name = deploy_model_to_endpoint_op(
|
||||
model_name=vertex_model_name,
|
||||
).outputs["endpoint_name"]
|
||||
|
||||
pipeline_func=train_tabular_regression_model_using_Tensorflow_pipeline
|
||||
|
||||
# %% Pipeline submission
|
||||
if __name__ == '__main__':
|
||||
from google.cloud import aiplatform
|
||||
aiplatform.PipelineJob.from_pipeline_func(pipeline_func=pipeline_func).submit()
|
||||
+99
@@ -0,0 +1,99 @@
|
||||
name: Train tabular regression model using XGBoost pipeline
|
||||
metadata:
|
||||
annotations:
|
||||
author: Alexey Volkov <alexey.volkov@ark-kun.com>
|
||||
canonical_location: https://raw.githubusercontent.com/Ark-kun/pipeline_components/master/samples/Google_Cloud_Vertex_AI/Train_tabular_regression_model_using_XGBoost_and_import_to_Vertex_AI/pipeline.component.yaml
|
||||
sdk: https://cloud-pipelines.net/pipeline-editor/
|
||||
implementation:
|
||||
graph:
|
||||
tasks:
|
||||
Download from GCS:
|
||||
componentRef:
|
||||
digest: 4175c9ff143cb8cc75d05451c0a0ebdf5a0d6d020816e29f5e9cefbb7d56f241
|
||||
url: https://raw.githubusercontent.com/Ark-kun/pipeline_components/27a5ea25e849c9e8c0cb6ed65518bc3ece259aaf/components/google-cloud/storage/download/workaround_for_buggy_KFPv2_compiler/component.yaml
|
||||
arguments:
|
||||
GCS path: gs://ml-pipeline-dataset/Chicago_taxi_trips/chicago_taxi_trips_2019-01-01_-_2019-02-01_limit=10000.csv
|
||||
annotations:
|
||||
editor.position: '{"x":40,"y":40,"width":180,"height":40}'
|
||||
Select columns using Pandas on CSV data:
|
||||
componentRef:
|
||||
digest: 9b9500f461c1d04f1e48992de9138db14a6800f23649d73048673d5ea6dc56ad
|
||||
url: https://raw.githubusercontent.com/Ark-kun/pipeline_components/8c78aae096806cff3bc331a40566f42f5c3e9d4b/components/pandas/Select_columns/in_CSV_format/component.yaml
|
||||
arguments:
|
||||
table:
|
||||
taskOutput:
|
||||
outputName: Data
|
||||
taskId: Download from GCS
|
||||
column_names: '["tips", "trip_seconds", "trip_miles", "pickup_community_area", "dropoff_community_area", "fare", "tolls", "extras"]'
|
||||
annotations:
|
||||
editor.position: '{"x":40,"y":140,"width":180,"height":54}'
|
||||
Fill all missing values using Pandas on CSV data:
|
||||
componentRef:
|
||||
digest: a1b0c29a4615f2e3652aa5d31b9255fa15700e146627c755f8fc172f82e71af7
|
||||
url: https://raw.githubusercontent.com/Ark-kun/pipeline_components/23405971f5f16a41b16c343129b893c52e4d1d48/components/pandas/Fill_all_missing_values/in_CSV_format/component.yaml
|
||||
arguments:
|
||||
table:
|
||||
taskOutput:
|
||||
outputName: transformed_table
|
||||
taskId: Select columns using Pandas on CSV data
|
||||
type: CSV
|
||||
replacement_value: '0'
|
||||
annotations:
|
||||
editor.position: '{"x":40,"y":250,"width":180,"height":54}'
|
||||
Split rows into subsets:
|
||||
componentRef:
|
||||
digest: a609c3c9196484290f24a1174955f95b27f07a7b458aa5cb8cde28866cb2cb46
|
||||
url: https://raw.githubusercontent.com/Ark-kun/pipeline_components/daae5a4abaa35e44501818b1534ed7827d7da073/components/dataset_manipulation/Split_rows_into_subsets/in_CSV/component.yaml
|
||||
arguments:
|
||||
table:
|
||||
taskOutput:
|
||||
outputName: transformed_table
|
||||
taskId: Fill all missing values using Pandas on CSV data
|
||||
type: CSV
|
||||
fraction_1: '0.8'
|
||||
annotations:
|
||||
editor.position: '{"x":170,"y":360,"width":180,"height":40}'
|
||||
Train XGBoost model on CSV:
|
||||
componentRef:
|
||||
digest: 538c5a01eb38deaf532d619f0bbeaff4efc550fe1f0f776fc06791097b68ceac
|
||||
url: https://raw.githubusercontent.com/Ark-kun/pipeline_components/58d3a47f904f32a64af8403330ba7e2134cae46d/components/XGBoost/Train/component.yaml
|
||||
arguments:
|
||||
training_data:
|
||||
taskOutput:
|
||||
outputName: split_1
|
||||
taskId: Split rows into subsets
|
||||
type: CSV
|
||||
label_column_name: tips
|
||||
annotations:
|
||||
editor.position: '{"x":40,"y":480,"width":180,"height":40}'
|
||||
Upload XGBoost model to Google Cloud Vertex AI:
|
||||
componentRef:
|
||||
digest: 5a5a273c403670743820986c03a4175b7cb4595a556524fefcce403656286977
|
||||
url: https://raw.githubusercontent.com/Ark-kun/pipeline_components/c6a8b67d1ada2cc17665c99ff6b410df588bee28/components/google-cloud/Vertex_AI/Models/Upload_XGBoost_model/workaround_for_buggy_KFPv2_compiler/component.yaml
|
||||
arguments:
|
||||
model:
|
||||
taskOutput:
|
||||
outputName: model
|
||||
taskId: Train XGBoost model on CSV
|
||||
type: XGBoostModel
|
||||
annotations:
|
||||
editor.position: '{"x":40,"y":600,"width":180,"height":54}'
|
||||
Xgboost predict on CSV:
|
||||
componentRef:
|
||||
digest: 0876233a0c7306fefec188bd70f059b46d1fb5aa57be231799570e3bbbdd0d95
|
||||
url: https://raw.githubusercontent.com/Ark-kun/pipeline_components/4694ec97baccf59284c2a1db4aa2250c22291eab/components/XGBoost/Predict/component.yaml
|
||||
arguments:
|
||||
data:
|
||||
taskOutput:
|
||||
outputName: split_2
|
||||
taskId: Split rows into subsets
|
||||
type: CSV
|
||||
model:
|
||||
taskOutput:
|
||||
outputName: model
|
||||
taskId: Train XGBoost model on CSV
|
||||
type: XGBoostModel
|
||||
label_column_name: tips
|
||||
annotations:
|
||||
editor.position: '{"x":240,"y":600,"width":180,"height":40}'
|
||||
outputValues: {}
|
||||
+85
@@ -0,0 +1,85 @@
|
||||
# python3 -m pip install "kfp<2.0.0" "google-cloud-aiplatform>=1.16.0" --upgrade --quiet
|
||||
from kfp import components
|
||||
|
||||
# %% Loading components
|
||||
download_from_gcs_op = components.load_component_from_url("https://raw.githubusercontent.com/GoogleCloudPlatform/vertex-ai-samples/399405402d95f4a011e2d2e967c96f8508ba5688/community-content/pipeline_components/google-cloud/storage/download/component.yaml")
|
||||
select_columns_using_Pandas_on_CSV_data_op = components.load_component_from_url("https://raw.githubusercontent.com/GoogleCloudPlatform/vertex-ai-samples/399405402d95f4a011e2d2e967c96f8508ba5688/community-content/pipeline_components/pandas/Select_columns/in_CSV_format/component.yaml")
|
||||
fill_all_missing_values_using_Pandas_on_CSV_data_op = components.load_component_from_url("https://raw.githubusercontent.com/GoogleCloudPlatform/vertex-ai-samples/399405402d95f4a011e2d2e967c96f8508ba5688/community-content/pipeline_components/pandas/Fill_all_missing_values/in_CSV_format/component.yaml")
|
||||
split_rows_into_subsets_op = components.load_component_from_url("https://raw.githubusercontent.com/GoogleCloudPlatform/vertex-ai-samples/399405402d95f4a011e2d2e967c96f8508ba5688/community-content/pipeline_components/dataset_manipulation/Split_rows_into_subsets/in_CSV/component.yaml")
|
||||
train_XGBoost_model_on_CSV_op = components.load_component_from_url("https://raw.githubusercontent.com/GoogleCloudPlatform/vertex-ai-samples/399405402d95f4a011e2d2e967c96f8508ba5688/community-content/pipeline_components/XGBoost/Train/component.yaml")
|
||||
xgboost_predict_on_CSV_op = components.load_component_from_url("https://raw.githubusercontent.com/GoogleCloudPlatform/vertex-ai-samples/399405402d95f4a011e2d2e967c96f8508ba5688/community-content/pipeline_components/XGBoost/Predict/component.yaml")
|
||||
upload_XGBoost_model_to_Google_Cloud_Vertex_AI_op = components.load_component_from_url("https://raw.githubusercontent.com/GoogleCloudPlatform/vertex-ai-samples/399405402d95f4a011e2d2e967c96f8508ba5688/community-content/pipeline_components/google-cloud/Vertex_AI/Models/Upload_XGBoost_model/component.yaml")
|
||||
deploy_model_to_endpoint_op = components.load_component_from_url("https://raw.githubusercontent.com/GoogleCloudPlatform/vertex-ai-samples/399405402d95f4a011e2d2e967c96f8508ba5688/community-content/pipeline_components/google-cloud/Vertex_AI/Models/Deploy_to_endpoint/component.yaml")
|
||||
|
||||
# %% Pipeline definition
|
||||
def train_tabular_regression_model_using_XGBoost_pipeline():
|
||||
dataset_gcs_uri = "gs://ml-pipeline-dataset/Chicago_taxi_trips/chicago_taxi_trips_2019-01-01_-_2019-02-01_limit=10000.csv"
|
||||
feature_columns = ["trip_seconds", "trip_miles", "pickup_community_area", "dropoff_community_area", "fare", "tolls", "extras"] # Excluded "trip_total"
|
||||
label_column = "tips"
|
||||
training_set_fraction = 0.8
|
||||
# Deploying the model might incur additional costs over time
|
||||
deploy_model = False
|
||||
|
||||
all_columns = [label_column] + feature_columns
|
||||
|
||||
dataset = download_from_gcs_op(
|
||||
gcs_path=dataset_gcs_uri
|
||||
).outputs["Data"]
|
||||
|
||||
dataset = select_columns_using_Pandas_on_CSV_data_op(
|
||||
table=dataset,
|
||||
column_names=all_columns,
|
||||
).outputs["transformed_table"]
|
||||
|
||||
dataset = fill_all_missing_values_using_Pandas_on_CSV_data_op(
|
||||
table=dataset,
|
||||
replacement_value="0",
|
||||
# # Optional:
|
||||
# column_names=None, # =[...]
|
||||
).outputs["transformed_table"]
|
||||
|
||||
split_task = split_rows_into_subsets_op(
|
||||
table=dataset,
|
||||
fraction_1=training_set_fraction,
|
||||
)
|
||||
training_data = split_task.outputs["split_1"]
|
||||
testing_data = split_task.outputs["split_2"]
|
||||
|
||||
model = train_XGBoost_model_on_CSV_op(
|
||||
training_data=training_data,
|
||||
label_column_name=label_column,
|
||||
# Optional:
|
||||
#starting_model=None,
|
||||
#num_iterations=10,
|
||||
#booster_params={},
|
||||
#objective="reg:squarederror",
|
||||
#booster="gbtree",
|
||||
#learning_rate=0.3,
|
||||
#min_split_loss=0,
|
||||
#max_depth=6,
|
||||
).outputs["model"]
|
||||
|
||||
# Predicting on the testing data
|
||||
predictions = xgboost_predict_on_CSV_op(
|
||||
data=testing_data,
|
||||
model=model,
|
||||
# label_column needs to be set when doing prediction on a dataset that has labels
|
||||
label_column_name=label_column,
|
||||
).outputs["predictions"]
|
||||
|
||||
vertex_model_name = upload_XGBoost_model_to_Google_Cloud_Vertex_AI_op(
|
||||
model=model,
|
||||
).outputs["model_name"]
|
||||
|
||||
# Deploying the model might incur additional costs over time
|
||||
if deploy_model:
|
||||
vertex_endpoint_name = deploy_model_to_endpoint_op(
|
||||
model_name=vertex_model_name,
|
||||
).outputs["endpoint_name"]
|
||||
|
||||
pipeline_func = train_tabular_regression_model_using_XGBoost_pipeline
|
||||
|
||||
# %% Pipeline submission
|
||||
if __name__ == '__main__':
|
||||
from google.cloud import aiplatform
|
||||
aiplatform.PipelineJob.from_pipeline_func(pipeline_func=pipeline_func).submit()
|
||||
+238
@@ -0,0 +1,238 @@
|
||||
name: Train tabular regression model using all frameworks pipeline
|
||||
metadata:
|
||||
annotations:
|
||||
author: Alexey Volkov <alexey.volkov@ark-kun.com>
|
||||
canonical_location: https://raw.githubusercontent.com/Ark-kun/pipeline_components/master/samples/Google_Cloud_Vertex_AI/Train_tabular_regression_model_using_all_frameworks_and_import_to_Vertex_AI/pipeline.component.yaml
|
||||
sdk: https://cloud-pipelines.net/pipeline-editor/
|
||||
implementation:
|
||||
graph:
|
||||
tasks:
|
||||
Download from GCS:
|
||||
componentRef:
|
||||
digest: 4175c9ff143cb8cc75d05451c0a0ebdf5a0d6d020816e29f5e9cefbb7d56f241
|
||||
url: https://raw.githubusercontent.com/Ark-kun/pipeline_components/27a5ea25e849c9e8c0cb6ed65518bc3ece259aaf/components/google-cloud/storage/download/workaround_for_buggy_KFPv2_compiler/component.yaml
|
||||
arguments:
|
||||
GCS path: gs://ml-pipeline-dataset/Chicago_taxi_trips/chicago_taxi_trips_2019-01-01_-_2019-02-01_limit=10000.csv
|
||||
annotations:
|
||||
editor.position: '{"x":550,"y":40,"width":180,"height":40}'
|
||||
Select columns using Pandas on CSV data:
|
||||
componentRef:
|
||||
digest: 9b9500f461c1d04f1e48992de9138db14a6800f23649d73048673d5ea6dc56ad
|
||||
url: https://raw.githubusercontent.com/Ark-kun/pipeline_components/8c78aae096806cff3bc331a40566f42f5c3e9d4b/components/pandas/Select_columns/in_CSV_format/component.yaml
|
||||
arguments:
|
||||
table:
|
||||
taskOutput:
|
||||
outputName: Data
|
||||
taskId: Download from GCS
|
||||
column_names: '["tips", "trip_seconds", "trip_miles", "pickup_community_area", "dropoff_community_area", "fare", "tolls", "extras"]'
|
||||
annotations:
|
||||
editor.position: '{"x":550,"y":140,"width":180,"height":54}'
|
||||
Fill all missing values using Pandas on CSV data:
|
||||
componentRef:
|
||||
digest: a1b0c29a4615f2e3652aa5d31b9255fa15700e146627c755f8fc172f82e71af7
|
||||
url: https://raw.githubusercontent.com/Ark-kun/pipeline_components/23405971f5f16a41b16c343129b893c52e4d1d48/components/pandas/Fill_all_missing_values/in_CSV_format/component.yaml
|
||||
arguments:
|
||||
table:
|
||||
taskOutput:
|
||||
outputName: transformed_table
|
||||
taskId: Select columns using Pandas on CSV data
|
||||
type: CSV
|
||||
replacement_value: '0'
|
||||
annotations:
|
||||
editor.position: '{"x":550,"y":250,"width":180,"height":54}'
|
||||
Split rows into subsets:
|
||||
componentRef:
|
||||
digest: a609c3c9196484290f24a1174955f95b27f07a7b458aa5cb8cde28866cb2cb46
|
||||
url: https://raw.githubusercontent.com/Ark-kun/pipeline_components/daae5a4abaa35e44501818b1534ed7827d7da073/components/dataset_manipulation/Split_rows_into_subsets/in_CSV/component.yaml
|
||||
arguments:
|
||||
table:
|
||||
taskOutput:
|
||||
outputName: transformed_table
|
||||
taskId: Fill all missing values using Pandas on CSV data
|
||||
type: CSV
|
||||
fraction_1: '0.8'
|
||||
annotations:
|
||||
editor.position: '{"x":550,"y":360,"width":180,"height":40}'
|
||||
Create fully connected pytorch network:
|
||||
componentRef:
|
||||
digest: d03d8248fd358a0275ec33568ee7dd7dce576cc112b09dfafe2651e4d97e04a9
|
||||
url: https://raw.githubusercontent.com/Ark-kun/pipeline_components/1a2ef3eeb77bc278f33cad0dd29008ea2431e191/components/PyTorch/Create_fully_connected_network/component.yaml
|
||||
arguments:
|
||||
input_size: '7'
|
||||
hidden_layer_sizes: '[10]'
|
||||
activation_name: elu
|
||||
annotations:
|
||||
editor.position: '{"x":380,"y":490,"width":180,"height":54}'
|
||||
Create fully connected tensorflow network:
|
||||
componentRef:
|
||||
digest: bfcafbc5ce711b1f69cabf1338212d10d50136a73db9f9f7c984de7b80b4bfb0
|
||||
url: https://raw.githubusercontent.com/Ark-kun/pipeline_components/9ca0f9eecf5f896f65b8538bbd809747052617d1/components/tensorflow/Create_fully_connected_network/component.yaml
|
||||
arguments:
|
||||
input_size: '7'
|
||||
hidden_layer_sizes: '[10]'
|
||||
activation_name: elu
|
||||
annotations:
|
||||
editor.position: '{"x":40,"y":500,"width":180,"height":54}'
|
||||
Train model using Keras on CSV:
|
||||
componentRef:
|
||||
digest: 42ae60c889034dbad74815653e95b4f7d576b5f47f803173e8679c7b54984609
|
||||
url: https://raw.githubusercontent.com/Ark-kun/pipeline_components/c504a4010348c50eaaf6d4337586ccc008f4dcef/components/tensorflow/Train_model_using_Keras/on_CSV/component.yaml
|
||||
arguments:
|
||||
training_data:
|
||||
taskOutput:
|
||||
outputName: split_1
|
||||
taskId: Split rows into subsets
|
||||
type: CSV
|
||||
model:
|
||||
taskOutput:
|
||||
outputName: model
|
||||
taskId: Create fully connected tensorflow network
|
||||
type: TensorflowSavedModel
|
||||
label_column_name: tips
|
||||
number_of_epochs: '10'
|
||||
metric_names: '["mean_absolute_error"]'
|
||||
annotations:
|
||||
editor.position: '{"x":40,"y":620,"width":180,"height":54}'
|
||||
Train pytorch model from csv:
|
||||
componentRef:
|
||||
digest: 40f3185eb61e9727f41a4e0c05dd3d3b44bd802aa0f378cfc31756560033949a
|
||||
url: https://raw.githubusercontent.com/Ark-kun/pipeline_components/d8c4cf5e6403bc65bcf8d606e6baf87e2528a3dc/components/PyTorch/Train_PyTorch_model/from_CSV/component.yaml
|
||||
arguments:
|
||||
model:
|
||||
taskOutput:
|
||||
outputName: model
|
||||
taskId: Create fully connected pytorch network
|
||||
type: PyTorchScriptModule
|
||||
training_data:
|
||||
taskOutput:
|
||||
outputName: split_1
|
||||
taskId: Split rows into subsets
|
||||
type: CSV
|
||||
label_column_name: tips
|
||||
annotations:
|
||||
editor.position: '{"x":380,"y":620,"width":180,"height":40}'
|
||||
Train XGBoost model on CSV:
|
||||
componentRef:
|
||||
digest: 538c5a01eb38deaf532d619f0bbeaff4efc550fe1f0f776fc06791097b68ceac
|
||||
url: https://raw.githubusercontent.com/Ark-kun/pipeline_components/58d3a47f904f32a64af8403330ba7e2134cae46d/components/XGBoost/Train/component.yaml
|
||||
arguments:
|
||||
training_data:
|
||||
taskOutput:
|
||||
outputName: split_1
|
||||
taskId: Split rows into subsets
|
||||
type: CSV
|
||||
label_column_name: tips
|
||||
annotations:
|
||||
editor.position: '{"x":720,"y":620,"width":180,"height":40}'
|
||||
Train linear regression model using scikit learn from CSV:
|
||||
componentRef:
|
||||
digest: c7fe7912ab0d1fb45d201d452e9ce6be5544e7d8c6d229db7a4b931ff58560f3
|
||||
url: https://raw.githubusercontent.com/Ark-kun/pipeline_components/f807e02b54d4886c65a05f40848fd51c72407f40/components/ML_frameworks/Scikit_learn/Train_linear_regression_model/from_CSV/component.yaml
|
||||
arguments:
|
||||
dataset:
|
||||
taskOutput:
|
||||
outputName: split_1
|
||||
taskId: Split rows into subsets
|
||||
type: CSV
|
||||
label_column_name: tips
|
||||
annotations:
|
||||
editor.position: '{"x":1030,"y":620,"width":180,"height":54}'
|
||||
Predict with TensorFlow model on CSV data:
|
||||
componentRef:
|
||||
digest: 921bb1563e93a78233b8acceab87055b9154ccf5595d056028cf0396ca224cd4
|
||||
url: https://raw.githubusercontent.com/Ark-kun/pipeline_components/59c759ce6f543184e30db6817d2a703879bc0f39/components/tensorflow/Predict/on_CSV/component.yaml
|
||||
arguments:
|
||||
dataset:
|
||||
taskOutput:
|
||||
outputName: split_2
|
||||
taskId: Split rows into subsets
|
||||
type: CSV
|
||||
model:
|
||||
taskOutput:
|
||||
outputName: trained_model
|
||||
taskId: Train model using Keras on CSV
|
||||
type: TensorflowSavedModel
|
||||
label_column_name: tips
|
||||
annotations:
|
||||
editor.position: '{"x":160,"y":750,"width":180,"height":54}'
|
||||
Create PyTorch Model Archive with base handler:
|
||||
componentRef:
|
||||
digest: 8298b5ee1b0f0879f893add4cf352c8dec7cf9e21bb9db134c91a2d046cdb0ec
|
||||
url: https://raw.githubusercontent.com/Ark-kun/pipeline_components/46d51383e6554b7f3ab4fd8cf614d8c2b422fb22/components/PyTorch/Create_PyTorch_Model_Archive/with_base_handler/component.yaml
|
||||
arguments:
|
||||
Model:
|
||||
taskOutput:
|
||||
outputName: trained_model
|
||||
taskId: Train pytorch model from csv
|
||||
type: PyTorchScriptModule
|
||||
Model name: model
|
||||
Model version: '1.0'
|
||||
annotations:
|
||||
editor.position: '{"x":380,"y":750,"width":180,"height":54}'
|
||||
Xgboost predict on CSV:
|
||||
componentRef:
|
||||
digest: 0876233a0c7306fefec188bd70f059b46d1fb5aa57be231799570e3bbbdd0d95
|
||||
url: https://raw.githubusercontent.com/Ark-kun/pipeline_components/4694ec97baccf59284c2a1db4aa2250c22291eab/components/XGBoost/Predict/component.yaml
|
||||
arguments:
|
||||
data:
|
||||
taskOutput:
|
||||
outputName: split_2
|
||||
taskId: Split rows into subsets
|
||||
type: CSV
|
||||
model:
|
||||
taskOutput:
|
||||
outputName: model
|
||||
taskId: Train XGBoost model on CSV
|
||||
type: XGBoostModel
|
||||
label_column_name: tips
|
||||
annotations:
|
||||
editor.position: '{"x":810,"y":750,"width":180,"height":40}'
|
||||
Upload Scikit learn pickle model to Google Cloud Vertex AI:
|
||||
componentRef:
|
||||
digest: 81c91c8d7d21ec97e0872f669d68bd89edea87279d703685db54aa94743bebcd
|
||||
url: https://raw.githubusercontent.com/Ark-kun/pipeline_components/c6a8b67d1ada2cc17665c99ff6b410df588bee28/components/google-cloud/Vertex_AI/Models/Upload_Scikit-learn_pickle_model/workaround_for_buggy_KFPv2_compiler/component.yaml
|
||||
arguments:
|
||||
model:
|
||||
taskOutput:
|
||||
outputName: model
|
||||
taskId: Train linear regression model using scikit learn from CSV
|
||||
type: ScikitLearnPickleModel
|
||||
annotations:
|
||||
editor.position: '{"x":1030,"y":750,"width":180,"height":70}'
|
||||
Upload Tensorflow model to Google Cloud Vertex AI:
|
||||
componentRef:
|
||||
digest: 2e45263ff640b1a688e359b6936e27a81b2407749a84f340af2aa5547e0cb92c
|
||||
url: https://raw.githubusercontent.com/Ark-kun/pipeline_components/c6a8b67d1ada2cc17665c99ff6b410df588bee28/components/google-cloud/Vertex_AI/Models/Upload_Tensorflow_model/workaround_for_buggy_KFPv2_compiler/component.yaml
|
||||
arguments:
|
||||
model:
|
||||
taskOutput:
|
||||
outputName: trained_model
|
||||
taskId: Train model using Keras on CSV
|
||||
type: TensorflowSavedModel
|
||||
annotations:
|
||||
editor.position: '{"x":40,"y":880,"width":180,"height":54}'
|
||||
Upload PyTorch model archive to Google Cloud Vertex AI:
|
||||
componentRef:
|
||||
digest: 4450212fae7b9001482aca7eb78b28413c205506eccf08a04e7754a8dfa99004
|
||||
url: https://raw.githubusercontent.com/Ark-kun/pipeline_components/c6a8b67d1ada2cc17665c99ff6b410df588bee28/components/google-cloud/Vertex_AI/Models/Upload_PyTorch_model_archive/workaround_for_buggy_KFPv2_compiler/component.yaml
|
||||
arguments:
|
||||
model_archive:
|
||||
taskOutput:
|
||||
outputName: Model archive
|
||||
taskId: Create PyTorch Model Archive with base handler
|
||||
type: PyTorchModelArchive
|
||||
annotations:
|
||||
editor.position: '{"x":380,"y":880,"width":180,"height":70}'
|
||||
Upload XGBoost model to Google Cloud Vertex AI:
|
||||
componentRef:
|
||||
digest: 5a5a273c403670743820986c03a4175b7cb4595a556524fefcce403656286977
|
||||
url: https://raw.githubusercontent.com/Ark-kun/pipeline_components/c6a8b67d1ada2cc17665c99ff6b410df588bee28/components/google-cloud/Vertex_AI/Models/Upload_XGBoost_model/workaround_for_buggy_KFPv2_compiler/component.yaml
|
||||
arguments:
|
||||
model:
|
||||
taskOutput:
|
||||
outputName: model
|
||||
taskId: Train XGBoost model on CSV
|
||||
type: XGBoostModel
|
||||
annotations:
|
||||
editor.position: '{"x":720,"y":880,"width":180,"height":54}'
|
||||
outputValues: {}
|
||||
+208
@@ -0,0 +1,208 @@
|
||||
# python3 -m pip install "kfp<2.0.0" "google-cloud-aiplatform>=1.16.0" --upgrade --quiet
|
||||
from kfp import components
|
||||
|
||||
# %% Loading components
|
||||
download_from_gcs_op = components.load_component_from_url("https://raw.githubusercontent.com/GoogleCloudPlatform/vertex-ai-samples/399405402d95f4a011e2d2e967c96f8508ba5688/community-content/pipeline_components/google-cloud/storage/download/component.yaml")
|
||||
select_columns_using_Pandas_on_CSV_data_op = components.load_component_from_url("https://raw.githubusercontent.com/GoogleCloudPlatform/vertex-ai-samples/399405402d95f4a011e2d2e967c96f8508ba5688/community-content/pipeline_components/pandas/Select_columns/in_CSV_format/component.yaml")
|
||||
fill_all_missing_values_using_Pandas_on_CSV_data_op = components.load_component_from_url("https://raw.githubusercontent.com/GoogleCloudPlatform/vertex-ai-samples/399405402d95f4a011e2d2e967c96f8508ba5688/community-content/pipeline_components/pandas/Fill_all_missing_values/in_CSV_format/component.yaml")
|
||||
split_rows_into_subsets_op = components.load_component_from_url("https://raw.githubusercontent.com/GoogleCloudPlatform/vertex-ai-samples/399405402d95f4a011e2d2e967c96f8508ba5688/community-content/pipeline_components/dataset_manipulation/Split_rows_into_subsets/in_CSV/component.yaml")
|
||||
|
||||
# TensorFlow
|
||||
create_fully_connected_tensorflow_network_op = components.load_component_from_url("https://raw.githubusercontent.com/GoogleCloudPlatform/vertex-ai-samples/399405402d95f4a011e2d2e967c96f8508ba5688/community-content/pipeline_components/tensorflow/Create_fully_connected_network/component.yaml")
|
||||
train_model_using_Keras_on_CSV_op = components.load_component_from_url("https://raw.githubusercontent.com/GoogleCloudPlatform/vertex-ai-samples/399405402d95f4a011e2d2e967c96f8508ba5688/community-content/pipeline_components/tensorflow/Train_model_using_Keras/on_CSV/component.yaml")
|
||||
predict_with_TensorFlow_model_on_CSV_data_op = components.load_component_from_url("https://raw.githubusercontent.com/GoogleCloudPlatform/vertex-ai-samples/399405402d95f4a011e2d2e967c96f8508ba5688/community-content/pipeline_components/tensorflow/Predict/on_CSV/component.yaml")
|
||||
upload_Tensorflow_model_to_Google_Cloud_Vertex_AI_op = components.load_component_from_url("https://raw.githubusercontent.com/GoogleCloudPlatform/vertex-ai-samples/399405402d95f4a011e2d2e967c96f8508ba5688/community-content/pipeline_components/google-cloud/Vertex_AI/Models/Upload_Tensorflow_model/component.yaml")
|
||||
|
||||
# PyTorch
|
||||
create_fully_connected_pytorch_network_op = components.load_component_from_url("https://raw.githubusercontent.com/GoogleCloudPlatform/vertex-ai-samples/399405402d95f4a011e2d2e967c96f8508ba5688/community-content/pipeline_components/PyTorch/Create_fully_connected_network/component.yaml")
|
||||
train_pytorch_model_from_csv_op = components.load_component_from_url("https://raw.githubusercontent.com/GoogleCloudPlatform/vertex-ai-samples/399405402d95f4a011e2d2e967c96f8508ba5688/community-content/pipeline_components/PyTorch/Train_PyTorch_model/from_CSV/component.yaml")
|
||||
create_pytorch_model_archive_with_base_handler_op = components.load_component_from_url("https://raw.githubusercontent.com/GoogleCloudPlatform/vertex-ai-samples/399405402d95f4a011e2d2e967c96f8508ba5688/community-content/pipeline_components/PyTorch/Create_PyTorch_Model_Archive/with_base_handler/component.yaml")
|
||||
upload_PyTorch_model_archive_to_Google_Cloud_Vertex_AI_op = components.load_component_from_url("https://raw.githubusercontent.com/GoogleCloudPlatform/vertex-ai-samples/399405402d95f4a011e2d2e967c96f8508ba5688/community-content/pipeline_components/google-cloud/Vertex_AI/Models/Upload_PyTorch_model_archive/component.yaml")
|
||||
|
||||
# XGBoost
|
||||
train_XGBoost_model_on_CSV_op = components.load_component_from_url("https://raw.githubusercontent.com/GoogleCloudPlatform/vertex-ai-samples/399405402d95f4a011e2d2e967c96f8508ba5688/community-content/pipeline_components/XGBoost/Train/component.yaml")
|
||||
xgboost_predict_on_CSV_op = components.load_component_from_url("https://raw.githubusercontent.com/GoogleCloudPlatform/vertex-ai-samples/399405402d95f4a011e2d2e967c96f8508ba5688/community-content/pipeline_components/XGBoost/Predict/component.yaml")
|
||||
upload_XGBoost_model_to_Google_Cloud_Vertex_AI_op = components.load_component_from_url("https://raw.githubusercontent.com/GoogleCloudPlatform/vertex-ai-samples/399405402d95f4a011e2d2e967c96f8508ba5688/community-content/pipeline_components/google-cloud/Vertex_AI/Models/Upload_XGBoost_model/component.yaml")
|
||||
|
||||
# Scikit-learn
|
||||
train_linear_regression_model_using_scikit_learn_from_CSV_op = components.load_component_from_url("https://raw.githubusercontent.com/GoogleCloudPlatform/vertex-ai-samples/1f5cf6e06409b704064b2086c0a705e4e6b4fcde/community-content/pipeline_components/ML_frameworks/Scikit_learn/Train_linear_regression_model/from_CSV/component.yaml")
|
||||
upload_Scikit_learn_pickle_model_to_Google_Cloud_Vertex_AI_op = components.load_component_from_url("https://raw.githubusercontent.com/GoogleCloudPlatform/vertex-ai-samples/399405402d95f4a011e2d2e967c96f8508ba5688/community-content/pipeline_components/google-cloud/Vertex_AI/Models/Upload_Scikit-learn_pickle_model/component.yaml")
|
||||
|
||||
# Vertex AI
|
||||
deploy_model_to_endpoint_op = components.load_component_from_url("https://raw.githubusercontent.com/GoogleCloudPlatform/vertex-ai-samples/399405402d95f4a011e2d2e967c96f8508ba5688/community-content/pipeline_components/google-cloud/Vertex_AI/Models/Deploy_to_endpoint/component.yaml")
|
||||
|
||||
# %% Pipeline definition
|
||||
def train_tabular_regression_model_using_all_frameworks_pipeline():
|
||||
dataset_gcs_uri = "gs://ml-pipeline-dataset/Chicago_taxi_trips/chicago_taxi_trips_2019-01-01_-_2019-02-01_limit=10000.csv"
|
||||
feature_columns = ["trip_seconds", "trip_miles", "pickup_community_area", "dropoff_community_area", "fare", "tolls", "extras"] # Excluded "trip_total"
|
||||
label_column = "tips"
|
||||
training_set_fraction = 0.8
|
||||
# Deploying the model might incur additional costs over time
|
||||
deploy_model = False
|
||||
|
||||
all_columns = [label_column] + feature_columns
|
||||
|
||||
dataset = download_from_gcs_op(
|
||||
gcs_path=dataset_gcs_uri
|
||||
).outputs["Data"]
|
||||
|
||||
dataset = select_columns_using_Pandas_on_CSV_data_op(
|
||||
table=dataset,
|
||||
column_names=all_columns,
|
||||
).outputs["transformed_table"]
|
||||
|
||||
dataset = fill_all_missing_values_using_Pandas_on_CSV_data_op(
|
||||
table=dataset,
|
||||
replacement_value="0",
|
||||
# # Optional:
|
||||
# column_names=None, # =[...]
|
||||
).outputs["transformed_table"]
|
||||
|
||||
split_task = split_rows_into_subsets_op(
|
||||
table=dataset,
|
||||
fraction_1=training_set_fraction,
|
||||
)
|
||||
training_data = split_task.outputs["split_1"]
|
||||
testing_data = split_task.outputs["split_2"]
|
||||
|
||||
# TensorFlow
|
||||
tensorflow_network = create_fully_connected_tensorflow_network_op(
|
||||
input_size=len(feature_columns),
|
||||
# Optional:
|
||||
hidden_layer_sizes=[10],
|
||||
activation_name="elu",
|
||||
# output_activation_name=None,
|
||||
# output_size=1,
|
||||
).outputs["model"]
|
||||
|
||||
tensorflow_model = train_model_using_Keras_on_CSV_op(
|
||||
training_data=training_data,
|
||||
model=tensorflow_network,
|
||||
label_column_name=label_column,
|
||||
# Optional:
|
||||
#loss_function_name="mean_squared_error",
|
||||
number_of_epochs=10,
|
||||
#learning_rate=0.1,
|
||||
#optimizer_name="Adadelta",
|
||||
#optimizer_parameters={},
|
||||
#batch_size=32,
|
||||
metric_names=["mean_absolute_error"],
|
||||
#random_seed=0,
|
||||
).outputs["trained_model"]
|
||||
|
||||
tensorflow_predictions = predict_with_TensorFlow_model_on_CSV_data_op(
|
||||
dataset=testing_data,
|
||||
model=tensorflow_model,
|
||||
# label_column_name needs to be set when doing prediction on a dataset that has labels
|
||||
label_column_name=label_column,
|
||||
# Optional:
|
||||
# batch_size=1000,
|
||||
).outputs["predictions"]
|
||||
|
||||
tensorflow_vertex_model_name = upload_Tensorflow_model_to_Google_Cloud_Vertex_AI_op(
|
||||
model=tensorflow_model,
|
||||
).outputs["model_name"]
|
||||
|
||||
# Deploying the model might incur additional costs over time
|
||||
if deploy_model:
|
||||
tensorflow_vertex_endpoint_name = deploy_model_to_endpoint_op(
|
||||
model_name=tensorflow_vertex_model_name,
|
||||
).outputs["endpoint_name"]
|
||||
|
||||
# PyTorch
|
||||
pytorch_network = create_fully_connected_pytorch_network_op(
|
||||
input_size=len(feature_columns),
|
||||
# Optional:
|
||||
hidden_layer_sizes=[10],
|
||||
activation_name="elu",
|
||||
# output_activation_name=None,
|
||||
# output_size=1,
|
||||
).outputs["model"]
|
||||
|
||||
pytorch_model = train_pytorch_model_from_csv_op(
|
||||
model=pytorch_network,
|
||||
training_data=training_data,
|
||||
label_column_name=label_column,
|
||||
# Optional:
|
||||
#loss_function_name="mse_loss",
|
||||
#number_of_epochs=1,
|
||||
#learning_rate=0.1,
|
||||
#optimizer_name="Adadelta",
|
||||
#optimizer_parameters={},
|
||||
#batch_size=32,
|
||||
#batch_log_interval=100,
|
||||
#random_seed=0,
|
||||
).outputs["trained_model"]
|
||||
|
||||
pytorch_model_archive = create_pytorch_model_archive_with_base_handler_op(
|
||||
model=pytorch_model,
|
||||
# Optional:
|
||||
# model_name="model",
|
||||
# model_version="1.0",
|
||||
).outputs["Model archive"]
|
||||
|
||||
pytorch_vertex_model_name = upload_PyTorch_model_archive_to_Google_Cloud_Vertex_AI_op(
|
||||
model_archive=pytorch_model_archive,
|
||||
).outputs["model_name"]
|
||||
|
||||
# Deploying the model might incur additional costs over time
|
||||
if deploy_model:
|
||||
pytorch_vertex_endpoint_name = deploy_model_to_endpoint_op(
|
||||
model_name=pytorch_vertex_model_name,
|
||||
).outputs["endpoint_name"]
|
||||
|
||||
# XGBoost
|
||||
xgboost_model = train_XGBoost_model_on_CSV_op(
|
||||
training_data=training_data,
|
||||
label_column_name=label_column,
|
||||
# Optional:
|
||||
#starting_model=None,
|
||||
#num_iterations=10,
|
||||
#booster_params={},
|
||||
#objective="reg:squarederror",
|
||||
#booster="gbtree",
|
||||
#learning_rate=0.3,
|
||||
#min_split_loss=0,
|
||||
#max_depth=6,
|
||||
).outputs["model"]
|
||||
|
||||
# Predicting on the testing data
|
||||
xgboost_predictions = xgboost_predict_on_CSV_op(
|
||||
data=testing_data,
|
||||
model=xgboost_model,
|
||||
# label_column needs to be set when doing prediction on a dataset that has labels
|
||||
label_column_name=label_column,
|
||||
).outputs["predictions"]
|
||||
|
||||
xgboost_vertex_model_name = upload_XGBoost_model_to_Google_Cloud_Vertex_AI_op(
|
||||
model=xgboost_model,
|
||||
).outputs["model_name"]
|
||||
|
||||
# Deploying the model might incur additional costs over time
|
||||
if deploy_model:
|
||||
xgboost_vertex_endpoint_name = deploy_model_to_endpoint_op(
|
||||
model_name=xgboost_vertex_model_name,
|
||||
).outputs["endpoint_name"]
|
||||
|
||||
# Scikit-learn
|
||||
sklearn_model = train_linear_regression_model_using_scikit_learn_from_CSV_op(
|
||||
dataset=training_data,
|
||||
label_column_name=label_column,
|
||||
).outputs["model"]
|
||||
|
||||
sklearn_vertex_model_name = upload_Scikit_learn_pickle_model_to_Google_Cloud_Vertex_AI_op(
|
||||
model=sklearn_model,
|
||||
).outputs["model_name"]
|
||||
|
||||
# Deploying the model might incur additional costs over time
|
||||
if deploy_model:
|
||||
sklearn_vertex_endpoint_name = deploy_model_to_endpoint_op(
|
||||
model_name=sklearn_vertex_model_name,
|
||||
).outputs["endpoint_name"]
|
||||
|
||||
pipeline_func=train_tabular_regression_model_using_all_frameworks_pipeline
|
||||
|
||||
# %% Pipeline submission
|
||||
if __name__ == '__main__':
|
||||
from google.cloud import aiplatform
|
||||
aiplatform.PipelineJob.from_pipeline_func(pipeline_func=pipeline_func).submit()
|
||||
@@ -2,4 +2,5 @@ cpr_model_server.py
|
||||
entrypoint.py
|
||||
state_dict.pth
|
||||
config.json
|
||||
**/__pycache__
|
||||
**/__pycache__
|
||||
!testdata/**
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
## About CPR
|
||||
|
||||
CPR ([custom prediction routines](https://github.com/googleapis/python-aiplatform/blob/custom-prediction-routine/google/cloud/aiplatform/prediction/README.md)) is a framework designed by Google Cloud developers to make it easier to combine machine learning models with custom preprocessing and postprocessing logic in a real-time serving application.
|
||||
CPR ([custom prediction routines](https://github.com/googleapis/python-aiplatform/blob/main/google/cloud/aiplatform/prediction/README.md)) is a framework designed by Google Cloud developers to make it easier to combine machine learning models with custom preprocessing and postprocessing logic in a real-time serving application.
|
||||
|
||||
## Using this example
|
||||
|
||||
@@ -34,6 +34,23 @@ Finally, install the Python modules required to build and run the model server:
|
||||
pip install -r requirements.txt
|
||||
```
|
||||
|
||||
### Auth
|
||||
|
||||
This example uses Google Cloud Storage for hosting model artifacts and Artifact Registry to store the container image.
|
||||
You'll need to authorize yourself before you can interact with these.
|
||||
|
||||
First, log in to GCP with application default credentials:
|
||||
```sh
|
||||
gcloud auth application-default login
|
||||
```
|
||||
|
||||
Next, if you haven't done so already, set up the [gcloud credential helper](https://cloud.google.com/artifact-registry/docs/docker/authentication)
|
||||
for the Artifact Registry region where you intend to host the image.
|
||||
```
|
||||
gcloud auth configure-docker <region>-docker.pkg.dev
|
||||
```
|
||||
|
||||
|
||||
### Predictor
|
||||
|
||||
The `TimmPredictor` class in `timm_serving/predictor.py` implements most of the important logic for the server.
|
||||
|
||||
@@ -60,9 +60,9 @@ class CPRConfig(object):
|
||||
image: str = "timm_predictor:latest"
|
||||
artifact_local_dir: str = ""
|
||||
region: str = "us-central1"
|
||||
project_id: str = "samthrasher-experimental"
|
||||
project_id: str = "<your project ID here>"
|
||||
repository: str = "cpr-images"
|
||||
artifact_gcs_dir: str = "gs://samthrasher-cpr-example/timm-vit224/"
|
||||
artifact_gcs_dir: str = "gs://<your bucket ID here>/timm-vit224/"
|
||||
model_name: str = ""
|
||||
endpoint_name: str = ""
|
||||
machine_type: str = "n1-standard-2"
|
||||
|
||||
@@ -5,4 +5,4 @@ timm==0.5.4
|
||||
smart_open==6.0.0
|
||||
|
||||
google-cloud-storage>=1.26.0,<2.0.0dev
|
||||
google-cloud-aiplatform[prediction] @ git+https://github.com/googleapis/python-aiplatform.git@custom-prediction-routine
|
||||
google-cloud-aiplatform[prediction]>=1.16.0
|
||||
@@ -70,7 +70,10 @@ class PredictorUnitTests(absltest.TestCase):
|
||||
def setUp(self):
|
||||
super().setUp()
|
||||
self.config = CPRConfig()
|
||||
self.config.load()
|
||||
try:
|
||||
self.config.load()
|
||||
except FileNotFoundError:
|
||||
logging.info("No saved config file found, using default values.")
|
||||
self.predictor = predictor.TimmPredictor()
|
||||
|
||||
def test_load_from_saved_state_dict_ok(self):
|
||||
@@ -170,7 +173,10 @@ class ServerEndToEndTests(absltest.TestCase):
|
||||
def setUp(self):
|
||||
super().setUp()
|
||||
self.config = CPRConfig()
|
||||
self.config.load()
|
||||
try:
|
||||
self.config.load()
|
||||
except FileNotFoundError:
|
||||
logging.info("No saved config file found, using default values.")
|
||||
self.local_model = cpr.LocalModel(
|
||||
serving_container_spec=aiplatform.gapic.ModelContainerSpec(
|
||||
image_uri=self.config.image
|
||||
|
||||
+1
@@ -0,0 +1 @@
|
||||
blah
|
||||
BIN
Binary file not shown.
+64
@@ -0,0 +1,64 @@
|
||||
name: Train linear regression model using scikit learn from CSV
|
||||
metadata:
|
||||
annotations: {author: Alexey Volkov <alexey.volkov@ark-kun.com>, canonical_location: 'https://raw.githubusercontent.com/Ark-kun/pipeline_components/master/components/ML_frameworks/Scikit_learn/Train_linear_regression_model/from_CSV/component.yaml'}
|
||||
inputs:
|
||||
- {name: dataset, type: CSV}
|
||||
- {name: label_column_name, type: String}
|
||||
outputs:
|
||||
- {name: model, type: ScikitLearnPickleModel}
|
||||
implementation:
|
||||
container:
|
||||
image: python:3.9
|
||||
command:
|
||||
- sh
|
||||
- -c
|
||||
- (PIP_DISABLE_PIP_VERSION_CHECK=1 python3 -m pip install --quiet --no-warn-script-location
|
||||
'scikit-learn==1.0.2' 'pandas==1.4.3' || PIP_DISABLE_PIP_VERSION_CHECK=1 python3
|
||||
-m pip install --quiet --no-warn-script-location 'scikit-learn==1.0.2' 'pandas==1.4.3'
|
||||
--user) && "$0" "$@"
|
||||
- sh
|
||||
- -ec
|
||||
- |
|
||||
program_path=$(mktemp)
|
||||
printf "%s" "$0" > "$program_path"
|
||||
python3 -u "$program_path" "$@"
|
||||
- |
|
||||
def _make_parent_dirs_and_return_path(file_path: str):
|
||||
import os
|
||||
os.makedirs(os.path.dirname(file_path), exist_ok=True)
|
||||
return file_path
|
||||
|
||||
def train_linear_regression_model_using_scikit_learn_from_CSV(
|
||||
dataset_path,
|
||||
model_path,
|
||||
label_column_name,
|
||||
):
|
||||
import pandas
|
||||
import pickle
|
||||
from sklearn import linear_model
|
||||
|
||||
df = pandas.read_csv(dataset_path)
|
||||
model = linear_model.LinearRegression()
|
||||
model.fit(
|
||||
X=df.drop(columns=label_column_name),
|
||||
y=df[label_column_name],
|
||||
)
|
||||
|
||||
with open(model_path, "wb") as f:
|
||||
pickle.dump(model, f)
|
||||
|
||||
import argparse
|
||||
_parser = argparse.ArgumentParser(prog='Train linear regression model using scikit learn from CSV', description='')
|
||||
_parser.add_argument("--dataset", dest="dataset_path", type=str, required=True, default=argparse.SUPPRESS)
|
||||
_parser.add_argument("--label-column-name", dest="label_column_name", type=str, required=True, default=argparse.SUPPRESS)
|
||||
_parser.add_argument("--model", dest="model_path", type=_make_parent_dirs_and_return_path, required=True, default=argparse.SUPPRESS)
|
||||
_parsed_args = vars(_parser.parse_args())
|
||||
|
||||
_outputs = train_linear_regression_model_using_scikit_learn_from_CSV(**_parsed_args)
|
||||
args:
|
||||
- --dataset
|
||||
- {inputPath: dataset}
|
||||
- --label-column-name
|
||||
- {inputValue: label_column_name}
|
||||
- --model
|
||||
- {outputPath: model}
|
||||
+163
@@ -0,0 +1,163 @@
|
||||
name: Train logistic regression model using scikit learn from CSV
|
||||
description: Train logistic regression model using Scikit-learn
|
||||
metadata:
|
||||
annotations: {author: Alexey Volkov <alexey.volkov@ark-kun.com>, canonical_location: 'https://raw.githubusercontent.com/Ark-kun/pipeline_components/master/components/ML_frameworks/Scikit_learn/Train_logistic_regression_model/from_CSV/component.yaml'}
|
||||
inputs:
|
||||
- {name: dataset, type: CSV}
|
||||
- {name: label_column_name, type: String}
|
||||
- {name: penalty, type: String, default: l2, optional: true}
|
||||
- {name: solver, type: String, default: lbfgs, optional: true}
|
||||
- {name: max_iterations, type: Integer, default: '100', optional: true}
|
||||
- {name: multi_class_mode, type: String, default: auto, optional: true}
|
||||
- {name: random_seed, type: Integer, default: '0', optional: true}
|
||||
outputs:
|
||||
- {name: model, type: ScikitLearnPickleModel}
|
||||
- {name: model_parameters, type: JsonObject}
|
||||
implementation:
|
||||
container:
|
||||
image: python:3.9
|
||||
command:
|
||||
- sh
|
||||
- -c
|
||||
- (PIP_DISABLE_PIP_VERSION_CHECK=1 python3 -m pip install --quiet --no-warn-script-location
|
||||
'scikit-learn==1.0.2' 'pandas==1.4.3' || PIP_DISABLE_PIP_VERSION_CHECK=1 python3
|
||||
-m pip install --quiet --no-warn-script-location 'scikit-learn==1.0.2' 'pandas==1.4.3'
|
||||
--user) && "$0" "$@"
|
||||
- sh
|
||||
- -ec
|
||||
- |
|
||||
program_path=$(mktemp)
|
||||
printf "%s" "$0" > "$program_path"
|
||||
python3 -u "$program_path" "$@"
|
||||
- |
|
||||
def _make_parent_dirs_and_return_path(file_path: str):
|
||||
import os
|
||||
os.makedirs(os.path.dirname(file_path), exist_ok=True)
|
||||
return file_path
|
||||
|
||||
def train_logistic_regression_model_using_scikit_learn_from_CSV(
|
||||
dataset_path,
|
||||
model_path,
|
||||
label_column_name,
|
||||
penalty = "l2", # l1, l2, elasticnet, none
|
||||
solver = "lbfgs", # newton-cg, lbfgs, liblinear, sag, saga
|
||||
max_iterations = 100,
|
||||
multi_class_mode = "auto", # auto, ovr, multinomial
|
||||
random_seed = 0,
|
||||
):
|
||||
"""Train logistic regression model using Scikit-learn
|
||||
|
||||
See https://scikit-learn.org/stable/modules/generated/sklearn.linear_model.LogisticRegression.html
|
||||
"""
|
||||
import json
|
||||
import pandas
|
||||
import pickle
|
||||
from sklearn import linear_model
|
||||
|
||||
df = pandas.read_csv(dataset_path)
|
||||
model = linear_model.LogisticRegression(
|
||||
penalty=penalty,
|
||||
#dual=False,
|
||||
#tol=1e-4,
|
||||
#C=1.0,
|
||||
#fit_intercept=True,
|
||||
#intercept_scaling=1,
|
||||
#class_weight=None,
|
||||
random_state=random_seed,
|
||||
solver=solver,
|
||||
max_iter=max_iterations,
|
||||
multi_class=multi_class_mode,
|
||||
#l1_ratio=None,
|
||||
verbose=1,
|
||||
)
|
||||
|
||||
model_parameters = model.get_params()
|
||||
model_parameters_json = json.dumps(model_parameters, indent=2)
|
||||
print("Model parameters:")
|
||||
print(model_parameters_json)
|
||||
print()
|
||||
|
||||
model.fit(
|
||||
X=df.drop(columns=label_column_name),
|
||||
y=df[label_column_name],
|
||||
)
|
||||
|
||||
with open(model_path, "wb") as f:
|
||||
pickle.dump(model, f)
|
||||
|
||||
return (model_parameters_json,)
|
||||
|
||||
def _serialize_json(obj) -> str:
|
||||
if isinstance(obj, str):
|
||||
return obj
|
||||
import json
|
||||
def default_serializer(obj):
|
||||
if hasattr(obj, 'to_struct'):
|
||||
return obj.to_struct()
|
||||
else:
|
||||
raise TypeError("Object of type '%s' is not JSON serializable and does not have .to_struct() method." % obj.__class__.__name__)
|
||||
return json.dumps(obj, default=default_serializer, sort_keys=True)
|
||||
|
||||
import argparse
|
||||
_parser = argparse.ArgumentParser(prog='Train logistic regression model using scikit learn from CSV', description='Train logistic regression model using Scikit-learn')
|
||||
_parser.add_argument("--dataset", dest="dataset_path", type=str, required=True, default=argparse.SUPPRESS)
|
||||
_parser.add_argument("--label-column-name", dest="label_column_name", type=str, required=True, default=argparse.SUPPRESS)
|
||||
_parser.add_argument("--penalty", dest="penalty", type=str, required=False, default=argparse.SUPPRESS)
|
||||
_parser.add_argument("--solver", dest="solver", type=str, required=False, default=argparse.SUPPRESS)
|
||||
_parser.add_argument("--max-iterations", dest="max_iterations", type=int, required=False, default=argparse.SUPPRESS)
|
||||
_parser.add_argument("--multi-class-mode", dest="multi_class_mode", type=str, required=False, default=argparse.SUPPRESS)
|
||||
_parser.add_argument("--random-seed", dest="random_seed", type=int, required=False, default=argparse.SUPPRESS)
|
||||
_parser.add_argument("--model", dest="model_path", type=_make_parent_dirs_and_return_path, required=True, default=argparse.SUPPRESS)
|
||||
_parser.add_argument("----output-paths", dest="_output_paths", type=str, nargs=1)
|
||||
_parsed_args = vars(_parser.parse_args())
|
||||
_output_files = _parsed_args.pop("_output_paths", [])
|
||||
|
||||
_outputs = train_logistic_regression_model_using_scikit_learn_from_CSV(**_parsed_args)
|
||||
|
||||
_output_serializers = [
|
||||
_serialize_json,
|
||||
|
||||
]
|
||||
|
||||
import os
|
||||
for idx, output_file in enumerate(_output_files):
|
||||
try:
|
||||
os.makedirs(os.path.dirname(output_file))
|
||||
except OSError:
|
||||
pass
|
||||
with open(output_file, 'w') as f:
|
||||
f.write(_output_serializers[idx](_outputs[idx]))
|
||||
args:
|
||||
- --dataset
|
||||
- {inputPath: dataset}
|
||||
- --label-column-name
|
||||
- {inputValue: label_column_name}
|
||||
- if:
|
||||
cond: {isPresent: penalty}
|
||||
then:
|
||||
- --penalty
|
||||
- {inputValue: penalty}
|
||||
- if:
|
||||
cond: {isPresent: solver}
|
||||
then:
|
||||
- --solver
|
||||
- {inputValue: solver}
|
||||
- if:
|
||||
cond: {isPresent: max_iterations}
|
||||
then:
|
||||
- --max-iterations
|
||||
- {inputValue: max_iterations}
|
||||
- if:
|
||||
cond: {isPresent: multi_class_mode}
|
||||
then:
|
||||
- --multi-class-mode
|
||||
- {inputValue: multi_class_mode}
|
||||
- if:
|
||||
cond: {isPresent: random_seed}
|
||||
then:
|
||||
- --random-seed
|
||||
- {inputValue: random_seed}
|
||||
- --model
|
||||
- {outputPath: model}
|
||||
- '----output-paths'
|
||||
- {outputPath: model_parameters}
|
||||
+41
@@ -0,0 +1,41 @@
|
||||
name: Create PyTorch Model Archive with base handler
|
||||
inputs:
|
||||
- {name: Model, type: PyTorchScriptModule}
|
||||
- {name: Model name, type: String, default: model}
|
||||
- {name: Model version, type: String, default: "1.0"}
|
||||
outputs:
|
||||
- {name: Model archive, type: PyTorchModelArchive}
|
||||
metadata:
|
||||
annotations:
|
||||
author: Alexey Volkov <alexey.volkov@ark-kun.com>
|
||||
canonical_location: 'https://raw.githubusercontent.com/Ark-kun/pipeline_components/master/components/PyTorch/Create_PyTorch_Model_Archive/with_base_handler/component.yaml'
|
||||
implementation:
|
||||
container:
|
||||
image: pytorch/torchserve:0.6.0-cpu
|
||||
command:
|
||||
- bash
|
||||
- -exc
|
||||
- |
|
||||
model_path=$0
|
||||
model_name=$1
|
||||
model_version=$2
|
||||
output_model_archive_path=$3
|
||||
|
||||
mkdir -p "$(dirname "$output_model_archive_path")"
|
||||
|
||||
# TODO: Use the built-in base_handler once my fix is merged: https://github.com/pytorch/serve/pull/1682
|
||||
echo '
|
||||
from ts.torch_handler import base_handler
|
||||
class BaseHandler(base_handler.BaseHandler):
|
||||
pass
|
||||
' > base_handler.py # torch-model-archiver needs the handler to have .py extension
|
||||
torch-model-archiver --model-name "$model_name" --version "$model_version" --serialized-file "$model_path" --handler base_handler.py
|
||||
|
||||
# torch-model-archiver does not allow specifying the output path, but always writes to "${model_name}.<format>"
|
||||
expected_model_archive_path="${model_name}.mar"
|
||||
mv "$expected_model_archive_path" "$output_model_archive_path"
|
||||
|
||||
- {inputPath: Model}
|
||||
- {inputValue: Model name}
|
||||
- {inputValue: Model version}
|
||||
- {outputPath: Model archive}
|
||||
+117
@@ -0,0 +1,117 @@
|
||||
name: Create fully connected pytorch network
|
||||
description: Creates fully-connected network in PyTorch ScriptModule format
|
||||
metadata:
|
||||
annotations: {author: Alexey Volkov <alexey.volkov@ark-kun.com>, canonical_location: 'https://raw.githubusercontent.com/Ark-kun/pipeline_components/master/components/PyTorch/Create_fully_connected_network/component.yaml'}
|
||||
inputs:
|
||||
- {name: input_size, type: Integer}
|
||||
- {name: hidden_layer_sizes, type: JsonArray, default: '[]', optional: true}
|
||||
- {name: output_size, type: Integer, default: '1', optional: true}
|
||||
- {name: activation_name, type: String, default: relu, optional: true}
|
||||
- {name: output_activation_name, type: String, optional: true}
|
||||
- {name: random_seed, type: Integer, default: '0', optional: true}
|
||||
outputs:
|
||||
- {name: model, type: PyTorchScriptModule}
|
||||
implementation:
|
||||
container:
|
||||
image: pytorch/pytorch:1.7.1-cuda11.0-cudnn8-runtime
|
||||
command:
|
||||
- sh
|
||||
- -ec
|
||||
- |
|
||||
program_path=$(mktemp)
|
||||
printf "%s" "$0" > "$program_path"
|
||||
python3 -u "$program_path" "$@"
|
||||
- |
|
||||
def _make_parent_dirs_and_return_path(file_path: str):
|
||||
import os
|
||||
os.makedirs(os.path.dirname(file_path), exist_ok=True)
|
||||
return file_path
|
||||
|
||||
def create_fully_connected_pytorch_network(
|
||||
input_size,
|
||||
model_path,
|
||||
hidden_layer_sizes = [],
|
||||
output_size = 1,
|
||||
activation_name = 'relu',
|
||||
output_activation_name = None,
|
||||
random_seed = 0,
|
||||
):
|
||||
'''Creates fully-connected network in PyTorch ScriptModule format'''
|
||||
import torch
|
||||
torch.manual_seed(random_seed)
|
||||
|
||||
activation = getattr(torch, activation_name, None) or getattr(torch.nn.functional, activation_name, None)
|
||||
if not activation:
|
||||
raise ValueError(f'Activation "{activation_name}" was not found.')
|
||||
|
||||
class ActivationLayer(torch.nn.Module):
|
||||
def forward(self, input):
|
||||
return activation(input)
|
||||
|
||||
layers = []
|
||||
prev_layer_size = input_size
|
||||
for layer_size in hidden_layer_sizes:
|
||||
layer = torch.nn.Linear(prev_layer_size, layer_size)
|
||||
prev_layer_size = layer_size
|
||||
layers.append(layer)
|
||||
layers.append(ActivationLayer())
|
||||
|
||||
# Adding the output layer
|
||||
layers.append(torch.nn.Linear(prev_layer_size, output_size))
|
||||
|
||||
# Adding the optional activation after the output layer
|
||||
if output_activation_name:
|
||||
output_activation = getattr(torch, output_activation_name, None) or getattr(torch.nn.functional, output_activation_name, None)
|
||||
class OutputActivationLayer(torch.nn.Module):
|
||||
def forward(self, input):
|
||||
return output_activation(input)
|
||||
layers.append(OutputActivationLayer())
|
||||
|
||||
network = torch.nn.Sequential(*layers)
|
||||
script_module = torch.jit.script(network)
|
||||
print(script_module)
|
||||
script_module.save(model_path)
|
||||
|
||||
import json
|
||||
import argparse
|
||||
_parser = argparse.ArgumentParser(prog='Create fully connected pytorch network', description='Creates fully-connected network in PyTorch ScriptModule format')
|
||||
_parser.add_argument("--input-size", dest="input_size", type=int, required=True, default=argparse.SUPPRESS)
|
||||
_parser.add_argument("--hidden-layer-sizes", dest="hidden_layer_sizes", type=json.loads, required=False, default=argparse.SUPPRESS)
|
||||
_parser.add_argument("--output-size", dest="output_size", type=int, required=False, default=argparse.SUPPRESS)
|
||||
_parser.add_argument("--activation-name", dest="activation_name", type=str, required=False, default=argparse.SUPPRESS)
|
||||
_parser.add_argument("--output-activation-name", dest="output_activation_name", type=str, required=False, default=argparse.SUPPRESS)
|
||||
_parser.add_argument("--random-seed", dest="random_seed", type=int, required=False, default=argparse.SUPPRESS)
|
||||
_parser.add_argument("--model", dest="model_path", type=_make_parent_dirs_and_return_path, required=True, default=argparse.SUPPRESS)
|
||||
_parsed_args = vars(_parser.parse_args())
|
||||
|
||||
_outputs = create_fully_connected_pytorch_network(**_parsed_args)
|
||||
args:
|
||||
- --input-size
|
||||
- {inputValue: input_size}
|
||||
- if:
|
||||
cond: {isPresent: hidden_layer_sizes}
|
||||
then:
|
||||
- --hidden-layer-sizes
|
||||
- {inputValue: hidden_layer_sizes}
|
||||
- if:
|
||||
cond: {isPresent: output_size}
|
||||
then:
|
||||
- --output-size
|
||||
- {inputValue: output_size}
|
||||
- if:
|
||||
cond: {isPresent: activation_name}
|
||||
then:
|
||||
- --activation-name
|
||||
- {inputValue: activation_name}
|
||||
- if:
|
||||
cond: {isPresent: output_activation_name}
|
||||
then:
|
||||
- --output-activation-name
|
||||
- {inputValue: output_activation_name}
|
||||
- if:
|
||||
cond: {isPresent: random_seed}
|
||||
then:
|
||||
- --random-seed
|
||||
- {inputValue: random_seed}
|
||||
- --model
|
||||
- {outputPath: model}
|
||||
+209
@@ -0,0 +1,209 @@
|
||||
name: Train pytorch model from csv
|
||||
description: Trains PyTorch model
|
||||
metadata:
|
||||
annotations:
|
||||
author: Alexey Volkov <alexey.volkov@ark-kun.com>
|
||||
canonical_location: 'https://raw.githubusercontent.com/Ark-kun/pipeline_components/master/components/PyTorch/Train_PyTorch_model/from_CSV/component.yaml'
|
||||
inputs:
|
||||
- {name: model, type: PyTorchScriptModule}
|
||||
- {name: training_data, type: CSV}
|
||||
- {name: label_column_name, type: String}
|
||||
- {name: loss_function_name, type: String, default: mse_loss, optional: true}
|
||||
- {name: number_of_epochs, type: Integer, default: '1', optional: true}
|
||||
- {name: learning_rate, type: Float, default: '0.1', optional: true}
|
||||
- {name: optimizer_name, type: String, default: Adadelta, optional: true}
|
||||
- {name: optimizer_parameters, type: JsonObject, optional: true}
|
||||
- {name: batch_size, type: Integer, default: '32', optional: true}
|
||||
- {name: batch_log_interval, type: Integer, default: '100', optional: true}
|
||||
- {name: random_seed, type: Integer, default: '0', optional: true}
|
||||
outputs:
|
||||
- {name: trained_model, type: PyTorchScriptModule}
|
||||
implementation:
|
||||
container:
|
||||
image: pytorch/pytorch:1.7.1-cuda11.0-cudnn8-runtime
|
||||
command:
|
||||
- sh
|
||||
- -c
|
||||
- (PIP_DISABLE_PIP_VERSION_CHECK=1 python3 -m pip install --quiet --no-warn-script-location
|
||||
'pandas==1.4.3' || PIP_DISABLE_PIP_VERSION_CHECK=1 python3 -m pip install --quiet
|
||||
--no-warn-script-location 'pandas==1.4.3' --user) && "$0" "$@"
|
||||
- sh
|
||||
- -ec
|
||||
- |
|
||||
program_path=$(mktemp)
|
||||
printf "%s" "$0" > "$program_path"
|
||||
python3 -u "$program_path" "$@"
|
||||
- |
|
||||
def _make_parent_dirs_and_return_path(file_path: str):
|
||||
import os
|
||||
os.makedirs(os.path.dirname(file_path), exist_ok=True)
|
||||
return file_path
|
||||
|
||||
def train_pytorch_model_from_csv(
|
||||
model_path,
|
||||
training_data_path,
|
||||
trained_model_path,
|
||||
label_column_name,
|
||||
loss_function_name = 'mse_loss',
|
||||
number_of_epochs = 1,
|
||||
learning_rate = 0.1,
|
||||
optimizer_name = 'Adadelta',
|
||||
optimizer_parameters = None,
|
||||
batch_size = 32,
|
||||
batch_log_interval = 100,
|
||||
random_seed = 0,
|
||||
):
|
||||
'''Trains PyTorch model'''
|
||||
import pandas
|
||||
import torch
|
||||
|
||||
torch.manual_seed(random_seed)
|
||||
|
||||
use_cuda = torch.cuda.is_available()
|
||||
device = torch.device("cuda" if use_cuda else "cpu")
|
||||
|
||||
model = torch.jit.load(model_path)
|
||||
model.to(device)
|
||||
model.train()
|
||||
|
||||
optimizer_class = getattr(torch.optim, optimizer_name, None)
|
||||
if not optimizer_class:
|
||||
raise ValueError(f'Optimizer "{optimizer_name}" was not found.')
|
||||
|
||||
optimizer_parameters = optimizer_parameters or {}
|
||||
optimizer_parameters['lr'] = learning_rate
|
||||
optimizer = optimizer_class(model.parameters(), **optimizer_parameters)
|
||||
|
||||
loss_function = getattr(torch, loss_function_name, None) or getattr(torch.nn, loss_function_name, None) or getattr(torch.nn.functional, loss_function_name, None)
|
||||
if not loss_function:
|
||||
raise ValueError(f'Loss function "{loss_function_name}" was not found.')
|
||||
|
||||
class CsvDataset(torch.utils.data.Dataset):
|
||||
|
||||
def __init__(self, file_path, label_column_name, drop_nan_columns_or_rows = 'columns'):
|
||||
dataframe = pandas.read_csv(file_path).convert_dtypes()
|
||||
# Preventing error: default_collate: batch must contain tensors, numpy arrays, numbers, dicts or lists; found object
|
||||
if drop_nan_columns_or_rows == 'columns':
|
||||
non_nan_data = dataframe.dropna(axis='columns')
|
||||
removed_columns = set(dataframe.columns) - set(non_nan_data.columns)
|
||||
if removed_columns:
|
||||
print('Skipping columns with NaNs: ' + str(removed_columns))
|
||||
dataframe = non_nan_data
|
||||
if drop_nan_columns_or_rows == 'rows':
|
||||
non_nan_data = dataframe.dropna(axis='index')
|
||||
number_of_removed_rows = len(dataframe) - len(non_nan_data)
|
||||
if number_of_removed_rows:
|
||||
print(f'Skipped {number_of_removed_rows} rows with NaNs.')
|
||||
dataframe = non_nan_data
|
||||
numerical_data = dataframe.select_dtypes(include='number')
|
||||
non_numerical_data = dataframe.select_dtypes(exclude='number')
|
||||
if not non_numerical_data.empty:
|
||||
print('Skipping non-number columns:')
|
||||
print(non_numerical_data.dtypes)
|
||||
self._dataframe = dataframe
|
||||
self.labels = numerical_data[[label_column_name]]
|
||||
self.features = numerical_data.drop(columns=[label_column_name])
|
||||
|
||||
def __len__(self):
|
||||
return len(self._dataframe)
|
||||
|
||||
def __getitem__(self, index):
|
||||
return [self.features.loc[index].to_numpy(dtype='float32'), self.labels.loc[index].to_numpy(dtype='float32')]
|
||||
|
||||
dataset = CsvDataset(
|
||||
file_path=training_data_path,
|
||||
label_column_name=label_column_name,
|
||||
)
|
||||
train_loader = torch.utils.data.DataLoader(
|
||||
dataset=dataset,
|
||||
batch_size=batch_size,
|
||||
shuffle=True,
|
||||
)
|
||||
|
||||
last_full_batch_loss = None
|
||||
for epoch in range(1, number_of_epochs + 1):
|
||||
for batch_idx, (data, target) in enumerate(train_loader):
|
||||
data, target = data.to(device), target.to(device)
|
||||
optimizer.zero_grad()
|
||||
output = model(data)
|
||||
loss = loss_function(output, target)
|
||||
loss.backward()
|
||||
optimizer.step()
|
||||
if len(data) == batch_size:
|
||||
last_full_batch_loss = loss.item()
|
||||
if batch_idx % batch_log_interval == 0:
|
||||
print('Train Epoch: {} [{}/{} ({:.0f}%)]\tLoss: {:.6f}'.format(
|
||||
epoch, batch_idx * len(data), len(train_loader.dataset),
|
||||
100. * batch_idx / len(train_loader), loss.item()))
|
||||
print(f'Training epoch {epoch} completed. Last full batch loss: {last_full_batch_loss:.6f}')
|
||||
|
||||
# print(optimizer.state_dict())
|
||||
model.save(trained_model_path)
|
||||
|
||||
import json
|
||||
import argparse
|
||||
_parser = argparse.ArgumentParser(prog='Train pytorch model from csv', description='Trains PyTorch model')
|
||||
_parser.add_argument("--model", dest="model_path", type=str, required=True, default=argparse.SUPPRESS)
|
||||
_parser.add_argument("--training-data", dest="training_data_path", type=str, required=True, default=argparse.SUPPRESS)
|
||||
_parser.add_argument("--label-column-name", dest="label_column_name", type=str, required=True, default=argparse.SUPPRESS)
|
||||
_parser.add_argument("--loss-function-name", dest="loss_function_name", type=str, required=False, default=argparse.SUPPRESS)
|
||||
_parser.add_argument("--number-of-epochs", dest="number_of_epochs", type=int, required=False, default=argparse.SUPPRESS)
|
||||
_parser.add_argument("--learning-rate", dest="learning_rate", type=float, required=False, default=argparse.SUPPRESS)
|
||||
_parser.add_argument("--optimizer-name", dest="optimizer_name", type=str, required=False, default=argparse.SUPPRESS)
|
||||
_parser.add_argument("--optimizer-parameters", dest="optimizer_parameters", type=json.loads, required=False, default=argparse.SUPPRESS)
|
||||
_parser.add_argument("--batch-size", dest="batch_size", type=int, required=False, default=argparse.SUPPRESS)
|
||||
_parser.add_argument("--batch-log-interval", dest="batch_log_interval", type=int, required=False, default=argparse.SUPPRESS)
|
||||
_parser.add_argument("--random-seed", dest="random_seed", type=int, required=False, default=argparse.SUPPRESS)
|
||||
_parser.add_argument("--trained-model", dest="trained_model_path", type=_make_parent_dirs_and_return_path, required=True, default=argparse.SUPPRESS)
|
||||
_parsed_args = vars(_parser.parse_args())
|
||||
|
||||
_outputs = train_pytorch_model_from_csv(**_parsed_args)
|
||||
args:
|
||||
- --model
|
||||
- {inputPath: model}
|
||||
- --training-data
|
||||
- {inputPath: training_data}
|
||||
- --label-column-name
|
||||
- {inputValue: label_column_name}
|
||||
- if:
|
||||
cond: {isPresent: loss_function_name}
|
||||
then:
|
||||
- --loss-function-name
|
||||
- {inputValue: loss_function_name}
|
||||
- if:
|
||||
cond: {isPresent: number_of_epochs}
|
||||
then:
|
||||
- --number-of-epochs
|
||||
- {inputValue: number_of_epochs}
|
||||
- if:
|
||||
cond: {isPresent: learning_rate}
|
||||
then:
|
||||
- --learning-rate
|
||||
- {inputValue: learning_rate}
|
||||
- if:
|
||||
cond: {isPresent: optimizer_name}
|
||||
then:
|
||||
- --optimizer-name
|
||||
- {inputValue: optimizer_name}
|
||||
- if:
|
||||
cond: {isPresent: optimizer_parameters}
|
||||
then:
|
||||
- --optimizer-parameters
|
||||
- {inputValue: optimizer_parameters}
|
||||
- if:
|
||||
cond: {isPresent: batch_size}
|
||||
then:
|
||||
- --batch-size
|
||||
- {inputValue: batch_size}
|
||||
- if:
|
||||
cond: {isPresent: batch_log_interval}
|
||||
then:
|
||||
- --batch-log-interval
|
||||
- {inputValue: batch_log_interval}
|
||||
- if:
|
||||
cond: {isPresent: random_seed}
|
||||
then:
|
||||
- --random-seed
|
||||
- {inputValue: random_seed}
|
||||
- --trained-model
|
||||
- {outputPath: trained_model}
|
||||
@@ -0,0 +1,110 @@
|
||||
name: Xgboost predict on CSV
|
||||
description: Makes predictions using a trained XGBoost model.
|
||||
metadata:
|
||||
annotations: {author: Alexey Volkov <alexey.volkov@ark-kun.com>, canonical_location: 'https://raw.githubusercontent.com/Ark-kun/pipeline_components/master/components/XGBoost/Predict/component.yaml'}
|
||||
inputs:
|
||||
- {name: data, type: CSV, description: Feature data in Apache Parquet format.}
|
||||
- {name: model, type: XGBoostModel, description: Trained model in binary XGBoost format.}
|
||||
- {name: label_column_name, type: String, description: Optional. Name of the column
|
||||
containing the label data that is excluded during the prediction., optional: true}
|
||||
outputs:
|
||||
- {name: predictions, description: Model predictions.}
|
||||
implementation:
|
||||
container:
|
||||
image: python:3.10
|
||||
command:
|
||||
- sh
|
||||
- -c
|
||||
- (PIP_DISABLE_PIP_VERSION_CHECK=1 python3 -m pip install --quiet --no-warn-script-location
|
||||
'xgboost==1.6.1' 'pandas==1.4.3' || PIP_DISABLE_PIP_VERSION_CHECK=1 python3
|
||||
-m pip install --quiet --no-warn-script-location 'xgboost==1.6.1' 'pandas==1.4.3'
|
||||
--user) && "$0" "$@"
|
||||
- sh
|
||||
- -ec
|
||||
- |
|
||||
program_path=$(mktemp)
|
||||
printf "%s" "$0" > "$program_path"
|
||||
python3 -u "$program_path" "$@"
|
||||
- |
|
||||
def _make_parent_dirs_and_return_path(file_path: str):
|
||||
import os
|
||||
os.makedirs(os.path.dirname(file_path), exist_ok=True)
|
||||
return file_path
|
||||
|
||||
def xgboost_predict_on_CSV(
|
||||
data_path,
|
||||
model_path,
|
||||
predictions_path,
|
||||
label_column_name = None,
|
||||
):
|
||||
"""Makes predictions using a trained XGBoost model.
|
||||
|
||||
Args:
|
||||
data_path: Feature data in Apache Parquet format.
|
||||
model_path: Trained model in binary XGBoost format.
|
||||
predictions_path: Model predictions.
|
||||
label_column_name: Optional. Name of the column containing the label data that is excluded during the prediction.
|
||||
|
||||
Annotations:
|
||||
author: Alexey Volkov <alexey.volkov@ark-kun.com>
|
||||
"""
|
||||
from pathlib import Path
|
||||
|
||||
import numpy
|
||||
import pandas
|
||||
import xgboost
|
||||
|
||||
df = pandas.read_csv(
|
||||
data_path,
|
||||
).convert_dtypes()
|
||||
print("Evaluation data information:")
|
||||
df.info(verbose=True)
|
||||
# Converting column types that XGBoost does not support
|
||||
for column_name, dtype in df.dtypes.items():
|
||||
if dtype in ["string", "object"]:
|
||||
print(f"Treating the {dtype.name} column '{column_name}' as categorical.")
|
||||
df[column_name] = df[column_name].astype("category")
|
||||
print(f"Inferred {len(df[column_name].cat.categories)} categories for the '{column_name}' column.")
|
||||
# Working around the XGBoost issue with nullable floats: https://github.com/dmlc/xgboost/issues/8213
|
||||
if pandas.api.types.is_float_dtype(dtype):
|
||||
# Converting from "Float64" to "float64"
|
||||
df[column_name] = df[column_name].astype(dtype.name.lower())
|
||||
print("Final evaluation data information:")
|
||||
df.info(verbose=True)
|
||||
|
||||
if label_column_name is not None:
|
||||
df = df.drop(columns=[label_column_name])
|
||||
|
||||
testing_data = xgboost.DMatrix(
|
||||
data=df,
|
||||
enable_categorical=True,
|
||||
)
|
||||
|
||||
model = xgboost.Booster(model_file=model_path)
|
||||
|
||||
predictions = model.predict(testing_data)
|
||||
|
||||
Path(predictions_path).parent.mkdir(parents=True, exist_ok=True)
|
||||
numpy.savetxt(predictions_path, predictions)
|
||||
|
||||
import argparse
|
||||
_parser = argparse.ArgumentParser(prog='Xgboost predict on CSV', description='Makes predictions using a trained XGBoost model.')
|
||||
_parser.add_argument("--data", dest="data_path", type=str, required=True, default=argparse.SUPPRESS)
|
||||
_parser.add_argument("--model", dest="model_path", type=str, required=True, default=argparse.SUPPRESS)
|
||||
_parser.add_argument("--label-column-name", dest="label_column_name", type=str, required=False, default=argparse.SUPPRESS)
|
||||
_parser.add_argument("--predictions", dest="predictions_path", type=_make_parent_dirs_and_return_path, required=True, default=argparse.SUPPRESS)
|
||||
_parsed_args = vars(_parser.parse_args())
|
||||
|
||||
_outputs = xgboost_predict_on_CSV(**_parsed_args)
|
||||
args:
|
||||
- --data
|
||||
- {inputPath: data}
|
||||
- --model
|
||||
- {inputPath: model}
|
||||
- if:
|
||||
cond: {isPresent: label_column_name}
|
||||
then:
|
||||
- --label-column-name
|
||||
- {inputValue: label_column_name}
|
||||
- --predictions
|
||||
- {outputPath: predictions}
|
||||
@@ -0,0 +1,241 @@
|
||||
name: Train XGBoost model on CSV
|
||||
description: Trains an XGBoost model.
|
||||
metadata:
|
||||
annotations: {author: Alexey Volkov <alexey.volkov@ark-kun.com>, canonical_location: 'https://raw.githubusercontent.com/Ark-kun/pipeline_components/master/components/XGBoost/Train/component.yaml'}
|
||||
inputs:
|
||||
- {name: training_data, type: CSV, description: Training data in CSV format.}
|
||||
- {name: label_column_name, type: String, description: Name of the column containing
|
||||
the label data.}
|
||||
- {name: starting_model, type: XGBoostModel, description: Existing trained model to
|
||||
start from (in the binary XGBoost format)., optional: true}
|
||||
- {name: num_iterations, type: Integer, description: Number of boosting iterations.,
|
||||
default: '10', optional: true}
|
||||
- name: objective
|
||||
type: String
|
||||
description: |-
|
||||
The learning task and the corresponding learning objective.
|
||||
See https://xgboost.readthedocs.io/en/latest/parameter.html#learning-task-parameters
|
||||
The most common values are:
|
||||
"reg:squarederror" - Regression with squared loss (default).
|
||||
"reg:logistic" - Logistic regression.
|
||||
"binary:logistic" - Logistic regression for binary classification, output probability.
|
||||
"binary:logitraw" - Logistic regression for binary classification, output score before logistic transformation
|
||||
"rank:pairwise" - Use LambdaMART to perform pairwise ranking where the pairwise loss is minimized
|
||||
"rank:ndcg" - Use LambdaMART to perform list-wise ranking where Normalized Discounted Cumulative Gain (NDCG) is maximized
|
||||
default: reg:squarederror
|
||||
optional: true
|
||||
- {name: booster, type: String, description: 'The booster to use. Can be `gbtree`,
|
||||
`gblinear` or `dart`; `gbtree` and `dart` use tree based models while `gblinear`
|
||||
uses linear functions.', default: gbtree, optional: true}
|
||||
- {name: learning_rate, type: Float, description: 'Step size shrinkage used in update
|
||||
to prevents overfitting. Range: [0,1].', default: '0.3', optional: true}
|
||||
- name: min_split_loss
|
||||
type: Float
|
||||
description: |-
|
||||
Minimum loss reduction required to make a further partition on a leaf node of the tree.
|
||||
The larger `min_split_loss` is, the more conservative the algorithm will be. Range: [0,Inf].
|
||||
default: '0'
|
||||
optional: true
|
||||
- name: max_depth
|
||||
type: Integer
|
||||
description: |-
|
||||
Maximum depth of a tree. Increasing this value will make the model more complex and more likely to overfit.
|
||||
0 indicates no limit on depth. Range: [0,Inf].
|
||||
default: '6'
|
||||
optional: true
|
||||
- {name: booster_params, type: JsonObject, description: 'Parameters for the booster.
|
||||
See https://xgboost.readthedocs.io/en/latest/parameter.html', optional: true}
|
||||
outputs:
|
||||
- {name: model, type: XGBoostModel, description: Trained model in the binary XGBoost
|
||||
format.}
|
||||
- {name: model_config, type: XGBoostModelConfig, description: The internal parameter
|
||||
configuration of Booster as a JSON string.}
|
||||
implementation:
|
||||
container:
|
||||
image: python:3.10
|
||||
command:
|
||||
- sh
|
||||
- -c
|
||||
- (PIP_DISABLE_PIP_VERSION_CHECK=1 python3 -m pip install --quiet --no-warn-script-location
|
||||
'xgboost==1.6.1' 'pandas==1.4.3' || PIP_DISABLE_PIP_VERSION_CHECK=1 python3
|
||||
-m pip install --quiet --no-warn-script-location 'xgboost==1.6.1' 'pandas==1.4.3'
|
||||
--user) && "$0" "$@"
|
||||
- sh
|
||||
- -ec
|
||||
- |
|
||||
program_path=$(mktemp)
|
||||
printf "%s" "$0" > "$program_path"
|
||||
python3 -u "$program_path" "$@"
|
||||
- |
|
||||
def _make_parent_dirs_and_return_path(file_path: str):
|
||||
import os
|
||||
os.makedirs(os.path.dirname(file_path), exist_ok=True)
|
||||
return file_path
|
||||
|
||||
def train_XGBoost_model_on_CSV(
|
||||
training_data_path,
|
||||
model_path,
|
||||
model_config_path,
|
||||
label_column_name,
|
||||
starting_model_path = None,
|
||||
num_iterations = 10,
|
||||
# Booster parameters
|
||||
objective = "reg:squarederror",
|
||||
booster = "gbtree",
|
||||
learning_rate = 0.3,
|
||||
min_split_loss = 0,
|
||||
max_depth = 6,
|
||||
booster_params = None,
|
||||
):
|
||||
"""Trains an XGBoost model.
|
||||
|
||||
Args:
|
||||
training_data_path: Training data in CSV format.
|
||||
model_path: Trained model in the binary XGBoost format.
|
||||
model_config_path: The internal parameter configuration of Booster as a JSON string.
|
||||
starting_model_path: Existing trained model to start from (in the binary XGBoost format).
|
||||
label_column_name: Name of the column containing the label data.
|
||||
num_iterations: Number of boosting iterations.
|
||||
booster_params: Parameters for the booster. See https://xgboost.readthedocs.io/en/latest/parameter.html
|
||||
objective: The learning task and the corresponding learning objective.
|
||||
See https://xgboost.readthedocs.io/en/latest/parameter.html#learning-task-parameters
|
||||
The most common values are:
|
||||
"reg:squarederror" - Regression with squared loss (default).
|
||||
"reg:logistic" - Logistic regression.
|
||||
"binary:logistic" - Logistic regression for binary classification, output probability.
|
||||
"binary:logitraw" - Logistic regression for binary classification, output score before logistic transformation
|
||||
"rank:pairwise" - Use LambdaMART to perform pairwise ranking where the pairwise loss is minimized
|
||||
"rank:ndcg" - Use LambdaMART to perform list-wise ranking where Normalized Discounted Cumulative Gain (NDCG) is maximized
|
||||
booster: The booster to use. Can be `gbtree`, `gblinear` or `dart`; `gbtree` and `dart` use tree based models while `gblinear` uses linear functions.
|
||||
learning_rate: Step size shrinkage used in update to prevents overfitting. Range: [0,1].
|
||||
min_split_loss: Minimum loss reduction required to make a further partition on a leaf node of the tree.
|
||||
The larger `min_split_loss` is, the more conservative the algorithm will be. Range: [0,Inf].
|
||||
max_depth: Maximum depth of a tree. Increasing this value will make the model more complex and more likely to overfit.
|
||||
0 indicates no limit on depth. Range: [0,Inf].
|
||||
|
||||
Annotations:
|
||||
author: Alexey Volkov <alexey.volkov@ark-kun.com>
|
||||
"""
|
||||
import pandas
|
||||
import xgboost
|
||||
|
||||
df = pandas.read_csv(
|
||||
training_data_path,
|
||||
).convert_dtypes()
|
||||
print("Training data information:")
|
||||
df.info(verbose=True)
|
||||
# Converting column types that XGBoost does not support
|
||||
for column_name, dtype in df.dtypes.items():
|
||||
if dtype in ["string", "object"]:
|
||||
print(f"Treating the {dtype.name} column '{column_name}' as categorical.")
|
||||
df[column_name] = df[column_name].astype("category")
|
||||
print(f"Inferred {len(df[column_name].cat.categories)} categories for the '{column_name}' column.")
|
||||
# Working around the XGBoost issue with nullable floats: https://github.com/dmlc/xgboost/issues/8213
|
||||
if pandas.api.types.is_float_dtype(dtype):
|
||||
# Converting from "Float64" to "float64"
|
||||
df[column_name] = df[column_name].astype(dtype.name.lower())
|
||||
print()
|
||||
print("Final training data information:")
|
||||
df.info(verbose=True)
|
||||
|
||||
training_data = xgboost.DMatrix(
|
||||
data=df.drop(columns=[label_column_name]),
|
||||
label=df[[label_column_name]],
|
||||
enable_categorical=True,
|
||||
)
|
||||
|
||||
booster_params = booster_params or {}
|
||||
booster_params.setdefault("objective", objective)
|
||||
booster_params.setdefault("booster", booster)
|
||||
booster_params.setdefault("learning_rate", learning_rate)
|
||||
booster_params.setdefault("min_split_loss", min_split_loss)
|
||||
booster_params.setdefault("max_depth", max_depth)
|
||||
|
||||
starting_model = None
|
||||
if starting_model_path:
|
||||
starting_model = xgboost.Booster(model_file=starting_model_path)
|
||||
|
||||
print()
|
||||
print("Training the model:")
|
||||
model = xgboost.train(
|
||||
params=booster_params,
|
||||
dtrain=training_data,
|
||||
num_boost_round=num_iterations,
|
||||
xgb_model=starting_model,
|
||||
evals=[(training_data, "training_data")],
|
||||
)
|
||||
|
||||
# Saving the model in binary format
|
||||
model.save_model(model_path)
|
||||
|
||||
model_config_str = model.save_config()
|
||||
with open(model_config_path, "w") as model_config_file:
|
||||
model_config_file.write(model_config_str)
|
||||
|
||||
import json
|
||||
import argparse
|
||||
_parser = argparse.ArgumentParser(prog='Train XGBoost model on CSV', description='Trains an XGBoost model.')
|
||||
_parser.add_argument("--training-data", dest="training_data_path", type=str, required=True, default=argparse.SUPPRESS)
|
||||
_parser.add_argument("--label-column-name", dest="label_column_name", type=str, required=True, default=argparse.SUPPRESS)
|
||||
_parser.add_argument("--starting-model", dest="starting_model_path", type=str, required=False, default=argparse.SUPPRESS)
|
||||
_parser.add_argument("--num-iterations", dest="num_iterations", type=int, required=False, default=argparse.SUPPRESS)
|
||||
_parser.add_argument("--objective", dest="objective", type=str, required=False, default=argparse.SUPPRESS)
|
||||
_parser.add_argument("--booster", dest="booster", type=str, required=False, default=argparse.SUPPRESS)
|
||||
_parser.add_argument("--learning-rate", dest="learning_rate", type=float, required=False, default=argparse.SUPPRESS)
|
||||
_parser.add_argument("--min-split-loss", dest="min_split_loss", type=float, required=False, default=argparse.SUPPRESS)
|
||||
_parser.add_argument("--max-depth", dest="max_depth", type=int, required=False, default=argparse.SUPPRESS)
|
||||
_parser.add_argument("--booster-params", dest="booster_params", type=json.loads, required=False, default=argparse.SUPPRESS)
|
||||
_parser.add_argument("--model", dest="model_path", type=_make_parent_dirs_and_return_path, required=True, default=argparse.SUPPRESS)
|
||||
_parser.add_argument("--model-config", dest="model_config_path", type=_make_parent_dirs_and_return_path, required=True, default=argparse.SUPPRESS)
|
||||
_parsed_args = vars(_parser.parse_args())
|
||||
|
||||
_outputs = train_XGBoost_model_on_CSV(**_parsed_args)
|
||||
args:
|
||||
- --training-data
|
||||
- {inputPath: training_data}
|
||||
- --label-column-name
|
||||
- {inputValue: label_column_name}
|
||||
- if:
|
||||
cond: {isPresent: starting_model}
|
||||
then:
|
||||
- --starting-model
|
||||
- {inputPath: starting_model}
|
||||
- if:
|
||||
cond: {isPresent: num_iterations}
|
||||
then:
|
||||
- --num-iterations
|
||||
- {inputValue: num_iterations}
|
||||
- if:
|
||||
cond: {isPresent: objective}
|
||||
then:
|
||||
- --objective
|
||||
- {inputValue: objective}
|
||||
- if:
|
||||
cond: {isPresent: booster}
|
||||
then:
|
||||
- --booster
|
||||
- {inputValue: booster}
|
||||
- if:
|
||||
cond: {isPresent: learning_rate}
|
||||
then:
|
||||
- --learning-rate
|
||||
- {inputValue: learning_rate}
|
||||
- if:
|
||||
cond: {isPresent: min_split_loss}
|
||||
then:
|
||||
- --min-split-loss
|
||||
- {inputValue: min_split_loss}
|
||||
- if:
|
||||
cond: {isPresent: max_depth}
|
||||
then:
|
||||
- --max-depth
|
||||
- {inputValue: max_depth}
|
||||
- if:
|
||||
cond: {isPresent: booster_params}
|
||||
then:
|
||||
- --booster-params
|
||||
- {inputValue: booster_params}
|
||||
- --model
|
||||
- {outputPath: model}
|
||||
- --model-config
|
||||
- {outputPath: model_config}
|
||||
+204
@@ -0,0 +1,204 @@
|
||||
name: Split rows into subsets
|
||||
description: Splits the data table according to the split fractions.
|
||||
metadata:
|
||||
annotations: {author: Alexey Volkov <alexey.volkov@ark-kun.com>, canonical_location: 'https://raw.githubusercontent.com/Ark-kun/pipeline_components/master/components/dataset_manipulation/Split_rows_into_subsets/in_CSV/component.yaml'}
|
||||
inputs:
|
||||
- {name: table, type: CSV}
|
||||
- {name: fraction_1, type: Float, description: 'The proportion of the lines to put
|
||||
into the 1st split. Range: [0, 1]'}
|
||||
- name: fraction_2
|
||||
type: Float
|
||||
description: |-
|
||||
The proportion of the lines to put into the 2nd split. Range: [0, 1]
|
||||
If fraction_2 is not specified, then fraction_2 = 1 - fraction_1.
|
||||
The remaining lines go to the 3rd split (if any).
|
||||
optional: true
|
||||
- {name: random_seed, type: Integer, default: '0', optional: true}
|
||||
outputs:
|
||||
- {name: split_1, type: CSV}
|
||||
- {name: split_2, type: CSV}
|
||||
- {name: split_3, type: CSV}
|
||||
- {name: split_1_count, type: Integer}
|
||||
- {name: split_2_count, type: Integer}
|
||||
- {name: split_3_count, type: Integer}
|
||||
implementation:
|
||||
container:
|
||||
image: python:3.9
|
||||
command:
|
||||
- sh
|
||||
- -ec
|
||||
- |
|
||||
program_path=$(mktemp)
|
||||
printf "%s" "$0" > "$program_path"
|
||||
python3 -u "$program_path" "$@"
|
||||
- |
|
||||
def _make_parent_dirs_and_return_path(file_path: str):
|
||||
import os
|
||||
os.makedirs(os.path.dirname(file_path), exist_ok=True)
|
||||
return file_path
|
||||
|
||||
def split_rows_into_subsets(
|
||||
table_path,
|
||||
split_1_path,
|
||||
split_2_path,
|
||||
split_3_path,
|
||||
fraction_1,
|
||||
fraction_2 = None,
|
||||
random_seed = 0,
|
||||
):
|
||||
"""Splits the data table according to the split fractions.
|
||||
|
||||
Args:
|
||||
fraction_1: The proportion of the lines to put into the 1st split. Range: [0, 1]
|
||||
fraction_2: The proportion of the lines to put into the 2nd split. Range: [0, 1]
|
||||
If fraction_2 is not specified, then fraction_2 = 1 - fraction_1.
|
||||
The remaining lines go to the 3rd split (if any).
|
||||
"""
|
||||
import random
|
||||
|
||||
random.seed(random_seed)
|
||||
|
||||
SHUFFLE_BUFFER_SIZE = 10000
|
||||
|
||||
num_splits = 3
|
||||
|
||||
if fraction_1 < 0 or fraction_1 > 1:
|
||||
raise ValueError("fraction_1 must be in between 0 and 1.")
|
||||
|
||||
if fraction_2 is None:
|
||||
fraction_2 = 1 - fraction_1
|
||||
if fraction_2 < 0 or fraction_2 > 1:
|
||||
raise ValueError("fraction_2 must be in between 0 and 1.")
|
||||
|
||||
fraction_3 = 1 - fraction_1 - fraction_2
|
||||
|
||||
fractions = [
|
||||
fraction_1,
|
||||
fraction_2,
|
||||
fraction_3,
|
||||
]
|
||||
|
||||
assert sum(fractions) == 1
|
||||
|
||||
written_line_counts = [0] * num_splits
|
||||
|
||||
output_files = [
|
||||
open(split_1_path, "wb"),
|
||||
open(split_2_path, "wb"),
|
||||
open(split_3_path, "wb"),
|
||||
]
|
||||
|
||||
with open(table_path, "rb") as input_file:
|
||||
# Writing the headers
|
||||
header_line = input_file.readline()
|
||||
for output_file in output_files:
|
||||
output_file.write(header_line)
|
||||
|
||||
while True:
|
||||
line_buffer = []
|
||||
for i in range(SHUFFLE_BUFFER_SIZE):
|
||||
line = input_file.readline()
|
||||
if not line:
|
||||
break
|
||||
line_buffer.append(line)
|
||||
|
||||
# We need to exactly partition the lines between the output files
|
||||
# To overcome possible systematic bias, we could calculate the total numbers
|
||||
# of lines written to each file and take that into account.
|
||||
num_read_lines = len(line_buffer)
|
||||
number_of_lines_for_files = [0] * num_splits
|
||||
# List that will have the index of the destination file for each line
|
||||
file_index_for_line = []
|
||||
remaining_lines = num_read_lines
|
||||
remaining_fraction = 1
|
||||
for i in range(num_splits):
|
||||
number_of_lines_for_file = (
|
||||
round(remaining_lines * (fractions[i] / remaining_fraction))
|
||||
if remaining_fraction > 0
|
||||
else 0
|
||||
)
|
||||
number_of_lines_for_files[i] = number_of_lines_for_file
|
||||
remaining_lines -= number_of_lines_for_file
|
||||
remaining_fraction -= fractions[i]
|
||||
file_index_for_line.extend([i] * number_of_lines_for_file)
|
||||
|
||||
assert remaining_lines == 0, f"{remaining_lines}"
|
||||
assert len(file_index_for_line) == num_read_lines
|
||||
|
||||
random.shuffle(file_index_for_line)
|
||||
|
||||
for i in range(num_read_lines):
|
||||
output_files[file_index_for_line[i]].write(line_buffer[i])
|
||||
written_line_counts[file_index_for_line[i]] += 1
|
||||
|
||||
# Exit if the file ended before we were able to fully fill the buffer
|
||||
if len(line_buffer) != SHUFFLE_BUFFER_SIZE:
|
||||
break
|
||||
|
||||
for output_file in output_files:
|
||||
output_file.close()
|
||||
|
||||
return written_line_counts
|
||||
|
||||
def _serialize_int(int_value: int) -> str:
|
||||
if isinstance(int_value, str):
|
||||
return int_value
|
||||
if not isinstance(int_value, int):
|
||||
raise TypeError('Value "{}" has type "{}" instead of int.'.format(str(int_value), str(type(int_value))))
|
||||
return str(int_value)
|
||||
|
||||
import argparse
|
||||
_parser = argparse.ArgumentParser(prog='Split rows into subsets', description='Splits the data table according to the split fractions.')
|
||||
_parser.add_argument("--table", dest="table_path", type=str, required=True, default=argparse.SUPPRESS)
|
||||
_parser.add_argument("--fraction-1", dest="fraction_1", type=float, required=True, default=argparse.SUPPRESS)
|
||||
_parser.add_argument("--fraction-2", dest="fraction_2", type=float, required=False, default=argparse.SUPPRESS)
|
||||
_parser.add_argument("--random-seed", dest="random_seed", type=int, required=False, default=argparse.SUPPRESS)
|
||||
_parser.add_argument("--split-1", dest="split_1_path", type=_make_parent_dirs_and_return_path, required=True, default=argparse.SUPPRESS)
|
||||
_parser.add_argument("--split-2", dest="split_2_path", type=_make_parent_dirs_and_return_path, required=True, default=argparse.SUPPRESS)
|
||||
_parser.add_argument("--split-3", dest="split_3_path", type=_make_parent_dirs_and_return_path, required=True, default=argparse.SUPPRESS)
|
||||
_parser.add_argument("----output-paths", dest="_output_paths", type=str, nargs=3)
|
||||
_parsed_args = vars(_parser.parse_args())
|
||||
_output_files = _parsed_args.pop("_output_paths", [])
|
||||
|
||||
_outputs = split_rows_into_subsets(**_parsed_args)
|
||||
|
||||
_output_serializers = [
|
||||
_serialize_int,
|
||||
_serialize_int,
|
||||
_serialize_int,
|
||||
|
||||
]
|
||||
|
||||
import os
|
||||
for idx, output_file in enumerate(_output_files):
|
||||
try:
|
||||
os.makedirs(os.path.dirname(output_file))
|
||||
except OSError:
|
||||
pass
|
||||
with open(output_file, 'w') as f:
|
||||
f.write(_output_serializers[idx](_outputs[idx]))
|
||||
args:
|
||||
- --table
|
||||
- {inputPath: table}
|
||||
- --fraction-1
|
||||
- {inputValue: fraction_1}
|
||||
- if:
|
||||
cond: {isPresent: fraction_2}
|
||||
then:
|
||||
- --fraction-2
|
||||
- {inputValue: fraction_2}
|
||||
- if:
|
||||
cond: {isPresent: random_seed}
|
||||
then:
|
||||
- --random-seed
|
||||
- {inputValue: random_seed}
|
||||
- --split-1
|
||||
- {outputPath: split_1}
|
||||
- --split-2
|
||||
- {outputPath: split_2}
|
||||
- --split-3
|
||||
- {outputPath: split_3}
|
||||
- '----output-paths'
|
||||
- {outputPath: split_1_count}
|
||||
- {outputPath: split_2_count}
|
||||
- {outputPath: split_3_count}
|
||||
+241
@@ -0,0 +1,241 @@
|
||||
name: Deploy model to endpoint for Google Cloud Vertex AI Model
|
||||
description: Deploys Google Cloud Vertex AI Model to a Google Cloud Vertex AI Endpoint.
|
||||
metadata:
|
||||
annotations: {author: Alexey Volkov <alexey.volkov@ark-kun.com>, canonical_location: 'https://raw.githubusercontent.com/Ark-kun/pipeline_components/KFPv2_hell/components/google-cloud/Vertex_AI/Models/Deploy_to_endpoint/workaround_for_buggy_KFPv2_compiler/component.yaml'}
|
||||
inputs:
|
||||
- {name: model_name, type: String, description: Full resource name of a Google Cloud
|
||||
Vertex AI Model}
|
||||
- name: endpoint_name
|
||||
type: String
|
||||
description: |-
|
||||
Optional. Full name of Google Cloud Vertex Endpoint. A new
|
||||
endpoint is created if the name is not passed.
|
||||
optional: true
|
||||
- name: machine_type
|
||||
type: String
|
||||
description: |-
|
||||
The type of the machine. See the [list of machine types
|
||||
supported for prediction
|
||||
](https://cloud.google.com/vertex-ai/docs/predictions/configure-compute#machine-types).
|
||||
Defaults to "n1-standard-2"
|
||||
default: n1-standard-2
|
||||
optional: true
|
||||
- name: min_replica_count
|
||||
type: Integer
|
||||
description: |-
|
||||
Optional. The minimum number of machine replicas this deployed
|
||||
model will be always deployed on. If traffic against it increases,
|
||||
it may dynamically be deployed onto more replicas, and as traffic
|
||||
decreases, some of these extra replicas may be freed.
|
||||
default: '1'
|
||||
optional: true
|
||||
- name: max_replica_count
|
||||
type: Integer
|
||||
description: |-
|
||||
Optional. The maximum number of replicas this deployed model may
|
||||
be deployed on when the traffic against it increases. If requested
|
||||
value is too large, the deployment will error, but if deployment
|
||||
succeeds then the ability to scale the model to that many replicas
|
||||
is guaranteed (barring service outages). If traffic against the
|
||||
deployed model increases beyond what its replicas at maximum may
|
||||
handle, a portion of the traffic will be dropped. If this value
|
||||
is not provided, the smaller value of min_replica_count or 1 will
|
||||
be used.
|
||||
default: '1'
|
||||
optional: true
|
||||
- name: accelerator_type
|
||||
type: String
|
||||
description: |-
|
||||
Optional. Hardware accelerator type. Must also set accelerator_count if used.
|
||||
One of ACCELERATOR_TYPE_UNSPECIFIED, NVIDIA_TESLA_K80, NVIDIA_TESLA_P100,
|
||||
NVIDIA_TESLA_V100, NVIDIA_TESLA_P4, NVIDIA_TESLA_T4
|
||||
optional: true
|
||||
- {name: accelerator_count, type: Integer, description: Optional. The number of accelerators
|
||||
to attach to a worker replica., optional: true}
|
||||
outputs:
|
||||
- {name: endpoint_name, type: String}
|
||||
- {name: endpoint_dict, type: JsonObject}
|
||||
implementation:
|
||||
container:
|
||||
image: python:3.9
|
||||
command:
|
||||
- sh
|
||||
- -c
|
||||
- (PIP_DISABLE_PIP_VERSION_CHECK=1 python3 -m pip install --quiet --no-warn-script-location
|
||||
'google-cloud-aiplatform==1.7.0' || PIP_DISABLE_PIP_VERSION_CHECK=1 python3
|
||||
-m pip install --quiet --no-warn-script-location 'google-cloud-aiplatform==1.7.0'
|
||||
--user) && "$0" "$@"
|
||||
- sh
|
||||
- -ec
|
||||
- |
|
||||
program_path=$(mktemp)
|
||||
printf "%s" "$0" > "$program_path"
|
||||
python3 -u "$program_path" "$@"
|
||||
- |
|
||||
def deploy_model_to_endpoint_for_Google_Cloud_Vertex_AI_Model(
|
||||
model_name,
|
||||
endpoint_name = None,
|
||||
machine_type = "n1-standard-2",
|
||||
min_replica_count = 1,
|
||||
max_replica_count = 1,
|
||||
accelerator_type = None,
|
||||
accelerator_count = None,
|
||||
#
|
||||
# Uncomment when anyone requests these:
|
||||
# deployed_model_display_name: str = None,
|
||||
# traffic_percentage: int = 0,
|
||||
# traffic_split: dict = None,
|
||||
# service_account: str = None,
|
||||
# explanation_metadata: "google.cloud.aiplatform_v1.types.explanation_metadata.ExplanationMetadata" = None,
|
||||
# explanation_parameters: "google.cloud.aiplatform_v1.types.explanation.ExplanationParameters" = None,
|
||||
#
|
||||
# encryption_spec_key_name: str = None,
|
||||
):
|
||||
"""Deploys Google Cloud Vertex AI Model to a Google Cloud Vertex AI Endpoint.
|
||||
|
||||
Args:
|
||||
model_name: Full resource name of a Google Cloud Vertex AI Model
|
||||
endpoint_name: Optional. Full name of Google Cloud Vertex Endpoint. A new
|
||||
endpoint is created if the name is not passed.
|
||||
machine_type: The type of the machine. See the [list of machine types
|
||||
supported for prediction
|
||||
](https://cloud.google.com/vertex-ai/docs/predictions/configure-compute#machine-types).
|
||||
Defaults to "n1-standard-2"
|
||||
min_replica_count (int):
|
||||
Optional. The minimum number of machine replicas this deployed
|
||||
model will be always deployed on. If traffic against it increases,
|
||||
it may dynamically be deployed onto more replicas, and as traffic
|
||||
decreases, some of these extra replicas may be freed.
|
||||
max_replica_count (int):
|
||||
Optional. The maximum number of replicas this deployed model may
|
||||
be deployed on when the traffic against it increases. If requested
|
||||
value is too large, the deployment will error, but if deployment
|
||||
succeeds then the ability to scale the model to that many replicas
|
||||
is guaranteed (barring service outages). If traffic against the
|
||||
deployed model increases beyond what its replicas at maximum may
|
||||
handle, a portion of the traffic will be dropped. If this value
|
||||
is not provided, the smaller value of min_replica_count or 1 will
|
||||
be used.
|
||||
accelerator_type (str):
|
||||
Optional. Hardware accelerator type. Must also set accelerator_count if used.
|
||||
One of ACCELERATOR_TYPE_UNSPECIFIED, NVIDIA_TESLA_K80, NVIDIA_TESLA_P100,
|
||||
NVIDIA_TESLA_V100, NVIDIA_TESLA_P4, NVIDIA_TESLA_T4
|
||||
accelerator_count (int):
|
||||
Optional. The number of accelerators to attach to a worker replica.
|
||||
"""
|
||||
import json
|
||||
from google.cloud import aiplatform
|
||||
|
||||
model = aiplatform.Model(model_name=model_name)
|
||||
|
||||
if endpoint_name:
|
||||
endpoint = aiplatform.Endpoint(endpoint_name=endpoint_name)
|
||||
else:
|
||||
endpoint_display_name = model.display_name[:118] + "_endpoint"
|
||||
endpoint = aiplatform.Endpoint.create(
|
||||
display_name=endpoint_display_name,
|
||||
project=model.project,
|
||||
location=model.location,
|
||||
# encryption_spec_key_name=encryption_spec_key_name,
|
||||
labels={"component-source": "github-com-ark-kun-pipeline-components"},
|
||||
)
|
||||
|
||||
endpoint = model.deploy(
|
||||
endpoint=endpoint,
|
||||
# deployed_model_display_name=deployed_model_display_name,
|
||||
machine_type=machine_type,
|
||||
min_replica_count=min_replica_count,
|
||||
max_replica_count=max_replica_count,
|
||||
accelerator_type=accelerator_type,
|
||||
accelerator_count=accelerator_count,
|
||||
# service_account=service_account,
|
||||
# explanation_metadata=explanation_metadata,
|
||||
# explanation_parameters=explanation_parameters,
|
||||
# encryption_spec_key_name=encryption_spec_key_name,
|
||||
)
|
||||
|
||||
endpoint_json = json.dumps(endpoint.to_dict(), indent=2)
|
||||
print(endpoint_json)
|
||||
return (endpoint.resource_name, endpoint_json)
|
||||
|
||||
def _serialize_json(obj) -> str:
|
||||
if isinstance(obj, str):
|
||||
return obj
|
||||
import json
|
||||
def default_serializer(obj):
|
||||
if hasattr(obj, 'to_struct'):
|
||||
return obj.to_struct()
|
||||
else:
|
||||
raise TypeError("Object of type '%s' is not JSON serializable and does not have .to_struct() method." % obj.__class__.__name__)
|
||||
return json.dumps(obj, default=default_serializer, sort_keys=True)
|
||||
|
||||
def _serialize_str(str_value: str) -> str:
|
||||
if not isinstance(str_value, str):
|
||||
raise TypeError('Value "{}" has type "{}" instead of str.'.format(str(str_value), str(type(str_value))))
|
||||
return str_value
|
||||
|
||||
import argparse
|
||||
_parser = argparse.ArgumentParser(prog='Deploy model to endpoint for Google Cloud Vertex AI Model', description='Deploys Google Cloud Vertex AI Model to a Google Cloud Vertex AI Endpoint.')
|
||||
_parser.add_argument("--model-name", dest="model_name", type=str, required=True, default=argparse.SUPPRESS)
|
||||
_parser.add_argument("--endpoint-name", dest="endpoint_name", type=str, required=False, default=argparse.SUPPRESS)
|
||||
_parser.add_argument("--machine-type", dest="machine_type", type=str, required=False, default=argparse.SUPPRESS)
|
||||
_parser.add_argument("--min-replica-count", dest="min_replica_count", type=int, required=False, default=argparse.SUPPRESS)
|
||||
_parser.add_argument("--max-replica-count", dest="max_replica_count", type=int, required=False, default=argparse.SUPPRESS)
|
||||
_parser.add_argument("--accelerator-type", dest="accelerator_type", type=str, required=False, default=argparse.SUPPRESS)
|
||||
_parser.add_argument("--accelerator-count", dest="accelerator_count", type=int, required=False, default=argparse.SUPPRESS)
|
||||
_parser.add_argument("----output-paths", dest="_output_paths", type=str, nargs=2)
|
||||
_parsed_args = vars(_parser.parse_args())
|
||||
_output_files = _parsed_args.pop("_output_paths", [])
|
||||
|
||||
_outputs = deploy_model_to_endpoint_for_Google_Cloud_Vertex_AI_Model(**_parsed_args)
|
||||
|
||||
_output_serializers = [
|
||||
_serialize_str,
|
||||
_serialize_json,
|
||||
|
||||
]
|
||||
|
||||
import os
|
||||
for idx, output_file in enumerate(_output_files):
|
||||
try:
|
||||
os.makedirs(os.path.dirname(output_file))
|
||||
except OSError:
|
||||
pass
|
||||
with open(output_file, 'w') as f:
|
||||
f.write(_output_serializers[idx](_outputs[idx]))
|
||||
args:
|
||||
- --model-name
|
||||
- {inputValue: model_name}
|
||||
- if:
|
||||
cond: {isPresent: endpoint_name}
|
||||
then:
|
||||
- --endpoint-name
|
||||
- {inputValue: endpoint_name}
|
||||
- if:
|
||||
cond: {isPresent: machine_type}
|
||||
then:
|
||||
- --machine-type
|
||||
- {inputValue: machine_type}
|
||||
- if:
|
||||
cond: {isPresent: min_replica_count}
|
||||
then:
|
||||
- --min-replica-count
|
||||
- {inputValue: min_replica_count}
|
||||
- if:
|
||||
cond: {isPresent: max_replica_count}
|
||||
then:
|
||||
- --max-replica-count
|
||||
- {inputValue: max_replica_count}
|
||||
- if:
|
||||
cond: {isPresent: accelerator_type}
|
||||
then:
|
||||
- --accelerator-type
|
||||
- {inputValue: accelerator_type}
|
||||
- if:
|
||||
cond: {isPresent: accelerator_count}
|
||||
then:
|
||||
- --accelerator-count
|
||||
- {inputValue: accelerator_count}
|
||||
- '----output-paths'
|
||||
- {outputPath: endpoint_name}
|
||||
- {outputPath: endpoint_dict}
|
||||
+297
@@ -0,0 +1,297 @@
|
||||
name: Upload PyTorch model archive to Google Cloud Vertex AI
|
||||
metadata:
|
||||
annotations: {author: Alexey Volkov <alexey.volkov@ark-kun.com>, canonical_location: 'https://raw.githubusercontent.com/Ark-kun/pipeline_components/KFPv2_hell/components/google-cloud/Vertex_AI/Models/Upload_PyTorch_model_archive/workaround_for_buggy_KFPv2_compiler/component.yaml'}
|
||||
inputs:
|
||||
- {name: model_archive, type: PyTorchModelArchive}
|
||||
- {name: torchserve_version, type: String, default: 0.6.0, optional: true}
|
||||
- name: use_gpu
|
||||
type: Boolean
|
||||
default: "False"
|
||||
optional: true
|
||||
- {name: display_name, type: String, optional: true}
|
||||
- {name: description, type: String, optional: true}
|
||||
- {name: project, type: String, optional: true}
|
||||
- {name: location, type: String, optional: true}
|
||||
- {name: labels, type: JsonObject, optional: true}
|
||||
- {name: staging_bucket, type: String, optional: true}
|
||||
outputs:
|
||||
- {name: model_name, type: String}
|
||||
- {name: model_dict, type: JsonObject}
|
||||
implementation:
|
||||
container:
|
||||
image: python:3.9
|
||||
command:
|
||||
- sh
|
||||
- -c
|
||||
- (PIP_DISABLE_PIP_VERSION_CHECK=1 python3 -m pip install --quiet --no-warn-script-location
|
||||
'google-cloud-aiplatform==1.13.1' 'google-cloud-build==3.8.3' || PIP_DISABLE_PIP_VERSION_CHECK=1
|
||||
python3 -m pip install --quiet --no-warn-script-location 'google-cloud-aiplatform==1.13.1'
|
||||
'google-cloud-build==3.8.3' --user) && "$0" "$@"
|
||||
- sh
|
||||
- -ec
|
||||
- |
|
||||
program_path=$(mktemp)
|
||||
printf "%s" "$0" > "$program_path"
|
||||
python3 -u "$program_path" "$@"
|
||||
- |
|
||||
def upload_PyTorch_model_archive_to_Google_Cloud_Vertex_AI(
|
||||
model_archive_path,
|
||||
torchserve_version = "0.6.0",
|
||||
use_gpu = False,
|
||||
|
||||
display_name = None,
|
||||
description = None,
|
||||
|
||||
# Uncomment when anyone requests these:
|
||||
# instance_schema_uri: str = None,
|
||||
# parameters_schema_uri: str = None,
|
||||
# prediction_schema_uri: str = None,
|
||||
# explanation_metadata: "google.cloud.aiplatform_v1.types.explanation_metadata.ExplanationMetadata" = None,
|
||||
# explanation_parameters: "google.cloud.aiplatform_v1.types.explanation.ExplanationParameters" = None,
|
||||
|
||||
project = None,
|
||||
location = None,
|
||||
labels = None,
|
||||
# encryption_spec_key_name: str = None,
|
||||
staging_bucket = None,
|
||||
):
|
||||
import json
|
||||
import os
|
||||
from google.cloud import aiplatform
|
||||
|
||||
if not location:
|
||||
location = os.environ.get("CLOUD_ML_REGION")
|
||||
|
||||
if not labels:
|
||||
labels = {}
|
||||
labels["component-source"] = "github-com-ark-kun-pipeline-components"
|
||||
|
||||
container_image_tag = torchserve_version + "-" + ("gpu" if use_gpu else "cpu")
|
||||
container_image_uri = f"pytorch/torchserve:{container_image_tag}"
|
||||
|
||||
# Vertex Endpoints refuse to support non-Google container registries.
|
||||
# We have to work around this to reduce user frustration
|
||||
# TODO: Remove this code when Vertex Endpoints service starts supporting other container registries.
|
||||
def copy_container_image(
|
||||
src_container_image_uri,
|
||||
dst_container_image_uri,
|
||||
project_id,
|
||||
):
|
||||
from google.cloud.devtools import cloudbuild
|
||||
from google import protobuf
|
||||
build_client = cloudbuild.CloudBuildClient()
|
||||
build_config = cloudbuild.Build(
|
||||
images=[dst_container_image_uri],
|
||||
steps=[
|
||||
cloudbuild.BuildStep(
|
||||
name="gcr.io/cloud-builders/docker",
|
||||
entrypoint="bash",
|
||||
args=[
|
||||
"-exc",
|
||||
'docker pull --quiet "$0" && docker tag "$0" "$1"',
|
||||
src_container_image_uri,
|
||||
dst_container_image_uri,
|
||||
],
|
||||
),
|
||||
],
|
||||
timeout=protobuf.duration_pb2.Duration(
|
||||
seconds=1800,
|
||||
),
|
||||
)
|
||||
build_operation = build_client.create_build(
|
||||
project_id=project_id,
|
||||
build=build_config,
|
||||
)
|
||||
try:
|
||||
result = build_operation.result()
|
||||
except:
|
||||
print(f"Logs are available at [{build_operation.metadata.build.log_url}].")
|
||||
raise
|
||||
return result
|
||||
|
||||
project_id = aiplatform.initializer.global_config.project
|
||||
mirrored_container_uri = f"gcr.io/{project_id}/container_mirror/{container_image_uri}"
|
||||
# FIX: Only mirror when image does not exist
|
||||
# docker does is unable to get the registry data from inside container (it cannot connecto to docker socket):
|
||||
# docker.errors.DockerException: Error while fetching server API version: ('Connection aborted.', FileNotFoundError(2, 'No such file or directory'))
|
||||
# import docker
|
||||
# try:
|
||||
# docker_client = docker.from_env()
|
||||
# docker_client.images.get_registry_data(mirrored_container_uri)
|
||||
# except docker.errors.NotFound:
|
||||
if True:
|
||||
print(f"Mirroring {container_image_uri} to {mirrored_container_uri}")
|
||||
copy_container_image(
|
||||
src_container_image_uri=container_image_uri,
|
||||
dst_container_image_uri=mirrored_container_uri,
|
||||
project_id=project_id,
|
||||
)
|
||||
container_image_uri = mirrored_container_uri
|
||||
# End of container image mirroring code
|
||||
|
||||
model_archive_file_name = os.path.basename(model_archive_path)
|
||||
model_archive_dir = os.path.dirname(model_archive_path)
|
||||
|
||||
model = aiplatform.Model.upload(
|
||||
# FIX: Use public image or mirror the official image
|
||||
#serving_container_image_uri="gcr.io/avolkov-31337/mirror/pytorch/torchserve",
|
||||
serving_container_image_uri=container_image_uri,
|
||||
artifact_uri=model_archive_dir,
|
||||
serving_container_command=[
|
||||
"bash",
|
||||
"-exc",
|
||||
'''
|
||||
model_archive_uri="$0"
|
||||
#model_archive_local_path=$(mktemp --suffix ".mar")
|
||||
# For some reason the model must already be inside the model-store directory.
|
||||
model_archive_local_path=./model-store/model.mar
|
||||
|
||||
# Downloading the model archive from GCS
|
||||
# TODO: Fix gsutil bugs (requires project ID, has auth issues) and use gsutil instead.
|
||||
# gsutil cp "$model_archive_uri" "$model_archive_local_path"
|
||||
pip install google-cloud-storage
|
||||
python -c '
|
||||
import sys
|
||||
from google.cloud import storage
|
||||
|
||||
model_archive_uri = sys.argv[1]
|
||||
model_archive_local_path = sys.argv[2]
|
||||
|
||||
storage_client = storage.Client()
|
||||
blob = storage.Blob.from_string(uri=model_archive_uri, client=storage_client)
|
||||
blob.download_to_filename(filename=model_archive_local_path)
|
||||
' "$model_archive_uri" "$model_archive_local_path"
|
||||
|
||||
#Note: config.properties is owned by root. Our user is not root.
|
||||
echo "
|
||||
service_envelope=json
|
||||
# Needed for external access
|
||||
inference_address=http://0.0.0.0:8080
|
||||
management_address=http://0.0.0.0:8081
|
||||
" > config2.properties
|
||||
torchserve --start --foreground --no-config-snapshots --models main-model="$model_archive_local_path" --model-store ./model-store/ --ts-config config2.properties
|
||||
''',
|
||||
"$(AIP_STORAGE_URI)/" + model_archive_file_name,
|
||||
],
|
||||
serving_container_predict_route="/predictions/main-model",
|
||||
#serving_container_predict_route="/v1/models/main-model:predict",
|
||||
serving_container_health_route="/ping",
|
||||
serving_container_ports=[8080],
|
||||
|
||||
display_name=display_name,
|
||||
description=description,
|
||||
|
||||
# instance_schema_uri=instance_schema_uri,
|
||||
# parameters_schema_uri=parameters_schema_uri,
|
||||
# prediction_schema_uri=prediction_schema_uri,
|
||||
# explanation_metadata=explanation_metadata,
|
||||
# explanation_parameters=explanation_parameters,
|
||||
|
||||
project=project,
|
||||
location=location,
|
||||
labels=labels,
|
||||
# encryption_spec_key_name=encryption_spec_key_name,
|
||||
staging_bucket=staging_bucket,
|
||||
)
|
||||
model_json = json.dumps(model.to_dict(), indent=2)
|
||||
print(model_json)
|
||||
return (model.resource_name, model_json)
|
||||
|
||||
def _deserialize_bool(s) -> bool:
|
||||
from distutils.util import strtobool
|
||||
return strtobool(s) == 1
|
||||
|
||||
def _serialize_json(obj) -> str:
|
||||
if isinstance(obj, str):
|
||||
return obj
|
||||
import json
|
||||
def default_serializer(obj):
|
||||
if hasattr(obj, 'to_struct'):
|
||||
return obj.to_struct()
|
||||
else:
|
||||
raise TypeError("Object of type '%s' is not JSON serializable and does not have .to_struct() method." % obj.__class__.__name__)
|
||||
return json.dumps(obj, default=default_serializer, sort_keys=True)
|
||||
|
||||
def _serialize_str(str_value: str) -> str:
|
||||
if not isinstance(str_value, str):
|
||||
raise TypeError('Value "{}" has type "{}" instead of str.'.format(str(str_value), str(type(str_value))))
|
||||
return str_value
|
||||
|
||||
import json
|
||||
import argparse
|
||||
_parser = argparse.ArgumentParser(prog='Upload PyTorch model archive to Google Cloud Vertex AI', description='')
|
||||
_parser.add_argument("--model-archive", dest="model_archive_path", type=str, required=True, default=argparse.SUPPRESS)
|
||||
_parser.add_argument("--torchserve-version", dest="torchserve_version", type=str, required=False, default=argparse.SUPPRESS)
|
||||
_parser.add_argument("--use-gpu", dest="use_gpu", type=_deserialize_bool, required=False, default=argparse.SUPPRESS)
|
||||
_parser.add_argument("--display-name", dest="display_name", type=str, required=False, default=argparse.SUPPRESS)
|
||||
_parser.add_argument("--description", dest="description", type=str, required=False, default=argparse.SUPPRESS)
|
||||
_parser.add_argument("--project", dest="project", type=str, required=False, default=argparse.SUPPRESS)
|
||||
_parser.add_argument("--location", dest="location", type=str, required=False, default=argparse.SUPPRESS)
|
||||
_parser.add_argument("--labels", dest="labels", type=json.loads, required=False, default=argparse.SUPPRESS)
|
||||
_parser.add_argument("--staging-bucket", dest="staging_bucket", type=str, required=False, default=argparse.SUPPRESS)
|
||||
_parser.add_argument("----output-paths", dest="_output_paths", type=str, nargs=2)
|
||||
_parsed_args = vars(_parser.parse_args())
|
||||
_output_files = _parsed_args.pop("_output_paths", [])
|
||||
|
||||
_outputs = upload_PyTorch_model_archive_to_Google_Cloud_Vertex_AI(**_parsed_args)
|
||||
|
||||
_output_serializers = [
|
||||
_serialize_str,
|
||||
_serialize_json,
|
||||
|
||||
]
|
||||
|
||||
import os
|
||||
for idx, output_file in enumerate(_output_files):
|
||||
try:
|
||||
os.makedirs(os.path.dirname(output_file))
|
||||
except OSError:
|
||||
pass
|
||||
with open(output_file, 'w') as f:
|
||||
f.write(_output_serializers[idx](_outputs[idx]))
|
||||
args:
|
||||
- --model-archive
|
||||
- {inputPath: model_archive}
|
||||
- if:
|
||||
cond: {isPresent: torchserve_version}
|
||||
then:
|
||||
- --torchserve-version
|
||||
- {inputValue: torchserve_version}
|
||||
- if:
|
||||
cond: {isPresent: use_gpu}
|
||||
then:
|
||||
- --use-gpu
|
||||
- {inputValue: use_gpu}
|
||||
- if:
|
||||
cond: {isPresent: display_name}
|
||||
then:
|
||||
- --display-name
|
||||
- {inputValue: display_name}
|
||||
- if:
|
||||
cond: {isPresent: description}
|
||||
then:
|
||||
- --description
|
||||
- {inputValue: description}
|
||||
- if:
|
||||
cond: {isPresent: project}
|
||||
then:
|
||||
- --project
|
||||
- {inputValue: project}
|
||||
- if:
|
||||
cond: {isPresent: location}
|
||||
then:
|
||||
- --location
|
||||
- {inputValue: location}
|
||||
- if:
|
||||
cond: {isPresent: labels}
|
||||
then:
|
||||
- --labels
|
||||
- {inputValue: labels}
|
||||
- if:
|
||||
cond: {isPresent: staging_bucket}
|
||||
then:
|
||||
- --staging-bucket
|
||||
- {inputValue: staging_bucket}
|
||||
- '----output-paths'
|
||||
- {outputPath: model_name}
|
||||
- {outputPath: model_dict}
|
||||
+181
@@ -0,0 +1,181 @@
|
||||
name: Upload Scikit learn pickle model to Google Cloud Vertex AI
|
||||
metadata:
|
||||
annotations: {author: Alexey Volkov <alexey.volkov@ark-kun.com>, canonical_location: 'https://raw.githubusercontent.com/Ark-kun/pipeline_components/KFPv2_hell/components/google-cloud/Vertex_AI/Models/Upload_Scikit-learn_pickle_model/workaround_for_buggy_KFPv2_compiler/component.yaml'}
|
||||
inputs:
|
||||
- {name: model, type: ScikitLearnPickleModel}
|
||||
- {name: sklearn_version, type: String, optional: true}
|
||||
- {name: display_name, type: String, optional: true}
|
||||
- {name: description, type: String, optional: true}
|
||||
- {name: project, type: String, optional: true}
|
||||
- {name: location, type: String, optional: true}
|
||||
- {name: labels, type: JsonObject, optional: true}
|
||||
- {name: staging_bucket, type: String, optional: true}
|
||||
outputs:
|
||||
- {name: model_name, type: String}
|
||||
- {name: model_dict, type: JsonObject}
|
||||
implementation:
|
||||
container:
|
||||
image: python:3.9
|
||||
command:
|
||||
- sh
|
||||
- -c
|
||||
- (PIP_DISABLE_PIP_VERSION_CHECK=1 python3 -m pip install --quiet --no-warn-script-location
|
||||
'google-cloud-aiplatform==1.16.0' || PIP_DISABLE_PIP_VERSION_CHECK=1 python3
|
||||
-m pip install --quiet --no-warn-script-location 'google-cloud-aiplatform==1.16.0'
|
||||
--user) && "$0" "$@"
|
||||
- sh
|
||||
- -ec
|
||||
- |
|
||||
program_path=$(mktemp)
|
||||
printf "%s" "$0" > "$program_path"
|
||||
python3 -u "$program_path" "$@"
|
||||
- |
|
||||
def upload_Scikit_learn_pickle_model_to_Google_Cloud_Vertex_AI(
|
||||
model_path,
|
||||
sklearn_version = None,
|
||||
|
||||
display_name = None,
|
||||
description = None,
|
||||
|
||||
# Uncomment when anyone requests these:
|
||||
# instance_schema_uri: str = None,
|
||||
# parameters_schema_uri: str = None,
|
||||
# prediction_schema_uri: str = None,
|
||||
# explanation_metadata: "google.cloud.aiplatform_v1.types.explanation_metadata.ExplanationMetadata" = None,
|
||||
# explanation_parameters: "google.cloud.aiplatform_v1.types.explanation.ExplanationParameters" = None,
|
||||
|
||||
project = None,
|
||||
location = None,
|
||||
labels = None,
|
||||
# encryption_spec_key_name: str = None,
|
||||
staging_bucket = None,
|
||||
):
|
||||
import json
|
||||
import os
|
||||
import shutil
|
||||
import tempfile
|
||||
from google.cloud import aiplatform
|
||||
|
||||
if not location:
|
||||
location = os.environ.get("CLOUD_ML_REGION")
|
||||
|
||||
if not labels:
|
||||
labels = {}
|
||||
labels["component-source"] = "github-com-ark-kun-pipeline-components"
|
||||
|
||||
# The serving container decides the model type based on the model file extension.
|
||||
# So we need to rename the mode file (e.g. /tmp/inputs/model/data) to *.pkl
|
||||
_, renamed_model_path = tempfile.mkstemp(suffix=".pkl")
|
||||
shutil.copyfile(src=model_path, dst=renamed_model_path)
|
||||
|
||||
model = aiplatform.Model.upload_scikit_learn_model_file(
|
||||
model_file_path=renamed_model_path,
|
||||
sklearn_version=sklearn_version,
|
||||
|
||||
display_name=display_name,
|
||||
description=description,
|
||||
|
||||
# instance_schema_uri=instance_schema_uri,
|
||||
# parameters_schema_uri=parameters_schema_uri,
|
||||
# prediction_schema_uri=prediction_schema_uri,
|
||||
# explanation_metadata=explanation_metadata,
|
||||
# explanation_parameters=explanation_parameters,
|
||||
|
||||
project=project,
|
||||
location=location,
|
||||
labels=labels,
|
||||
# encryption_spec_key_name=encryption_spec_key_name,
|
||||
staging_bucket=staging_bucket,
|
||||
)
|
||||
model_json = json.dumps(model.to_dict(), indent=2)
|
||||
print(model_json)
|
||||
return (model.resource_name, model_json)
|
||||
|
||||
def _serialize_json(obj) -> str:
|
||||
if isinstance(obj, str):
|
||||
return obj
|
||||
import json
|
||||
def default_serializer(obj):
|
||||
if hasattr(obj, 'to_struct'):
|
||||
return obj.to_struct()
|
||||
else:
|
||||
raise TypeError("Object of type '%s' is not JSON serializable and does not have .to_struct() method." % obj.__class__.__name__)
|
||||
return json.dumps(obj, default=default_serializer, sort_keys=True)
|
||||
|
||||
def _serialize_str(str_value: str) -> str:
|
||||
if not isinstance(str_value, str):
|
||||
raise TypeError('Value "{}" has type "{}" instead of str.'.format(str(str_value), str(type(str_value))))
|
||||
return str_value
|
||||
|
||||
import json
|
||||
import argparse
|
||||
_parser = argparse.ArgumentParser(prog='Upload Scikit learn pickle model to Google Cloud Vertex AI', description='')
|
||||
_parser.add_argument("--model", dest="model_path", type=str, required=True, default=argparse.SUPPRESS)
|
||||
_parser.add_argument("--sklearn-version", dest="sklearn_version", type=str, required=False, default=argparse.SUPPRESS)
|
||||
_parser.add_argument("--display-name", dest="display_name", type=str, required=False, default=argparse.SUPPRESS)
|
||||
_parser.add_argument("--description", dest="description", type=str, required=False, default=argparse.SUPPRESS)
|
||||
_parser.add_argument("--project", dest="project", type=str, required=False, default=argparse.SUPPRESS)
|
||||
_parser.add_argument("--location", dest="location", type=str, required=False, default=argparse.SUPPRESS)
|
||||
_parser.add_argument("--labels", dest="labels", type=json.loads, required=False, default=argparse.SUPPRESS)
|
||||
_parser.add_argument("--staging-bucket", dest="staging_bucket", type=str, required=False, default=argparse.SUPPRESS)
|
||||
_parser.add_argument("----output-paths", dest="_output_paths", type=str, nargs=2)
|
||||
_parsed_args = vars(_parser.parse_args())
|
||||
_output_files = _parsed_args.pop("_output_paths", [])
|
||||
|
||||
_outputs = upload_Scikit_learn_pickle_model_to_Google_Cloud_Vertex_AI(**_parsed_args)
|
||||
|
||||
_output_serializers = [
|
||||
_serialize_str,
|
||||
_serialize_json,
|
||||
|
||||
]
|
||||
|
||||
import os
|
||||
for idx, output_file in enumerate(_output_files):
|
||||
try:
|
||||
os.makedirs(os.path.dirname(output_file))
|
||||
except OSError:
|
||||
pass
|
||||
with open(output_file, 'w') as f:
|
||||
f.write(_output_serializers[idx](_outputs[idx]))
|
||||
args:
|
||||
- --model
|
||||
- {inputPath: model}
|
||||
- if:
|
||||
cond: {isPresent: sklearn_version}
|
||||
then:
|
||||
- --sklearn-version
|
||||
- {inputValue: sklearn_version}
|
||||
- if:
|
||||
cond: {isPresent: display_name}
|
||||
then:
|
||||
- --display-name
|
||||
- {inputValue: display_name}
|
||||
- if:
|
||||
cond: {isPresent: description}
|
||||
then:
|
||||
- --description
|
||||
- {inputValue: description}
|
||||
- if:
|
||||
cond: {isPresent: project}
|
||||
then:
|
||||
- --project
|
||||
- {inputValue: project}
|
||||
- if:
|
||||
cond: {isPresent: location}
|
||||
then:
|
||||
- --location
|
||||
- {inputValue: location}
|
||||
- if:
|
||||
cond: {isPresent: labels}
|
||||
then:
|
||||
- --labels
|
||||
- {inputValue: labels}
|
||||
- if:
|
||||
cond: {isPresent: staging_bucket}
|
||||
then:
|
||||
- --staging-bucket
|
||||
- {inputValue: staging_bucket}
|
||||
- '----output-paths'
|
||||
- {outputPath: model_name}
|
||||
- {outputPath: model_dict}
|
||||
+190
@@ -0,0 +1,190 @@
|
||||
name: Upload Tensorflow model to Google Cloud Vertex AI
|
||||
metadata:
|
||||
annotations: {author: Alexey Volkov <alexey.volkov@ark-kun.com>, canonical_location: 'https://raw.githubusercontent.com/Ark-kun/pipeline_components/KFPv2_hell/components/google-cloud/Vertex_AI/Models/Upload_Tensorflow_model/workaround_for_buggy_KFPv2_compiler/component.yaml'}
|
||||
inputs:
|
||||
- {name: model, type: TensorflowSavedModel}
|
||||
- {name: tensorflow_version, type: String, optional: true}
|
||||
- name: use_gpu
|
||||
type: Boolean
|
||||
default: "False"
|
||||
optional: true
|
||||
- {name: display_name, type: String, optional: true}
|
||||
- {name: description, type: String, optional: true}
|
||||
- {name: project, type: String, optional: true}
|
||||
- {name: location, type: String, optional: true}
|
||||
- {name: labels, type: JsonObject, optional: true}
|
||||
- {name: staging_bucket, type: String, optional: true}
|
||||
outputs:
|
||||
- {name: model_name, type: String}
|
||||
- {name: model_dict, type: JsonObject}
|
||||
implementation:
|
||||
container:
|
||||
image: python:3.9
|
||||
command:
|
||||
- sh
|
||||
- -c
|
||||
- (PIP_DISABLE_PIP_VERSION_CHECK=1 python3 -m pip install --quiet --no-warn-script-location
|
||||
'google-cloud-aiplatform==1.16.0' || PIP_DISABLE_PIP_VERSION_CHECK=1 python3
|
||||
-m pip install --quiet --no-warn-script-location 'google-cloud-aiplatform==1.16.0'
|
||||
--user) && "$0" "$@"
|
||||
- sh
|
||||
- -ec
|
||||
- |
|
||||
program_path=$(mktemp)
|
||||
printf "%s" "$0" > "$program_path"
|
||||
python3 -u "$program_path" "$@"
|
||||
- |
|
||||
def upload_Tensorflow_model_to_Google_Cloud_Vertex_AI(
|
||||
model_path,
|
||||
tensorflow_version = None,
|
||||
use_gpu = False,
|
||||
|
||||
display_name = None,
|
||||
description = None,
|
||||
|
||||
# Uncomment when anyone requests these:
|
||||
# instance_schema_uri: str = None,
|
||||
# parameters_schema_uri: str = None,
|
||||
# prediction_schema_uri: str = None,
|
||||
# explanation_metadata: "google.cloud.aiplatform_v1.types.explanation_metadata.ExplanationMetadata" = None,
|
||||
# explanation_parameters: "google.cloud.aiplatform_v1.types.explanation.ExplanationParameters" = None,
|
||||
|
||||
project = None,
|
||||
location = None,
|
||||
labels = None,
|
||||
# encryption_spec_key_name: str = None,
|
||||
staging_bucket = None,
|
||||
):
|
||||
import json
|
||||
import os
|
||||
from google.cloud import aiplatform
|
||||
|
||||
if not location:
|
||||
location = os.environ.get("CLOUD_ML_REGION")
|
||||
|
||||
if not labels:
|
||||
labels = {}
|
||||
labels["component-source"] = "github-com-ark-kun-pipeline-components"
|
||||
|
||||
model = aiplatform.Model.upload_tensorflow_saved_model(
|
||||
saved_model_dir=model_path,
|
||||
tensorflow_version=tensorflow_version,
|
||||
use_gpu=use_gpu,
|
||||
|
||||
display_name=display_name,
|
||||
description=description,
|
||||
|
||||
# instance_schema_uri=instance_schema_uri,
|
||||
# parameters_schema_uri=parameters_schema_uri,
|
||||
# prediction_schema_uri=prediction_schema_uri,
|
||||
# explanation_metadata=explanation_metadata,
|
||||
# explanation_parameters=explanation_parameters,
|
||||
|
||||
project=project,
|
||||
location=location,
|
||||
labels=labels,
|
||||
# encryption_spec_key_name=encryption_spec_key_name,
|
||||
staging_bucket=staging_bucket,
|
||||
)
|
||||
model_json = json.dumps(model.to_dict(), indent=2)
|
||||
print(model_json)
|
||||
return (model.resource_name, model_json)
|
||||
|
||||
def _deserialize_bool(s) -> bool:
|
||||
from distutils.util import strtobool
|
||||
return strtobool(s) == 1
|
||||
|
||||
def _serialize_json(obj) -> str:
|
||||
if isinstance(obj, str):
|
||||
return obj
|
||||
import json
|
||||
def default_serializer(obj):
|
||||
if hasattr(obj, 'to_struct'):
|
||||
return obj.to_struct()
|
||||
else:
|
||||
raise TypeError("Object of type '%s' is not JSON serializable and does not have .to_struct() method." % obj.__class__.__name__)
|
||||
return json.dumps(obj, default=default_serializer, sort_keys=True)
|
||||
|
||||
def _serialize_str(str_value: str) -> str:
|
||||
if not isinstance(str_value, str):
|
||||
raise TypeError('Value "{}" has type "{}" instead of str.'.format(str(str_value), str(type(str_value))))
|
||||
return str_value
|
||||
|
||||
import json
|
||||
import argparse
|
||||
_parser = argparse.ArgumentParser(prog='Upload Tensorflow model to Google Cloud Vertex AI', description='')
|
||||
_parser.add_argument("--model", dest="model_path", type=str, required=True, default=argparse.SUPPRESS)
|
||||
_parser.add_argument("--tensorflow-version", dest="tensorflow_version", type=str, required=False, default=argparse.SUPPRESS)
|
||||
_parser.add_argument("--use-gpu", dest="use_gpu", type=_deserialize_bool, required=False, default=argparse.SUPPRESS)
|
||||
_parser.add_argument("--display-name", dest="display_name", type=str, required=False, default=argparse.SUPPRESS)
|
||||
_parser.add_argument("--description", dest="description", type=str, required=False, default=argparse.SUPPRESS)
|
||||
_parser.add_argument("--project", dest="project", type=str, required=False, default=argparse.SUPPRESS)
|
||||
_parser.add_argument("--location", dest="location", type=str, required=False, default=argparse.SUPPRESS)
|
||||
_parser.add_argument("--labels", dest="labels", type=json.loads, required=False, default=argparse.SUPPRESS)
|
||||
_parser.add_argument("--staging-bucket", dest="staging_bucket", type=str, required=False, default=argparse.SUPPRESS)
|
||||
_parser.add_argument("----output-paths", dest="_output_paths", type=str, nargs=2)
|
||||
_parsed_args = vars(_parser.parse_args())
|
||||
_output_files = _parsed_args.pop("_output_paths", [])
|
||||
|
||||
_outputs = upload_Tensorflow_model_to_Google_Cloud_Vertex_AI(**_parsed_args)
|
||||
|
||||
_output_serializers = [
|
||||
_serialize_str,
|
||||
_serialize_json,
|
||||
|
||||
]
|
||||
|
||||
import os
|
||||
for idx, output_file in enumerate(_output_files):
|
||||
try:
|
||||
os.makedirs(os.path.dirname(output_file))
|
||||
except OSError:
|
||||
pass
|
||||
with open(output_file, 'w') as f:
|
||||
f.write(_output_serializers[idx](_outputs[idx]))
|
||||
args:
|
||||
- --model
|
||||
- {inputPath: model}
|
||||
- if:
|
||||
cond: {isPresent: tensorflow_version}
|
||||
then:
|
||||
- --tensorflow-version
|
||||
- {inputValue: tensorflow_version}
|
||||
- if:
|
||||
cond: {isPresent: use_gpu}
|
||||
then:
|
||||
- --use-gpu
|
||||
- {inputValue: use_gpu}
|
||||
- if:
|
||||
cond: {isPresent: display_name}
|
||||
then:
|
||||
- --display-name
|
||||
- {inputValue: display_name}
|
||||
- if:
|
||||
cond: {isPresent: description}
|
||||
then:
|
||||
- --description
|
||||
- {inputValue: description}
|
||||
- if:
|
||||
cond: {isPresent: project}
|
||||
then:
|
||||
- --project
|
||||
- {inputValue: project}
|
||||
- if:
|
||||
cond: {isPresent: location}
|
||||
then:
|
||||
- --location
|
||||
- {inputValue: location}
|
||||
- if:
|
||||
cond: {isPresent: labels}
|
||||
then:
|
||||
- --labels
|
||||
- {inputValue: labels}
|
||||
- if:
|
||||
cond: {isPresent: staging_bucket}
|
||||
then:
|
||||
- --staging-bucket
|
||||
- {inputValue: staging_bucket}
|
||||
- '----output-paths'
|
||||
- {outputPath: model_name}
|
||||
- {outputPath: model_dict}
|
||||
+181
@@ -0,0 +1,181 @@
|
||||
name: Upload XGBoost model to Google Cloud Vertex AI
|
||||
metadata:
|
||||
annotations: {author: Alexey Volkov <alexey.volkov@ark-kun.com>, canonical_location: 'https://raw.githubusercontent.com/Ark-kun/pipeline_components/master/components/google-cloud/Vertex_AI/Models/Upload_XGBoost_model/workaround_for_buggy_KFPv2_compiler/component.yaml'}
|
||||
inputs:
|
||||
- {name: model, type: XGBoostModel}
|
||||
- {name: xgboost_version, type: String, optional: true}
|
||||
- {name: display_name, type: String, optional: true}
|
||||
- {name: description, type: String, optional: true}
|
||||
- {name: project, type: String, optional: true}
|
||||
- {name: location, type: String, optional: true}
|
||||
- {name: labels, type: JsonObject, optional: true}
|
||||
- {name: staging_bucket, type: String, optional: true}
|
||||
outputs:
|
||||
- {name: model_name, type: String}
|
||||
- {name: model_dict, type: JsonObject}
|
||||
implementation:
|
||||
container:
|
||||
image: python:3.9
|
||||
command:
|
||||
- sh
|
||||
- -c
|
||||
- (PIP_DISABLE_PIP_VERSION_CHECK=1 python3 -m pip install --quiet --no-warn-script-location
|
||||
'google-cloud-aiplatform==1.16.0' || PIP_DISABLE_PIP_VERSION_CHECK=1 python3
|
||||
-m pip install --quiet --no-warn-script-location 'google-cloud-aiplatform==1.16.0'
|
||||
--user) && "$0" "$@"
|
||||
- sh
|
||||
- -ec
|
||||
- |
|
||||
program_path=$(mktemp)
|
||||
printf "%s" "$0" > "$program_path"
|
||||
python3 -u "$program_path" "$@"
|
||||
- |
|
||||
def upload_XGBoost_model_to_Google_Cloud_Vertex_AI(
|
||||
model_path,
|
||||
xgboost_version = None,
|
||||
|
||||
display_name = None,
|
||||
description = None,
|
||||
|
||||
# Uncomment when anyone requests these:
|
||||
# instance_schema_uri: str = None,
|
||||
# parameters_schema_uri: str = None,
|
||||
# prediction_schema_uri: str = None,
|
||||
# explanation_metadata: "google.cloud.aiplatform_v1.types.explanation_metadata.ExplanationMetadata" = None,
|
||||
# explanation_parameters: "google.cloud.aiplatform_v1.types.explanation.ExplanationParameters" = None,
|
||||
|
||||
project = None,
|
||||
location = None,
|
||||
labels = None,
|
||||
# encryption_spec_key_name: str = None,
|
||||
staging_bucket = None,
|
||||
):
|
||||
import json
|
||||
import os
|
||||
import shutil
|
||||
import tempfile
|
||||
from google.cloud import aiplatform
|
||||
|
||||
if not location:
|
||||
location = os.environ.get("CLOUD_ML_REGION")
|
||||
|
||||
if not labels:
|
||||
labels = {}
|
||||
labels["component-source"] = "github-com-ark-kun-pipeline-components"
|
||||
|
||||
# The serving container decides the model type based on the model file extension.
|
||||
# So we need to rename the mode file (e.g. /tmp/inputs/model/data) to *.pkl
|
||||
_, renamed_model_path = tempfile.mkstemp(suffix=".pkl")
|
||||
shutil.copyfile(src=model_path, dst=renamed_model_path)
|
||||
|
||||
model = aiplatform.Model.upload_xgboost_model_file(
|
||||
model_file_path=renamed_model_path,
|
||||
xgboost_version=xgboost_version,
|
||||
|
||||
display_name=display_name,
|
||||
description=description,
|
||||
|
||||
# instance_schema_uri=instance_schema_uri,
|
||||
# parameters_schema_uri=parameters_schema_uri,
|
||||
# prediction_schema_uri=prediction_schema_uri,
|
||||
# explanation_metadata=explanation_metadata,
|
||||
# explanation_parameters=explanation_parameters,
|
||||
|
||||
project=project,
|
||||
location=location,
|
||||
labels=labels,
|
||||
# encryption_spec_key_name=encryption_spec_key_name,
|
||||
staging_bucket=staging_bucket,
|
||||
)
|
||||
model_json = json.dumps(model.to_dict(), indent=2)
|
||||
print(model_json)
|
||||
return (model.resource_name, model_json)
|
||||
|
||||
def _serialize_json(obj) -> str:
|
||||
if isinstance(obj, str):
|
||||
return obj
|
||||
import json
|
||||
def default_serializer(obj):
|
||||
if hasattr(obj, 'to_struct'):
|
||||
return obj.to_struct()
|
||||
else:
|
||||
raise TypeError("Object of type '%s' is not JSON serializable and does not have .to_struct() method." % obj.__class__.__name__)
|
||||
return json.dumps(obj, default=default_serializer, sort_keys=True)
|
||||
|
||||
def _serialize_str(str_value: str) -> str:
|
||||
if not isinstance(str_value, str):
|
||||
raise TypeError('Value "{}" has type "{}" instead of str.'.format(str(str_value), str(type(str_value))))
|
||||
return str_value
|
||||
|
||||
import json
|
||||
import argparse
|
||||
_parser = argparse.ArgumentParser(prog='Upload XGBoost model to Google Cloud Vertex AI', description='')
|
||||
_parser.add_argument("--model", dest="model_path", type=str, required=True, default=argparse.SUPPRESS)
|
||||
_parser.add_argument("--xgboost-version", dest="xgboost_version", type=str, required=False, default=argparse.SUPPRESS)
|
||||
_parser.add_argument("--display-name", dest="display_name", type=str, required=False, default=argparse.SUPPRESS)
|
||||
_parser.add_argument("--description", dest="description", type=str, required=False, default=argparse.SUPPRESS)
|
||||
_parser.add_argument("--project", dest="project", type=str, required=False, default=argparse.SUPPRESS)
|
||||
_parser.add_argument("--location", dest="location", type=str, required=False, default=argparse.SUPPRESS)
|
||||
_parser.add_argument("--labels", dest="labels", type=json.loads, required=False, default=argparse.SUPPRESS)
|
||||
_parser.add_argument("--staging-bucket", dest="staging_bucket", type=str, required=False, default=argparse.SUPPRESS)
|
||||
_parser.add_argument("----output-paths", dest="_output_paths", type=str, nargs=2)
|
||||
_parsed_args = vars(_parser.parse_args())
|
||||
_output_files = _parsed_args.pop("_output_paths", [])
|
||||
|
||||
_outputs = upload_XGBoost_model_to_Google_Cloud_Vertex_AI(**_parsed_args)
|
||||
|
||||
_output_serializers = [
|
||||
_serialize_str,
|
||||
_serialize_json,
|
||||
|
||||
]
|
||||
|
||||
import os
|
||||
for idx, output_file in enumerate(_output_files):
|
||||
try:
|
||||
os.makedirs(os.path.dirname(output_file))
|
||||
except OSError:
|
||||
pass
|
||||
with open(output_file, 'w') as f:
|
||||
f.write(_output_serializers[idx](_outputs[idx]))
|
||||
args:
|
||||
- --model
|
||||
- {inputPath: model}
|
||||
- if:
|
||||
cond: {isPresent: xgboost_version}
|
||||
then:
|
||||
- --xgboost-version
|
||||
- {inputValue: xgboost_version}
|
||||
- if:
|
||||
cond: {isPresent: display_name}
|
||||
then:
|
||||
- --display-name
|
||||
- {inputValue: display_name}
|
||||
- if:
|
||||
cond: {isPresent: description}
|
||||
then:
|
||||
- --description
|
||||
- {inputValue: description}
|
||||
- if:
|
||||
cond: {isPresent: project}
|
||||
then:
|
||||
- --project
|
||||
- {inputValue: project}
|
||||
- if:
|
||||
cond: {isPresent: location}
|
||||
then:
|
||||
- --location
|
||||
- {inputValue: location}
|
||||
- if:
|
||||
cond: {isPresent: labels}
|
||||
then:
|
||||
- --labels
|
||||
- {inputValue: labels}
|
||||
- if:
|
||||
cond: {isPresent: staging_bucket}
|
||||
then:
|
||||
- --staging-bucket
|
||||
- {inputValue: staging_bucket}
|
||||
- '----output-paths'
|
||||
- {outputPath: model_name}
|
||||
- {outputPath: model_dict}
|
||||
@@ -0,0 +1,35 @@
|
||||
name: Download from GCS
|
||||
inputs:
|
||||
- {name: GCS path, type: String}
|
||||
outputs:
|
||||
- {name: Data}
|
||||
metadata:
|
||||
annotations:
|
||||
author: Alexey Volkov <alexey.volkov@ark-kun.com>
|
||||
canonical_location: 'https://raw.githubusercontent.com/Ark-kun/pipeline_components/master/components/google-cloud/storage/download/workaround_for_buggy_KFPv2_compiler/component.yaml'
|
||||
implementation:
|
||||
container:
|
||||
image: google/cloud-sdk
|
||||
command:
|
||||
- bash # Pattern comparison only works in Bash
|
||||
- -ex
|
||||
- -c
|
||||
- |
|
||||
if [ -n "${GOOGLE_APPLICATION_CREDENTIALS}" ]; then
|
||||
gcloud auth activate-service-account --key-file="${GOOGLE_APPLICATION_CREDENTIALS}"
|
||||
fi
|
||||
|
||||
uri="$0"
|
||||
output_path="$1"
|
||||
|
||||
# Checking whether the URI points to a single blob, a directory or a URI pattern
|
||||
# URI points to a blob when that URI does not end with slash and listing that URI only yields the same URI
|
||||
if [[ "$uri" != */ ]] && (gsutil ls "$uri" | grep --fixed-strings --line-regexp "$uri"); then
|
||||
mkdir -p "$(dirname "$output_path")"
|
||||
gsutil -m cp -r "$uri" "$output_path"
|
||||
else
|
||||
mkdir -p "$output_path" # When source path is a directory, gsutil requires the destination to also be a directory
|
||||
gsutil -m rsync -r "$uri" "$output_path" # gsutil cp has different path handling than Linux cp. It always puts the source directory (name) inside the destination directory. gsutil rsync does not have that problem.
|
||||
fi
|
||||
- inputValue: GCS path
|
||||
- outputPath: Data
|
||||
+112
@@ -0,0 +1,112 @@
|
||||
name: Load image classification model from tfhub
|
||||
description: |
|
||||
Loads specified model from TFHub, creates layer to receive additional (3 channel) imagery data.
|
||||
Args:
|
||||
class_names (Sequence[str]):
|
||||
Sequence of strings of categories for classification corresponding to input data.
|
||||
loaded_model_path (str):
|
||||
Output path for the loaded model.
|
||||
image_size_path (str):
|
||||
Output path for the model expected image size.
|
||||
model_name (Optional[str]):
|
||||
Name of the pre-trained image classification model to load from TFHub.
|
||||
Eligible model_name:
|
||||
- efficientnetv2-s
|
||||
- efficientnetv2-m
|
||||
- efficientnetv2-l
|
||||
- efficientnetv2-s-21k
|
||||
- efficientnetv2-m-21k
|
||||
- efficientnetv2-l-21k
|
||||
- efficientnetv2-xl-21k
|
||||
- efficientnetv2-b0-21k
|
||||
- efficientnetv2-b1-21k
|
||||
- efficientnetv2-b2-21k
|
||||
- efficientnetv2-b3-21k
|
||||
- efficientnetv2-s-21k-ft1k
|
||||
- efficientnetv2-m-21k-ft1k
|
||||
- efficientnetv2-l-21k-ft1k
|
||||
- efficientnetv2-xl-21k-ft1k
|
||||
- efficientnetv2-b0-21k-ft1k
|
||||
- efficientnetv2-b1-21k-ft1k
|
||||
- efficientnetv2-b2-21k-ft1k
|
||||
- efficientnetv2-b3-21k-ft1k
|
||||
- efficientnetv2-b0
|
||||
- efficientnetv2-b1
|
||||
- efficientnetv2-b2
|
||||
- efficientnetv2-b3
|
||||
- efficientnet_b0
|
||||
- efficientnet_b1
|
||||
- efficientnet_b2
|
||||
- efficientnet_b3
|
||||
- efficientnet_b4
|
||||
- efficientnet_b5
|
||||
- efficientnet_b6
|
||||
- efficientnet_b7
|
||||
- bit_s-r50x1
|
||||
- inception_v3
|
||||
- inception_resnet_v2
|
||||
- resnet_v1_50
|
||||
- resnet_v1_101
|
||||
- resnet_v1_152
|
||||
- resnet_v2_50
|
||||
- resnet_v2_101
|
||||
- resnet_v2_152
|
||||
- nasnet_large
|
||||
- nasnet_mobile
|
||||
- pnasnet_large
|
||||
- mobilenet_v2_100_224
|
||||
- mobilenet_v2_130_224
|
||||
- mobilenet_v2_140_224
|
||||
- mobilenet_v3_small_100_224
|
||||
- mobilenet_v3_small_075_224
|
||||
- mobilenet_v3_large_100_224
|
||||
- mobilenet_v3_large_075_224
|
||||
dropout_rate (Optional[float]):
|
||||
Fraction of input units to drop in the last layer. Value should be between 0.0 and 1.0.
|
||||
trainable (Optional[bool]):
|
||||
If true fine tuning will be performed on entire Hub model. If false only additional
|
||||
layers will be trained.
|
||||
l2_regularization_penalty (Optional[float]):
|
||||
l2 regularization penalty.
|
||||
inputs:
|
||||
- {name: class_names, type: 'typing.List[str]', description: List of class names corresponding
|
||||
to the input image data}
|
||||
- {name: model_name, type: String, description: Name of the TFHub model to load, default: efficientnetv2-xl-21k,
|
||||
optional: true}
|
||||
- {name: dropout_rate, type: Float, description: Dropout rate, default: '0.2', optional: true}
|
||||
- name: trainable
|
||||
type: Boolean
|
||||
description: True if fine tuning should be performed
|
||||
default: "True"
|
||||
optional: true
|
||||
- {name: l2_regularization_penalty, type: Float, description: Regularization penalty,
|
||||
default: '0.0001', optional: true}
|
||||
outputs:
|
||||
- {name: loaded_model_path, type: TensorflowSavedModel, description: Output path for
|
||||
the loaded model}
|
||||
- {name: image_size_path, type: HeightWidth}
|
||||
implementation:
|
||||
container:
|
||||
image: us-docker.pkg.dev/vertex-ai/ready-to-go-image-classification/image-components:v0.1
|
||||
# command is a list of strings (command-line arguments).
|
||||
# The YAML language has two syntaxes for lists and you can use either of them.
|
||||
# Here we use the "flow syntax" - comma-separated strings inside square brackets.
|
||||
command: [
|
||||
python3,
|
||||
# Path of the program inside the container
|
||||
/pipelines/component/src/loading_component.py,
|
||||
--loaded-model-path,
|
||||
{outputPath: loaded_model_path},
|
||||
--class-names,
|
||||
{inputValue: class_names},
|
||||
--model-name,
|
||||
{inputValue: model_name},
|
||||
--dropout-rate,
|
||||
{inputValue: dropout_rate},
|
||||
--trainable,
|
||||
{inputValue: trainable},
|
||||
--l2-regularization-penalty,
|
||||
{inputValue: l2_regularization_penalty},
|
||||
--image-size-path,
|
||||
{outputPath: image_size_path},
|
||||
]
|
||||
+57
@@ -0,0 +1,57 @@
|
||||
name: Preprocess image data
|
||||
description: |
|
||||
Preprocess the image data and split between train and validation.
|
||||
Args:
|
||||
input_data_path (str):
|
||||
Input path for the TFRecord image data. Data will be formatted as 'label' (encoded image
|
||||
label), and 'image_raw' (the binary string of the image data).
|
||||
height_width_path (str):
|
||||
Path to square height and width to resize images to. File should contain single float value.
|
||||
Value is dependent on training model.
|
||||
preprocessed_training_data_path (str):
|
||||
Output path for the TFRecord training data. Data will be formatted as 'label' (encoded image
|
||||
label), and 'image_raw' (the binary string of the image data).
|
||||
preprocessed_validation_data_path (str):
|
||||
Output path for the TFRecord validation data. Data will be formatted as 'label' (encoded
|
||||
image label), and 'image_raw' (the binary string of the image data).
|
||||
validation_split (Optional[float]):
|
||||
Fraction of data that will make up validation dataset. Value should be between 0.0 and 1.0.
|
||||
seed (Optional[int]):
|
||||
The global random seed to ensure the system gets a unique random sequence
|
||||
that is deterministic (https://www.tensorflow.org/api_docs/python/tf/random/set_seed).
|
||||
inputs:
|
||||
- {name: input_data_path, type: ImageDatasetTFRecord, description: 'Input path for
|
||||
the TFRecord image data,'}
|
||||
- {name: height_width_path, type: HeightWidth, description: 'Path to square height and width to
|
||||
resize images to,'}
|
||||
- {name: validation_split, type: Float, description: 'Fraction of data that will make
|
||||
up validation dataset,', default: '0.2', optional: true}
|
||||
- {name: seed, type: Integer, description: Random seed, default: '0', optional: true}
|
||||
outputs:
|
||||
- {name: preprocessed_training_data_path, type: ImageDatasetTFRecord, description: 'Output
|
||||
path for the training data,'}
|
||||
- {name: preprocessed_validation_data_path, type: ImageDatasetTFRecord, description: 'Output
|
||||
path for the validation data,'}
|
||||
implementation:
|
||||
container:
|
||||
image: us-docker.pkg.dev/vertex-ai/ready-to-go-image-classification/image-components:v0.1
|
||||
# command is a list of strings (command-line arguments).
|
||||
# The YAML language has two syntaxes for lists and you can use either of them.
|
||||
# Here we use the "flow syntax" - comma-separated strings inside square brackets.
|
||||
command: [
|
||||
python3,
|
||||
# Path of the program inside the container
|
||||
/pipelines/component/src/preprocessing_component.py,
|
||||
--input-data-path,
|
||||
{inputPath: input_data_path},
|
||||
--height-width-path,
|
||||
{inputPath: height_width_path},
|
||||
--validation-split,
|
||||
{inputValue: validation_split},
|
||||
--seed,
|
||||
{inputValue: seed},
|
||||
--preprocessed-training-data-path,
|
||||
{outputPath: preprocessed_training_data_path},
|
||||
--preprocessed-validation-data-path,
|
||||
{outputPath: preprocessed_validation_data_path},
|
||||
]
|
||||
+90
@@ -0,0 +1,90 @@
|
||||
name: Train tensorflow image classification model
|
||||
description: |
|
||||
Creates a trained image classification TensorFlow model.
|
||||
Args:
|
||||
preprocessed_training_data_path (str):
|
||||
Input path to the TFRecord training data. Data will be formatted as 'label' (encoded image
|
||||
label), and 'image_raw' (the binary string of the image data).
|
||||
preprocessed_validation_data_path (str):
|
||||
Input path to the TFRecord validation data. Data will be formatted as 'label' (encoded
|
||||
image label), and 'image_raw' (the binary string of the image data).
|
||||
model_path (str):
|
||||
Input path to the loaded pre-trained model.
|
||||
trained_model_path (str):
|
||||
Output path to save the trained model to.
|
||||
optimizer_name (Optional[str]):
|
||||
Name of the tf.keras optimizer. Available optimizers are listed at
|
||||
https://keras.io/api/optimizers/
|
||||
optimizer_parameters (Optional[Dict[str, str]]):
|
||||
Optimizer parameters.
|
||||
loss_function_name (Optional[str]):
|
||||
Name of the loss function.
|
||||
loss_function_parameters (Optional[Dict[str, str]]):
|
||||
Loss function parameters.
|
||||
number_of_epochs (Optional[int]):
|
||||
Number of training iterations over data.
|
||||
metric_names (Optional[Sequence[str]]):
|
||||
List of tf.keras.metrics to be evaluated by the model during training and testing. Available
|
||||
metrics are listed at https://keras.io/api/metrics/.
|
||||
seed Optional(int):
|
||||
The global random seed to ensure the system gets a unique random sequence
|
||||
that is deterministic (https://www.tensorflow.org/api_docs/python/tf/random/set_seed).
|
||||
inputs:
|
||||
- {name: preprocessed_training_data_path, type: ImageDatasetTFRecord, description: 'Input
|
||||
path for the training data,'}
|
||||
- {name: preprocessed_validation_data_path, type: ImageDatasetTFRecord, description: 'Input
|
||||
path for the validation data,'}
|
||||
- {name: model_path, type: TensorflowSavedModel, description: 'Input path for the
|
||||
model,'}
|
||||
- {name: optimizer_name, type: String, description: 'Name of the optimizer,', default: SGD,
|
||||
optional: true}
|
||||
- {name: optimizer_parameters, type: 'typing.Dict[str, str]', description: 'Optimizer
|
||||
parameters,', default: '{}', optional: true}
|
||||
- {name: loss_function_name, type: String, description: 'Name of the loss function,',
|
||||
default: CategoricalCrossentropy, optional: true}
|
||||
- {name: loss_function_parameters, type: 'typing.Dict[str, str]', description: 'Loss
|
||||
function parameters,', default: '{}', optional: true}
|
||||
- {name: number_of_epochs, type: Integer, description: 'Number of epochs,', default: '10',
|
||||
optional: true}
|
||||
- {name: metric_names, type: 'typing.List[str]', description: 'List of metrics to
|
||||
use,', default: '["accuracy"]', optional: true}
|
||||
- {name: seed, type: Integer, description: 'Random seed,', default: '0', optional: true}
|
||||
- {name: batch_size, type: Integer, description: Batch size, default: '16', optional: true}
|
||||
outputs:
|
||||
- {name: trained_model_path, type: TensorflowSavedModel, description: 'Output path
|
||||
for the saved model,'}
|
||||
implementation:
|
||||
container:
|
||||
image: us-docker.pkg.dev/vertex-ai/ready-to-go-image-classification/image-components:v0.1
|
||||
# command is a list of strings (command-line arguments).
|
||||
# The YAML language has two syntaxes for lists and you can use either of them.
|
||||
# Here we use the "flow syntax" - comma-separated strings inside square brackets.
|
||||
command: [
|
||||
python3,
|
||||
# Path of the program inside the container
|
||||
/pipelines/component/src/training_component.py,
|
||||
--preprocessed-training-data-path,
|
||||
{inputPath: preprocessed_training_data_path},
|
||||
--preprocessed-validation-data-path,
|
||||
{inputPath: preprocessed_validation_data_path},
|
||||
--model-path,
|
||||
{inputPath: model_path},
|
||||
--trained-model-path,
|
||||
{outputPath: trained_model_path},
|
||||
--optimizer-name,
|
||||
{inputValue: optimizer_name},
|
||||
--loss-function-name,
|
||||
{inputValue: loss_function_name},
|
||||
--number-of-epochs,
|
||||
{inputValue: number_of_epochs},
|
||||
--seed,
|
||||
{inputValue: seed},
|
||||
--batch-size,
|
||||
{inputValue: batch_size},
|
||||
--metric-names,
|
||||
{inputValue: metric_names},
|
||||
--optimizer-parameters,
|
||||
{inputValue: optimizer_parameters},
|
||||
--loss-function-parameters,
|
||||
{inputValue: loss_function_parameters},
|
||||
]
|
||||
+37
@@ -0,0 +1,37 @@
|
||||
name: Transcode imagedataset tfrecord from csv
|
||||
description: |
|
||||
Transcodes CSV Data into TFRecord file of TFExamples.
|
||||
Args:
|
||||
csv_image_data_path (str):
|
||||
Path to the CSV image data. Data must include 'image_filepath' (Path to image file) and
|
||||
'image_label' (output for a prediction) fields.
|
||||
class_names (Sequence[str]):
|
||||
Sequence of strings of categories for classification corresponding to input data.
|
||||
tfrecord_image_data_path (str):
|
||||
Output path for the TFRecord image data. Data will be formatted as 'label' (encoded image
|
||||
label), and 'image_raw' (the binary string of the image data).
|
||||
inputs:
|
||||
- {name: csv_image_data_path, type: ImageDatasetCSV, description: Input path for the
|
||||
CSV image data}
|
||||
- {name: class_names, type: 'typing.List[str]', description: List of class names corresponding
|
||||
to the input image data}
|
||||
outputs:
|
||||
- {name: tfrecord_image_data_path, type: ImageDatasetTFRecord, description: Output
|
||||
path for the TFRecord image data}
|
||||
implementation:
|
||||
container:
|
||||
image: us-docker.pkg.dev/vertex-ai/ready-to-go-image-classification/image-components:v0.1
|
||||
# command is a list of strings (command-line arguments).
|
||||
# The YAML language has two syntaxes for lists and you can use either of them.
|
||||
# Here we use the "flow syntax" - comma-separated strings inside square brackets.
|
||||
command: [
|
||||
python3,
|
||||
# Path of the program inside the container
|
||||
/pipelines/component/src/transcoding_csv_component.py,
|
||||
--csv-image-data-path,
|
||||
{inputPath: csv_image_data_path},
|
||||
--tfrecord-image-data-path,
|
||||
{outputPath: tfrecord_image_data_path},
|
||||
--class-names,
|
||||
{inputValue: class_names},
|
||||
]
|
||||
+39
@@ -0,0 +1,39 @@
|
||||
name: Transcode imagedataset tfrecord from jsonlines
|
||||
description: |
|
||||
Transcodes JSONL Data into TFRecord file of TFExamples.
|
||||
Args:
|
||||
jsonl_image_data_path (str):
|
||||
Input path for the JSONL image data
|
||||
Path to the JSONL image data. Each line corresponds to a JSON input describing an image.
|
||||
Schema follows AutoML image classification JSONL format
|
||||
https://cloud.google.com/vertex-ai/docs/image-data/classification/prepare-data#json-lines.
|
||||
class_names (Sequence[str]):
|
||||
Sequence of strings of categories for classification corresponding to input data.
|
||||
tfrecord_image_data_path (str):
|
||||
Output path for the TFRecord image data. Data will be formatted as 'label' (encoded image
|
||||
label), and 'image_raw' (the binary string of the image data).
|
||||
inputs:
|
||||
- {name: jsonl_image_data_path, type: ImageDatasetJsonLines, description: Input path
|
||||
for the JSONL image data}
|
||||
- {name: class_names, type: 'typing.List[str]', description: List of class names corresponding
|
||||
to the input image data}
|
||||
outputs:
|
||||
- {name: tfrecord_image_data_path, type: ImageDatasetTFRecord, description: Output
|
||||
path for the TFRecord image data}
|
||||
implementation:
|
||||
container:
|
||||
image: us-docker.pkg.dev/vertex-ai/ready-to-go-image-classification/image-components:v0.1
|
||||
# command is a list of strings (command-line arguments).
|
||||
# The YAML language has two syntaxes for lists and you can use either of them.
|
||||
# Here we use the "flow syntax" - comma-separated strings inside square brackets.
|
||||
command: [
|
||||
python3,
|
||||
# Path of the program inside the container
|
||||
/pipelines/component/src/transcoding_jsonl_component.py,
|
||||
--jsonl-image-data-path,
|
||||
{inputPath: jsonl_image_data_path},
|
||||
--tfrecord-image-data-path,
|
||||
{outputPath: tfrecord_image_data_path},
|
||||
--class-names,
|
||||
{inputValue: class_names},
|
||||
]
|
||||
+113
@@ -0,0 +1,113 @@
|
||||
name: Binarize column using Pandas on CSV data
|
||||
metadata:
|
||||
annotations: {author: Alexey Volkov <alexey.volkov@ark-kun.com>, canonical_location: 'https://raw.githubusercontent.com/Ark-kun/pipeline_components/master/components/pandas/Binarize_column/in_CSV_format/component.yaml'}
|
||||
inputs:
|
||||
- {name: table, type: CSV}
|
||||
- {name: column_name, type: String}
|
||||
- {name: predicate, type: String, default: '> 0', optional: true}
|
||||
- {name: new_column_name, type: String, optional: true}
|
||||
- name: keep_original_column
|
||||
type: Boolean
|
||||
default: "False"
|
||||
optional: true
|
||||
outputs:
|
||||
- {name: transformed_table, type: CSV}
|
||||
implementation:
|
||||
container:
|
||||
image: python:3.9
|
||||
command:
|
||||
- sh
|
||||
- -c
|
||||
- (PIP_DISABLE_PIP_VERSION_CHECK=1 python3 -m pip install --quiet --no-warn-script-location
|
||||
'pandas==1.4.3' || PIP_DISABLE_PIP_VERSION_CHECK=1 python3 -m pip install --quiet
|
||||
--no-warn-script-location 'pandas==1.4.3' --user) && "$0" "$@"
|
||||
- sh
|
||||
- -ec
|
||||
- |
|
||||
program_path=$(mktemp)
|
||||
printf "%s" "$0" > "$program_path"
|
||||
python3 -u "$program_path" "$@"
|
||||
- |
|
||||
def _make_parent_dirs_and_return_path(file_path: str):
|
||||
import os
|
||||
os.makedirs(os.path.dirname(file_path), exist_ok=True)
|
||||
return file_path
|
||||
|
||||
def binarize_column_using_Pandas_on_CSV_data(
|
||||
table_path,
|
||||
transformed_table_path,
|
||||
column_name,
|
||||
predicate = "> 0",
|
||||
new_column_name = None,
|
||||
keep_original_column = False,
|
||||
):
|
||||
import pandas
|
||||
|
||||
df = pandas.read_csv(table_path).convert_dtypes()
|
||||
original_series = df[column_name]
|
||||
|
||||
# Dynamically executing the predicate code
|
||||
# Variable namespace for code execution
|
||||
namespace = dict(x=original_series)
|
||||
# I though that there should be no space before `predicate` so that "dot" predicate methods like ".between(min, max)" work.
|
||||
# However Python allows spaces before dot: `df .isna()`.
|
||||
# So having a space is not a problem
|
||||
transform_code = f"""new_series_boolean = x {predicate}"""
|
||||
# Note: exec() takes no keyword arguments
|
||||
# exec(__source=transform_code, __globals=namespace)
|
||||
exec(transform_code, namespace)
|
||||
new_series_boolean = namespace["new_series_boolean"]
|
||||
|
||||
# There are multiple ways to convert boolean column to integer.
|
||||
# .apply(int) might be faster. https://stackoverflow.com/a/49804868/1497385
|
||||
# TODO: Do a proper benchmark.
|
||||
new_series = new_series_boolean.apply(int)
|
||||
# new_series = new_series_boolean.astype(int)
|
||||
# new_series = new_series_boolean.replace({False: 0, True: 1})
|
||||
|
||||
if new_column_name:
|
||||
df.insert(loc=0, column=new_column_name, value=new_series)
|
||||
if not keep_original_column:
|
||||
df = df.drop(columns=[column_name])
|
||||
else:
|
||||
df[column_name] = new_series
|
||||
|
||||
df.to_csv(transformed_table_path, index=False)
|
||||
|
||||
def _deserialize_bool(s) -> bool:
|
||||
from distutils.util import strtobool
|
||||
return strtobool(s) == 1
|
||||
|
||||
import argparse
|
||||
_parser = argparse.ArgumentParser(prog='Binarize column using Pandas on CSV data', description='')
|
||||
_parser.add_argument("--table", dest="table_path", type=str, required=True, default=argparse.SUPPRESS)
|
||||
_parser.add_argument("--column-name", dest="column_name", type=str, required=True, default=argparse.SUPPRESS)
|
||||
_parser.add_argument("--predicate", dest="predicate", type=str, required=False, default=argparse.SUPPRESS)
|
||||
_parser.add_argument("--new-column-name", dest="new_column_name", type=str, required=False, default=argparse.SUPPRESS)
|
||||
_parser.add_argument("--keep-original-column", dest="keep_original_column", type=_deserialize_bool, required=False, default=argparse.SUPPRESS)
|
||||
_parser.add_argument("--transformed-table", dest="transformed_table_path", type=_make_parent_dirs_and_return_path, required=True, default=argparse.SUPPRESS)
|
||||
_parsed_args = vars(_parser.parse_args())
|
||||
|
||||
_outputs = binarize_column_using_Pandas_on_CSV_data(**_parsed_args)
|
||||
args:
|
||||
- --table
|
||||
- {inputPath: table}
|
||||
- --column-name
|
||||
- {inputValue: column_name}
|
||||
- if:
|
||||
cond: {isPresent: predicate}
|
||||
then:
|
||||
- --predicate
|
||||
- {inputValue: predicate}
|
||||
- if:
|
||||
cond: {isPresent: new_column_name}
|
||||
then:
|
||||
- --new-column-name
|
||||
- {inputValue: new_column_name}
|
||||
- if:
|
||||
cond: {isPresent: keep_original_column}
|
||||
then:
|
||||
- --keep-original-column
|
||||
- {inputValue: keep_original_column}
|
||||
- --transformed-table
|
||||
- {outputPath: transformed_table}
|
||||
+75
@@ -0,0 +1,75 @@
|
||||
name: Fill all missing values using Pandas on CSV data
|
||||
metadata:
|
||||
annotations: {author: Alexey Volkov <alexey.volkov@ark-kun.com>, canonical_location: 'https://raw.githubusercontent.com/Ark-kun/pipeline_components/master/components/pandas/Fill_all_missing_values/in_CSV_format/component.yaml'}
|
||||
inputs:
|
||||
- {name: table, type: CSV}
|
||||
- {name: replacement_value, type: String, default: '0', optional: true}
|
||||
- {name: column_names, type: JsonArray, optional: true}
|
||||
outputs:
|
||||
- {name: transformed_table, type: CSV}
|
||||
implementation:
|
||||
container:
|
||||
image: python:3.9
|
||||
command:
|
||||
- sh
|
||||
- -c
|
||||
- (PIP_DISABLE_PIP_VERSION_CHECK=1 python3 -m pip install --quiet --no-warn-script-location
|
||||
'pandas==1.4.1' || PIP_DISABLE_PIP_VERSION_CHECK=1 python3 -m pip install --quiet
|
||||
--no-warn-script-location 'pandas==1.4.1' --user) && "$0" "$@"
|
||||
- sh
|
||||
- -ec
|
||||
- |
|
||||
program_path=$(mktemp)
|
||||
printf "%s" "$0" > "$program_path"
|
||||
python3 -u "$program_path" "$@"
|
||||
- |
|
||||
def _make_parent_dirs_and_return_path(file_path: str):
|
||||
import os
|
||||
os.makedirs(os.path.dirname(file_path), exist_ok=True)
|
||||
return file_path
|
||||
|
||||
def fill_all_missing_values_using_Pandas_on_CSV_data(
|
||||
table_path,
|
||||
transformed_table_path,
|
||||
replacement_value = "0",
|
||||
column_names = None,
|
||||
):
|
||||
import pandas
|
||||
|
||||
df = pandas.read_csv(
|
||||
table_path,
|
||||
dtype="string",
|
||||
)
|
||||
|
||||
for column_name in column_names or df.columns:
|
||||
df[column_name] = df[column_name].fillna(value=replacement_value)
|
||||
|
||||
df.to_csv(
|
||||
transformed_table_path, index=False,
|
||||
)
|
||||
|
||||
import json
|
||||
import argparse
|
||||
_parser = argparse.ArgumentParser(prog='Fill all missing values using Pandas on CSV data', description='')
|
||||
_parser.add_argument("--table", dest="table_path", type=str, required=True, default=argparse.SUPPRESS)
|
||||
_parser.add_argument("--replacement-value", dest="replacement_value", type=str, required=False, default=argparse.SUPPRESS)
|
||||
_parser.add_argument("--column-names", dest="column_names", type=json.loads, required=False, default=argparse.SUPPRESS)
|
||||
_parser.add_argument("--transformed-table", dest="transformed_table_path", type=_make_parent_dirs_and_return_path, required=True, default=argparse.SUPPRESS)
|
||||
_parsed_args = vars(_parser.parse_args())
|
||||
|
||||
_outputs = fill_all_missing_values_using_Pandas_on_CSV_data(**_parsed_args)
|
||||
args:
|
||||
- --table
|
||||
- {inputPath: table}
|
||||
- if:
|
||||
cond: {isPresent: replacement_value}
|
||||
then:
|
||||
- --replacement-value
|
||||
- {inputValue: replacement_value}
|
||||
- if:
|
||||
cond: {isPresent: column_names}
|
||||
then:
|
||||
- --column-names
|
||||
- {inputValue: column_names}
|
||||
- --transformed-table
|
||||
- {outputPath: transformed_table}
|
||||
+59
@@ -0,0 +1,59 @@
|
||||
name: Select columns using Pandas on CSV data
|
||||
metadata:
|
||||
annotations: {author: Alexey Volkov <alexey.volkov@ark-kun.com>, canonical_location: 'https://raw.githubusercontent.com/Ark-kun/pipeline_components/master/components/pandas/Select_columns/in_CSV_format/component.yaml'}
|
||||
inputs:
|
||||
- {name: table, type: CSV}
|
||||
- {name: column_names, type: JsonArray}
|
||||
outputs:
|
||||
- {name: transformed_table, type: CSV}
|
||||
implementation:
|
||||
container:
|
||||
image: python:3.9
|
||||
command:
|
||||
- sh
|
||||
- -c
|
||||
- (PIP_DISABLE_PIP_VERSION_CHECK=1 python3 -m pip install --quiet --no-warn-script-location
|
||||
'pandas==1.4.2' || PIP_DISABLE_PIP_VERSION_CHECK=1 python3 -m pip install --quiet
|
||||
--no-warn-script-location 'pandas==1.4.2' --user) && "$0" "$@"
|
||||
- sh
|
||||
- -ec
|
||||
- |
|
||||
program_path=$(mktemp)
|
||||
printf "%s" "$0" > "$program_path"
|
||||
python3 -u "$program_path" "$@"
|
||||
- |
|
||||
def _make_parent_dirs_and_return_path(file_path: str):
|
||||
import os
|
||||
os.makedirs(os.path.dirname(file_path), exist_ok=True)
|
||||
return file_path
|
||||
|
||||
def select_columns_using_Pandas_on_CSV_data(
|
||||
table_path,
|
||||
transformed_table_path,
|
||||
column_names,
|
||||
):
|
||||
import pandas
|
||||
|
||||
df = pandas.read_csv(
|
||||
table_path,
|
||||
dtype="string",
|
||||
)
|
||||
df = df[column_names]
|
||||
df.to_csv(transformed_table_path, index=False)
|
||||
|
||||
import json
|
||||
import argparse
|
||||
_parser = argparse.ArgumentParser(prog='Select columns using Pandas on CSV data', description='')
|
||||
_parser.add_argument("--table", dest="table_path", type=str, required=True, default=argparse.SUPPRESS)
|
||||
_parser.add_argument("--column-names", dest="column_names", type=json.loads, required=True, default=argparse.SUPPRESS)
|
||||
_parser.add_argument("--transformed-table", dest="transformed_table_path", type=_make_parent_dirs_and_return_path, required=True, default=argparse.SUPPRESS)
|
||||
_parsed_args = vars(_parser.parse_args())
|
||||
|
||||
_outputs = select_columns_using_Pandas_on_CSV_data(**_parsed_args)
|
||||
args:
|
||||
- --table
|
||||
- {inputPath: table}
|
||||
- --column-names
|
||||
- {inputValue: column_names}
|
||||
- --transformed-table
|
||||
- {outputPath: transformed_table}
|
||||
+102
@@ -0,0 +1,102 @@
|
||||
name: Create fully connected tensorflow network
|
||||
description: Creates fully-connected network in Tensorflow SavedModel format
|
||||
metadata:
|
||||
annotations: {author: Alexey Volkov <alexey.volkov@ark-kun.com>, canonical_location: 'https://raw.githubusercontent.com/Ark-kun/pipeline_components/master/components/tensorflow/Create_fully_connected_network/component.yaml'}
|
||||
inputs:
|
||||
- {name: input_size, type: Integer}
|
||||
- {name: hidden_layer_sizes, type: JsonArray, default: '[]', optional: true}
|
||||
- {name: output_size, type: Integer, default: '1', optional: true}
|
||||
- {name: activation_name, type: String, default: relu, optional: true}
|
||||
- {name: output_activation_name, type: String, optional: true}
|
||||
- {name: random_seed, type: Integer, default: '0', optional: true}
|
||||
outputs:
|
||||
- {name: model, type: TensorflowSavedModel}
|
||||
implementation:
|
||||
container:
|
||||
image: tensorflow/tensorflow:2.7.0
|
||||
command:
|
||||
- sh
|
||||
- -ec
|
||||
- |
|
||||
program_path=$(mktemp)
|
||||
printf "%s" "$0" > "$program_path"
|
||||
python3 -u "$program_path" "$@"
|
||||
- |
|
||||
def _make_parent_dirs_and_return_path(file_path: str):
|
||||
import os
|
||||
os.makedirs(os.path.dirname(file_path), exist_ok=True)
|
||||
return file_path
|
||||
|
||||
def create_fully_connected_tensorflow_network(
|
||||
input_size,
|
||||
model_path,
|
||||
hidden_layer_sizes = [],
|
||||
output_size = 1,
|
||||
activation_name = "relu",
|
||||
output_activation_name = None,
|
||||
random_seed = 0,
|
||||
):
|
||||
"""Creates fully-connected network in Tensorflow SavedModel format"""
|
||||
import tensorflow as tf
|
||||
tf.random.set_seed(seed=random_seed)
|
||||
|
||||
model = tf.keras.models.Sequential()
|
||||
model.add(tf.keras.Input(shape=(input_size,)))
|
||||
for layer_size in hidden_layer_sizes:
|
||||
model.add(tf.keras.layers.Dense(units=layer_size, activation=activation_name))
|
||||
# The last layer is left without activation
|
||||
model.add(tf.keras.layers.Dense(units=output_size, activation=output_activation_name))
|
||||
|
||||
print(model.summary())
|
||||
|
||||
# Using tf.keras.models.save_model instead of tf.saved_model.save to prevent downstream error:
|
||||
#tf.saved_model.save(model, model_path)
|
||||
# ValueError: Unable to create a Keras model from this SavedModel.
|
||||
# This SavedModel was created with `tf.saved_model.save`, and lacks the Keras metadata.
|
||||
# Please save your Keras model by calling `model.save`or `tf.keras.models.save_model`.
|
||||
# See https://github.com/keras-team/keras/issues/16451
|
||||
tf.keras.models.save_model(model, model_path)
|
||||
|
||||
import json
|
||||
import argparse
|
||||
_parser = argparse.ArgumentParser(prog='Create fully connected tensorflow network', description='Creates fully-connected network in Tensorflow SavedModel format')
|
||||
_parser.add_argument("--input-size", dest="input_size", type=int, required=True, default=argparse.SUPPRESS)
|
||||
_parser.add_argument("--hidden-layer-sizes", dest="hidden_layer_sizes", type=json.loads, required=False, default=argparse.SUPPRESS)
|
||||
_parser.add_argument("--output-size", dest="output_size", type=int, required=False, default=argparse.SUPPRESS)
|
||||
_parser.add_argument("--activation-name", dest="activation_name", type=str, required=False, default=argparse.SUPPRESS)
|
||||
_parser.add_argument("--output-activation-name", dest="output_activation_name", type=str, required=False, default=argparse.SUPPRESS)
|
||||
_parser.add_argument("--random-seed", dest="random_seed", type=int, required=False, default=argparse.SUPPRESS)
|
||||
_parser.add_argument("--model", dest="model_path", type=_make_parent_dirs_and_return_path, required=True, default=argparse.SUPPRESS)
|
||||
_parsed_args = vars(_parser.parse_args())
|
||||
|
||||
_outputs = create_fully_connected_tensorflow_network(**_parsed_args)
|
||||
args:
|
||||
- --input-size
|
||||
- {inputValue: input_size}
|
||||
- if:
|
||||
cond: {isPresent: hidden_layer_sizes}
|
||||
then:
|
||||
- --hidden-layer-sizes
|
||||
- {inputValue: hidden_layer_sizes}
|
||||
- if:
|
||||
cond: {isPresent: output_size}
|
||||
then:
|
||||
- --output-size
|
||||
- {inputValue: output_size}
|
||||
- if:
|
||||
cond: {isPresent: activation_name}
|
||||
then:
|
||||
- --activation-name
|
||||
- {inputValue: activation_name}
|
||||
- if:
|
||||
cond: {isPresent: output_activation_name}
|
||||
then:
|
||||
- --output-activation-name
|
||||
- {inputValue: output_activation_name}
|
||||
- if:
|
||||
cond: {isPresent: random_seed}
|
||||
then:
|
||||
- --random-seed
|
||||
- {inputValue: random_seed}
|
||||
- --model
|
||||
- {outputPath: model}
|
||||
@@ -0,0 +1,100 @@
|
||||
name: Predict with TensorFlow model on CSV data
|
||||
metadata:
|
||||
annotations: {author: Alexey Volkov <alexey.volkov@ark-kun.com>, canonical_location: 'https://raw.githubusercontent.com/Ark-kun/pipeline_components/master/components/tensorflow/Predict/on_CSV/component.yaml'}
|
||||
inputs:
|
||||
- {name: dataset, type: CSV}
|
||||
- {name: model, type: TensorflowSavedModel}
|
||||
- {name: label_column_name, type: String, optional: true}
|
||||
- {name: batch_size, type: Integer, default: '1000', optional: true}
|
||||
outputs:
|
||||
- {name: predictions}
|
||||
implementation:
|
||||
container:
|
||||
image: tensorflow/tensorflow:2.9.1
|
||||
command:
|
||||
- sh
|
||||
- -ec
|
||||
- |
|
||||
program_path=$(mktemp)
|
||||
printf "%s" "$0" > "$program_path"
|
||||
python3 -u "$program_path" "$@"
|
||||
- |
|
||||
def _make_parent_dirs_and_return_path(file_path: str):
|
||||
import os
|
||||
os.makedirs(os.path.dirname(file_path), exist_ok=True)
|
||||
return file_path
|
||||
|
||||
def predict_with_TensorFlow_model_on_CSV_data(
|
||||
dataset_path,
|
||||
model_path,
|
||||
predictions_path,
|
||||
label_column_name = None,
|
||||
batch_size = 1000,
|
||||
):
|
||||
import numpy
|
||||
import tensorflow as tf
|
||||
|
||||
model = tf.saved_model.load(export_dir=model_path)
|
||||
|
||||
dataset = tf.data.experimental.make_csv_dataset(
|
||||
file_pattern=dataset_path,
|
||||
batch_size=batch_size,
|
||||
label_name=label_column_name,
|
||||
header=True,
|
||||
num_epochs=1,
|
||||
shuffle=False,
|
||||
ignore_errors=False,
|
||||
)
|
||||
|
||||
def stack_feature_batches(features_batch):
|
||||
# Need to stack individual feature columns to create a single feature tensor
|
||||
# Need to cast all column tensor types to float to prevent errors.
|
||||
list_of_feature_batches = list(
|
||||
tf.cast(x=feature_batch, dtype=tf.float32)
|
||||
for feature_batch in features_batch.values()
|
||||
)
|
||||
return tf.stack(list_of_feature_batches, axis=-1)
|
||||
|
||||
def transform_features_and_drop_labels(features_batch, labels_batch):
|
||||
return stack_feature_batches(features_batch)
|
||||
|
||||
dataset_map_fn = (
|
||||
transform_features_and_drop_labels
|
||||
if label_column_name
|
||||
else stack_feature_batches
|
||||
)
|
||||
|
||||
dataset = dataset.map(dataset_map_fn)
|
||||
|
||||
with open(predictions_path, "w") as predictions_file:
|
||||
for features_batch in dataset:
|
||||
predictions_tensor = model(features_batch)
|
||||
numpy.savetxt(predictions_file, predictions_tensor.numpy())
|
||||
|
||||
import argparse
|
||||
_parser = argparse.ArgumentParser(prog='Predict with TensorFlow model on CSV data', description='')
|
||||
_parser.add_argument("--dataset", dest="dataset_path", type=str, required=True, default=argparse.SUPPRESS)
|
||||
_parser.add_argument("--model", dest="model_path", type=str, required=True, default=argparse.SUPPRESS)
|
||||
_parser.add_argument("--label-column-name", dest="label_column_name", type=str, required=False, default=argparse.SUPPRESS)
|
||||
_parser.add_argument("--batch-size", dest="batch_size", type=int, required=False, default=argparse.SUPPRESS)
|
||||
_parser.add_argument("--predictions", dest="predictions_path", type=_make_parent_dirs_and_return_path, required=True, default=argparse.SUPPRESS)
|
||||
_parsed_args = vars(_parser.parse_args())
|
||||
|
||||
_outputs = predict_with_TensorFlow_model_on_CSV_data(**_parsed_args)
|
||||
args:
|
||||
- --dataset
|
||||
- {inputPath: dataset}
|
||||
- --model
|
||||
- {inputPath: model}
|
||||
- if:
|
||||
cond: {isPresent: label_column_name}
|
||||
then:
|
||||
- --label-column-name
|
||||
- {inputValue: label_column_name}
|
||||
- if:
|
||||
cond: {isPresent: batch_size}
|
||||
then:
|
||||
- --batch-size
|
||||
- {inputValue: batch_size}
|
||||
- --predictions
|
||||
- {outputPath: predictions}
|
||||
+170
@@ -0,0 +1,170 @@
|
||||
name: Train model using Keras on CSV
|
||||
metadata:
|
||||
annotations: {author: Alexey Volkov <alexey.volkov@ark-kun.com>, canonical_location: 'https://raw.githubusercontent.com/Ark-kun/pipeline_components/master/components/tensorflow/Train_model_using_Keras/on_CSV/component.yaml'}
|
||||
inputs:
|
||||
- {name: training_data, type: CSV}
|
||||
- {name: model, type: TensorflowSavedModel}
|
||||
- {name: label_column_name, type: String}
|
||||
- {name: loss_function_name, type: String, default: mean_squared_error, optional: true}
|
||||
- {name: number_of_epochs, type: Integer, default: '1', optional: true}
|
||||
- {name: learning_rate, type: Float, default: '0.1', optional: true}
|
||||
- {name: optimizer_name, type: String, default: Adadelta, optional: true}
|
||||
- {name: optimizer_parameters, type: JsonObject, optional: true}
|
||||
- {name: batch_size, type: Integer, default: '32', optional: true}
|
||||
- {name: metric_names, type: JsonArray, optional: true}
|
||||
- {name: random_seed, type: Integer, default: '0', optional: true}
|
||||
outputs:
|
||||
- {name: trained_model, type: TensorflowSavedModel}
|
||||
implementation:
|
||||
container:
|
||||
image: tensorflow/tensorflow:2.8.0
|
||||
command:
|
||||
- sh
|
||||
- -ec
|
||||
- |
|
||||
program_path=$(mktemp)
|
||||
printf "%s" "$0" > "$program_path"
|
||||
python3 -u "$program_path" "$@"
|
||||
- |
|
||||
def _make_parent_dirs_and_return_path(file_path: str):
|
||||
import os
|
||||
os.makedirs(os.path.dirname(file_path), exist_ok=True)
|
||||
return file_path
|
||||
|
||||
def train_model_using_Keras_on_CSV(
|
||||
training_data_path,
|
||||
model_path,
|
||||
trained_model_path,
|
||||
label_column_name,
|
||||
loss_function_name = "mean_squared_error",
|
||||
number_of_epochs = 1,
|
||||
learning_rate = 0.1,
|
||||
optimizer_name = "Adadelta",
|
||||
optimizer_parameters = None,
|
||||
batch_size = 32,
|
||||
metric_names = None,
|
||||
random_seed = 0,
|
||||
):
|
||||
import tensorflow as tf
|
||||
tf.random.set_seed(seed=random_seed)
|
||||
|
||||
# Loading model using Keras. Model loaded using TensorFlow does not have .fit.
|
||||
#model = tf.saved_model.load(export_dir=model_path)
|
||||
keras_model = tf.keras.models.load_model(filepath=model_path)
|
||||
|
||||
optimizer_parameters = optimizer_parameters or {}
|
||||
optimizer_parameters["learning_rate"] = learning_rate
|
||||
optimizer_config = {
|
||||
"class_name": optimizer_name,
|
||||
"config": optimizer_parameters,
|
||||
}
|
||||
optimizer = tf.keras.optimizers.get(optimizer_config)
|
||||
loss = tf.keras.losses.get(loss_function_name)
|
||||
|
||||
training_dataset = tf.data.experimental.make_csv_dataset(
|
||||
file_pattern=training_data_path,
|
||||
batch_size=batch_size,
|
||||
label_name=label_column_name,
|
||||
header=True,
|
||||
# Need to specify num_epochs=1 otherwise the training becomes infinite
|
||||
num_epochs=1,
|
||||
shuffle=True,
|
||||
shuffle_seed=random_seed,
|
||||
ignore_errors=True,
|
||||
)
|
||||
def stack_feature_batches(features_batch, labels_batch):
|
||||
# Need to stack individual feature columns to create a single feature tensor
|
||||
# Need to cast all column tensor types to float to prevent error:
|
||||
# TypeError: Tensors in list passed to 'values' of 'Pack' Op have types [int32, float32, float32, int32, int32] that don't all match.
|
||||
list_of_feature_batches = list(tf.cast(x=feature_batch, dtype=tf.float32) for feature_batch in features_batch.values())
|
||||
return tf.stack(list_of_feature_batches, axis=-1), labels_batch
|
||||
|
||||
training_dataset = training_dataset.map(stack_feature_batches)
|
||||
|
||||
# Need to compile the model to prevent error:
|
||||
# ValueError: No gradients provided for any variable: [..., ...].
|
||||
keras_model.compile(
|
||||
optimizer=optimizer,
|
||||
loss=loss,
|
||||
metrics=metric_names,
|
||||
)
|
||||
keras_model.fit(
|
||||
training_dataset,
|
||||
epochs=number_of_epochs,
|
||||
)
|
||||
|
||||
# Using tf.keras.models.save_model instead of tf.saved_model.save to prevent downstream error:
|
||||
#tf.saved_model.save(keras_model, trained_model_path)
|
||||
# ValueError: Unable to create a Keras model from this SavedModel.
|
||||
# This SavedModel was created with `tf.saved_model.save`, and lacks the Keras metadata.
|
||||
# Please save your Keras model by calling `model.save`or `tf.keras.models.save_model`.
|
||||
# See https://github.com/keras-team/keras/issues/16451
|
||||
tf.keras.models.save_model(keras_model, trained_model_path)
|
||||
|
||||
import json
|
||||
import argparse
|
||||
_parser = argparse.ArgumentParser(prog='Train model using Keras on CSV', description='')
|
||||
_parser.add_argument("--training-data", dest="training_data_path", type=str, required=True, default=argparse.SUPPRESS)
|
||||
_parser.add_argument("--model", dest="model_path", type=str, required=True, default=argparse.SUPPRESS)
|
||||
_parser.add_argument("--label-column-name", dest="label_column_name", type=str, required=True, default=argparse.SUPPRESS)
|
||||
_parser.add_argument("--loss-function-name", dest="loss_function_name", type=str, required=False, default=argparse.SUPPRESS)
|
||||
_parser.add_argument("--number-of-epochs", dest="number_of_epochs", type=int, required=False, default=argparse.SUPPRESS)
|
||||
_parser.add_argument("--learning-rate", dest="learning_rate", type=float, required=False, default=argparse.SUPPRESS)
|
||||
_parser.add_argument("--optimizer-name", dest="optimizer_name", type=str, required=False, default=argparse.SUPPRESS)
|
||||
_parser.add_argument("--optimizer-parameters", dest="optimizer_parameters", type=json.loads, required=False, default=argparse.SUPPRESS)
|
||||
_parser.add_argument("--batch-size", dest="batch_size", type=int, required=False, default=argparse.SUPPRESS)
|
||||
_parser.add_argument("--metric-names", dest="metric_names", type=json.loads, required=False, default=argparse.SUPPRESS)
|
||||
_parser.add_argument("--random-seed", dest="random_seed", type=int, required=False, default=argparse.SUPPRESS)
|
||||
_parser.add_argument("--trained-model", dest="trained_model_path", type=_make_parent_dirs_and_return_path, required=True, default=argparse.SUPPRESS)
|
||||
_parsed_args = vars(_parser.parse_args())
|
||||
|
||||
_outputs = train_model_using_Keras_on_CSV(**_parsed_args)
|
||||
args:
|
||||
- --training-data
|
||||
- {inputPath: training_data}
|
||||
- --model
|
||||
- {inputPath: model}
|
||||
- --label-column-name
|
||||
- {inputValue: label_column_name}
|
||||
- if:
|
||||
cond: {isPresent: loss_function_name}
|
||||
then:
|
||||
- --loss-function-name
|
||||
- {inputValue: loss_function_name}
|
||||
- if:
|
||||
cond: {isPresent: number_of_epochs}
|
||||
then:
|
||||
- --number-of-epochs
|
||||
- {inputValue: number_of_epochs}
|
||||
- if:
|
||||
cond: {isPresent: learning_rate}
|
||||
then:
|
||||
- --learning-rate
|
||||
- {inputValue: learning_rate}
|
||||
- if:
|
||||
cond: {isPresent: optimizer_name}
|
||||
then:
|
||||
- --optimizer-name
|
||||
- {inputValue: optimizer_name}
|
||||
- if:
|
||||
cond: {isPresent: optimizer_parameters}
|
||||
then:
|
||||
- --optimizer-parameters
|
||||
- {inputValue: optimizer_parameters}
|
||||
- if:
|
||||
cond: {isPresent: batch_size}
|
||||
then:
|
||||
- --batch-size
|
||||
- {inputValue: batch_size}
|
||||
- if:
|
||||
cond: {isPresent: metric_names}
|
||||
then:
|
||||
- --metric-names
|
||||
- {inputValue: metric_names}
|
||||
- if:
|
||||
cond: {isPresent: random_seed}
|
||||
then:
|
||||
- --random-seed
|
||||
- {inputValue: random_seed}
|
||||
- --trained-model
|
||||
- {outputPath: trained_model}
|
||||
@@ -0,0 +1,33 @@
|
||||
# PyTorch Efficient Training Examples
|
||||
|
||||
This folder provides PyTorch efficient training examples using ResNet-50 and ImageNet data.
|
||||
|
||||
## Requirements
|
||||
|
||||
```shell
|
||||
pip install --upgrade pip
|
||||
pip install -r requirements.txt
|
||||
```
|
||||
|
||||
## Description
|
||||
|
||||
* resnet.py - Train ResNet-50 on single GPU.
|
||||
* resnet_dp.py - Train ResNet-50 on single node multiple GPUs with `DataParallel` strategy.
|
||||
* resnet_ddp.py - Train ResNet-50 on single node multiple GPUs with `DistributedDataParallel` strategy.
|
||||
* resnet_ddp_wds.py - Train ResNet-50 on single node multiple GPUs with `DistributedDataParallel` strategy and `Webdataset`.
|
||||
* resnet_fsdp.py - Train ResNet-50 on single node multiple GPUs with `FullyShardedDataParallel` strategy.
|
||||
* resnet_fsdp_wds.py - Train ResNet-50 on single node multiple GPUs with `FullyShardedDataParallel` strategy and `Webdataset`.
|
||||
* shard_imagenet.py - Shard ImagNet individual files into `tar` files.
|
||||
|
||||
## Benchmark
|
||||
|
||||
When run the benchmark on Nvidia T4 GPUs using ImageNet validation dataset, you can get the result like:
|
||||
Strategy | Seconds/Epoch - Local Data | Seconds/Epoch - Cloud Data
|
||||
---------------------- | -------------------------- | --------------------------
|
||||
On 1 GPU | 489 | 804 (2x slower)
|
||||
On 4 GPUs (DP) | 157 | 738 (5x slower)
|
||||
On 4 GPUs (DDP) | 134 | 432 (3x slower)
|
||||
On 4 GPUs (DDP + WDS) | 131 | 133 (same performance)
|
||||
On 4 GPUs (FSDP) | 139 | 353 (3x slower)
|
||||
On 4 GPUs (FSDP + WDS) | 138 | 135 (same performance)
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
webdataset == 0.2.26
|
||||
@@ -0,0 +1,197 @@
|
||||
# Copyright 2022 Google LLC
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the \"License\");
|
||||
# you may not use this file except in compliance with the License.\n",
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an \"AS IS\" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
"""Train resnet on single GPU."""
|
||||
|
||||
import argparse
|
||||
import time
|
||||
|
||||
from PIL import Image
|
||||
import torch
|
||||
from torch import nn
|
||||
import torchmetrics
|
||||
import torchvision
|
||||
from torchvision.models import resnet50
|
||||
|
||||
|
||||
class ImageFolder(torchvision.datasets.ImageFolder):
|
||||
"""Class for loading imagenet."""
|
||||
|
||||
def __init__(self, image_list_file, transform=None, target_transform=None):
|
||||
self.samples = self._make_dataset(image_list_file)
|
||||
self.loader = self._loader
|
||||
|
||||
self.imgs = self.samples
|
||||
self.targets = [s[1] for s in self.samples]
|
||||
|
||||
self.transform = transform
|
||||
self.target_transform = target_transform
|
||||
|
||||
def _make_dataset(self, image_list_file):
|
||||
items = []
|
||||
with open(image_list_file, 'r') as f:
|
||||
for line in f:
|
||||
item = line.strip().split(' ')
|
||||
items.append((item[0], int(item[1])))
|
||||
return items
|
||||
|
||||
def _loader(self, image_path):
|
||||
with open(image_path, 'rb') as f:
|
||||
img = Image.open(f)
|
||||
img = img.convert('RGB')
|
||||
return img
|
||||
|
||||
|
||||
def train(model, device, dataloader, optimizer):
|
||||
model.train()
|
||||
for image, target in dataloader:
|
||||
image, target = image.to(device), target.to(device)
|
||||
pred = model(image)
|
||||
# pred.shape (N, C), target.shape (N)
|
||||
loss = nn.functional.cross_entropy(pred, target)
|
||||
optimizer.zero_grad()
|
||||
loss.backward()
|
||||
optimizer.step()
|
||||
return loss
|
||||
|
||||
|
||||
def evaluate(model, device, dataloader, metric):
|
||||
model.eval()
|
||||
with torch.no_grad():
|
||||
for image, target in dataloader:
|
||||
image, target = image.to(device), target.to(device)
|
||||
pred = model(image)
|
||||
metric.update(pred, target)
|
||||
accuracy = metric.compute()
|
||||
metric.reset()
|
||||
return accuracy
|
||||
|
||||
|
||||
def run_training(args):
|
||||
"""Run training and evaluation."""
|
||||
# Create model.
|
||||
model = resnet50(weights=None)
|
||||
model = model.to(args.device)
|
||||
|
||||
# Create train dataloader.
|
||||
train_dataset = ImageFolder(
|
||||
image_list_file=args.train_data_path,
|
||||
transform=torchvision.transforms.Compose([
|
||||
torchvision.transforms.RandomResizedCrop(224),
|
||||
torchvision.transforms.RandomHorizontalFlip(),
|
||||
torchvision.transforms.ToTensor(),
|
||||
torchvision.transforms.Normalize(
|
||||
mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225]),
|
||||
]))
|
||||
train_dataloader = torch.utils.data.DataLoader(
|
||||
dataset=train_dataset,
|
||||
batch_size=args.train_batch_size,
|
||||
shuffle=True,
|
||||
num_workers=args.dataloader_num_workers,
|
||||
pin_memory=True)
|
||||
print(f'Train dataloader | samples: {len(train_dataloader.dataset)}, '
|
||||
f'num workers: {train_dataloader.num_workers}, '
|
||||
f'batch size: {args.train_batch_size}, '
|
||||
f'batches/epoch: {len(train_dataloader)}')
|
||||
|
||||
# Create eval dataloader.
|
||||
eval_dataset = ImageFolder(
|
||||
image_list_file=args.eval_data_path,
|
||||
transform=torchvision.transforms.Compose([
|
||||
torchvision.transforms.Resize(256),
|
||||
torchvision.transforms.CenterCrop(224),
|
||||
torchvision.transforms.ToTensor(),
|
||||
torchvision.transforms.Normalize(
|
||||
mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225]),
|
||||
]))
|
||||
eval_dataloader = torch.utils.data.DataLoader(
|
||||
dataset=eval_dataset,
|
||||
batch_size=args.eval_batch_size,
|
||||
shuffle=False,
|
||||
num_workers=args.dataloader_num_workers,
|
||||
pin_memory=True,
|
||||
drop_last=True)
|
||||
print(f'Eval dataloader | samples: {len(eval_dataloader.dataset)}, '
|
||||
f'num workers: {eval_dataloader.num_workers}, '
|
||||
f'batch size: {args.eval_batch_size}, '
|
||||
f'batches/epoch: {len(eval_dataloader)}')
|
||||
|
||||
# Optimizer.
|
||||
optimizer = torch.optim.SGD(model.parameters(), 0.1)
|
||||
|
||||
# Main loop.
|
||||
metric = torchmetrics.classification.Accuracy(top_k=1).to(args.device)
|
||||
for epoch in range(1, args.epochs + 1):
|
||||
print(f'Running epoch {epoch}')
|
||||
|
||||
start = time.time()
|
||||
train(model, args.device, train_dataloader, optimizer)
|
||||
end = time.time()
|
||||
print(f'Training finished in {(end - start):>0.3f} seconds')
|
||||
|
||||
start = time.time()
|
||||
evaluate(model, args.device, eval_dataloader, metric)
|
||||
end = time.time()
|
||||
print(f'Evaluation finished in {(end - start):>0.3f} seconds')
|
||||
print('Done')
|
||||
|
||||
|
||||
def create_args():
|
||||
"""Create main args."""
|
||||
parser = argparse.ArgumentParser(
|
||||
formatter_class=argparse.ArgumentDefaultsHelpFormatter)
|
||||
parser.add_argument(
|
||||
'--epochs',
|
||||
default=1,
|
||||
type=int,
|
||||
help='number of total epochs to run')
|
||||
parser.add_argument(
|
||||
'--dataloader_num_workers',
|
||||
default=2,
|
||||
type=int,
|
||||
help='number of workders for dataloader')
|
||||
parser.add_argument(
|
||||
'--train_data_path',
|
||||
default='',
|
||||
type=str,
|
||||
help='path to training data')
|
||||
parser.add_argument(
|
||||
'--train_batch_size',
|
||||
default=32,
|
||||
type=int,
|
||||
help='batch size for training')
|
||||
parser.add_argument(
|
||||
'--eval_data_path',
|
||||
default='',
|
||||
type=str,
|
||||
help='path to evaluation data')
|
||||
parser.add_argument(
|
||||
'--eval_batch_size',
|
||||
default=32,
|
||||
type=int,
|
||||
help='batch size for evaluation')
|
||||
args = parser.parse_args()
|
||||
return args
|
||||
|
||||
|
||||
def main():
|
||||
args = create_args()
|
||||
args.device = torch.device('cuda:0' if torch.cuda.is_available() else 'cpu')
|
||||
|
||||
print('Launch job on 1 GPU')
|
||||
run_training(args)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
@@ -0,0 +1,234 @@
|
||||
# Copyright 2022 Google LLC
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the \"License\");
|
||||
# you may not use this file except in compliance with the License.\n",
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an \"AS IS\" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
"""Train resnet on multiple GPUs with DDP."""
|
||||
|
||||
import argparse
|
||||
import os
|
||||
import time
|
||||
|
||||
from PIL import Image
|
||||
import torch
|
||||
from torch import nn
|
||||
import torch.distributed as dist
|
||||
import torch.multiprocessing as mp
|
||||
import torchmetrics
|
||||
import torchvision
|
||||
from torchvision.models import resnet50
|
||||
|
||||
|
||||
class ImageFolder(torchvision.datasets.ImageFolder):
|
||||
"""Class for loading imagenet."""
|
||||
|
||||
def __init__(self, image_list_file, transform=None, target_transform=None):
|
||||
self.samples = self._make_dataset(image_list_file)
|
||||
self.loader = self._loader
|
||||
|
||||
self.imgs = self.samples
|
||||
self.targets = [s[1] for s in self.samples]
|
||||
|
||||
self.transform = transform
|
||||
self.target_transform = target_transform
|
||||
|
||||
def _make_dataset(self, image_list_file):
|
||||
items = []
|
||||
with open(image_list_file, 'r') as f:
|
||||
for line in f:
|
||||
item = line.strip().split(' ')
|
||||
items.append((item[0], int(item[1])))
|
||||
return items
|
||||
|
||||
def _loader(self, image_path):
|
||||
with open(image_path, 'rb') as f:
|
||||
img = Image.open(f)
|
||||
img = img.convert('RGB')
|
||||
return img
|
||||
|
||||
|
||||
def train(model, device, dataloader, optimizer):
|
||||
model.train()
|
||||
for image, target in dataloader:
|
||||
image = image.to(device, non_blocking=True)
|
||||
target = target.to(device, non_blocking=True)
|
||||
pred = model(image)
|
||||
# pred.shape (N, C), target.shape (N)
|
||||
loss = nn.functional.cross_entropy(pred, target)
|
||||
optimizer.zero_grad()
|
||||
loss.backward()
|
||||
optimizer.step()
|
||||
return loss
|
||||
|
||||
|
||||
def evaluate(model, device, dataloader, metric):
|
||||
model.eval()
|
||||
with torch.no_grad():
|
||||
for image, target in dataloader:
|
||||
image = image.to(device, non_blocking=True)
|
||||
target = target.to(device, non_blocking=True)
|
||||
pred = model(image)
|
||||
metric.update(pred, target)
|
||||
accuracy = metric.compute()
|
||||
metric.reset()
|
||||
return accuracy
|
||||
|
||||
|
||||
def worker(gpu, args):
|
||||
"""Run training and evaluation."""
|
||||
# Init process group.
|
||||
print(f'Initiating process {gpu}')
|
||||
dist.init_process_group(
|
||||
backend='nccl',
|
||||
init_method='env://',
|
||||
world_size=args.gpus,
|
||||
rank=gpu)
|
||||
|
||||
# Create model.
|
||||
model = resnet50(weights=None)
|
||||
torch.cuda.set_device(gpu)
|
||||
model.to(args.device)
|
||||
model = torch.nn.SyncBatchNorm.convert_sync_batchnorm(model)
|
||||
model = nn.parallel.DistributedDataParallel(model, device_ids=[gpu])
|
||||
|
||||
# Create train dataloader.
|
||||
train_dataset = ImageFolder(
|
||||
image_list_file=args.train_data_path,
|
||||
transform=torchvision.transforms.Compose([
|
||||
torchvision.transforms.RandomResizedCrop(224),
|
||||
torchvision.transforms.RandomHorizontalFlip(),
|
||||
torchvision.transforms.ToTensor(),
|
||||
torchvision.transforms.Normalize(
|
||||
mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225]),
|
||||
]))
|
||||
train_sampler = torch.utils.data.distributed.DistributedSampler(
|
||||
train_dataset, num_replicas=args.gpus, rank=gpu)
|
||||
train_dataloader = torch.utils.data.DataLoader(
|
||||
dataset=train_dataset,
|
||||
batch_size=args.train_batch_size,
|
||||
shuffle=False,
|
||||
num_workers=args.dataloader_num_workers,
|
||||
pin_memory=True,
|
||||
sampler=train_sampler)
|
||||
if gpu == 0:
|
||||
print(f'Train dataloader | samples: {len(train_dataloader.dataset)}, '
|
||||
f'num workers: {train_dataloader.num_workers}, '
|
||||
f'global batch size: {args.train_batch_size * args.gpus}, '
|
||||
f'batches/epoch: {len(train_dataloader)}')
|
||||
|
||||
# Create eval dataloader.
|
||||
eval_dataset = ImageFolder(
|
||||
image_list_file=args.eval_data_path,
|
||||
transform=torchvision.transforms.Compose([
|
||||
torchvision.transforms.Resize(256),
|
||||
torchvision.transforms.CenterCrop(224),
|
||||
torchvision.transforms.ToTensor(),
|
||||
torchvision.transforms.Normalize(
|
||||
mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225]),
|
||||
]))
|
||||
eval_sampler = torch.utils.data.distributed.DistributedSampler(
|
||||
eval_dataset, num_replicas=args.gpus, rank=gpu)
|
||||
eval_dataloader = torch.utils.data.DataLoader(
|
||||
dataset=eval_dataset,
|
||||
batch_size=args.eval_batch_size,
|
||||
shuffle=False,
|
||||
num_workers=args.dataloader_num_workers,
|
||||
pin_memory=True,
|
||||
drop_last=True,
|
||||
sampler=eval_sampler)
|
||||
if gpu == 0:
|
||||
print(f'Eval dataloader | samples: {len(eval_dataloader.dataset)}, '
|
||||
f'num workers: {eval_dataloader.num_workers}, '
|
||||
f'batch size: {args.eval_batch_size}, '
|
||||
f'batches/epoch: {len(eval_dataloader)}')
|
||||
|
||||
# Optimizer.
|
||||
optimizer = torch.optim.SGD(model.parameters(), 0.1)
|
||||
|
||||
# Main loop.
|
||||
metric = torchmetrics.classification.Accuracy(top_k=1).to(args.device)
|
||||
for epoch in range(1, args.epochs + 1):
|
||||
if gpu == 0:
|
||||
print(f'Running epoch {epoch}')
|
||||
train_sampler.set_epoch(epoch)
|
||||
|
||||
start = time.time()
|
||||
train(model, args.device, train_dataloader, optimizer)
|
||||
end = time.time()
|
||||
if gpu == 0:
|
||||
print(f'Training finished in {(end - start):>0.3f} seconds')
|
||||
|
||||
start = time.time()
|
||||
evaluate(model, args.device, eval_dataloader, metric)
|
||||
end = time.time()
|
||||
if gpu == 0:
|
||||
print(f'Evaluation finished in {(end - start):>0.3f} seconds')
|
||||
|
||||
if gpu == 0:
|
||||
print('Done')
|
||||
|
||||
|
||||
def create_args():
|
||||
"""Create main args."""
|
||||
parser = argparse.ArgumentParser(
|
||||
formatter_class=argparse.ArgumentDefaultsHelpFormatter)
|
||||
parser.add_argument(
|
||||
'--gpus',
|
||||
default=4,
|
||||
type=int,
|
||||
help='number of gpus to use')
|
||||
parser.add_argument(
|
||||
'--epochs',
|
||||
default=1,
|
||||
type=int,
|
||||
help='number of total epochs to run')
|
||||
parser.add_argument(
|
||||
'--dataloader_num_workers',
|
||||
default=2,
|
||||
type=int,
|
||||
help='number of workders for dataloader')
|
||||
parser.add_argument(
|
||||
'--train_data_path',
|
||||
default='',
|
||||
type=str,
|
||||
help='path to training data')
|
||||
parser.add_argument(
|
||||
'--train_batch_size',
|
||||
default=32,
|
||||
type=int,
|
||||
help='batch size for training per gpu')
|
||||
parser.add_argument(
|
||||
'--eval_data_path',
|
||||
default='',
|
||||
type=str,
|
||||
help='path to evaluation data')
|
||||
parser.add_argument(
|
||||
'--eval_batch_size',
|
||||
default=32,
|
||||
type=int,
|
||||
help='batch size for evaluation per gpu')
|
||||
args = parser.parse_args()
|
||||
return args
|
||||
|
||||
|
||||
def main():
|
||||
args = create_args()
|
||||
os.environ['MASTER_ADDR'] = 'localhost'
|
||||
os.environ['MASTER_PORT'] = '8888'
|
||||
|
||||
args.device = 'cuda' if torch.cuda.is_available() else 'cpu'
|
||||
print(f'Launch job on {args.gpus} GPUs with DDP')
|
||||
mp.spawn(worker, nprocs=args.gpus, args=(args,))
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
@@ -0,0 +1,249 @@
|
||||
# Copyright 2022 Google LLC
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the \"License\");
|
||||
# you may not use this file except in compliance with the License.\n",
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an \"AS IS\" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
"""Train resnet on multiple GPUs with DDP."""
|
||||
|
||||
import argparse
|
||||
import functools
|
||||
import itertools
|
||||
import math
|
||||
import os
|
||||
import time
|
||||
|
||||
import torch
|
||||
from torch import nn
|
||||
import torch.distributed as dist
|
||||
import torch.multiprocessing as mp
|
||||
import torchmetrics
|
||||
from torchvision.models import resnet50
|
||||
from torchvision.transforms import transforms
|
||||
import webdataset as wds
|
||||
|
||||
|
||||
def wds_split(src, rank, world_size):
|
||||
"""Shards split function for webdataset."""
|
||||
# The context of caller of this function is within multiple processes
|
||||
# (by DDP world_size) and multiple workers (by dataloader_num_workers).
|
||||
# So we totally have (world_size * num_workers) workers for processing data.
|
||||
# NOTE: Raw data should be sharded to enough shards to make sure one process
|
||||
# can handle at least one shard, otherwise the process may hang.
|
||||
worker_id = 0
|
||||
num_workers = 1
|
||||
worker_info = torch.utils.data.get_worker_info()
|
||||
if worker_info:
|
||||
worker_id = worker_info.id
|
||||
num_workers = worker_info.num_workers
|
||||
for s in itertools.islice(src, rank * num_workers + worker_id, None,
|
||||
world_size * num_workers):
|
||||
yield s
|
||||
|
||||
|
||||
def identity(x):
|
||||
return x
|
||||
|
||||
|
||||
def create_wds_dataloader(rank, args, mode):
|
||||
"""Create webdataset dataset and dataloader."""
|
||||
if mode == 'train':
|
||||
transform = transforms.Compose([
|
||||
transforms.RandomResizedCrop(224),
|
||||
transforms.RandomHorizontalFlip(),
|
||||
transforms.ToTensor(),
|
||||
transforms.Normalize(
|
||||
mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225]),
|
||||
])
|
||||
data_path = args.train_data_path
|
||||
data_size = args.train_data_size
|
||||
batch_size_local = args.train_batch_size
|
||||
batch_size_global = args.train_batch_size * args.gpus
|
||||
# Since webdataset disallows partial batch, we pad the last batch for train.
|
||||
batches = int(math.ceil(data_size / batch_size_global))
|
||||
else:
|
||||
transform = transforms.Compose([
|
||||
transforms.Resize(256),
|
||||
transforms.CenterCrop(224),
|
||||
transforms.ToTensor(),
|
||||
transforms.Normalize(
|
||||
mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225]),
|
||||
])
|
||||
data_path = args.eval_data_path
|
||||
data_size = args.eval_data_size
|
||||
batch_size_local = args.eval_batch_size
|
||||
batch_size_global = args.eval_batch_size * args.gpus
|
||||
# Since webdataset disallows partial batch, we drop the last batch for eval.
|
||||
batches = int(data_size / batch_size_global)
|
||||
|
||||
dataset = wds.DataPipeline(
|
||||
wds.SimpleShardList(data_path),
|
||||
functools.partial(wds_split, rank=rank, world_size=args.gpus),
|
||||
wds.tarfile_to_samples(),
|
||||
wds.decode('pil'),
|
||||
wds.to_tuple('jpg;png;jpeg cls'),
|
||||
wds.map_tuple(transform, identity),
|
||||
wds.batched(batch_size_local, partial=False),
|
||||
)
|
||||
num_workers = args.dataloader_num_workers
|
||||
dataloader = wds.WebLoader(
|
||||
dataset=dataset,
|
||||
batch_size=None,
|
||||
shuffle=False,
|
||||
num_workers=num_workers,
|
||||
persistent_workers=True if num_workers > 0 else False,
|
||||
pin_memory=True).repeat(nbatches=batches)
|
||||
print(f'{mode} dataloader | samples: {data_size}, '
|
||||
f'num_workers: {num_workers}, '
|
||||
f'local batch size: {batch_size_local}, '
|
||||
f'global batch size: {batch_size_global}, '
|
||||
f'batches: {batches}')
|
||||
return dataloader
|
||||
|
||||
|
||||
def train(model, device, dataloader, optimizer):
|
||||
model.train()
|
||||
for image, target in dataloader:
|
||||
image = image.to(device, non_blocking=True)
|
||||
target = target.to(device, non_blocking=True)
|
||||
pred = model(image)
|
||||
# pred.shape (N, C), target.shape (N)
|
||||
loss = nn.functional.cross_entropy(pred, target)
|
||||
optimizer.zero_grad()
|
||||
loss.backward()
|
||||
optimizer.step()
|
||||
return loss
|
||||
|
||||
|
||||
def evaluate(model, device, dataloader, metric):
|
||||
model.eval()
|
||||
with torch.no_grad():
|
||||
for image, target in dataloader:
|
||||
image = image.to(device, non_blocking=True)
|
||||
target = target.to(device, non_blocking=True)
|
||||
pred = model(image)
|
||||
metric.update(pred, target)
|
||||
accuracy = metric.compute()
|
||||
metric.reset()
|
||||
return accuracy
|
||||
|
||||
|
||||
def worker(gpu, args):
|
||||
"""Run training and evaluation."""
|
||||
# Init process group.
|
||||
print(f'Initiating process {gpu}')
|
||||
dist.init_process_group(
|
||||
backend='nccl',
|
||||
init_method='env://',
|
||||
world_size=args.gpus,
|
||||
rank=gpu)
|
||||
|
||||
# Create model.
|
||||
model = resnet50(weights=None)
|
||||
torch.cuda.set_device(gpu)
|
||||
model.to(args.device)
|
||||
model = torch.nn.SyncBatchNorm.convert_sync_batchnorm(model)
|
||||
model = nn.parallel.DistributedDataParallel(model, device_ids=[gpu])
|
||||
|
||||
# Create dataloader.
|
||||
train_dataloader = create_wds_dataloader(gpu, args, 'train')
|
||||
eval_dataloader = create_wds_dataloader(gpu, args, 'eval')
|
||||
|
||||
# Optimizer.
|
||||
optimizer = torch.optim.SGD(model.parameters(), 0.1)
|
||||
|
||||
# Main loop.
|
||||
metric = torchmetrics.classification.Accuracy(top_k=1).to(args.device)
|
||||
for epoch in range(1, args.epochs + 1):
|
||||
if gpu == 0:
|
||||
print(f'Running epoch {epoch}')
|
||||
|
||||
start = time.time()
|
||||
train(model, args.device, train_dataloader, optimizer)
|
||||
end = time.time()
|
||||
if gpu == 0:
|
||||
print(f'Training finished in {(end - start):>0.3f} seconds')
|
||||
|
||||
start = time.time()
|
||||
evaluate(model, args.device, eval_dataloader, metric)
|
||||
end = time.time()
|
||||
if gpu == 0:
|
||||
print(f'Evaluation finished in {(end - start):>0.3f} seconds')
|
||||
|
||||
if gpu == 0:
|
||||
print('Done')
|
||||
|
||||
|
||||
def create_args():
|
||||
"""Create main args."""
|
||||
parser = argparse.ArgumentParser(
|
||||
formatter_class=argparse.ArgumentDefaultsHelpFormatter)
|
||||
parser.add_argument(
|
||||
'--gpus',
|
||||
default=4,
|
||||
type=int,
|
||||
help='number of gpus to use')
|
||||
parser.add_argument(
|
||||
'--epochs',
|
||||
default=1,
|
||||
type=int,
|
||||
help='number of total epochs to run')
|
||||
parser.add_argument(
|
||||
'--dataloader_num_workers',
|
||||
default=2,
|
||||
type=int,
|
||||
help='number of workders for dataloader')
|
||||
parser.add_argument(
|
||||
'--train_data_path',
|
||||
default='',
|
||||
type=str,
|
||||
help='path to training data')
|
||||
parser.add_argument(
|
||||
'--train_batch_size',
|
||||
default=32,
|
||||
type=int,
|
||||
help='batch size for training per gpu')
|
||||
parser.add_argument(
|
||||
'--train_data_size',
|
||||
default=50000,
|
||||
type=int,
|
||||
help='data size for training')
|
||||
parser.add_argument(
|
||||
'--eval_data_path',
|
||||
default='',
|
||||
type=str,
|
||||
help='path to evaluation data')
|
||||
parser.add_argument(
|
||||
'--eval_batch_size',
|
||||
default=32,
|
||||
type=int,
|
||||
help='batch size for evaluation per gpu')
|
||||
parser.add_argument(
|
||||
'--eval_data_size',
|
||||
default=50000,
|
||||
type=int,
|
||||
help='data size for evaluation')
|
||||
args = parser.parse_args()
|
||||
return args
|
||||
|
||||
|
||||
def main():
|
||||
args = create_args()
|
||||
os.environ['MASTER_ADDR'] = 'localhost'
|
||||
os.environ['MASTER_PORT'] = '8888'
|
||||
|
||||
args.device = 'cuda' if torch.cuda.is_available() else 'cpu'
|
||||
print(f'Launch job on {args.gpus} GPUs with DDP')
|
||||
mp.spawn(worker, nprocs=args.gpus, args=(args,))
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
@@ -0,0 +1,207 @@
|
||||
# Copyright 2022 Google LLC
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the \"License\");
|
||||
# you may not use this file except in compliance with the License.\n",
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an \"AS IS\" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
"""Train resnet on multiple GPUs with DP."""
|
||||
|
||||
import argparse
|
||||
import time
|
||||
|
||||
from PIL import Image
|
||||
import torch
|
||||
from torch import nn
|
||||
import torchmetrics
|
||||
import torchvision
|
||||
from torchvision.models import resnet50
|
||||
|
||||
|
||||
class ImageFolder(torchvision.datasets.ImageFolder):
|
||||
"""Class for loading imagenet."""
|
||||
|
||||
def __init__(self, image_list_file, transform=None, target_transform=None):
|
||||
self.samples = self._make_dataset(image_list_file)
|
||||
self.loader = self._loader
|
||||
|
||||
self.imgs = self.samples
|
||||
self.targets = [s[1] for s in self.samples]
|
||||
|
||||
self.transform = transform
|
||||
self.target_transform = target_transform
|
||||
|
||||
def _make_dataset(self, image_list_file):
|
||||
items = []
|
||||
with open(image_list_file, 'r') as f:
|
||||
for line in f:
|
||||
item = line.strip().split(' ')
|
||||
items.append((item[0], int(item[1])))
|
||||
return items
|
||||
|
||||
def _loader(self, image_path):
|
||||
with open(image_path, 'rb') as f:
|
||||
img = Image.open(f)
|
||||
img = img.convert('RGB')
|
||||
return img
|
||||
|
||||
|
||||
def train(model, device, dataloader, optimizer):
|
||||
model.train()
|
||||
for image, target in dataloader:
|
||||
image, target = image.to(device), target.to(device)
|
||||
pred = model(image)
|
||||
# pred.shape (N, C), target.shape (N)
|
||||
loss = nn.functional.cross_entropy(pred, target)
|
||||
optimizer.zero_grad()
|
||||
loss.backward()
|
||||
optimizer.step()
|
||||
return loss
|
||||
|
||||
|
||||
def evaluate(model, device, dataloader, metric):
|
||||
model.eval()
|
||||
with torch.no_grad():
|
||||
for image, target in dataloader:
|
||||
image, target = image.to(device), target.to(device)
|
||||
pred = model(image)
|
||||
metric.update(pred, target)
|
||||
accuracy = metric.compute()
|
||||
metric.reset()
|
||||
return accuracy
|
||||
|
||||
|
||||
def run_training(args):
|
||||
"""Run training and evaluation."""
|
||||
# Create model.
|
||||
model = resnet50(weights=None)
|
||||
model = nn.DataParallel(model)
|
||||
model = model.to(args.device)
|
||||
|
||||
# Create train dataloader.
|
||||
train_dataset = ImageFolder(
|
||||
image_list_file=args.train_data_path,
|
||||
transform=torchvision.transforms.Compose([
|
||||
torchvision.transforms.RandomResizedCrop(224),
|
||||
torchvision.transforms.RandomHorizontalFlip(),
|
||||
torchvision.transforms.ToTensor(),
|
||||
torchvision.transforms.Normalize(
|
||||
mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225]),
|
||||
]))
|
||||
train_dataloader = torch.utils.data.DataLoader(
|
||||
dataset=train_dataset,
|
||||
batch_size=args.train_batch_size,
|
||||
shuffle=True,
|
||||
num_workers=args.dataloader_num_workers,
|
||||
pin_memory=True)
|
||||
print(f'Train dataloader | samples: {len(train_dataloader.dataset)}, '
|
||||
f'num workers: {train_dataloader.num_workers}, '
|
||||
f'global batch size: {args.train_batch_size}, '
|
||||
f'batches/epoch: {len(train_dataloader)}')
|
||||
|
||||
# Create eval dataloader.
|
||||
eval_dataset = ImageFolder(
|
||||
image_list_file=args.eval_data_path,
|
||||
transform=torchvision.transforms.Compose([
|
||||
torchvision.transforms.Resize(256),
|
||||
torchvision.transforms.CenterCrop(224),
|
||||
torchvision.transforms.ToTensor(),
|
||||
torchvision.transforms.Normalize(
|
||||
mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225]),
|
||||
]))
|
||||
eval_dataloader = torch.utils.data.DataLoader(
|
||||
dataset=eval_dataset,
|
||||
batch_size=args.eval_batch_size,
|
||||
shuffle=False,
|
||||
num_workers=args.dataloader_num_workers,
|
||||
pin_memory=True,
|
||||
drop_last=True)
|
||||
print(f'Eval dataloader | samples: {len(eval_dataloader.dataset)}, '
|
||||
f'num workers: {eval_dataloader.num_workers}, '
|
||||
f'global batch size: {args.eval_batch_size}, '
|
||||
f'batches/epoch: {len(eval_dataloader)}')
|
||||
|
||||
# Optimizer.
|
||||
optimizer = torch.optim.SGD(model.parameters(), 0.1)
|
||||
|
||||
# Main loop.
|
||||
metric = torchmetrics.classification.Accuracy(top_k=1).to(args.device)
|
||||
for epoch in range(1, args.epochs + 1):
|
||||
print(f'Running epoch {epoch}')
|
||||
|
||||
start = time.time()
|
||||
train(model, args.device, train_dataloader, optimizer)
|
||||
end = time.time()
|
||||
print(f'Training finished in {(end - start):>0.3f} seconds')
|
||||
|
||||
start = time.time()
|
||||
evaluate(model, args.device, eval_dataloader, metric)
|
||||
end = time.time()
|
||||
print(f'Evaluation finished in {(end - start):>0.3f} seconds')
|
||||
print('Done')
|
||||
|
||||
|
||||
def create_args():
|
||||
"""Create main args."""
|
||||
parser = argparse.ArgumentParser(
|
||||
formatter_class=argparse.ArgumentDefaultsHelpFormatter)
|
||||
parser.add_argument(
|
||||
'--gpus',
|
||||
default=4,
|
||||
type=int,
|
||||
help='number of gpus to use')
|
||||
parser.add_argument(
|
||||
'--epochs',
|
||||
default=1,
|
||||
type=int,
|
||||
help='number of total epochs to run')
|
||||
parser.add_argument(
|
||||
'--dataloader_num_workers',
|
||||
default=2,
|
||||
type=int,
|
||||
help='number of workders for dataloader')
|
||||
parser.add_argument(
|
||||
'--train_data_path',
|
||||
default='',
|
||||
type=str,
|
||||
help='path to training data')
|
||||
parser.add_argument(
|
||||
'--train_batch_size',
|
||||
default=32,
|
||||
type=int,
|
||||
help='batch size for training per gpu')
|
||||
parser.add_argument(
|
||||
'--eval_data_path',
|
||||
default='',
|
||||
type=str,
|
||||
help='path to evaluation data')
|
||||
parser.add_argument(
|
||||
'--eval_batch_size',
|
||||
default=32,
|
||||
type=int,
|
||||
help='batch size for evaluation per gpu')
|
||||
args = parser.parse_args()
|
||||
return args
|
||||
|
||||
|
||||
def main():
|
||||
args = create_args()
|
||||
|
||||
args.device = torch.device('cuda:0' if torch.cuda.is_available() else 'cpu')
|
||||
args.train_batch_size *= args.gpus
|
||||
args.eval_batch_size *= args.gpus
|
||||
args.dataloader_num_workers *= args.gpus
|
||||
|
||||
print(f'Launch job on {args.gpus} GPU with nn.DataParallel')
|
||||
run_training(args)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
@@ -0,0 +1,242 @@
|
||||
# Copyright 2022 Google LLC
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the \"License\");
|
||||
# you may not use this file except in compliance with the License.\n",
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an \"AS IS\" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
"""Train resnet on multiple GPUs with FSDP."""
|
||||
|
||||
import argparse
|
||||
import functools
|
||||
import os
|
||||
import time
|
||||
|
||||
from PIL import Image
|
||||
import torch
|
||||
from torch import nn
|
||||
import torch.distributed as dist
|
||||
from torch.distributed.fsdp import FullyShardedDataParallel as FSDP
|
||||
from torch.distributed.fsdp.wrap import size_based_auto_wrap_policy
|
||||
import torch.multiprocessing as mp
|
||||
import torchmetrics
|
||||
import torchvision
|
||||
from torchvision.models import resnet50
|
||||
|
||||
|
||||
class ImageFolder(torchvision.datasets.ImageFolder):
|
||||
"""Class for loading imagenet."""
|
||||
|
||||
def __init__(self, image_list_file, transform=None, target_transform=None):
|
||||
self.samples = self._make_dataset(image_list_file)
|
||||
self.loader = self._loader
|
||||
|
||||
self.imgs = self.samples
|
||||
self.targets = [s[1] for s in self.samples]
|
||||
|
||||
self.transform = transform
|
||||
self.target_transform = target_transform
|
||||
|
||||
def _make_dataset(self, image_list_file):
|
||||
items = []
|
||||
with open(image_list_file, 'r') as f:
|
||||
for line in f:
|
||||
item = line.strip().split(' ')
|
||||
items.append((item[0], int(item[1])))
|
||||
return items
|
||||
|
||||
def _loader(self, image_path):
|
||||
with open(image_path, 'rb') as f:
|
||||
img = Image.open(f)
|
||||
img = img.convert('RGB')
|
||||
return img
|
||||
|
||||
|
||||
def train(model, device, dataloader, optimizer):
|
||||
model.train()
|
||||
for image, target in dataloader:
|
||||
image = image.to(device, non_blocking=True)
|
||||
target = target.to(device, non_blocking=True)
|
||||
pred = model(image)
|
||||
# pred.shape (N, C), target.shape (N)
|
||||
loss = nn.functional.cross_entropy(pred, target)
|
||||
optimizer.zero_grad()
|
||||
loss.backward()
|
||||
optimizer.step()
|
||||
return loss
|
||||
|
||||
|
||||
def evaluate(model, device, dataloader, metric):
|
||||
model.eval()
|
||||
with torch.no_grad():
|
||||
for image, target in dataloader:
|
||||
image = image.to(device, non_blocking=True)
|
||||
target = target.to(device, non_blocking=True)
|
||||
pred = model(image)
|
||||
metric.update(pred, target)
|
||||
accuracy = metric.compute()
|
||||
metric.reset()
|
||||
return accuracy
|
||||
|
||||
|
||||
def worker(gpu, args):
|
||||
"""Run training and evaluation."""
|
||||
# Init process group.
|
||||
print(f'Initiating process {gpu}')
|
||||
dist.init_process_group(
|
||||
backend='nccl',
|
||||
init_method='env://',
|
||||
world_size=args.gpus,
|
||||
rank=gpu)
|
||||
|
||||
# Create train dataloader.
|
||||
train_dataset = ImageFolder(
|
||||
image_list_file=args.train_data_path,
|
||||
transform=torchvision.transforms.Compose([
|
||||
torchvision.transforms.RandomResizedCrop(224),
|
||||
torchvision.transforms.RandomHorizontalFlip(),
|
||||
torchvision.transforms.ToTensor(),
|
||||
torchvision.transforms.Normalize(
|
||||
mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225]),
|
||||
]))
|
||||
train_sampler = torch.utils.data.distributed.DistributedSampler(
|
||||
train_dataset, num_replicas=args.gpus, rank=gpu)
|
||||
train_dataloader = torch.utils.data.DataLoader(
|
||||
dataset=train_dataset,
|
||||
batch_size=args.train_batch_size,
|
||||
shuffle=False,
|
||||
num_workers=args.dataloader_num_workers,
|
||||
pin_memory=True,
|
||||
sampler=train_sampler)
|
||||
if gpu == 0:
|
||||
print(f'Train dataloader | samples: {len(train_dataloader.dataset)}, '
|
||||
f'num workers: {train_dataloader.num_workers}, '
|
||||
f'global batch size: {args.train_batch_size * args.gpus}, '
|
||||
f'batches/epoch: {len(train_dataloader)}')
|
||||
|
||||
# Create eval dataloader.
|
||||
eval_dataset = ImageFolder(
|
||||
image_list_file=args.eval_data_path,
|
||||
transform=torchvision.transforms.Compose([
|
||||
torchvision.transforms.Resize(256),
|
||||
torchvision.transforms.CenterCrop(224),
|
||||
torchvision.transforms.ToTensor(),
|
||||
torchvision.transforms.Normalize(
|
||||
mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225]),
|
||||
]))
|
||||
eval_sampler = torch.utils.data.distributed.DistributedSampler(
|
||||
eval_dataset, num_replicas=args.gpus, rank=gpu)
|
||||
eval_dataloader = torch.utils.data.DataLoader(
|
||||
dataset=eval_dataset,
|
||||
batch_size=args.eval_batch_size,
|
||||
shuffle=False,
|
||||
num_workers=args.dataloader_num_workers,
|
||||
pin_memory=True,
|
||||
drop_last=True,
|
||||
sampler=eval_sampler)
|
||||
if gpu == 0:
|
||||
print(f'Eval dataloader | samples: {len(eval_dataloader.dataset)}, '
|
||||
f'num workers: {eval_dataloader.num_workers}, '
|
||||
f'batch size: {args.eval_batch_size}, '
|
||||
f'batches/epoch: {len(eval_dataloader)}')
|
||||
|
||||
# Wrap policy.
|
||||
my_auto_wrap_policy = functools.partial(
|
||||
size_based_auto_wrap_policy, min_num_params=100)
|
||||
torch.cuda.set_device(gpu)
|
||||
|
||||
# Create model.
|
||||
model = resnet50(weights=None)
|
||||
model.to(args.device)
|
||||
model = FSDP(model, auto_wrap_policy=my_auto_wrap_policy)
|
||||
|
||||
# Optimizer.
|
||||
optimizer = torch.optim.SGD(model.parameters(), 0.1)
|
||||
|
||||
# Main loop.
|
||||
metric = torchmetrics.classification.Accuracy(top_k=1).to(args.device)
|
||||
for epoch in range(1, args.epochs + 1):
|
||||
if gpu == 0:
|
||||
print(f'Running epoch {epoch}')
|
||||
train_sampler.set_epoch(epoch)
|
||||
|
||||
start = time.time()
|
||||
train(model, args.device, train_dataloader, optimizer)
|
||||
end = time.time()
|
||||
if gpu == 0:
|
||||
print(f'Training finished in {(end - start):>0.3f} seconds')
|
||||
|
||||
start = time.time()
|
||||
evaluate(model, args.device, eval_dataloader, metric)
|
||||
end = time.time()
|
||||
if gpu == 0:
|
||||
print(f'Evaluation finished in {(end - start):>0.3f} seconds')
|
||||
|
||||
if gpu == 0:
|
||||
print('Done')
|
||||
dist.destroy_process_group()
|
||||
|
||||
|
||||
def create_args():
|
||||
"""Create main args."""
|
||||
parser = argparse.ArgumentParser(
|
||||
formatter_class=argparse.ArgumentDefaultsHelpFormatter)
|
||||
parser.add_argument(
|
||||
'--gpus',
|
||||
default=4,
|
||||
type=int,
|
||||
help='number of gpus to use')
|
||||
parser.add_argument(
|
||||
'--epochs',
|
||||
default=2,
|
||||
type=int,
|
||||
help='number of total epochs to run')
|
||||
parser.add_argument(
|
||||
'--dataloader_num_workers',
|
||||
default=2,
|
||||
type=int,
|
||||
help='number of workders for dataloader')
|
||||
parser.add_argument(
|
||||
'--train_data_path',
|
||||
default='',
|
||||
type=str,
|
||||
help='path to training data')
|
||||
parser.add_argument(
|
||||
'--train_batch_size',
|
||||
default=32,
|
||||
type=int,
|
||||
help='batch size for training per gpu')
|
||||
parser.add_argument(
|
||||
'--eval_data_path',
|
||||
default='',
|
||||
type=str,
|
||||
help='path to evaluation data')
|
||||
parser.add_argument(
|
||||
'--eval_batch_size',
|
||||
default=32,
|
||||
type=int,
|
||||
help='batch size for evaluation per gpu')
|
||||
args = parser.parse_args()
|
||||
return args
|
||||
|
||||
|
||||
def main():
|
||||
args = create_args()
|
||||
|
||||
os.environ['MASTER_ADDR'] = 'localhost'
|
||||
os.environ['MASTER_PORT'] = '8888'
|
||||
|
||||
args.device = 'cuda' if torch.cuda.is_available() else 'cpu'
|
||||
print(f'Launch job on {args.gpus} GPUs with FSDP')
|
||||
mp.spawn(worker, nprocs=args.gpus, args=(args,))
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
@@ -0,0 +1,240 @@
|
||||
"""Train resnet on multiple GPUs with DDP."""
|
||||
|
||||
import argparse
|
||||
import functools
|
||||
import itertools
|
||||
import math
|
||||
import os
|
||||
import time
|
||||
|
||||
import torch
|
||||
from torch import nn
|
||||
import torch.distributed as dist
|
||||
from torch.distributed.fsdp import FullyShardedDataParallel as FSDP
|
||||
from torch.distributed.fsdp.wrap import size_based_auto_wrap_policy
|
||||
import torch.multiprocessing as mp
|
||||
import torchmetrics
|
||||
from torchvision.models import resnet50
|
||||
from torchvision.transforms import transforms
|
||||
import webdataset as wds
|
||||
|
||||
|
||||
def wds_split(src, rank, world_size):
|
||||
"""Shards split function for webdataset."""
|
||||
# The context of caller of this function is within multiple processes
|
||||
# (by DDP world_size) and multiple workers (by dataloader_num_workers).
|
||||
# So we totally have (world_size * num_workers) workers for processing data.
|
||||
# NOTE: Raw data should be sharded to enough shards to make sure one process
|
||||
# can handle at least one shard, otherwise the process may hang.
|
||||
worker_id = 0
|
||||
num_workers = 1
|
||||
worker_info = torch.utils.data.get_worker_info()
|
||||
if worker_info:
|
||||
worker_id = worker_info.id
|
||||
num_workers = worker_info.num_workers
|
||||
for s in itertools.islice(src, rank * num_workers + worker_id, None,
|
||||
world_size * num_workers):
|
||||
yield s
|
||||
|
||||
|
||||
def identity(x):
|
||||
return x
|
||||
|
||||
|
||||
def create_wds_dataloader(rank, args, mode):
|
||||
"""Create webdataset dataset and dataloader."""
|
||||
if mode == 'train':
|
||||
transform = transforms.Compose([
|
||||
transforms.RandomResizedCrop(224),
|
||||
transforms.RandomHorizontalFlip(),
|
||||
transforms.ToTensor(),
|
||||
transforms.Normalize(
|
||||
mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225]),
|
||||
])
|
||||
data_path = args.train_data_path
|
||||
data_size = args.train_data_size
|
||||
batch_size_local = args.train_batch_size
|
||||
batch_size_global = args.train_batch_size * args.gpus
|
||||
# Since webdataset disallows partial batch, we pad the last batch for train.
|
||||
batches = int(math.ceil(data_size / batch_size_global))
|
||||
else:
|
||||
transform = transforms.Compose([
|
||||
transforms.Resize(256),
|
||||
transforms.CenterCrop(224),
|
||||
transforms.ToTensor(),
|
||||
transforms.Normalize(
|
||||
mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225]),
|
||||
])
|
||||
data_path = args.eval_data_path
|
||||
data_size = args.eval_data_size
|
||||
batch_size_local = args.eval_batch_size
|
||||
batch_size_global = args.eval_batch_size * args.gpus
|
||||
# Since webdataset disallows partial batch, we drop the last batch for eval.
|
||||
batches = int(data_size / batch_size_global)
|
||||
|
||||
dataset = wds.DataPipeline(
|
||||
wds.SimpleShardList(data_path),
|
||||
functools.partial(wds_split, rank=rank, world_size=args.gpus),
|
||||
wds.tarfile_to_samples(),
|
||||
wds.decode('pil'),
|
||||
wds.to_tuple('jpg;png;jpeg cls'),
|
||||
wds.map_tuple(transform, identity),
|
||||
wds.batched(batch_size_local, partial=False),
|
||||
)
|
||||
num_workers = args.dataloader_num_workers
|
||||
dataloader = wds.WebLoader(
|
||||
dataset=dataset,
|
||||
batch_size=None,
|
||||
shuffle=False,
|
||||
num_workers=num_workers,
|
||||
persistent_workers=True if num_workers > 0 else False,
|
||||
pin_memory=True).repeat(nbatches=batches)
|
||||
print(f'{mode} dataloader | samples: {data_size}, '
|
||||
f'num_workers: {num_workers}, '
|
||||
f'local batch size: {batch_size_local}, '
|
||||
f'global batch size: {batch_size_global}, '
|
||||
f'batches: {batches}')
|
||||
return dataloader
|
||||
|
||||
|
||||
def train(model, device, dataloader, optimizer):
|
||||
model.train()
|
||||
for image, target in dataloader:
|
||||
image = image.to(device, non_blocking=True)
|
||||
target = target.to(device, non_blocking=True)
|
||||
pred = model(image)
|
||||
# pred.shape (N, C), target.shape (N)
|
||||
loss = nn.functional.cross_entropy(pred, target)
|
||||
optimizer.zero_grad()
|
||||
loss.backward()
|
||||
optimizer.step()
|
||||
return loss
|
||||
|
||||
|
||||
def evaluate(model, device, dataloader, metric):
|
||||
model.eval()
|
||||
with torch.no_grad():
|
||||
for image, target in dataloader:
|
||||
image = image.to(device, non_blocking=True)
|
||||
target = target.to(device, non_blocking=True)
|
||||
pred = model(image)
|
||||
metric.update(pred, target)
|
||||
accuracy = metric.compute()
|
||||
metric.reset()
|
||||
return accuracy
|
||||
|
||||
|
||||
def worker(gpu, args):
|
||||
"""Run training and evaluation."""
|
||||
# Init process group.
|
||||
print(f'Initiating process {gpu}')
|
||||
dist.init_process_group(
|
||||
backend='nccl',
|
||||
init_method='env://',
|
||||
world_size=args.gpus,
|
||||
rank=gpu)
|
||||
|
||||
# Create dataloader.
|
||||
train_dataloader = create_wds_dataloader(gpu, args, 'train')
|
||||
eval_dataloader = create_wds_dataloader(gpu, args, 'eval')
|
||||
|
||||
# Wrap policy.
|
||||
my_auto_wrap_policy = functools.partial(
|
||||
size_based_auto_wrap_policy, min_num_params=100)
|
||||
torch.cuda.set_device(gpu)
|
||||
|
||||
# Create model.
|
||||
model = resnet50(weights=None)
|
||||
model.to(args.device)
|
||||
model = FSDP(model, auto_wrap_policy=my_auto_wrap_policy)
|
||||
|
||||
# Optimizer.
|
||||
optimizer = torch.optim.SGD(model.parameters(), 0.1)
|
||||
|
||||
# Main loop.
|
||||
metric = torchmetrics.classification.Accuracy(top_k=1).to(args.device)
|
||||
for epoch in range(1, args.epochs + 1):
|
||||
if gpu == 0:
|
||||
print(f'Running epoch {epoch}')
|
||||
|
||||
start = time.time()
|
||||
train(model, args.device, train_dataloader, optimizer)
|
||||
end = time.time()
|
||||
if gpu == 0:
|
||||
print(f'Training finished in {(end - start):>0.3f} seconds')
|
||||
|
||||
start = time.time()
|
||||
evaluate(model, args.device, eval_dataloader, metric)
|
||||
end = time.time()
|
||||
if gpu == 0:
|
||||
print(f'Evaluation finished in {(end - start):>0.3f} seconds')
|
||||
|
||||
if gpu == 0:
|
||||
print('Done')
|
||||
|
||||
|
||||
def create_args():
|
||||
"""Create main args."""
|
||||
parser = argparse.ArgumentParser(
|
||||
formatter_class=argparse.ArgumentDefaultsHelpFormatter)
|
||||
parser.add_argument(
|
||||
'--gpus',
|
||||
default=4,
|
||||
type=int,
|
||||
help='number of gpus to use')
|
||||
parser.add_argument(
|
||||
'--epochs',
|
||||
default=2,
|
||||
type=int,
|
||||
help='number of total epochs to run')
|
||||
parser.add_argument(
|
||||
'--dataloader_num_workers',
|
||||
default=2,
|
||||
type=int,
|
||||
help='number of workders for dataloader')
|
||||
parser.add_argument(
|
||||
'--train_data_path',
|
||||
default='',
|
||||
type=str,
|
||||
help='path to training data')
|
||||
parser.add_argument(
|
||||
'--train_batch_size',
|
||||
default=32,
|
||||
type=int,
|
||||
help='batch size for training per gpu')
|
||||
parser.add_argument(
|
||||
'--train_data_size',
|
||||
default=50000,
|
||||
type=int,
|
||||
help='data size for training')
|
||||
parser.add_argument(
|
||||
'--eval_data_path',
|
||||
default='',
|
||||
type=str,
|
||||
help='path to evaluation data')
|
||||
parser.add_argument(
|
||||
'--eval_batch_size',
|
||||
default=32,
|
||||
type=int,
|
||||
help='batch size for evaluation per gpu')
|
||||
parser.add_argument(
|
||||
'--eval_data_size',
|
||||
default=50000,
|
||||
type=int,
|
||||
help='data size for evaluation')
|
||||
args = parser.parse_args()
|
||||
return args
|
||||
|
||||
|
||||
def main():
|
||||
args = create_args()
|
||||
os.environ['MASTER_ADDR'] = 'localhost'
|
||||
os.environ['MASTER_PORT'] = '8888'
|
||||
|
||||
args.device = 'cuda' if torch.cuda.is_available() else 'cpu'
|
||||
print(f'Launch job on {args.gpus} GPUs with FSDP')
|
||||
mp.spawn(worker, nprocs=args.gpus, args=(args,))
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
@@ -0,0 +1,98 @@
|
||||
# Copyright 2022 Google LLC
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the \"License\");
|
||||
# you may not use this file except in compliance with the License.\n",
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an \"AS IS\" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
r"""Main function to shard ImageNet dataset.
|
||||
|
||||
Example usage:
|
||||
python3 -u shard_imagenet.py \
|
||||
--image_list_file=/home/jupyter/data/imagenet/train_list.txt \
|
||||
--output_pattern=/home/jupyter/data/imagenet/validation-%06d.tar
|
||||
"""
|
||||
|
||||
import argparse
|
||||
import os
|
||||
import random
|
||||
import webdataset as wds # version: 0.2.26
|
||||
|
||||
|
||||
# NOTE: only supports writing to local path,
|
||||
# need gcsfuse mounting if want to write to gcs bucket.
|
||||
def write_shards(args):
|
||||
"""Shard individual data files."""
|
||||
output_dir = os.path.dirname(args.output_pattern)
|
||||
if not os.path.isdir(output_dir):
|
||||
os.makedirs(output_dir)
|
||||
|
||||
items = []
|
||||
# Image list file is a text file, each line is a pair (image_path, label).
|
||||
with open(args.image_list_file, 'r') as f:
|
||||
for line in f:
|
||||
item = line.strip().split(' ')
|
||||
items.append((item[0], int(item[1])))
|
||||
# Shuffle items to avoid any large sequences of a single class
|
||||
# in the dataset.
|
||||
random.shuffle(items)
|
||||
|
||||
def _read_image(image_path):
|
||||
with open(image_path, 'rb') as f:
|
||||
return f.read()
|
||||
|
||||
with wds.ShardWriter(pattern=args.output_pattern,
|
||||
maxcount=args.max_images_per_shard,
|
||||
maxsize=args.max_bytes_per_shard) as sink:
|
||||
for i, (image_path, target) in enumerate(items):
|
||||
key = str(i)
|
||||
image = _read_image(image_path)
|
||||
sample = {'__key__': key, 'jpg': image, 'cls': target}
|
||||
sink.write(sample)
|
||||
if len(items) != sink.total:
|
||||
raise ValueError('Items read {} != items written {}'.format(
|
||||
len(items), sink.total))
|
||||
|
||||
|
||||
def create_args():
|
||||
"""Creates arg parser."""
|
||||
parser = argparse.ArgumentParser(
|
||||
formatter_class=argparse.ArgumentDefaultsHelpFormatter)
|
||||
parser.add_argument(
|
||||
'--image_list_file',
|
||||
default='',
|
||||
type=str,
|
||||
help='path to image list file')
|
||||
parser.add_argument(
|
||||
'--output_pattern',
|
||||
default='',
|
||||
type=str,
|
||||
help='the pattern for output shards, like /path/to/train-%06d.tar')
|
||||
parser.add_argument(
|
||||
'--max_images_per_shard',
|
||||
default=10 * 1024,
|
||||
type=int,
|
||||
help='max number of images per shard')
|
||||
parser.add_argument(
|
||||
'--max_bytes_per_shard',
|
||||
default=300 * 1024 * 1024,
|
||||
type=int,
|
||||
help='max bytes per shard')
|
||||
args = parser.parse_args()
|
||||
return args
|
||||
|
||||
|
||||
def main():
|
||||
args = create_args()
|
||||
write_shards(args)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
@@ -0,0 +1,102 @@
|
||||
# Administrative Howto notes on CI Notebook Ingestion
|
||||
|
||||
|
||||
This readme covers administrative actions that are performed on an as-needed basis.
|
||||
|
||||
## Team: vertex-ai-owners
|
||||
|
||||
Members of the vertex-ai-owners (git team) have administrative privileges.
|
||||
|
||||
|
||||
### Viewing members
|
||||
|
||||
1. Goto the repo
|
||||
2. From top-level menu, select: (Settings -> Collaborators and Teams)[https://github.com/GoogleCloudPlatform/vertex-ai-samples/settings/access]
|
||||
|
||||
|
||||
### Adding a new member
|
||||
|
||||
If another member needs to be added:
|
||||
- Have the new member make a request to join the team.
|
||||
- vertex-ai-owners with the `Maintainer` tag may add the new member.
|
||||
|
||||
|
||||
## Executing CI notebook ingestion checks on a PR
|
||||
|
||||
### Killing a stuck PR
|
||||
|
||||
If the CI notebook ingestion test is stuck (not terminating), you can kill the process by:
|
||||
|
||||
1. Goto the PR
|
||||
2. Under checks, find the entry: vertex-ai-notebook-execution-test (python-docs-samples-tests) In progress —> Summary
|
||||
3. Select Details
|
||||
4. At bottom of details page, select: View more details on Google Cloud Build
|
||||
5. In Cloud Build history page, select Cancel on the top menu bar.
|
||||
|
||||
### Restart a PR test
|
||||
|
||||
There are two ways to restart the CI notebook ingestion tests on an open PR.
|
||||
|
||||
1. In Cloud Build history page, select Rebuild on the top menu bar.
|
||||
2. or, in a comment in the PR enter: /gcbrun
|
||||
|
||||
## Bypassing CI notebook ingestion checks on a PR
|
||||
|
||||
We strongly discourage this, unless there is a compelling reason that would impact the integrity of the quality process.
|
||||
|
||||
There are two ways of doing this. In both cases, you do:
|
||||
|
||||
1. Goto the repo
|
||||
2. From top-level menu, select: (Settings -> Branches)[https://github.com/GoogleCloudPlatform/vertex-ai-samples/settings/branches]
|
||||
3. Under Branch Protection Rules, select the `main` branch.
|
||||
|
||||
### Allowing a member to disable requirements for merging
|
||||
|
||||
Specific member(s) can be assigned the ability to override requirements and merge a PR, by:
|
||||
|
||||
1. Select Edit for the `main` branch in Branch Protection Rules.
|
||||
2. Find the entry "Allow specified actors to bypass required pull requests".
|
||||
3. Under this entry, add the member's git LDAP.
|
||||
4. Select SAVE.
|
||||
5. The "Squash and Merge" button will now be enabled on all PRs viewed by that member.
|
||||
|
||||
### Temporarily disable checks.
|
||||
|
||||
You can disable requirement checks temporarily on all PRs.
|
||||
|
||||
1. Select Edit for the `main` branch in Branch Protection Rules.
|
||||
2. Uncheck:
|
||||
- Require approvals
|
||||
- Require review from Code Owners
|
||||
- Require status checks to pass before merging
|
||||
3. Select SAVE
|
||||
4. Now all members will see a green "Squash and Merge" on all PRs viewed by that member.
|
||||
|
||||
To reverse, recheck the settings you unchecked above.
|
||||
|
||||
## Linting
|
||||
|
||||
To execute the identical lint image locally, from the CI notebook ingestion checks, do:
|
||||
|
||||
1. Goto the corresponding local folder in the repo.
|
||||
2. Run: `docker run -v ${PWD}:/setup/app gcr.io/python-docs-samples-tests/notebook_linter:latest <your_notebooks>`
|
||||
|
||||
## Install dependency issues
|
||||
|
||||
Some packages (and combinations) have dependencies that fail on the virgin VM image used for the CI notebook ingestion test.
|
||||
|
||||
### TFDV
|
||||
|
||||
If the notebook installs and uses tensorflow_data_validation, install as follows:
|
||||
|
||||
! pip3 install -q {USER_FLAG} google-cloud-aiplatform \
|
||||
tensorflow-data-validation \
|
||||
protobuf==3.20.3
|
||||
|
||||
! pip3 install -q {USER_FLAG} cachetools==5.2.0
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -7,24 +7,33 @@
|
||||
/gapic @andrewferlitsch
|
||||
/gapic/custom/showcase_custom_image_classification_online_explain_example_based_api.ipynb @inardini
|
||||
/ml_ops @andrewferlitsch
|
||||
/model_monitoring/* @mco-gh
|
||||
/model_monitoring/* @andrewferlitsch
|
||||
/structured_data/rapid_prototyping_* @rafael-carvalho
|
||||
|
||||
/managed_notebooks/
|
||||
/bigquery_ml/ @polong
|
||||
/sdk/SDK_FBProphet_Forecasting_Online.ipynb @brianchunkang
|
||||
/pipelines/google_cloud_pipeline_components_TPU_model_train_upload_deploy.ipynb @brianchunkang
|
||||
/explainable_ai/SDK_Custom_Container_XAI.ipynb @brianchunkang
|
||||
/matching_engine/sdk_matching_engine_for_indexing.ipynb @ivanmkc
|
||||
/matching_engine/matching_engine_for_indexing.ipynb @yinghsienwu
|
||||
/matching_engine/stream_update_for_matching_engine.ipynb @peterping666
|
||||
/sdk/pytorch_lightning_custom_container_training.ipynb @brianchunkang
|
||||
/sdk/sdk_pytorch_torchrun_custom_container_training_imagenet.ipynb @brianchunkang
|
||||
/tensorboard @yfang1
|
||||
/feature_store @nayaknishant @morgandu
|
||||
/prediction @googleapis/vertex-prediction-team
|
||||
/vertex_endpoints/tf_hub_obj_detection/deploy_tfhub_object_detection_on_vertex_endpoints.ipynb @entrpn
|
||||
/vertex_endpoints/find_ideal_machine_type/find_ideal_machine_type/find_ideal_machine_type.ipynb @entrpn
|
||||
/vertex_endpoints/nvidia-triton/nvidia-triton-custom-container-prediction.ipynb @RajeshThallam
|
||||
/vertex_endpoints/optimized_tensorflow_runtime @vlasenkoalexey
|
||||
/notebooks/community/ml_ops/stage2/get_started_with_visionapi_and_automl.ipynb @mansari
|
||||
/notebooks/community/neo4j/graph_paysim.ipynb @benofben @laeg
|
||||
/notebooks/community/ml_ops/stage1/get_started_with_visionapi_and_vertex_datasets.ipynb @mansari
|
||||
/notebooks/community/pipelines/google_cloud_pipeline_components_bqml_pipeline_demand_forecasting.ipynb @inardini
|
||||
/notebooks/community/pipelines/google_cloud_pipeline_components_bqml_pipeline_demand_forecasting.ipynb @inardini
|
||||
/notebooks/community/ml_ops/stage2/get_started_vertex_hpt_r_kernel.ipynb @fhirschmann
|
||||
/notebooks/community/ml_ops/stage2/get_started_vertex_training_r_using_r_kernel.ipynb @fhirschmann
|
||||
/notebooks/community/vertex-ai-samples/notebooks/community/model_registry/vertex_ai_model_registry_bqml_custom_model_versioning.ipynb @inardini
|
||||
/notebooks/community/vertex-ai-samples/notebooks/community/model_registry/vertex_ai_model_registry_automl_model_versioning.ipynb @inardini
|
||||
/notebooks/community/vizier/conversions_vertex_vizier_and_open_source_vizier.ipynb @halio-g
|
||||
/notebooks/community/experiments/vertex_ai_model_experimentation.ipynb @inardini @asobran
|
||||
/notebooks/community/pipelines/google_cloud_pipeline_components_bqml_pipeline_anomaly_detection.ipynb @inardini
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -14,5 +14,5 @@ The purpose of this set of notebooks and markdown files is to demonstrate Google
|
||||
4. [Evaluation](stage4)
|
||||
5. [Deployment](stage5)
|
||||
6. [Serving](stage6)
|
||||
7. Monitoring
|
||||
7. Monitoring(stage7)
|
||||
8. Continuous Training
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
## Before you begin
|
||||
|
||||
### Set up your Google Cloud project
|
||||
|
||||
**The following steps are required, regardless of your notebook environment.**
|
||||
|
||||
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.
|
||||
|
||||
1. [Make sure that billing is enabled for your project](https://cloud.google.com/billing/docs/how-to/modify-project).
|
||||
|
||||
1. [Enable the Vertex AI, BigQuery, Compute Engine and Cloud Storage APIs](https://console.cloud.google.com/flows/enableapi?apiid=aiplatform.googleapis.com,bigquery,compute_component,storage_component).
|
||||
|
||||
1. If you are running this notebook locally, you need to install the [Cloud SDK](https://cloud.google.com/sdk).
|
||||
|
||||
1. Enter your project ID in the cell below. Then run the cell to make sure the
|
||||
Cloud SDK uses the right project for all the commands in this notebook.
|
||||
|
||||
**Note**: Jupyter runs lines prefixed with `!` as shell commands, and it interpolates Python variables prefixed with `$` into these commands.
|
||||
|
||||
### Set up your local development environment
|
||||
|
||||
**If you are using Colab or Vertex AI Workbench Notebooks**, your environment already meets all the requirements to run this notebook. You can skip this step.
|
||||
|
||||
**Otherwise**, make sure your environment meets this notebook's requirements. You need the following:
|
||||
|
||||
- The Cloud Storage SDK
|
||||
- Python 3
|
||||
- virtualenv
|
||||
- Jupyter notebook running in a virtual environment with Python 3
|
||||
|
||||
The Cloud Storage guide to [Setting up a Python development environment](https://cloud.google.com/python/setup) and the [Jupyter installation guide](https://jupyter.org/install) provide detailed instructions for meeting these requirements. The following steps provide a condensed set of instructions:
|
||||
|
||||
1. [Install and initialize the SDK](https://cloud.google.com/sdk/docs/).
|
||||
|
||||
2. [Install Python 3](https://cloud.google.com/python/setup#installing_python).
|
||||
|
||||
3. [Install virtualenv](https://cloud.google.com/python/setup#installing_and_using_virtualenv) and create a virtual environment that uses Python 3. Activate the virtual environment.
|
||||
|
||||
4. To install Jupyter, run `pip3 install jupyter` on the command-line in a terminal shell.
|
||||
|
||||
5. To launch Jupyter, run `jupyter notebook` on the command-line in a terminal shell.
|
||||
|
||||
6. Open this notebook in the Jupyter Notebook Dashboard.
|
||||
@@ -0,0 +1,112 @@
|
||||
import os
|
||||
import sys
|
||||
import argparse
|
||||
import subprocess
|
||||
import random
|
||||
import string
|
||||
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument('--bucket', dest='bucket_required', action='store_true',
|
||||
default=False, help='Bucket required')
|
||||
parser.add_argument('--email', dest='email_required', action='store_true',
|
||||
default=False, help='Email required')
|
||||
parser.add_argument('--sa', dest='sa_required', action='store_true',
|
||||
default=False, help='Service account required')
|
||||
parser.add_argument('--packages', dest='extra_packages',
|
||||
default='', type=str, help='additional required packages')
|
||||
args = parser.parse_args()
|
||||
|
||||
extra_pkgs = args.extra_packages
|
||||
|
||||
|
||||
# Installation
|
||||
|
||||
|
||||
# The Vertex AI Workbench Notebook product has specific requirements
|
||||
IS_WORKBENCH_NOTEBOOK = os.getenv("DL_ANACONDA_HOME")
|
||||
IS_USER_MANAGED_WORKBENCH_NOTEBOOK = os.path.exists(
|
||||
"/opt/deeplearning/metadata/env_version"
|
||||
)
|
||||
IS_COLAB = "google.colab" in sys.modules
|
||||
|
||||
# Vertex AI Notebook requires dependencies to be installed with '--user'
|
||||
USER_FLAG = ""
|
||||
if IS_WORKBENCH_NOTEBOOK:
|
||||
USER_FLAG = "--user"
|
||||
|
||||
# not used
|
||||
'''
|
||||
print("Installing packages")
|
||||
os.system(f"pip3 install --upgrade --quiet {USER_FLAG} google-cloud-aiplatform {args.extra_packages}")
|
||||
print("Done installation")
|
||||
'''
|
||||
|
||||
# Authenticate
|
||||
if IS_COLAB:
|
||||
from google.colab import auth as google_auth
|
||||
|
||||
google_auth.authenticate_user()
|
||||
|
||||
|
||||
# project ID
|
||||
if IS_WORKBENCH_NOTEBOOK:
|
||||
shell_output = subprocess.check_output("gcloud config list --format 'value(core.project)' 2>/dev/null", shell=True)
|
||||
PROJECT_ID = shell_output[0:-1].decode('utf-8')
|
||||
print("PROJECT ID: ", PROJECT_ID)
|
||||
else:
|
||||
PROJECT_ID = input("Enter PROJECT_ID: ")
|
||||
os.system(f"gcloud config set project {PROJECT_ID}")
|
||||
|
||||
# email
|
||||
if args.email_required:
|
||||
shell_output = subprocess.check_output("gcloud config list --format 'value(core.account)' 2>/dev/null", shell=True)
|
||||
EMAIL_ADDR = shell_output[0:-1].decode('utf-8')
|
||||
if EMAIL_ADDR == '':
|
||||
EMAIL_ADDR = input("Enter Email Address: ")
|
||||
print("EMAIL_ADDR: ", EMAIL_ADDR)
|
||||
|
||||
# region
|
||||
shell_output = subprocess.check_output("gcloud config list --format 'value(ai.region)'", shell=True)
|
||||
REGION = shell_output[0:-1].decode('utf-8')
|
||||
if REGION == '':
|
||||
REGION = input("Enter REGION: ")
|
||||
print("REGION: ", REGION)
|
||||
|
||||
# multi-region
|
||||
MULTI_REGION = REGION.split('-')[0]
|
||||
|
||||
|
||||
# UUID
|
||||
# Generate a uuid of a specifed length(default=8)
|
||||
def generate_uuid(length: int = 8) -> str:
|
||||
return "".join(random.choices(string.ascii_lowercase + string.digits, k=length))
|
||||
|
||||
|
||||
UUID = generate_uuid()
|
||||
print("UUID", UUID)
|
||||
|
||||
# Bucket
|
||||
if args.bucket_required:
|
||||
BUCKET_NAME = PROJECT_ID + "aip-" + UUID
|
||||
BUCKET_URI = f"gs://{BUCKET_NAME}"
|
||||
os.system(f"gsutil mb -l {REGION} {BUCKET_URI}")
|
||||
print("BUCKET_URI", BUCKET_URI)
|
||||
|
||||
|
||||
# Project Number
|
||||
if args.sa_required:
|
||||
if IS_WORKBENCH_NOTEBOOK:
|
||||
shell_output = subprocess.check_output("gcloud auth list 2>/dev/null", shell=True)
|
||||
SERVICE_ACCOUNT = shell_output[:-1].decode('utf-8').split('\n')[2].strip()
|
||||
PROJECT_NUMBER = SERVICE_ACCOUNT.split('-')[0]
|
||||
else:
|
||||
shell_output = subprocess.check_output(f"gcloud projects describe {PROJECT_ID}", shell=True)
|
||||
try:
|
||||
PROJECT_NUMBER = shell_output[:-1].decode('utf-8').split('\n')[7].split(':')[-1].strip().replace("'", "")
|
||||
SERVICE_ACCOUNT = f"{PROJECT_NUMBER}-compute@developer.gserviceaccount.com"
|
||||
except:
|
||||
PROJECT_NUMBER = input("Enter project number: ")
|
||||
SERVICE_ACCOUNT = f"{PROJECT_NUMBER}-compute@developer.gserviceaccount.com"
|
||||
|
||||
print("SERVICE_ACCOUNT", SERVICE_ACCOUNT)
|
||||
print("PROJECT_NUMBER", PROJECT_NUMBER)
|
||||
@@ -28,28 +28,14 @@ The first stage in MLOps is the collection and preparation for the purpose of de
|
||||
|
||||
### Get Started
|
||||
|
||||
[Get started with Vertex AI datasets](get_started_vertex_datasets.ipynb)
|
||||
|
||||
[Get started with Dataflow](https://github.com/GoogleCloudPlatform/vertex-ai-samples/blob/main/notebooks/community/ml_ops/stage1/get_started_dataflow.ipynb)
|
||||
|
||||
```
|
||||
Learn how to use `Dataflow` for training with `Vertex AI`.
|
||||
|
||||
The steps performed include:
|
||||
- Create a Vertex AI `Dataset` resource for:
|
||||
- image data
|
||||
- text data
|
||||
- video data
|
||||
- tabular data
|
||||
- forecasting data
|
||||
- Search `Dataset` resources using a filter.
|
||||
- Read a sample of a `BigQuery` dataset into a dataframe.
|
||||
- Generate statistics and data schema using TensorFlow Data Validation from the samples in the dataframe.
|
||||
- Detect anomalies in new data using TensorFlow Data Validation.
|
||||
- Generate a TFRecord feature specification using TensorFlow Transform from the data schema.
|
||||
- Export a dataset and convert to TFRecords.
|
||||
```
|
||||
|
||||
[Get started with Dataflow](get_started_dataflow.ipynb)
|
||||
|
||||
```
|
||||
The steps performed include:
|
||||
- Offline preprocessing of data:
|
||||
- Serially - w/o dataflow
|
||||
- Parallel - with dataflow
|
||||
@@ -58,20 +44,38 @@ The steps performed include:
|
||||
- image data
|
||||
```
|
||||
|
||||
[Create an unlabelled Vertex AI AutoML text entity extraction dataset from pdfs using Vision API](get_started_with_visionapi_and_vertex_datasets.ipynb)
|
||||
|
||||
[Get started with Vertex AI datasets](https://github.com/GoogleCloudPlatform/vertex-ai-samples/blob/main/notebooks/community/ml_ops/stage1/get_started_vertex_datasets.ipynb)
|
||||
|
||||
```
|
||||
Learn how to use `Vertex AI Dataset` for training with `Vertex AI`.
|
||||
|
||||
The steps performed include:
|
||||
1. Using `Vision API` to perform Optical Character Recognition (OCR) to extract text from PDF files.
|
||||
2. Processing the results and saving them to text files.
|
||||
3. Generating a `Vertex AI Dataset` import file.
|
||||
4. Creating a new unlabelled text entity extraction `Vertex AI Dataset` resource in `Vertex AI`.
|
||||
|
||||
- Create a Vertex AI `Dataset` resource for:
|
||||
- image data
|
||||
- text data
|
||||
- video data
|
||||
- tabular data
|
||||
- forecasting data
|
||||
|
||||
|
||||
- Search `Dataset` resources using a filter.
|
||||
- Read a sample of a `BigQuery` dataset into a dataframe.
|
||||
- Generate statistics and data schema using TensorFlow Data Validation from the samples in the dataframe.
|
||||
- Detect anomalies in new data using TensorFlow Data Validation.
|
||||
- Generate a TFRecord feature specification using TensorFlow Transform from the data schema.
|
||||
- Export a dataset and convert to TFRecords.
|
||||
```
|
||||
|
||||
[Get started with BigQuery datasets](get_started_bq_datasets.ipynb)
|
||||
|
||||
[Get started with BigQuery datasets](https://github.com/GoogleCloudPlatform/vertex-ai-samples/blob/main/notebooks/community/ml_ops/stage1/get_started_bq_datasets.ipynb)
|
||||
|
||||
```
|
||||
Learn how to use `BigQuery` as a dataset for training with `Vertex AI`.
|
||||
|
||||
The steps performed include:
|
||||
|
||||
- Create a Vertex AI `Dataset` resource from `BigQuery` table -- compatible for `AutoML` training.
|
||||
- Extract a copy of the dataset from `BigQuery` to a CSV file in Cloud Storage -- compatible for `AutoML` or custom training.
|
||||
- Select rows from a `BigQuery` dataset into a `pandas` dataframe -- compatible for custom training.
|
||||
@@ -81,25 +85,44 @@ The steps performed include:
|
||||
- Extract data from `BigQuery` table into a `DMatrix` -- compatible for custom training `XGBoost` models.
|
||||
```
|
||||
|
||||
[Get started with Vertex AI data labeling](get_started_with_data_labeling.ipynb)
|
||||
|
||||
[Get started with Vertex AI Data Labeling](https://github.com/GoogleCloudPlatform/vertex-ai-samples/blob/main/notebooks/community/ml_ops/stage1/get_started_with_data_labeling.ipynb)
|
||||
|
||||
```
|
||||
Learn how to use the `Vertex AI Data Labeling` service/
|
||||
|
||||
The steps performed include:
|
||||
|
||||
- Create a Specialist Pool for data labelers.
|
||||
- Create a data labeling job.
|
||||
- Submit the data labeling job.
|
||||
- List data labeling jobs.
|
||||
- Cancel a data labeling job.
|
||||
```
|
||||
|
||||
|
||||
[Create an unlabelled Vertex AI AutoML text entity extraction dataset from PDFs using Vision API](https://github.com/GoogleCloudPlatform/vertex-ai-samples/blob/main/notebooks/community/ml_ops/stage1/get_started_with_visionapi_and_vertex_datasets.ipynb)
|
||||
|
||||
```
|
||||
Learn to use `Vision API` to extract text from PDF files stored on a Cloud Storage bucket.
|
||||
|
||||
The steps performed include:
|
||||
|
||||
1. Using `Vision API` to perform Optical Character Recognition (OCR) to extract text from PDF files.
|
||||
2. Processing the results and saving them to text files.
|
||||
3. Generating a `Vertex AI Dataset` import file.
|
||||
4. Cr
|
||||
|
||||
|
||||
### E2E Stage Example
|
||||
|
||||
[Stage 1: Data Management](mlops_data_management.ipynb)
|
||||
|
||||
[Data management](https://github.com/GoogleCloudPlatform/vertex-ai-samples/blob/main/notebooks/community/ml_ops/stage1/mlops_data_management.ipynb)
|
||||
|
||||
```
|
||||
In this tutorial, you create a MLOps stage 1: data management process.
|
||||
|
||||
The steps performed include:
|
||||
|
||||
- Explore and visualize the data.
|
||||
- Create a Vertex AI `Dataset` resource from `BigQuery` table -- for AutoML training.
|
||||
- Extract a copy of the dataset to a CSV file in Cloud Storage.
|
||||
@@ -108,4 +131,4 @@ The steps performed include:
|
||||
- Generate statistics and data schema using TensorFlow Data Validation from the samples in the dataframe.
|
||||
- Generate a TFRecord feature specification using TensorFlow Data Validation from the data schema.
|
||||
- Preprocess a portion of the BigQuery data using `Dataflow` -- for custom training.
|
||||
```
|
||||
```
|
||||
@@ -120,7 +120,7 @@
|
||||
" - XGBoost model training:\n",
|
||||
" - Use BigQuery ML built-in XGBoost training.\n",
|
||||
" - Alternatively, create a DMatrix generator from CSV files extracted from BigQuery table.\n",
|
||||
" - Pytorch model training:\n",
|
||||
" - PyTorch model training:\n",
|
||||
" - Extract the BigQuery to a pandas dataframe.\n",
|
||||
" - Preprocess the data in the dataframe.\n",
|
||||
" - Create a DataLoader generator from the pandas dataframe.\n",
|
||||
@@ -191,13 +191,8 @@
|
||||
"if IS_WORKBENCH_NOTEBOOK:\n",
|
||||
" USER_FLAG = \"--user\"\n",
|
||||
"\n",
|
||||
"# Install the packages\n",
|
||||
"! pip3 install --upgrade pyarrow $USER_FLAG -q\n",
|
||||
"! pip3 install --upgrade google-cloud-bigquery $USER_FLAG -q\n",
|
||||
"! pip3 install --upgrade google-cloud-aiplatform $USER_FLAG -q\n",
|
||||
"! pip3 install -U xgboost $USER_FLAG -q\n",
|
||||
"! pip3 install -U tensorflow $USER_FLAG -q\n",
|
||||
"! pip3 install -U tensorflow-io==0.18 $USER_FLAG -q"
|
||||
"extra_pkgs = \"tensorflow tensorflow-io==0.18 pyarrow xgboost google-cloud-bigquery\"\n",
|
||||
"! pip3 install --upgrade --quiet {USER_FLAG} google-cloud-aiplatform $extra_pkgs"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -219,9 +214,9 @@
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"import os\n",
|
||||
"import sys\n",
|
||||
"\n",
|
||||
"if not os.getenv(\"IS_TESTING\"):\n",
|
||||
"if \"google.colab\" in sys.modules:\n",
|
||||
" # Automatically restart kernel after installs\n",
|
||||
" import IPython\n",
|
||||
"\n",
|
||||
@@ -232,274 +227,42 @@
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "84cd83853240"
|
||||
"id": "fc8fb52b5cca"
|
||||
},
|
||||
"source": [
|
||||
"## Before you begin\n",
|
||||
"### Common setup\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",
|
||||
"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, BigQuery, Compute Engine and Cloud Storage APIs](https://console.cloud.google.com/flows/enableapi?apiid=aiplatform.googleapis.com,bigquery,compute_component,storage_component).\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."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "project_id"
|
||||
},
|
||||
"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`."
|
||||
"Now, execute the common setup for the notebook tutorials."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"id": "set_project_id"
|
||||
"id": "001a0fcd5d78"
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"PROJECT_ID = \"[your-project-id]\" # @param {type:\"string\"}"
|
||||
"# Common code setup for notebook tutorials\n",
|
||||
"\n",
|
||||
"! wget https://raw.githubusercontent.com/GoogleCloudPlatform/vertex-ai-samples/main/notebooks/community/ml_ops/setup.py -O setup.py\n",
|
||||
"\n",
|
||||
"%run setup.py --bucket"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"id": "autoset_project_id"
|
||||
"id": "d809f07a8935"
|
||||
},
|
||||
"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"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "region"
|
||||
},
|
||||
"source": [
|
||||
"#### Region\n",
|
||||
"# Other Common setup instructions for notebook tutorials\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. We recommend that you choose the region closest to you.\n",
|
||||
"! wget https://raw.githubusercontent.com/GoogleCloudPlatform/vertex-ai-samples/main/notebooks/community/ml_ops/setup.md -O setup.md\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)."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"id": "region"
|
||||
},
|
||||
"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": [
|
||||
"#### Timestamp\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 timestamp for each instance session, and append the timestamp onto the name of resources you create in this tutorial."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"id": "timestamp"
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"from datetime import datetime\n",
|
||||
"\n",
|
||||
"TIMESTAMP = datetime.now().strftime(\"%Y%m%d%H%M%S\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "77c385f0db59"
|
||||
},
|
||||
"source": [
|
||||
"### Authenticate your Google Cloud account\n",
|
||||
"\n",
|
||||
"**If you are using Vertex AI Workbench Notebooks**, your environment is already authenticated. Skip this step.\n",
|
||||
"\n",
|
||||
"**If you are using Colab**, run the cell below and follow the instructions when prompted to authenticate your account via oAuth.\n",
|
||||
"\n",
|
||||
"**Otherwise**, follow these steps:\n",
|
||||
"\n",
|
||||
"In the Cloud Console, go to the [Create service account key](https://console.cloud.google.com/apis/credentials/serviceaccountkey) page.\n",
|
||||
"\n",
|
||||
"1. **Click Create service account**.\n",
|
||||
"\n",
|
||||
"2. In the **Service account name** field, enter a name, and click **Create**.\n",
|
||||
"\n",
|
||||
"3. In the **Grant this service account access to project** section, click the Role drop-down list. Type \"Vertex AI\" into the filter box, and select **Vertex AI Administrator**. Type \"Storage Object Admin\" into the filter box, and select **Storage Object Admin**.\n",
|
||||
"\n",
|
||||
"4. Click Create. A JSON file that contains your key downloads to your local environment.\n",
|
||||
"\n",
|
||||
"5. Enter the path to your service account key as the GOOGLE_APPLICATION_CREDENTIALS variable in the cell below and run the cell."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"id": "535223fa4b84"
|
||||
},
|
||||
"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 = False\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",
|
||||
" IS_COLAB = True\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 ''"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "bucket:custom"
|
||||
},
|
||||
"source": [
|
||||
"### Create a Cloud Storage bucket\n",
|
||||
"\n",
|
||||
"**The following steps are required, regardless of your notebook environment.**\n",
|
||||
"\n",
|
||||
"When you create a dataset resource using the Vertex SDK, you can provide a Cloud Storage bucket that contains the data. Vertex AI creates the dataset resource from the data. In this tutorial, Vertex AI also creates a dataset resource from your data in the Cloud Storage bucket.\n",
|
||||
"\n",
|
||||
"Set the name of your Cloud Storage bucket below. Bucket names must be globally unique across all Google Cloud projects, including those outside of your organization."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"id": "bucket"
|
||||
},
|
||||
"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_URI == \"\" or BUCKET_URI is None or BUCKET_URI == \"gs://[your-bucket-name]\":\n",
|
||||
" BUCKET_NAME = PROJECT_ID + \"aip-\" + TIMESTAMP\n",
|
||||
" BUCKET_URI = \"gs://\" + BUCKET_NAME"
|
||||
]
|
||||
},
|
||||
{
|
||||
"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": "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"
|
||||
"%load setup.md"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -620,7 +383,7 @@
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"dataset = aiplatform.TabularDataset.create(\n",
|
||||
" display_name=\"NOAA historical weather data\" + \"_\" + TIMESTAMP,\n",
|
||||
" display_name=\"NOAA historical weather data\" + \"_\" + UUID,\n",
|
||||
" bq_source=[IMPORT_FILE],\n",
|
||||
" labels={\"user_metadata\": BUCKET_URI[5:]},\n",
|
||||
")\n",
|
||||
@@ -695,7 +458,7 @@
|
||||
"gcs_source = IMPORT_FILES\n",
|
||||
"\n",
|
||||
"dataset = aiplatform.TabularDataset.create(\n",
|
||||
" display_name=\"NOAA historical weather data\" + \"_\" + TIMESTAMP,\n",
|
||||
" display_name=\"NOAA historical weather data\" + \"_\" + UUID,\n",
|
||||
" gcs_source=gcs_source,\n",
|
||||
" labels={\"user_metadata\": BUCKET_URI[5:]},\n",
|
||||
")\n",
|
||||
@@ -737,10 +500,10 @@
|
||||
" or BQ_MY_DATASET is None\n",
|
||||
" or BQ_MY_DATASET == \"[your-dataset-name]\"\n",
|
||||
"):\n",
|
||||
" BQ_MY_DATASET = \"mlops_dataset_\" + TIMESTAMP\n",
|
||||
" BQ_MY_DATASET = \"mlops_dataset_\" + UUID\n",
|
||||
"\n",
|
||||
"if BQ_MY_TABLE == \"\" or BQ_MY_TABLE is None or BQ_MY_TABLE == \"[your-view-name]\":\n",
|
||||
" BQ_MY_TABLE = \"mlops_view_\" + TIMESTAMP"
|
||||
" BQ_MY_TABLE = \"mlops_view_\" + UUID"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
||||
@@ -44,7 +44,7 @@
|
||||
" </a>\n",
|
||||
" </td>\n",
|
||||
" <td>\n",
|
||||
" <a href=\"https://console.cloud.google.com/vertex-ai/workbench/deploy-notebook?download_url=https://github.com/GoogleCloudPlatform/vertex-ai-samples/blob/main/notebooks/community/ml_ops/stage1/get_started_dataflow.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/community/ml_ops/stage1/get_started_dataflow.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",
|
||||
@@ -186,13 +186,9 @@
|
||||
"if IS_WORKBENCH_NOTEBOOK:\n",
|
||||
" USER_FLAG = \"--user\"\n",
|
||||
"\n",
|
||||
"! pip3 install -U tensorflow==2.5 $USER_FLAG -q\n",
|
||||
"! pip3 install -U tensorflow-data-validation==1.2 $USER_FLAG -q\n",
|
||||
"! pip3 install -U tensorflow-transform==1.2 $USER_FLAG -q\n",
|
||||
"! pip3 install -U tensorflow-io==0.18 $USER_FLAG -q\n",
|
||||
"! pip3 install --upgrade google-cloud-aiplatform $USER_FLAG -q\n",
|
||||
"! pip3 install --upgrade google-cloud-bigquery $USER_FLAG -q\n",
|
||||
"! pip3 install --upgrade apache-beam[gcp] $USER_FLAG -q"
|
||||
"extra_pkgs = \"tensorflow==2.5 tensorflow-data-validation==1.2 tensorflow-transform==1.2 \\\n",
|
||||
" tensorflow-io==0.18 pyarrow pandas apache-beam[gcp] google-cloud-bigquery\"\n",
|
||||
"! pip3 install --upgrade --quiet {USER_FLAG} google-cloud-aiplatform $extra_pkgs"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -214,9 +210,9 @@
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"import os\n",
|
||||
"import sys\n",
|
||||
"\n",
|
||||
"if not os.getenv(\"IS_TESTING\"):\n",
|
||||
"if \"google.colab\" in sys.modules:\n",
|
||||
" # Automatically restart kernel after installs\n",
|
||||
" import IPython\n",
|
||||
"\n",
|
||||
@@ -227,279 +223,42 @@
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "84cd83853240"
|
||||
"id": "fc8fb52b5cca"
|
||||
},
|
||||
"source": [
|
||||
"## Before you begin\n",
|
||||
"### Common setup\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",
|
||||
"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, BigQuery, Compute Engine and Cloud Storage APIs](https://console.cloud.google.com/flows/enableapi?apiid=aiplatform.googleapis.com,bigquery,compute_component,storage_component).\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."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "project_id"
|
||||
},
|
||||
"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`."
|
||||
"Now, execute the common setup for the notebook tutorials."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"id": "set_project_id"
|
||||
"id": "001a0fcd5d78"
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"PROJECT_ID = \"[your-project-id]\" # @param {type:\"string\"}"
|
||||
"# Common code setup for notebook tutorials\n",
|
||||
"\n",
|
||||
"! wget https://raw.githubusercontent.com/GoogleCloudPlatform/vertex-ai-samples/main/notebooks/community/ml_ops/setup.py -O setup.py\n",
|
||||
"\n",
|
||||
"%run setup.py --bucket"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"id": "autoset_project_id"
|
||||
"id": "d809f07a8935"
|
||||
},
|
||||
"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"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "region"
|
||||
},
|
||||
"source": [
|
||||
"#### Region\n",
|
||||
"# Other Common setup instructions for notebook tutorials\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. We recommend that you choose the region closest to you.\n",
|
||||
"! wget https://raw.githubusercontent.com/GoogleCloudPlatform/vertex-ai-samples/main/notebooks/community/ml_ops/setup.md -O setup.md\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)."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"id": "region"
|
||||
},
|
||||
"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": [
|
||||
"#### Timestamp\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 timestamp for each instance session, and append the timestamp onto the name of resources you create in this tutorial."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"id": "timestamp"
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"from datetime import datetime\n",
|
||||
"\n",
|
||||
"TIMESTAMP = datetime.now().strftime(\"%Y%m%d%H%M%S\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "77c385f0db59"
|
||||
},
|
||||
"source": [
|
||||
"### Authenticate your Google Cloud account\n",
|
||||
"\n",
|
||||
"**If you are using Vertex AI Workbench Notebooks**, your environment is already authenticated. Skip this step.\n",
|
||||
"\n",
|
||||
"**If you are using Colab**, run the cell below and follow the instructions when prompted to authenticate your account via oAuth.\n",
|
||||
"\n",
|
||||
"**Otherwise**, follow these steps:\n",
|
||||
"\n",
|
||||
"In the Cloud Console, go to the [Create service account key](https://console.cloud.google.com/apis/credentials/serviceaccountkey) page.\n",
|
||||
"\n",
|
||||
"1. **Click Create service account**.\n",
|
||||
"\n",
|
||||
"2. In the **Service account name** field, enter a name, and click **Create**.\n",
|
||||
"\n",
|
||||
"3. In the **Grant this service account access to project** section, click the Role drop-down list. Type \"Vertex AI\" into the filter box, and select **Vertex AI Administrator**. Type \"Storage Object Admin\" into the filter box, and select **Storage Object Admin**.\n",
|
||||
"\n",
|
||||
"4. Click Create. A JSON file that contains your key downloads to your local environment.\n",
|
||||
"\n",
|
||||
"5. Enter the path to your service account key as the GOOGLE_APPLICATION_CREDENTIALS variable in the cell below and run the cell."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"id": "535223fa4b84"
|
||||
},
|
||||
"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 = False\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",
|
||||
" IS_COLAB = True\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 ''"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "bucket:custom"
|
||||
},
|
||||
"source": [
|
||||
"### Create a Cloud Storage bucket\n",
|
||||
"\n",
|
||||
"**The following steps are required, regardless of your notebook environment.**\n",
|
||||
"\n",
|
||||
"When you submit a custom training job using the Vertex SDK, you upload a Python package\n",
|
||||
"containing your training code to a Cloud Storage bucket. Vertex AI runs\n",
|
||||
"the code from this package. In this tutorial, Vertex AI also saves the\n",
|
||||
"trained model that results from your job in the same bucket. You can then\n",
|
||||
"create an `Endpoint` resource based on this output in order to serve\n",
|
||||
"online predictions.\n",
|
||||
"\n",
|
||||
"Set the name of your Cloud Storage bucket below. Bucket names must be globally unique across all Google Cloud projects, including those outside of your organization."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"id": "bucket"
|
||||
},
|
||||
"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-\" + TIMESTAMP\n",
|
||||
" BUCKET_URI = \"gs://\" + BUCKET_NAME"
|
||||
]
|
||||
},
|
||||
{
|
||||
"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": "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"
|
||||
"%load setup.md "
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -1319,7 +1078,7 @@
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"delete_storage = True\n",
|
||||
"delete_storage = False\n",
|
||||
"\n",
|
||||
"if delete_storage or os.getenv(\"IS_TESTING\"):\n",
|
||||
" if \"BUCKET_URI\" in globals():\n",
|
||||
|
||||
@@ -33,12 +33,12 @@
|
||||
"\n",
|
||||
"<table align=\"left\">\n",
|
||||
" <td>\n",
|
||||
" <a href=\"https://github.com/GoogleCloudPlatform/vertex-ai-samples/blob/main/notebooks/community/ml_ops/stage1/get_started_vertex_datasets.ipynb\">\n",
|
||||
" <a href=\"https://colab.research.google.com/github/GoogleCloudPlatform/vertex-ai-samples/blob/main/notebooks/community/ml_ops/stage1/get_started_vertex_datasets.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://console.cloud.google.com/ai/platform/notebooks/deploy-notebook?download_url=https://github.com/GoogleCloudPlatform/vertex-ai-samples/blob/main/notebooks/community/ml_ops/stage1/get_started_vertex_datasets.ipynb\">\n",
|
||||
" <a href=\"https://github.com/GoogleCloudPlatform/vertex-ai-samples/blob/main/notebooks/community/ml_ops/stage1/get_started_vertex_datasets.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",
|
||||
|
||||
@@ -212,7 +212,7 @@
|
||||
"\n",
|
||||
"3. [Enable the Vertex AI APIs and Compute Engine APIs.](https://console.cloud.google.com/flows/enableapi?apiid=aiplatform.googleapis.com,compute_component)\n",
|
||||
"\n",
|
||||
"4. [Google Cloud SDK](https://cloud.google.com/sdk) is already installed in Google Cloud Notebooks.\n",
|
||||
"4. [Google Cloud SDK](https://cloud.google.com/sdk) is already installed in Vertex AI Workbench Notebooks.\n",
|
||||
"\n",
|
||||
"5. 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",
|
||||
@@ -374,15 +374,8 @@
|
||||
"### Authenticate your Google Cloud account\n",
|
||||
"\n",
|
||||
"**If you are using Vertex AI Workbench Notebooks**, your environment is already\n",
|
||||
"authenticated. Skip this step."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "32e1cd21a5d5"
|
||||
},
|
||||
"source": [
|
||||
"authenticated. \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",
|
||||
"\n",
|
||||
|
||||
@@ -39,18 +39,15 @@
|
||||
" </a>\n",
|
||||
" </td>\n",
|
||||
" <td>\n",
|
||||
" <a href=\"https://colab.research.google.com/github/GoogleCloudPlatform/vertex-ai-samples/blob/main/notebooks/community/ml_ops/stage1/mlops_data_management.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://console.cloud.google.com/vertex-ai/workbench/deploy-notebook?download_url=https://raw.githubusercontent.com/GoogleCloudPlatform/vertex-ai-samples/main/notebooks/community/ml_ops/stage1/mlops_data_management.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>\n",
|
||||
"<br/><br/><br/>"
|
||||
"<br/><br/><br/>\n",
|
||||
"\n",
|
||||
"*Note: This notebook is not supported for execution in Colab*"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -169,21 +166,20 @@
|
||||
"if IS_WORKBENCH_NOTEBOOK:\n",
|
||||
" USER_FLAG = \"--user\"\n",
|
||||
"\n",
|
||||
"ONCE_ONLY = True\n",
|
||||
"ONCE_ONLY = False\n",
|
||||
"if ONCE_ONLY:\n",
|
||||
" ! pip3 install -U tensorflow==2.5 $USER_FLAG -q\n",
|
||||
" ! pip3 install -U tensorflow-data-validation==1.2 $USER_FLAG -q\n",
|
||||
" ! pip3 install -U tensorflow-transform==1.2 $USER_FLAG -q\n",
|
||||
" ! pip3 install -U tensorflow-io==0.18 $USER_FLAG -q\n",
|
||||
" ! pip3 install --upgrade google-cloud-aiplatform[tensorboard] $USER_FLAG -q\n",
|
||||
" ! pip3 install --upgrade google-cloud-pipeline-components $USER_FLAG -q\n",
|
||||
" ! pip3 install --upgrade google-cloud-bigquery $USER_FLAG -q\n",
|
||||
" ! pip3 install --upgrade google-cloud-logging $USER_FLAG -q\n",
|
||||
" ! pip3 install --upgrade apache-beam[gcp]==2.33.0 $USER_FLAG -q\n",
|
||||
" ! pip3 install --upgrade pyarrow $USER_FLAG -q\n",
|
||||
" ! pip3 install --upgrade cloudml-hypertune $USER_FLAG -q\n",
|
||||
" ! pip3 install --upgrade kfp $USER_FLAG -q\n",
|
||||
" ! pip3 install future $USER_FLAG -q"
|
||||
" ! pip3 install -U {USER_FLAG} -q tensorflow==2.5 \\\n",
|
||||
" tensorflow-data-validation==1.2 \\\n",
|
||||
" tensorflow-transform==1.2 \\\n",
|
||||
" tensorflow-io==0.18 \n",
|
||||
" \n",
|
||||
" ! pip3 install --upgrade {USER_FLAG} -q google-cloud-aiplatform[tensorboard] \\\n",
|
||||
" google-cloud-pipeline-components \\\n",
|
||||
" google-cloud-bigquery \\\n",
|
||||
" google-cloud-logging \\\n",
|
||||
" apache-beam[gcp] \\\n",
|
||||
" pyarrow \\\n",
|
||||
" cloudml-hypertune\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -355,7 +351,7 @@
|
||||
"source": [
|
||||
"### Authenticate your Google Cloud account\n",
|
||||
"\n",
|
||||
"**If you are using Vertex AI Workbench Notebooks**, your environment is already authenticated. Skip this step.\n",
|
||||
"**If you are using Vertex AI Workbench Notebooks**, your environment is already authenticated. \n",
|
||||
"\n",
|
||||
"**If you are using Colab**, run the cell below and follow the instructions when prompted to authenticate your account via oAuth.\n",
|
||||
"\n",
|
||||
@@ -417,7 +413,7 @@
|
||||
"\n",
|
||||
"**The following steps are required, regardless of your notebook environment.**\n",
|
||||
"\n",
|
||||
"When you submit a custom training job using the Vertex SDK, you upload a Python package\n",
|
||||
"When you submit a custom training job using the Vertex AI SDK, you upload a Python package\n",
|
||||
"containing your training code to a Cloud Storage bucket. Vertex AI runs\n",
|
||||
"the code from this package. In this tutorial, Vertex AI also saves the\n",
|
||||
"trained model that results from your job in the same bucket. You can then\n",
|
||||
|
||||
@@ -35,44 +35,76 @@ The second stage in MLOps is experimenting in developing one or more baseline mo
|
||||
|
||||
### Get Started
|
||||
|
||||
|
||||
[Get started with Vertex AI Training for Pytorch](get_started_vertex_training_pytorch.ipynb)
|
||||
[Get started with Vertex AI Training for R](https://github.com/GoogleCloudPlatform/vertex-ai-samples/blob/main/notebooks/community/ml_ops/stage2/get_started_vertex_training_r.ipynb)
|
||||
|
||||
```
|
||||
Learn how to use `Vertex AI Training` for training a R custom model.
|
||||
|
||||
The steps performed include:
|
||||
- Single node training using a Python package.
|
||||
|
||||
- Locally train an R model in a notebook using %%R magic commands
|
||||
- Create a deployment image with trained R model and serving functions.
|
||||
- Test the deployment image locally.
|
||||
- Create a `Vertex AI Model` resource for the deployment image with embedded R model.
|
||||
- Deploy the deployment image with embedded R model to a `Vertex AI Endpoint` resource.
|
||||
- Test the deployment image with embedded R model.
|
||||
- Create a R-to-Python training package.
|
||||
- Create a training image for training the model.
|
||||
- Train a R model using `Vertex AI Trainingh` service with the R-to-Python training package.
|
||||
|
||||
```
|
||||
|
||||
|
||||
[Get started with Logging](https://github.com/GoogleCloudPlatform/vertex-ai-samples/blob/main/notebooks/community/ml_ops/stage2/get_started_with_logging.ipynb)
|
||||
|
||||
```
|
||||
Learn how to use Python and Cloud logging when training with `Vertex AI`.
|
||||
|
||||
The steps performed include:
|
||||
|
||||
- Use Python logging to log training configuration/results locally.
|
||||
- Use Google Cloud Logging to log training configuration/results in cloud storage.
|
||||
|
||||
```
|
||||
|
||||
|
||||
[Get started with Vertex AI Hyperparameter Tuning for XGBoost](https://github.com/GoogleCloudPlatform/vertex-ai-samples/blob/main/notebooks/community/ml_ops/stage2/get_started_vertex_hpt_xgboost.ipynb)
|
||||
|
||||
```
|
||||
Learn how to use `Vertex AI Hyperparameter Tuning` for training a XGBoost custom model.
|
||||
|
||||
The steps performed include:
|
||||
|
||||
- Training using a Python package.
|
||||
- Report accuracy when hyperparameter tuning.
|
||||
- Save the model artifacts to Cloud Storage using GCSFuse.
|
||||
- Create a `Vertex AI Model` resource.
|
||||
```
|
||||
|
||||
[Get started with prebuilt TFHub models](get_started_with_tfhub_models.ipynb)
|
||||
|
||||
```
|
||||
|
||||
|
||||
[Get started with Vertex AI Training for XGBoost](https://github.com/GoogleCloudPlatform/vertex-ai-samples/blob/main/notebooks/community/ml_ops/stage2/get_started_vertex_training_xgboost.ipynb)
|
||||
|
||||
```
|
||||
Learn how to use `Vertex AI Training` for training a XGBoost custom model.
|
||||
|
||||
The steps performed include:
|
||||
- Download a TensorFlow Hub prebuilt model.
|
||||
- Add the task component as a classifier for the CIFAR-10 dataset.
|
||||
- Fine tune locally the model with transfer learning training.
|
||||
- Construct a custom training script:
|
||||
- Get training data from TensorFlow Datasets
|
||||
- Get model architecture from TensorFlow Hub
|
||||
- Train then model
|
||||
- Save model artifacts and upload as Vertex AI Model resource.
|
||||
```
|
||||
|
||||
[Get started with Vertex AI TensorBoard](get_started_vertex_tensorboard.ipynb)
|
||||
- Training using a Python package.
|
||||
- Report accuracy when hyperparameter tuning.
|
||||
- Save the model artifacts to Cloud Storage using GCSFuse.
|
||||
- Create a `Vertex AI Model` resource.
|
||||
|
||||
```
|
||||
|
||||
|
||||
[Get started with TabNet builtin algorithm for training tabular models](https://github.com/GoogleCloudPlatform/vertex-ai-samples/blob/main/notebooks/community/ml_ops/stage2/get_started_with_tabnet.ipynb)
|
||||
|
||||
```
|
||||
Learn how to run `Vertex AI TabNet` built algorithm for training custom tabular models.
|
||||
|
||||
The steps performed include:
|
||||
- Create a TensorBoard callback when training a model.
|
||||
- Using Tensorboard with locally trained model.
|
||||
- Using Vertex AI TensorBoard with Vertex AI Training.
|
||||
```
|
||||
|
||||
[Get started with TabNet builtin algorithm for training tabular models](get_started_with_tabnet.ipynb)
|
||||
|
||||
```
|
||||
The steps performed include:
|
||||
- Get the training data.
|
||||
- Configure training parameters for the `Vertex AI TabNet` container.
|
||||
- Train the model using `Vertex AI Training` using CSV data.
|
||||
@@ -84,48 +116,136 @@ The steps performed include:
|
||||
|
||||
```
|
||||
|
||||
[Get started with Vertex AI Vizier](get_started_vertex_vizier.ipynb)
|
||||
|
||||
[Get started with prebuilt TFHub models](https://github.com/GoogleCloudPlatform/vertex-ai-samples/blob/main/notebooks/community/ml_ops/stage2/get_started_with_tfhub_models.ipynb)
|
||||
|
||||
```
|
||||
Learn how to use `Vertex AI Training` with prebuilt models from TensorFlow Hub.
|
||||
|
||||
The steps performed include:
|
||||
|
||||
- Download a TensorFlow Hub prebuilt model.
|
||||
- Add the task component as a classifier for the CIFAR-10 dataset.
|
||||
- Fine tune locally the model with transfer learning training.
|
||||
- Construct a custom training script:
|
||||
- Get training data from TensorFlow Datasets
|
||||
- Get model architecture from TensorFlow Hub
|
||||
- Train then model
|
||||
- Save model artifacts and upload as Vertex AI Model resource.
|
||||
|
||||
```
|
||||
|
||||
|
||||
[Get started with BigQuery ML Training](https://github.com/GoogleCloudPlatform/vertex-ai-samples/blob/main/notebooks/community/ml_ops/stage2/get_started_bqml_training.ipynb)
|
||||
|
||||
```
|
||||
Learn how to use `BigQueryML` for training with `Vertex AI`.
|
||||
|
||||
The steps performed include:
|
||||
|
||||
- Create a local BigQuery table in your project
|
||||
- Train a BigQuery ML model
|
||||
- Evaluate the BigQuery ML model
|
||||
- Export the BigQuery ML model as a cloud model
|
||||
- Upload the exported model as a `Vertex AI Model` resource
|
||||
- Hyperparameter tune a BigQuery ML model with `Vertex AI Vizier`
|
||||
- Automatically register a BigQuery ML model to `Vertex AI Model Registry`
|
||||
|
||||
```
|
||||
|
||||
|
||||
[Get started with Vertex AI Vizier](https://github.com/GoogleCloudPlatform/vertex-ai-samples/blob/main/notebooks/community/ml_ops/stage2/get_started_vertex_vizier.ipynb)
|
||||
|
||||
```
|
||||
Learn how to use `Vertex AI Vizier` for when training with `Vertex AI`.
|
||||
|
||||
The steps performed include:
|
||||
|
||||
- Hyperparameter tuning with Random algorithm.
|
||||
- Hyperparameter tuning with Vizier (Bayesian) algorithm.
|
||||
```
|
||||
|
||||
[Automl image classfication training with customer managed encryption keys (CMEK)](get_started_with_cmek_training.ipynb)
|
||||
- Suggesting trials and updating results for Vizier study
|
||||
|
||||
```
|
||||
|
||||
|
||||
[Get started with distributed training using DASK](https://github.com/GoogleCloudPlatform/vertex-ai-samples/blob/main/notebooks/community/ml_ops/stage2/get_started_with_distributed_training_xgboost.ipynb)
|
||||
|
||||
```
|
||||
Learn how to use `Vertex AI Training` for distributed training of XGBoost model using the OSS package DASK.
|
||||
|
||||
The steps performed include:
|
||||
- Creating a customer managed encryption key.
|
||||
- Creating an image dataset with CMEK encryption.
|
||||
- Train an AutoML model with CMEK encryption.
|
||||
```
|
||||
|
||||
[Get started with Vertex AI distributed training](get_started_vertex_distributed_training.ipynb)
|
||||
- Construct an XGBoost training script using DASK for distributed training.
|
||||
- Construct a custom training container.
|
||||
- Configure a distributed custom training job.
|
||||
- Execute the custom training job.
|
||||
- Construct a custom serving container using Flask.
|
||||
- Upload the trained XGBoost model as a `Vertex AI Model` resource.
|
||||
- Create a `Vertex AI Endpoint` resource.
|
||||
- Deploy the `Vertex AI Model` resource to `Vertex AI Endpoint` resource.
|
||||
- Make a prediction.
|
||||
|
||||
```
|
||||
|
||||
|
||||
[Get started with Vertex AI TensorBoard](https://github.com/GoogleCloudPlatform/vertex-ai-samples/blob/main/notebooks/community/ml_ops/stage2/get_started_vertex_tensorboard.ipynb)
|
||||
|
||||
```
|
||||
Learn how to use `Vertex AI TensorBoard` when training with `Vertex AI`.
|
||||
|
||||
The steps performed include:
|
||||
- `MirroredStrategy`: Train on a single VM with multiple GPUs.
|
||||
- `MultiWorkerMirroredStrategy`: Train on multiple VMs with automatic setup of replicas.
|
||||
- `MultiWorkerMirroredStrategy`: Train on multiple VMs with fine grain control of replicas.
|
||||
- `ReductionServer`: Train on multiple VMS and sync updates across VMS with `Vertex AI Reduction Server`.
|
||||
- `TPUTraining`: Train with multiple Cloud TPUs.
|
||||
```
|
||||
|
||||
[Get started with Vertex AI Training for scikit-learn](get_started_vertex_training_sklearn.ipynb)
|
||||
- Create a TensorBoard callback when training a model.
|
||||
- Using TensorBoard with locally trained model.
|
||||
- Using Vertex AI TensorBoard with Vertex AI Training.
|
||||
|
||||
```
|
||||
|
||||
|
||||
[Get started with Vertex AI Training for R using R Kernel](https://github.com/GoogleCloudPlatform/vertex-ai-samples/blob/main/notebooks/community/ml_ops/stage2/get_started_vertex_training_r_using_r_kernel.ipynb)
|
||||
|
||||
```
|
||||
Learn how to use `Vertex AI`, using an R kernel, for training and deploying an R custom model.
|
||||
|
||||
The steps performed include:
|
||||
- Training using a Python package.
|
||||
- Report accuracy when hyperparameter tuning.
|
||||
- Save the model artifacts to Cloud Storage using GCSFuse.
|
||||
- Create a `Vertex AI Model` resource.
|
||||
```
|
||||
|
||||
[Get started with Vertex AI Experiments](get_started_vertex_experiments.ipynb)
|
||||
- Create a custom R training script
|
||||
- Create a custom R serving script
|
||||
- Create a custom R deployment (serving) container.
|
||||
- Train the model using `Vertex AI` custom training.
|
||||
- Create an `Endpoint` resouce.
|
||||
- Deploy the `Model` resource (trained R model) to the `Endpoint` resource.
|
||||
- Make an online prediction.
|
||||
|
||||
```
|
||||
|
||||
|
||||
[Get started Vision API test preprocessing and AutoML text model generation](https://github.com/GoogleCloudPlatform/vertex-ai-samples/blob/main/notebooks/community/ml_ops/stage2/get_started_with_visionapi_and_automl.ipynb)
|
||||
|
||||
```
|
||||
In this tutorial, you create an `AutoML` text entity extraction model pre-existing extracted data by generating a custom import file.
|
||||
|
||||
The steps performed include:
|
||||
|
||||
- Preprocess training files using `Vision AI` APIs to extract the text from PDF files.
|
||||
- Create a custom import file that includes annotation data based on the sample `BigQuery` dataset.
|
||||
- Create a `Vertex AI Dataset` resource.
|
||||
- Train the model.
|
||||
- View the model evaluation.
|
||||
- Deploy the `Vertex AI Model` resource to a serving `Endpoint` resource.
|
||||
- Make a prediction.
|
||||
- Undeploy the `Model`.
|
||||
|
||||
```
|
||||
|
||||
|
||||
[Get started with Vertex AI Experiments](https://github.com/GoogleCloudPlatform/vertex-ai-samples/blob/main/notebooks/community/ml_ops/stage2/get_started_vertex_experiments.ipynb)
|
||||
|
||||
```
|
||||
Learn how to use `Vertex AI Experiments` when training with `Vertex AI`.
|
||||
|
||||
The steps performed include:
|
||||
|
||||
- Local (notebook) Training
|
||||
- Create an experiment
|
||||
- Create a first run in the experiment
|
||||
@@ -142,23 +262,31 @@ The steps performed include:
|
||||
- Create a `Vertex AI Training` custom job
|
||||
- Execute the custom job
|
||||
- Visualize the experiment results
|
||||
```
|
||||
|
||||
[Get started with Vertex AI Hyperparameter Tuning for XGBoost](get_started_vertex_hpt_xgboost.ipynb)
|
||||
|
||||
```
|
||||
|
||||
|
||||
[AutoML Image Classfication Training with Customer Managed Encryption Keys (CMEK)](https://github.com/GoogleCloudPlatform/vertex-ai-samples/blob/main/notebooks/community/ml_ops/stage2/get_started_with_cmek_training.ipynb)
|
||||
|
||||
```
|
||||
Learn how to use a customer managed encryption key (CMEK) for `Vertex AI AutoML` training.
|
||||
|
||||
The steps performed include:
|
||||
- Training using a Python package.
|
||||
- Report accuracy when hyperparameter tuning.
|
||||
- Save the model artifacts to Cloud Storage using GCSFuse.
|
||||
- Create a `Vertex AI Model` resource.
|
||||
|
||||
- Creating a customer managed encryption key.
|
||||
- Creating an image dataset with CMEK encryption.
|
||||
- Train an AutoML model with CMEK encryption.
|
||||
|
||||
```
|
||||
|
||||
[Get started with Vertex AI Feature Store](get_started_vertex_feature_store.ipynb)
|
||||
|
||||
[Get started with Vertex AI Feature Store](https://github.com/GoogleCloudPlatform/vertex-ai-samples/blob/main/notebooks/community/ml_ops/stage2/get_started_vertex_feature_store.ipynb)
|
||||
|
||||
```
|
||||
Learn how to use `Vertex AI Feature Store` when training and predicting with `Vertex AI`.
|
||||
|
||||
The steps performed include:
|
||||
|
||||
- Creating a Vertex AI `Featurestore` resource.
|
||||
- Creating `EntityType` resources for the `Featurestore` resource.
|
||||
- Creating `Feature` resources for each `EntityType` resource.
|
||||
@@ -167,96 +295,50 @@ The steps performed include:
|
||||
- From a pandas DataFrame.
|
||||
- Perform online serving from a `Featurestore` resource.
|
||||
- Perform batch serving from a `Featurestore` resource.
|
||||
```
|
||||
|
||||
[Get started with Vertex AI Training for R](get_started_vertex_training_r.ipynb)
|
||||
|
||||
```
|
||||
|
||||
|
||||
[Get started with AutoML Training](https://github.com/GoogleCloudPlatform/vertex-ai-samples/blob/main/notebooks/community/ml_ops/stage2/get_started_automl_training.ipynb)
|
||||
|
||||
```
|
||||
Learn how to use `AutoML` for training with `Vertex AI`.
|
||||
|
||||
The steps performed include:
|
||||
- Locally train an R model in a notebook using %%R magic commands
|
||||
- Create a deployment image with trained R model and serving functions.
|
||||
- Test the deployment image locally.
|
||||
- Create a `Vertex AI Model` resource for the deployment image with embedded R model.
|
||||
- Deploy the deployment image with embedded R model to a `Vertex AI Endpoint` resource.
|
||||
- Test the deployment image with embedded R model.
|
||||
- Create a R-to-Python training package.
|
||||
- Create a training image for training the model.
|
||||
- Train a R model using `Vertex AI Trainingh` service with the R-to-Python training package.
|
||||
```
|
||||
|
||||
[Get started with logging](get_started_with_logging.ipynb)
|
||||
|
||||
```
|
||||
The steps performed include:
|
||||
- Use Python logging to log training configuration/results locally.
|
||||
- Use Google Cloud Logging to log training configuration/results in cloud storage.
|
||||
```
|
||||
|
||||
[Get started with Vertex AI Training for R using R Kernel](get_started_vertex_training_r_using_r_kernel.ipynb)
|
||||
|
||||
```
|
||||
The steps performed include:
|
||||
- Create a custom R training script
|
||||
- Create a custom R serving script
|
||||
- Create a custom R deployment (serving) container.
|
||||
- Train the model using `Vertex AI` custom training.
|
||||
- Create an `Endpoint` resouce.
|
||||
- Deploy the `Model` resource (trained R model) to the `Endpoint` resource.
|
||||
- Make an online prediction.
|
||||
|
||||
```
|
||||
|
||||
[Get started with BigQuery ML training](get_started_bqml_training.ipynb)
|
||||
|
||||
```
|
||||
The steps performed include:
|
||||
- Create a local BigQuery table in your project
|
||||
- Train a BQML model
|
||||
- Evaluate the BQML model
|
||||
- Export the BQML model as a cloud model
|
||||
- Upload the exported model as a `Vertex AI Model` resource
|
||||
- Hyperparameter tune a BQML model with `Vertex AI Vizier`
|
||||
- Automatically register a BQML model to `Vertex AI Model Registry`
|
||||
|
||||
```
|
||||
|
||||
[Get started with AutoML training](get_started_automl_training.ipynb)
|
||||
|
||||
```
|
||||
The steps performed include:
|
||||
- Train an image model
|
||||
- Export the image model as an edge model
|
||||
- Train a tabular model
|
||||
- Export the tabular model as a cloud model
|
||||
- Train a text model
|
||||
- Train a video model
|
||||
```
|
||||
|
||||
[Get started with Vertex AI Training for XGBoost](get_started_vertex_training_xgboost.ipynb)
|
||||
|
||||
```
|
||||
|
||||
|
||||
[Get started with autologging using Vertex AI Experiments for XGBoost models](https://github.com/GoogleCloudPlatform/vertex-ai-samples/blob/main/notebooks/community/ml_ops/stage2/get_started_with_vertex_experiments_autologging_xgboost.ipynb)
|
||||
|
||||
```
|
||||
Learn how to create an experiment for training an XGBoost model, and automatically log parameters and metrics using the enclosed do-it-yourself (DIY) code.
|
||||
|
||||
The steps performed include:
|
||||
- Training using a Python package.
|
||||
- Report accuracy when hyperparameter tuning.
|
||||
- Save the model artifacts to Cloud Storage using GCSFuse.
|
||||
- Create a `Vertex AI Model` resource.
|
||||
|
||||
- Construct the DIY autologging code.
|
||||
- Construct training package with call to autologging.
|
||||
- Train a model.
|
||||
- View the experiment
|
||||
- Delete the experiment.
|
||||
|
||||
```
|
||||
|
||||
[Get started with Vertex AI Training](get_started_vertex_training.ipynb)
|
||||
|
||||
[Get started with Vertex AI Training for LightGBM](https://github.com/GoogleCloudPlatform/vertex-ai-samples/blob/main/notebooks/community/ml_ops/stage2/get_started_vertex_training_lightgbm.ipynb)
|
||||
|
||||
```
|
||||
Learn how to use `Vertex AI Training` for training a LightGBM custom model.
|
||||
|
||||
The steps performed include:
|
||||
- Training using a single Python script.
|
||||
- Training using a Python package.
|
||||
- Training using a custom training image.
|
||||
- Laying out a training package.
|
||||
```
|
||||
|
||||
[Get started with Vertex AI Training for LightGBM](get_started_vertex_training_lightgbm.ipynb)
|
||||
|
||||
```
|
||||
The steps performed include:
|
||||
- Training using a Python package.
|
||||
- Save the model artifacts to Cloud Storage using GCSFuse.
|
||||
- Construct a FastAPI prediction server.
|
||||
@@ -266,26 +348,107 @@ The steps performed include:
|
||||
|
||||
```
|
||||
|
||||
[Get started Vision API test preprocessing and AutoML text model generation](get_started_with_visionapi_and_automl.ipynb)
|
||||
|
||||
[Vertex AI Hyperparameter Tuning with R kernel](None)
|
||||
|
||||
```
|
||||
Learn how to use `Vertex AI`, using an R kernel, for tuning hyperparameters of a R custom model.
|
||||
|
||||
The steps performed include:
|
||||
- Preprocess training files using `Vision AI` APIs to extract the text from PDF files.
|
||||
- Create a custom import file that includes annotation data based on the sample `BigQuery` dataset.
|
||||
- Create a `Vertex AI Dataset` resource.
|
||||
- Train the model.
|
||||
- View the model evaluation.
|
||||
- Deploy the `Vertex AI Model` resource to a serving `Endpoint` resource.
|
||||
- Make a prediction.
|
||||
- Undeploy the `Model`.
|
||||
|
||||
- Create a custom R training script
|
||||
- Create a custom R deployment container.
|
||||
- Perform hyperparameter tuning using `Vertex AI`.
|
||||
|
||||
```
|
||||
|
||||
[Get started with Vertex AI Training for Scikit-Learn](https://github.com/GoogleCloudPlatform/vertex-ai-samples/blob/main/notebooks/community/ml_ops/stage2/get_started_vertex_training_sklearn.ipynb)
|
||||
|
||||
```
|
||||
Learn how to use `Vertex AI Training` for training a Scikit-Learn custom model.
|
||||
|
||||
The steps performed include:
|
||||
|
||||
- Training using a Python package.
|
||||
- Report accuracy when hyperparameter tuning.
|
||||
- Save the model artifacts to Cloud Storage using GCSFuse.
|
||||
- Create a `Vertex AI Model` resource.
|
||||
|
||||
```
|
||||
|
||||
|
||||
[Get started with Vertex AI Training](https://github.com/GoogleCloudPlatform/vertex-ai-samples/blob/main/notebooks/community/ml_ops/stage2/get_started_vertex_training.ipynb)
|
||||
|
||||
```
|
||||
Learn how to use `Vertex AI Training` for custom models when training with `Vertex AI`.
|
||||
|
||||
The steps performed include:
|
||||
|
||||
- Training using a single Python script.
|
||||
- Training using a Python package.
|
||||
- Training using a custom training image.
|
||||
- Laying out a training package.
|
||||
|
||||
```
|
||||
|
||||
|
||||
[Get started with Vertex AI Training for PyTorch](https://github.com/GoogleCloudPlatform/vertex-ai-samples/blob/main/notebooks/community/ml_ops/stage2/get_started_vertex_training_pytorch.ipynb)
|
||||
|
||||
```
|
||||
Learn how to use `Vertex AI Training` for training a PyTorch custom model.
|
||||
|
||||
The steps performed include:
|
||||
|
||||
- Single node training using a Python package.
|
||||
- Report accuracy when hyperparameter tuning.
|
||||
- Save the model artifacts to Cloud Storage using GCSFuse.
|
||||
- Create a `Vertex AI Model` resource.
|
||||
|
||||
```
|
||||
|
||||
|
||||
[Get started with autologging using Vertex AI Experiments for TensorFlow models](https://github.com/GoogleCloudPlatform/vertex-ai-samples/blob/main/notebooks/community/ml_ops/stage2/get_started_with_vertex_experiments_autologging_tf.ipynb)
|
||||
|
||||
```
|
||||
Learn how to create an experiment for training a TensorFlow model, and automatically log parameters and metrics using the enclosed do-it-yourself (DIY) code.
|
||||
|
||||
The steps performed include:
|
||||
|
||||
- Construct the DIY autologging code.
|
||||
- Construct training package for TensorFlow Sequential model with call to autologging.
|
||||
- Train a model.
|
||||
- View the experiment
|
||||
- Construct training package for TensorFlow Functional model with call to autologging.
|
||||
- Compare the experiment runs.
|
||||
- Delete the experiment.
|
||||
|
||||
```
|
||||
|
||||
|
||||
[Get started with Vertex AI Distributed Training](https://github.com/GoogleCloudPlatform/vertex-ai-samples/blob/main/notebooks/community/ml_ops/stage2/get_started_vertex_distributed_training.ipynb)
|
||||
|
||||
```
|
||||
Learn how to use `Vertex AI Distributed Training` for when training with `Vertex AI`.
|
||||
|
||||
The steps performed include:
|
||||
|
||||
- `MirroredStrategy`: Train on a single VM with multiple GPUs.
|
||||
- `MultiWorkerMirroredStrategy`: Train on multiple VMs with automatic setup of replicas.
|
||||
- `MultiWorkerMirroredStrategy`: Train on multiple VMs with fine grain control of replicas.
|
||||
- `ReductionServer`: Train on multiple VMS and sync updates across VMS with `Vertex AI Reduction Server`.
|
||||
- `TPUTraining`: Train with multiple Cloud TPUs.
|
||||
|
||||
```
|
||||
|
||||
### E2E Stage Example
|
||||
|
||||
[Stage 2: Experimentation](mlops_experimentation.ipynb)
|
||||
[Experimentation](https://github.com/GoogleCloudPlatform/vertex-ai-samples/blob/main/notebooks/community/ml_ops/stage2/mlops_experimentation.ipynb)
|
||||
|
||||
```
|
||||
In this tutorial, you create a MLOps stage 2: experimentation process.
|
||||
|
||||
The steps performed include:
|
||||
|
||||
- Review the `Dataset` resource created during stage 1.
|
||||
- Train an AutoML tabular binary classifier model in the background.
|
||||
- Build the experimental model architecture.
|
||||
@@ -302,4 +465,5 @@ The steps performed include:
|
||||
- Set the evaluation results of the AutoML model as the baseline.
|
||||
- If the evaluation of the custom model is below baseline, continue to experiment with the custom model.
|
||||
- If the evaluation of the custom model is above baseline, save the model as the first best model.
|
||||
|
||||
```
|
||||
|
||||
@@ -78,6 +78,7 @@
|
||||
"This tutorial uses the following Google Cloud ML services:\n",
|
||||
"\n",
|
||||
"- `AutoML Training`\n",
|
||||
"- `Vertex AI Datasets`\n",
|
||||
"\n",
|
||||
"The steps performed include:\n",
|
||||
"\n",
|
||||
@@ -498,7 +499,7 @@
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"execution_count": 1,
|
||||
"metadata": {
|
||||
"id": "import_aip:mbsdk"
|
||||
},
|
||||
@@ -568,6 +569,142 @@
|
||||
"Learn more about [AutoML Model Types](https://cloud.google.com/vertex-ai/docs/start/automl-model-types)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "data_preparation:image,u_dataset"
|
||||
},
|
||||
"source": [
|
||||
"### Data preparation\n",
|
||||
"\n",
|
||||
"The Vertex `Dataset` resource for images has some requirements for your data:\n",
|
||||
"\n",
|
||||
"- Images must be stored in a Cloud Storage bucket.\n",
|
||||
"- Each image file must be in an image format (PNG, JPEG, BMP, ...).\n",
|
||||
"- There must be an index file stored in your Cloud Storage bucket that contains the path and label for each image.\n",
|
||||
"- The index file must be either CSV or JSONL.\n",
|
||||
"\n",
|
||||
"Learn more about [Preparing image data](https://cloud.google.com/vertex-ai/docs/datasets/prepare-image)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "data_import_format:icn,u_dataset,csv"
|
||||
},
|
||||
"source": [
|
||||
"#### CSV\n",
|
||||
"\n",
|
||||
"For image classification, the CSV index file has the requirements:\n",
|
||||
"\n",
|
||||
"- No heading.\n",
|
||||
"- First column is the Cloud Storage path to the image.\n",
|
||||
"- Second column is the label.\n",
|
||||
"- Any remaining columns are additional labels for multi-label image classification.\n",
|
||||
"\n",
|
||||
"For image object detection, the CSV index file has the requirements:\n",
|
||||
"\n",
|
||||
"- No heading.\n",
|
||||
"- First column is the Cloud Storage path to the image.\n",
|
||||
"- Second column is the label.\n",
|
||||
"- Third/Fourth columns are the upper left corner of bounding box. Coordinates are normalized, between 0 and 1.\n",
|
||||
"- Fifth/Sixth/Seventh columns are not used and should be 0.\n",
|
||||
"- Eighth/Ninth columns are the lower right corner of the bounding box.\n",
|
||||
"\n",
|
||||
"##### ML_USE\n",
|
||||
"\n",
|
||||
"Each row may additionally specify which split to assign the data item to when the dataset is split for training; otherwise, the dataset will be randomly split: 80/10/10.\n",
|
||||
"\n",
|
||||
"The `ml_use` assignment is specified by prepending a column for specifying the assignment -- as the first column. The value may be one of: training, test, or validation."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "data_import_format:isg,u_dataset,jsonl"
|
||||
},
|
||||
"source": [
|
||||
"#### JSONL\n",
|
||||
"\n",
|
||||
"For image classification, the JSONL index file has the requirements:\n",
|
||||
"\n",
|
||||
"- Each data item is a separate JSON object, on a separate line.\n",
|
||||
"- The key/value pair `image_gcs_uri` is the Cloud Storage path to the image.\n",
|
||||
"- The key/value pair `display_name` is the label for the image.\n",
|
||||
"\n",
|
||||
" { 'image_gcs_uri': image, \n",
|
||||
" 'classification_annotations': \n",
|
||||
" { 'display_name': label\n",
|
||||
" }\n",
|
||||
" }\n",
|
||||
" \n",
|
||||
"For multi-label, the labels are specified as a list of `display_name` key/value pairs:\n",
|
||||
"\n",
|
||||
" { 'image_gcs_uri': image, \n",
|
||||
" 'classification_annotations': [\n",
|
||||
" { 'display_name': label1\n",
|
||||
" },\n",
|
||||
" { 'display_name': labelN\n",
|
||||
" },\n",
|
||||
" ]\n",
|
||||
" }\n",
|
||||
" \n",
|
||||
"For object detection, the JSONL index file has the requirements:\n",
|
||||
"\n",
|
||||
"- Each data item is a separate JSON object, on a separate line.\n",
|
||||
"- The key/value pair `image_gcs_uri` is the Cloud Storage path to the image.\n",
|
||||
"- The key/value pair `bounding_box_annotations` is a list of:\n",
|
||||
" - `display_name`: The label of the object\n",
|
||||
" - `x_min`, `y_min`, `x_max`, `y_max`: The coordinates for the bounding box\n",
|
||||
"\n",
|
||||
"{\n",
|
||||
" \"image_gcs_uri\": image,\n",
|
||||
" \"bounding_box_annotations\": [\n",
|
||||
" {\n",
|
||||
" \"display name\": label,\n",
|
||||
" \"x_min\": \"X_MIN\",\n",
|
||||
" \"y_min\": \"Y_MIN\",\n",
|
||||
" \"x_max\": \"X_MAX\",\n",
|
||||
" \"y_max\": \"Y_MAX\"\n",
|
||||
" }\n",
|
||||
" },\n",
|
||||
" {\n",
|
||||
" \"displayName\": \"OBJECT2_LABEL\",\n",
|
||||
" \"x_min\": \"X_MIN\",\n",
|
||||
" \"y_min\": \"Y_MIN\",\n",
|
||||
" \"x_max\": \"X_MAX\",\n",
|
||||
" \"y_max\": \"Y_MAX\"\n",
|
||||
" }\n",
|
||||
" ]\n",
|
||||
"}\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"For image segmentation, the JSONL index file has the requirements:\n",
|
||||
"\n",
|
||||
"- Each data item is a separate JSON object, on a separate line.\n",
|
||||
"- The key/value pair `image_gcs_uri` is the Cloud Storage path to the image.\n",
|
||||
"- The key/value pair `category_mask_uri` is the Cloud Storage path to the mask image in PNG format.\n",
|
||||
"- The key/value pair `'annotation_spec_colors'` is a list mapping mask colors to a label.\n",
|
||||
" - The key/value pair pair `display_name` is the label for the pixel color mask.\n",
|
||||
" - The key/value pair pair `color` are the RGB normalized pixel values (between 0 and 1) of the mask for the corresponding label.\n",
|
||||
"\n",
|
||||
" { 'image_gcs_uri': image, \n",
|
||||
" 'segmentation_annotations': { 'category_mask_uri': mask_image, 'annotation_spec_colors' : [ \n",
|
||||
" { 'display_name': label, 'color': {\"red\": value, \"blue\", value, \"green\": value} }, ...\n",
|
||||
" ] \n",
|
||||
" }\n",
|
||||
" \n",
|
||||
"##### ML_USE\n",
|
||||
"\n",
|
||||
"Each JSONL object may additionally specify which split to assign the data item to when the dataset is split for training; otherwise, the dataset will be randomly split: 80/10/10.\n",
|
||||
"\n",
|
||||
"\"data_item_resource_labels\": {\n",
|
||||
" \"aiplatform.googleapis.com/ml_use\": \"training|test|validation\"\n",
|
||||
" }\n",
|
||||
"\n",
|
||||
"*Note*: The dictionary key fields may alternatively be in camelCase. For example, 'image_gcs_uri' can also be 'imageGcsUri'."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
@@ -1068,6 +1205,42 @@
|
||||
"Learn more about [AutoML Model Types](https://cloud.google.com/vertex-ai/docs/start/automl-model-types)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "data_preparation:tabular,u_dataset"
|
||||
},
|
||||
"source": [
|
||||
"### Data preparation\n",
|
||||
"\n",
|
||||
"The Vertex AI `Dataset` resource for tabular has a couple of requirements for your tabular data.\n",
|
||||
"\n",
|
||||
"- Must be in a CSV file or a BigQuery table.\n",
|
||||
"\n",
|
||||
"Learn more about [Preparing tabular data](https://cloud.google.com/vertex-ai/docs/datasets/prepare-tabular)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "data_import_format:lbn,u_dataset,csv"
|
||||
},
|
||||
"source": [
|
||||
"#### CSV\n",
|
||||
"\n",
|
||||
"For tabular models, the CSV file has a few requirements:\n",
|
||||
"\n",
|
||||
"- The first row must be the heading -- note how this is different from Image, Text and Video where the requirement is no heading.\n",
|
||||
"- All but one column are features.\n",
|
||||
"- One column is the label, which you will specify when you subsequently create the training pipeline.\n",
|
||||
"\n",
|
||||
"##### ML_USE\n",
|
||||
"\n",
|
||||
"Each row may additionally specify which split to assign the data item to when the dataset is split for training; otherwise, the dataset will be randomly split: 80/10/10.\n",
|
||||
"\n",
|
||||
"The `ml_use` assignment is specified by prepending a column for specifying the assignment -- as the first column. The value may be one of: training, test, or validation."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
@@ -1427,6 +1600,155 @@
|
||||
"Learn more about [AutoML Model Types](https://cloud.google.com/vertex-ai/docs/start/automl-model-types)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "data_preparation:text,u_dataset"
|
||||
},
|
||||
"source": [
|
||||
"### Data preparation\n",
|
||||
"\n",
|
||||
"The Vertex AI `Dataset` resource for text has a couple of requirements for your text data.\n",
|
||||
"\n",
|
||||
"- Text examples must be stored in a CSV or JSONL file.\n",
|
||||
"\n",
|
||||
"Learn more about [Preparing text data](https://cloud.google.com/vertex-ai/docs/datasets/prepare-text)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "data_import_format:tcn,u_dataset,csv"
|
||||
},
|
||||
"source": [
|
||||
"#### CSV\n",
|
||||
"\n",
|
||||
"For text classification, the CSV file has a few requirements:\n",
|
||||
"\n",
|
||||
"- No heading.\n",
|
||||
"- First column is the text example or Cloud Storage path to text file (.txt suffix).\n",
|
||||
"- Second column the label.\n",
|
||||
"- Any remaining columns are additional labels for multi-label text classification.\n",
|
||||
"\n",
|
||||
"For text sentiment analysis, the CSV file has a few requirements:\n",
|
||||
"\n",
|
||||
"- No heading.\n",
|
||||
"- First column is the text example or Cloud Storage path to text file (.txt suffix).\n",
|
||||
"- Second column is the sentiment value.\n",
|
||||
"- Third column is the maximum possible sentiment value.\n",
|
||||
"\n",
|
||||
"##### ML_USE\n",
|
||||
"\n",
|
||||
"Each row may additionally specify which split to assign the data item to when the dataset is split for training; otherwise, the dataset will be randomly split: 80/10/10.\n",
|
||||
"\n",
|
||||
"The `ml_use` assignment is specified by prepending a column for specifying the assignment -- as the first column. The value may be one of: training, test, or validation."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "766c838de8a0"
|
||||
},
|
||||
"source": [
|
||||
"#### JSONL \n",
|
||||
"\n",
|
||||
"For text classification, the JSONL file has a few requirements:\n",
|
||||
"\n",
|
||||
"- Each data item is a separate JSON object, on a separate line.\n",
|
||||
"- The key/value pair `text_gcs_uri` is the Cloud Storage path to the text file.\n",
|
||||
"- The key/value pair `text_content` is the alternate way of specifying the text as inlined.\n",
|
||||
"- The key/value pair `display_name` is the label for the text.\n",
|
||||
"\n",
|
||||
"{\n",
|
||||
" \"classification_annotation\": {\n",
|
||||
" \"display_name\": label\n",
|
||||
" },\n",
|
||||
" \"text_content\": text\n",
|
||||
"}\n",
|
||||
"{\n",
|
||||
" \"classification_annotation\": {\n",
|
||||
" \"display_name\": label\n",
|
||||
" },\n",
|
||||
" \"text_gcs_uri\": \"gcs_uri_to_file\"\n",
|
||||
"}\n",
|
||||
"\n",
|
||||
" \n",
|
||||
"For multi-label, the labels are specified as a list of `display_name` key/value pairs:\n",
|
||||
"\n",
|
||||
" 'classification_annotations': [\n",
|
||||
" { 'display_name': label1\n",
|
||||
" },\n",
|
||||
" { 'display_name': labelN\n",
|
||||
" },\n",
|
||||
" ]\n",
|
||||
"\n",
|
||||
"For text sentiment analysis, the JSONL file has a few requirements:\n",
|
||||
"\n",
|
||||
"- Each data item is a separate JSON object, on a separate line.\n",
|
||||
"- The key/value pair `text_gcs_uri` is the Cloud Storage path to the text file.\n",
|
||||
"- The key/value pair `text_content` is the alternate way of specifying the text as inlined.\n",
|
||||
"- The key/value pair `sentiment` is the sentiment value as an integer value greater than 0.\n",
|
||||
"- The key/value pair `sentiment_max`is the maximum possible value for the sentiment.\n",
|
||||
"\n",
|
||||
"{\n",
|
||||
" \"sentiment_annotation\": {\n",
|
||||
" \"sentiment\": number,\n",
|
||||
" \"sentiment_max\": number\n",
|
||||
" },\n",
|
||||
" \"text_content\": text,\n",
|
||||
"}\n",
|
||||
"{\n",
|
||||
" \"sentiment_annotation\": {\n",
|
||||
" \"sentiment\": number,\n",
|
||||
" \"sentiment_max\": number\n",
|
||||
" },\n",
|
||||
" \"text_gcs_uri\": \"gcs_uri_to_file\"\n",
|
||||
"}\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"For text entity extraction, the JSONL file has a few requirements:\n",
|
||||
"\n",
|
||||
"- Each data item is a separate JSON object, on a separate line.\n",
|
||||
"- The key/value pair `text_gcs_uri` is the Cloud Storage path to the text file.\n",
|
||||
"- The key/value pair `text_content` is the alternate way of specifying the text as inlined.\n",
|
||||
"- The key/value pair `start_offset` is the character offset of the start of the text.\n",
|
||||
"- The key/value pair `end_offset` is the character offset of the end of the text.\n",
|
||||
"- The key/value pair `display_name` is the label for the text.\n",
|
||||
"\n",
|
||||
"{\n",
|
||||
" \"text_segment_annotations\": [\n",
|
||||
" {\n",
|
||||
" \"start_offset\":number,\n",
|
||||
" \"end_offset\":number,\n",
|
||||
" \"display_name\": label\n",
|
||||
" },\n",
|
||||
" ...\n",
|
||||
" ],\n",
|
||||
" \"textContent\": \"inline_text\"\n",
|
||||
"}\n",
|
||||
"{\n",
|
||||
" \"textSegmentAnnotations\": [\n",
|
||||
" {\n",
|
||||
" \"start_offset\": number,\n",
|
||||
" \"end_offset\": number,\n",
|
||||
" \"displayName\": label\n",
|
||||
" },\n",
|
||||
" ...\n",
|
||||
" ],\n",
|
||||
" \"text_gcs_uri\": \"gcs_uri_to_file\"\n",
|
||||
"}\n",
|
||||
"\n",
|
||||
"##### ML_USE\n",
|
||||
"\n",
|
||||
"Each JSONL object may additionally specify which split to assign the data item to when the dataset is split for training; otherwise, the dataset will be randomly split: 80/10/10.\n",
|
||||
"\n",
|
||||
"\"data_item_resource_labels\": {\n",
|
||||
" \"aiplatform.googleapis.com/ml_use\": \"training|test|validation\"\n",
|
||||
" }\n",
|
||||
"\n",
|
||||
"*Note*: The dictionary key fields may alternatively be in camelCase. For example, 'text_gcs_uri' can also be 'textGcsUri'."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
@@ -1749,6 +2071,144 @@
|
||||
"Learn more about [AutoML Model Types](https://cloud.google.com/vertex-ai/docs/start/automl-model-types)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "data_preparation:text,u_dataset"
|
||||
},
|
||||
"source": [
|
||||
"### Data preparation\n",
|
||||
"\n",
|
||||
"The Vertex AI `Dataset` resource for text has a couple of requirements for your text data.\n",
|
||||
"\n",
|
||||
"- Text examples must be stored in a CSV or JSONL file.\n",
|
||||
"\n",
|
||||
"Learn more about [Preparing video data](https://cloud.google.com/vertex-ai/docs/datasets/prepare-video)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "427212b48840"
|
||||
},
|
||||
"source": [
|
||||
"#### CSV\n",
|
||||
"\n",
|
||||
"For video classification, the CSV file has a few requirements:\n",
|
||||
"\n",
|
||||
"- No heading.\n",
|
||||
"- First column is the Cloud Storage path to video file.\n",
|
||||
"- Second column the label.\n",
|
||||
"- Third column is the start time (seconds) in the video to classify.\n",
|
||||
"- Fourth column is the end time (seconds) in the video to classify.\n",
|
||||
"\n",
|
||||
"For multi-label classification, each label is a separate row entry.\n",
|
||||
"\n",
|
||||
"For video object tracking, the CSV file has a few requirements:\n",
|
||||
"\n",
|
||||
"- No heading.\n",
|
||||
"- First column is the Cloud Storage path to video file.\n",
|
||||
"- Second column the label.\n",
|
||||
"- Third column is unused (blank).\n",
|
||||
"- Fourth column is the start time (seconds) in the video to start tracking the object.\n",
|
||||
"- The fifth through eighth columns are the vertices of the object to track.\n",
|
||||
" - x_min\n",
|
||||
" - y_min\n",
|
||||
" - x_max\n",
|
||||
" - y_max\n",
|
||||
" \n",
|
||||
"For action recognition, the CSV file has a few requirements:\n",
|
||||
"\n",
|
||||
"- No heading.\n",
|
||||
"- Each row can be one of the following four formats:\n",
|
||||
"\n",
|
||||
"VIDEO_URI, TIME_SEGMENT_START, TIME_SEGMENT_END, LABEL, ANNOTATION_FRAME_TIMESTAMP\n",
|
||||
"\n",
|
||||
"VIDEO_URI, , , LABEL, ANNOTATION_FRAME_TIMESTAMP\n",
|
||||
"\n",
|
||||
"VIDEO_URI, TIME_SEGMENT_START, TIME_SEGMENT_END, LABEL, ANNOTATION_SEGMENT_START, ANNOTATION_SEGMENT_END\n",
|
||||
"\n",
|
||||
"VIDEO_URI, , , LABEL, ANNOTATION_SEGMENT_START, ANNOTATION_SEGMENT_END\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"##### ML_USE\n",
|
||||
"\n",
|
||||
"Each row may additionally specify which split to assign the data item to when the dataset is split for training; otherwise, the dataset will be randomly split: 80/10/10.\n",
|
||||
"\n",
|
||||
"The `ml_use` assignment is specified by prepending a column for specifying the assignment -- as the first column. The value may be one of: training, or test."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "461301339727"
|
||||
},
|
||||
"source": [
|
||||
"#### JSONL\n",
|
||||
"\n",
|
||||
"For video classification, the CSV file has a few requirements:\n",
|
||||
"\n",
|
||||
"- Each data item is a separate JSON object, on a separate line.\n",
|
||||
"- The key/value pair `video_gcs_uri` is the Cloud Storage path to the text file.\n",
|
||||
"- The key/value pair `display_name` is the label for the text.\n",
|
||||
"- The key/value pair `start_time` is the start time (seconds) for classifying.\n",
|
||||
"- The key/value pair `end_time` is the end time (seconds) for classifying.\n",
|
||||
"\n",
|
||||
"\n",
|
||||
" {\n",
|
||||
" \"video_gcs_uri\": video,\n",
|
||||
" \"time_segment_annotations\": [{\n",
|
||||
" \"display_name\": label,\n",
|
||||
" \"start_time\": \"start_time_of_segment\",\n",
|
||||
" \"end_time\": \"end_time_of_segment\"\n",
|
||||
" }]\n",
|
||||
" }\n",
|
||||
"\n",
|
||||
"For video object tracking, the CSV file has a few requirements:\n",
|
||||
"\n",
|
||||
"- Each data item is a separate JSON object, on a separate line.\n",
|
||||
"- The key/value pair `video_gcs_uri` is the Cloud Storage path to the text file.\n",
|
||||
"\n",
|
||||
" {\n",
|
||||
" \"video_gcs_uri\": video,\n",
|
||||
" \"temporal_bounding_box_annotations\": [{\n",
|
||||
" \"display_name\": label,\n",
|
||||
" \"x_min\": \"leftmost_coordinate_of_the_bounding box\",\n",
|
||||
" \"x_max\": \"rightmost_coordinate_of_the_bounding box\",\n",
|
||||
" \"y_min\": \"topmost_coordinate_of_the_bounding box\",\n",
|
||||
" \"y_max\": \"bottommost_coordinate_of_the_bounding box\",\n",
|
||||
" \"time_offset\": \"timeframe_object-detected\"\n",
|
||||
" }]\n",
|
||||
" }\n",
|
||||
"\n",
|
||||
"For video action recognition, the CSV file has a few requirements:\n",
|
||||
"\n",
|
||||
"- Each data item is a separate JSON object, on a separate line.\n",
|
||||
"- The key/value pair `video_gcs_uri` is the Cloud Storage path to the text file.\n",
|
||||
"\n",
|
||||
" {\n",
|
||||
" \"video_gcs_uri': video,\n",
|
||||
" \"time_segments\": [{\n",
|
||||
" \"start_time\": \"start_time_of_fully_annotated_segment\",\n",
|
||||
" \"end_time\": \"end_time_of_segment\"}],\n",
|
||||
" \"time_segment_annotations\": [{\n",
|
||||
" \"display_name\": label,\n",
|
||||
" \"start_time\": \"start_time_of_segment\",\n",
|
||||
" \"end_time\": \"end_time_of_segment\"\n",
|
||||
" }]\n",
|
||||
" }\n",
|
||||
"\n",
|
||||
"##### ML_USE\n",
|
||||
"\n",
|
||||
"Each JSONL object may additionally specify which split to assign the data item to when the dataset is split for training; otherwise, the dataset will be randomly split: 80/20.\n",
|
||||
"\n",
|
||||
"\"data_item_resource_labels\": {\n",
|
||||
" \"aiplatform.googleapis.com/ml_use\": \"training|test\"\n",
|
||||
" }\n",
|
||||
"\n",
|
||||
"*Note*: The dictionary key fields may alternatively be in camelCase. For example, 'video_gcs_uri' can also be 'videoGcsUri'."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
|
||||
@@ -73,7 +73,7 @@
|
||||
"source": [
|
||||
"### Objective\n",
|
||||
"\n",
|
||||
"In this tutorial, you learn how to use `BigQueryML` (BQML) for training with `Vertex AI`.\n",
|
||||
"In this tutorial, you learn how to use `BigQueryML` for training with `Vertex AI`.\n",
|
||||
"\n",
|
||||
"This tutorial uses the following Google Cloud ML services:\n",
|
||||
"\n",
|
||||
@@ -84,12 +84,12 @@
|
||||
"The steps performed include:\n",
|
||||
"\n",
|
||||
"- Create a local BigQuery table in your project\n",
|
||||
"- Train a BQML model\n",
|
||||
"- Evaluate the BQML model\n",
|
||||
"- Export the BQML model as a cloud model\n",
|
||||
"- Train a BigQuery ML model\n",
|
||||
"- Evaluate the BigQuery ML model\n",
|
||||
"- Export the BigQuery ML model as a cloud model\n",
|
||||
"- Upload the exported model as a `Vertex AI Model` resource\n",
|
||||
"- Hyperparameter tune a BQML model with `Vertex AI Vizier`\n",
|
||||
"- Automatically register a BQML model to `Vertex AI Model Registry`"
|
||||
"- Hyperparameter tune a BigQuery ML model with `Vertex AI Vizier`\n",
|
||||
"- Automatically register a BigQuery ML model to `Vertex AI Model Registry`"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -749,9 +749,9 @@
|
||||
"id": "bqml_create_model"
|
||||
},
|
||||
"source": [
|
||||
"### Train BQML model\n",
|
||||
"### Train BigQuery ML model\n",
|
||||
"\n",
|
||||
"Next, you create and train a BQML tabular classification model from the public dataset penguins and store the model in your project using the `CREATE MODEL` statement. The model configuration is specified in the `OPTIONS` statement as follows:\n",
|
||||
"Next, you create and train a BigQuery ML tabular classification model from the public dataset penguins and store the model in your project using the `CREATE MODEL` statement. The model configuration is specified in the `OPTIONS` statement as follows:\n",
|
||||
"\n",
|
||||
"- `model_type`: The type and archictecture of tabular model to train, e.g., DNN classification.\n",
|
||||
"- `labels`: The column which are the labels.\n",
|
||||
@@ -800,9 +800,9 @@
|
||||
"id": "bqml_eval_model"
|
||||
},
|
||||
"source": [
|
||||
"### Evaluate the trained BQML model\n",
|
||||
"### Evaluate the trained BigQuery ML model\n",
|
||||
"\n",
|
||||
"Next, retrieve the model evaluation for the trained BQML model.\n",
|
||||
"Next, retrieve the model evaluation for the trained BigQuery ML model.\n",
|
||||
"\n",
|
||||
"Learn more about [The ML.EVALUATE function](https://cloud.google.com/bigquery-ml/docs/reference/standard-sql/bigqueryml-syntax-evaluate)."
|
||||
]
|
||||
@@ -833,9 +833,9 @@
|
||||
"id": "bqml_export_model"
|
||||
},
|
||||
"source": [
|
||||
"### Export the model from BQML\n",
|
||||
"### Export the model from BigQuery ML\n",
|
||||
"\n",
|
||||
"The model you trained in BQML is a TensorFlow model. Next, you export the TensorFlow model artifacts in TF.SavedModel format."
|
||||
"The model you trained in BigQuery ML is a TensorFlow model. Next, you export the TensorFlow model artifacts in TF.SavedModel format."
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -1028,9 +1028,9 @@
|
||||
"id": "bqml_create_model:vizier"
|
||||
},
|
||||
"source": [
|
||||
"### Hyperparameter Tune and train a BQML model\n",
|
||||
"### Hyperparameter Tune and train a BigQuery ML model\n",
|
||||
"\n",
|
||||
"Next, you train a BQML tabular classification model with hyperparameter tuning using the `Vertex AI Vizier` service. The hyperparameter settings are specified in the `OPTIONS` statement as follows:\n",
|
||||
"Next, you train a BigQuery ML tabular classification model with hyperparameter tuning using the `Vertex AI Vizier` service. The hyperparameter settings are specified in the `OPTIONS` statement as follows:\n",
|
||||
"\n",
|
||||
"- `HPARAM_TUNING_ALGORITHM`: The algorithm for selecting the next trial parameters.\n",
|
||||
"- `num_trials`: The number of trials.\n",
|
||||
@@ -1083,9 +1083,9 @@
|
||||
"id": "bqml_eval_model"
|
||||
},
|
||||
"source": [
|
||||
"### Evaluate the BQML trained model\n",
|
||||
"### Evaluate the BigQuery ML trained model\n",
|
||||
"\n",
|
||||
"Next, retrieve the model evaluation results for the trained BQML model.\n",
|
||||
"Next, retrieve the model evaluation results for the trained BigQuery ML model.\n",
|
||||
"\n",
|
||||
"Learn more about [The ML.EVALUATE function](https://cloud.google.com/bigquery-ml/docs/reference/standard-sql/bigqueryml-syntax-evaluate)."
|
||||
]
|
||||
@@ -1142,9 +1142,9 @@
|
||||
"id": "bqml_create_model:xai"
|
||||
},
|
||||
"source": [
|
||||
"### Train a BQML model with Explainability\n",
|
||||
"### Train a BigQuery ML model with Explainability\n",
|
||||
"\n",
|
||||
"Next, you train the same BQML model, but this time you enable Vertex AI Explainability on the model predictions by adding the option:\n",
|
||||
"Next, you train the same BigQuery ML model, but this time you enable Vertex AI Explainability on the model predictions by adding the option:\n",
|
||||
"\n",
|
||||
"- `ENABLE_GLOBAL_EXPLAIN`"
|
||||
]
|
||||
|
||||
@@ -87,7 +87,7 @@
|
||||
"This tutorial uses the following Google Cloud ML services:\n",
|
||||
"\n",
|
||||
"- `Vertex AI Experiments`\n",
|
||||
"- `Vertex AI ML Metadata`\n",
|
||||
"- `Vertex ML Metadata`\n",
|
||||
"- `Vertex AI Training`\n",
|
||||
"\n",
|
||||
"The steps performed include:\n",
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -44,7 +44,7 @@
|
||||
" </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/notebook_template.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/community/ml_ops/stage2/get_started_vertex_tensorboard.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",
|
||||
|
||||
@@ -48,7 +48,7 @@
|
||||
" </a>\n",
|
||||
" </td>\n",
|
||||
" <td>\n",
|
||||
" <a href=\"https://github.com/GoogleCloudPlatform/vertex-ai-samples/tree/main/notebooks/community/ml_ops/stage2/get_started_vertex_training_lightgbm.ipynb\">\n",
|
||||
" <a href=\"https://github.com/GoogleCloudPlatform/vertex-ai-samples/blob/main/notebooks/community/ml_ops/stage2/get_started_vertex_training_lightgbm.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",
|
||||
|
||||
@@ -29,7 +29,7 @@
|
||||
"id": "title:generic,gcp"
|
||||
},
|
||||
"source": [
|
||||
"# E2E ML on GCP: MLOps stage 2 : experimentation: get started with Vertex AI Training for Pytorch\n",
|
||||
"# E2E ML on GCP: MLOps stage 2 : experimentation: get started with Vertex AI Training for PyTorch\n",
|
||||
"\n",
|
||||
"<table align=\"left\">\n",
|
||||
" <td>\n",
|
||||
@@ -44,7 +44,7 @@
|
||||
" </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/notebook_template.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/community/ml_ops/stage2/get_started_vertex_training_pytorch.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",
|
||||
@@ -62,7 +62,7 @@
|
||||
"## Overview\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"This tutorial demonstrates how to use Vertex AI for E2E MLOps on Google Cloud in production. This tutorial covers stage 2 : experimentation: get started with Vertex AI Training for Pytorch."
|
||||
"This tutorial demonstrates how to use Vertex AI for E2E MLOps on Google Cloud in production. This tutorial covers stage 2 : experimentation: get started with Vertex AI Training for PyTorch."
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -73,7 +73,7 @@
|
||||
"source": [
|
||||
"### Objective\n",
|
||||
"\n",
|
||||
"In this tutorial, you learn how to use `Vertex AI Training` for training a Pytorch custom model.\n",
|
||||
"In this tutorial, you learn how to use `Vertex AI Training` for training a PyTorch custom model.\n",
|
||||
"\n",
|
||||
"This tutorial uses the following Google Cloud ML services:\n",
|
||||
"\n",
|
||||
@@ -97,7 +97,7 @@
|
||||
"source": [
|
||||
"### Dataset\n",
|
||||
"\n",
|
||||
"The dataset used for this tutorial is the [CIFAR10 dataset](https://pytorch.org/vision/stable/datasets.html#cifar) from [Pytorch Datasets](https://pytorch.org/vision/stable/datasets.html). The version of the dataset is built into TensorFlow. The trained model predicts which type of class an image is from ten classes: airplane, automobile, bird, cat, deer, dog, frog, horse, ship, or truck."
|
||||
"The dataset used for this tutorial is the [CIFAR10 dataset](https://pytorch.org/vision/stable/datasets.html#cifar) from [PyTorch Datasets](https://pytorch.org/vision/stable/datasets.html). The version of the dataset is built into TensorFlow. The trained model predicts which type of class an image is from ten classes: airplane, automobile, bird, cat, deer, dog, frog, horse, ship, or truck."
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -672,17 +672,17 @@
|
||||
"id": "pytorch_intro"
|
||||
},
|
||||
"source": [
|
||||
"## Introduction to Pytorch training\n",
|
||||
"## Introduction to PyTorch training\n",
|
||||
"\n",
|
||||
"The Pytorch package supports both single node and distributed model training.\n",
|
||||
"The PyTorch package supports both single node and distributed model training.\n",
|
||||
"\n",
|
||||
"Once you have trained a Pytorch model, you will want to save it at a Cloud Storage location, so it can subsequently be uploaded to a `Vertex AI Model` resource.\n",
|
||||
"The Pytorch package does not have support to save the model to a Cloud Storage location. Instead, you will do the following steps to save to a Cloud Storage location.\n",
|
||||
"Once you have trained a PyTorch model, you will want to save it at a Cloud Storage location, so it can subsequently be uploaded to a `Vertex AI Model` resource.\n",
|
||||
"The PyTorch package does not have support to save the model to a Cloud Storage location. Instead, you will do the following steps to save to a Cloud Storage location.\n",
|
||||
"\n",
|
||||
"1. Save the in-memory model to the local filesystem (e.g., model.pth).\n",
|
||||
"2. Use gsutil to copy the local copy to the specified Cloud Storage location.\n",
|
||||
"\n",
|
||||
"*Note*: You can do hyperparameter tuning with a Pytorch model."
|
||||
"*Note*: You can do hyperparameter tuning with a PyTorch model."
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -1069,9 +1069,9 @@
|
||||
"id": "docker_write,prediction,pytorch"
|
||||
},
|
||||
"source": [
|
||||
"### Make Pytorch container for prediction\n",
|
||||
"### Make PyTorch container for prediction\n",
|
||||
"\n",
|
||||
"Currently, Vertex AI does not have a predefined container for making predictions with a deployed Pytorch model. No problem, you can assemble your own custom container. Typically, one would base the container on the `Torch Server`. For demonstration purpose, you build a placeholder container (not complete) that includes the latest `Torch Server` image, and push it to the `Container Registry`."
|
||||
"Currently, Vertex AI does not have a predefined container for making predictions with a deployed PyTorch model. No problem, you can assemble your own custom container. Typically, one would base the container on the `Torch Server`. For demonstration purpose, you build a placeholder container (not complete) that includes the latest `Torch Server` image, and push it to the `Container Registry`."
|
||||
]
|
||||
},
|
||||
{
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user