1. Przegląd
W tym laboratorium dowiesz się, jak używać Vertex AI do dostrajania hiperparametrów i trenowania rozproszonego. W tym laboratorium używamy TensorFlow do tworzenia kodu modelu, ale te same koncepcje mają zastosowanie również do innych platform ML.
Czego się dowiesz
Poznasz takie zagadnienia jak:
- Trenowanie modelu z użyciem trenowania rozproszonego w kontenerze niestandardowym
- Uruchamianie wielu prób kodu trenującego na potrzeby automatycznego dostrajania hiperparametrów
Całkowity koszt przeprowadzenia tego laboratorium w Google Cloud wynosi około 6 USD.
2. Wprowadzenie do Vertex AI
W tym module wykorzystujemy najnowszą ofertę produktów AI dostępną w Google Cloud. Vertex AI integruje oferty ML w Google Cloud, zapewniając płynne środowisko programistyczne. Wcześniej modele wytrenowane za pomocą AutoML i modele niestandardowe były dostępne w ramach osobnych usług. Nowa oferta łączy je w jeden interfejs API wraz z innymi nowymi usługami. Możesz też przeprowadzić migrację istniejących projektów do Vertex AI. Jeśli masz jakieś uwagi, odwiedź stronę pomocy.
Vertex AI obejmuje wiele różnych usług, które obsługują kompleksowe przepływy pracy związane z uczeniem maszynowym. Ten moduł skupia się na trenowaniu i Workbench.

3. Omówienie przypadku użycia
W tym module użyjesz dostrajania hiperparametrów, aby znaleźć optymalne parametry modelu klasyfikacji obrazów wytrenowanego na zbiorze danych konie lub ludzie z TensorFlow Datasets.
Dostrajanie hiperparametrów
Dostrajanie hiperparametrów za pomocą Vertex AI Training polega na uruchamianiu wielu prób aplikacji treningowej z wartościami wybranych hiperparametrów ustawionymi w określonych przez Ciebie granicach. Vertex AI śledzi wyniki każdego testu i wprowadza korekty w przypadku kolejnych testów.
Aby używać optymalizacji hiperparametrów w usłudze Vertex AI Training, musisz wprowadzić w kodzie trenowania 2 zmiany:
- W głównym module trenowania zdefiniuj argument wiersza poleceń dla każdego hiperparametru, który chcesz dostroić.
- Użyj wartości przekazanej w tych argumentach, aby ustawić odpowiedni hiperparametr w kodzie aplikacji.
Trenowanie rozproszone
Jeśli masz pojedynczy procesor GPU, TensorFlow użyje tego akceleratora, aby przyspieszyć trenowanie modelu bez dodatkowej pracy z Twojej strony. Jeśli jednak chcesz uzyskać dodatkowe korzyści z używania wielu procesorów GPU, musisz użyć modułu tf.distribute TensorFlow, który umożliwia uruchamianie obliczeń na wielu urządzeniach.
W tym module użyjemy tf.distribute.MirroredStrategy, które możesz dodać do aplikacji szkoleniowych, wprowadzając tylko kilka zmian w kodzie. Ta strategia tworzy kopię modelu na każdym procesorze GPU na Twoim komputerze. Kolejne aktualizacje gradientu będą przeprowadzane synchronicznie. Oznacza to, że każdy procesor GPU oblicza przejścia w przód i w tył przez model na innym wycinku danych wejściowych. Obliczone gradienty z każdego z tych wycinków są następnie agregowane na wszystkich procesorach GPU i uśredniane w procesie zwanym all-reduce. Parametry modelu są aktualizowane za pomocą tych uśrednionych gradientów.
Aby ukończyć ten moduł, nie musisz znać szczegółów, ale jeśli chcesz dowiedzieć się więcej o tym, jak działa trenowanie rozproszone w TensorFlow, obejrzyj poniższy film:
4. Konfigurowanie środowiska
Aby wykonać to ćwiczenie, musisz mieć projekt w Google Cloud Platform z włączonymi płatnościami. Aby utworzyć projekt, postępuj zgodnie z instrukcjami.
Krok 1. Włącz interfejs Compute Engine API
Przejdź do Compute Engine i kliknij Włącz, jeśli nie jest jeszcze włączona.
Krok 2. Włącz interfejs Container Registry API
Otwórz Container Registry i kliknij Włącz, jeśli nie jest jeszcze włączona. Użyjesz go do utworzenia kontenera na potrzeby niestandardowego zadania trenowania.
Krok 3. Włącz interfejs Vertex AI API
Otwórz sekcję Vertex AI w konsoli Cloud i kliknij Włącz interfejs Vertex AI API.

Krok 4. Tworzenie instancji Vertex AI Workbench
W sekcji Vertex AI w konsoli Cloud kliknij Workbench:

Włącz interfejs Notebooks API, jeśli nie jest jeszcze włączony.

Po włączeniu kliknij ZARZĄDZANE NOTATNIKI:

Następnie wybierz NOWY NOTEBOOK.

Nadaj notatnikowi nazwę, a potem kliknij Ustawienia zaawansowane.

W sekcji Ustawienia zaawansowane włącz wyłączanie w przypadku bezczynności i ustaw liczbę minut na 60. Oznacza to, że Twój notebook będzie się automatycznie wyłączać, gdy nie jest używany, dzięki czemu nie poniesiesz niepotrzebnych kosztów.

W sekcji Zabezpieczenia wybierz „Włącz terminal”, jeśli nie jest jeszcze włączony.

Wszystkie pozostałe ustawienia zaawansowane możesz pozostawić bez zmian.
Następnie kliknij Utwórz. Udostępnienie instancji zajmie kilka minut.
Po utworzeniu instancji wybierz Otwórz JupyterLab.

Przy pierwszym użyciu nowej instancji pojawi się prośba o uwierzytelnienie. Aby to zrobić, postępuj zgodnie z instrukcjami wyświetlanymi w interfejsie.

5. Pisanie kodu szkoleniowego
Aby rozpocząć, w menu Launchera otwórz okno terminala w instancji notatnika:

Utwórz nowy katalog o nazwie vertex-codelab i przejdź do niego.
mkdir vertex-codelab
cd vertex-codelab
Aby utworzyć katalog z kodem trenowania i plik Pythona, w którym dodasz kod, uruchom to polecenie:
mkdir trainer
touch trainer/task.py
W katalogu vertex-codelab powinny się teraz znajdować te pliki:
+ trainer/
+ task.py
Następnie otwórz utworzony plik task.py i wklej do niego cały poniższy kod.
import tensorflow as tf
import tensorflow_datasets as tfds
import argparse
import hypertune
import os
NUM_EPOCHS = 10
BATCH_SIZE = 64
def get_args():
'''Parses args. Must include all hyperparameters you want to tune.'''
parser = argparse.ArgumentParser()
parser.add_argument(
'--learning_rate',
required=True,
type=float,
help='learning rate')
parser.add_argument(
'--momentum',
required=True,
type=float,
help='SGD momentum value')
parser.add_argument(
'--num_units',
required=True,
type=int,
help='number of units in last hidden layer')
args = parser.parse_args()
return args
def preprocess_data(image, label):
'''Resizes and scales images.'''
image = tf.image.resize(image, (150,150))
return tf.cast(image, tf.float32) / 255., label
def create_dataset(batch_size):
'''Loads Horses Or Humans dataset and preprocesses data.'''
data, info = tfds.load(name='horses_or_humans', as_supervised=True, with_info=True)
# Create train dataset
train_data = data['train'].map(preprocess_data)
train_data = train_data.shuffle(1000)
train_data = train_data.batch(batch_size)
# Create validation dataset
validation_data = data['test'].map(preprocess_data)
validation_data = validation_data.batch(batch_size)
return train_data, validation_data
def create_model(num_units, learning_rate, momentum):
'''Defines and compiles model.'''
inputs = tf.keras.Input(shape=(150, 150, 3))
x = tf.keras.layers.Conv2D(16, (3, 3), activation='relu')(inputs)
x = tf.keras.layers.MaxPooling2D((2, 2))(x)
x = tf.keras.layers.Conv2D(32, (3, 3), activation='relu')(x)
x = tf.keras.layers.MaxPooling2D((2, 2))(x)
x = tf.keras.layers.Conv2D(64, (3, 3), activation='relu')(x)
x = tf.keras.layers.MaxPooling2D((2, 2))(x)
x = tf.keras.layers.Flatten()(x)
x = tf.keras.layers.Dense(num_units, activation='relu')(x)
outputs = tf.keras.layers.Dense(1, activation='sigmoid')(x)
model = tf.keras.Model(inputs, outputs)
model.compile(
loss='binary_crossentropy',
optimizer=tf.keras.optimizers.SGD(learning_rate=learning_rate, momentum=momentum),
metrics=['accuracy'])
return model
def main():
args = get_args()
# Create distribution strategy
strategy = tf.distribute.MirroredStrategy()
# Get data
GLOBAL_BATCH_SIZE = BATCH_SIZE * strategy.num_replicas_in_sync
train_data, validation_data = create_dataset(GLOBAL_BATCH_SIZE)
# Wrap variable creation within strategy scope
with strategy.scope():
model = create_model(args.num_units, args.learning_rate, args.momentum)
# Train model
history = model.fit(train_data, epochs=NUM_EPOCHS, validation_data=validation_data)
# Define metric
hp_metric = history.history['val_accuracy'][-1]
hpt = hypertune.HyperTune()
hpt.report_hyperparameter_tuning_metric(
hyperparameter_metric_tag='accuracy',
metric_value=hp_metric,
global_step=NUM_EPOCHS)
if __name__ == "__main__":
main()
Przyjrzyjmy się dokładniej kodowi i zbadajmy komponenty związane z trenowaniem rozproszonym i dostrajaniem hiperparametrów.
Trenowanie rozproszone
- W funkcji
main()tworzony jest obiektMirroredStrategy. Następnie umieść tworzenie zmiennych modelu w zakresie strategii. Ten krok informuje TensorFlow, które zmienne powinny być odzwierciedlane na wszystkich procesorach GPU. - Wielkość wsadu jest zwiększana o
num_replicas_in_sync. Skalowanie wielkości wsadu jest sprawdzoną metodą w przypadku korzystania w TensorFlow ze strategii synchronicznego równoległego przetwarzania danych. Więcej informacji znajdziesz tutaj
Dostrajanie hiperparametrów
- Skrypt importuje bibliotekę
hypertune. Gdy później będziemy tworzyć obraz kontenera, musimy pamiętać o zainstalowaniu tej biblioteki. - Funkcja
get_args()definiuje argument wiersza poleceń dla każdego hiperparametru, który chcesz dostroić. W tym przykładzie dostrajane hiperparametry to tempo uczenia się, wartość momentum w optymalizatorze i liczba jednostek w ostatniej warstwie ukrytej modelu, ale możesz eksperymentować z innymi. Wartość przekazana w tych argumentach jest następnie używana do ustawienia odpowiedniego hiperparametru w kodzie (np. ustawienialearning_rate = args.learning_rate). - Na końcu funkcji
main()bibliotekahypertunesłuży do zdefiniowania danych, które chcesz zoptymalizować. W TensorFlow metoda Kerasmodel.fitzwraca obiektHistory. AtrybutHistory.historyto zapis wartości funkcji straty i wartości danych w kolejnych epokach. Jeśli przekażesz dane weryfikacyjne domodel.fit, atrybutHistory.historybędzie zawierać również wartości utraty i wartości wskaźników weryfikacji. Jeśli na przykład wytrenujesz model w 3 epokach z danymi do weryfikacji i podaszaccuracyjako wskaźnik, atrybutHistory.historybędzie wyglądać podobnie do tego słownika.
{
"accuracy": [
0.7795261740684509,
0.9471358060836792,
0.9870933294296265
],
"loss": [
0.6340447664260864,
0.16712145507335663,
0.04546636343002319
],
"val_accuracy": [
0.3795261740684509,
0.4471358060836792,
0.4870933294296265
],
"val_loss": [
2.044623374938965,
4.100203514099121,
3.0728273391723633
]
Jeśli chcesz, aby usługa dostrajania hiperparametrów odkryła wartości, które maksymalizują dokładność weryfikacji modelu, zdefiniuj dane jako ostatni wpis (lub NUM_EPOCS - 1) na liście val_accuracy. Następnie przekaż te dane do instancji elementu HyperTune. W przypadku parametru hyperparameter_metric_tag możesz wybrać dowolny ciąg znaków, ale musisz go użyć ponownie później, gdy uruchomisz zadanie dostrajania hiperparametrów.
6. Konteneryzacja kodu
Pierwszym krokiem w procesie kontenerowania kodu jest utworzenie pliku Dockerfile. W pliku Dockerfile umieścisz wszystkie polecenia potrzebne do uruchomienia obrazu. Zainstaluje wszystkie niezbędne biblioteki i skonfiguruje punkt wejścia dla kodu trenowania.
Krok 1. Napisz plik Dockerfile
W terminalu sprawdź, czy jesteś w katalogu vertex-codelab, i utwórz pusty plik Dockerfile:
touch Dockerfile
W katalogu vertex-codelab powinny się teraz znajdować te pliki:
+ Dockerfile
+ trainer/
+ task.py
Otwórz plik Dockerfile i skopiuj do niego ten kod:
FROM gcr.io/deeplearning-platform-release/tf2-gpu.2-7
WORKDIR /
# Installs hypertune library
RUN pip install cloudml-hypertune
# Copies the trainer code to the docker image.
COPY trainer /trainer
# Sets up the entry point to invoke the trainer.
ENTRYPOINT ["python", "-m", "trainer.task"]
Ten plik Dockerfile używa obrazu Dockera kontenera Deep Learning Container TensorFlow Enterprise 2.7 z GPU. Kontenery do deep learningu w Google Cloud mają fabrycznie zainstalowanych wiele popularnych platform ML i narzędzi do nauki o danych. Po pobraniu tego obrazu ten plik Dockerfile konfiguruje punkt wejścia dla kodu trenującego.
Krok 2. Utwórz kontener
W terminalu uruchom to polecenie, aby zdefiniować zmienną środowiskową dla projektu. Pamiętaj, aby zastąpić your-cloud-project identyfikatorem projektu:
PROJECT_ID='your-cloud-project'
Zdefiniuj zmienną z identyfikatorem URI obrazu kontenera w Google Container Registry:
IMAGE_URI="gcr.io/$PROJECT_ID/horse-human-codelab:latest"
Konfigurowanie Dockera
gcloud auth configure-docker
Następnie utwórz kontener, uruchamiając to polecenie w katalogu głównym vertex-codelab:
docker build ./ -t $IMAGE_URI
Na koniec przenieś go do Google Container Registry:
docker push $IMAGE_URI
Krok 3. Utwórz zasobnik Cloud Storage
W naszym zadaniu trenowania przekażemy ścieżkę do zasobnika tymczasowego.
Aby utworzyć nowy zasobnik w projekcie, uruchom w terminalu to polecenie:
BUCKET_NAME="gs://${PROJECT_ID}-hptune-bucket"
gsutil mb -l us-central1 $BUCKET_NAME
7. Uruchamianie zadania dostrajania hiperparametrów
Krok 1. Utwórz niestandardowe zadanie trenowania z dostrajaniem hiperparametrów
W programie uruchamiającym otwórz nowy notatnik TensorFlow 2.

Zaimportuj pakiet Vertex AI Python SDK.
from google.cloud import aiplatform
from google.cloud.aiplatform import hyperparameter_tuning as hpt
Aby uruchomić zadanie dostrajania hiperparametrów, musisz najpierw zdefiniować worker_pool_specs, który określa typ maszyny i obraz Dockera. Poniższa specyfikacja określa 1 maszynę z 2 procesorami graficznymi NVIDIA Tesla V100.
W image_uri musisz zastąpić {PROJECT_ID} nazwą swojego projektu.
# The spec of the worker pools including machine type and Docker image
# Be sure to replace PROJECT_ID in the "image_uri" with your project.
worker_pool_specs = [{
"machine_spec": {
"machine_type": "n1-standard-4",
"accelerator_type": "NVIDIA_TESLA_V100",
"accelerator_count": 2
},
"replica_count": 1,
"container_spec": {
"image_uri": "gcr.io/{PROJECT_ID}/horse-human-codelab:latest"
}
}]
Następnie zdefiniuj parameter_spec, czyli słownik określający parametry, które chcesz optymalizować. Kluczem słownika jest ciąg tekstowy przypisany do argumentu wiersza poleceń dla każdego hiperparametru, a wartością słownika jest specyfikacja parametru.
W przypadku każdego hiperparametru musisz określić typ oraz zakres wartości, które będzie testować usługa optymalizacji. Hiperparametry mogą być typu Double, Integer, Categorical lub Discrete. Jeśli wybierzesz typ Double lub Integer, musisz podać wartość minimalną i maksymalną. Jeśli wybierzesz opcję Kategorialne lub Dyskretne, musisz podać wartości. W przypadku typów Double i Integer musisz też podać wartość skalowania. Więcej informacji o tym, jak wybrać najlepszą skalę, znajdziesz w tym filmie.
# Dictionary representing parameters to optimize.
# The dictionary key is the parameter_id, which is passed into your training
# job as a command line argument,
# And the dictionary value is the parameter specification of the metric.
parameter_spec = {
"learning_rate": hpt.DoubleParameterSpec(min=0.001, max=1, scale="log"),
"momentum": hpt.DoubleParameterSpec(min=0, max=1, scale="linear"),
"num_units": hpt.DiscreteParameterSpec(values=[64, 128, 512], scale=None)
}
Ostatnią specyfikacją do zdefiniowania jest metric_spec, czyli słownik reprezentujący wskaźnik, który ma zostać zoptymalizowany. Kluczem słownika jest hyperparameter_metric_tag ustawiony w kodzie aplikacji do trenowania, a wartością jest cel optymalizacji.
# Dicionary representing metrics to optimize.
# The dictionary key is the metric_id, which is reported by your training job,
# And the dictionary value is the optimization goal of the metric.
metric_spec={'accuracy':'maximize'}
Po zdefiniowaniu specyfikacji utworzysz CustomJob, czyli wspólną specyfikację, która będzie używana do uruchamiania zadania w każdej próbie dostrajania hiperparametrów.
Zastąp {YOUR_BUCKET} utworzonym wcześniej zasobnikiem.
# Replace YOUR_BUCKET
my_custom_job = aiplatform.CustomJob(display_name='horses-humans',
worker_pool_specs=worker_pool_specs,
staging_bucket='gs://{YOUR_BUCKET}')
Następnie utwórz i uruchom HyperparameterTuningJob.
hp_job = aiplatform.HyperparameterTuningJob(
display_name='horses-humans',
custom_job=my_custom_job,
metric_spec=metric_spec,
parameter_spec=parameter_spec,
max_trial_count=6,
parallel_trial_count=2,
search_algorithm=None)
hp_job.run()
Warto zwrócić uwagę na kilka argumentów:
- max_trial_count: musisz podać górną granicę liczby prób, które usługa przeprowadzi. Większa liczba prób zwykle pozwala uzyskać lepsze wyniki, ale w pewnym momencie dodatkowe próby przestają przynosić korzyści i mają niewielki lub żaden wpływ na wskaźnik, który próbujesz zoptymalizować. Zalecamy rozpoczęcie od mniejszej liczby prób i sprawdzenie, jak duże znaczenie mają wybrane hiperparametry, zanim zwiększysz skalę.
- parallel_trial_count: jeśli używasz prób równoległych, usługa udostępnia wiele klastrów przetwarzania treningowego. Zwiększenie liczby równoległych prób skraca czas działania zadania dostrajania hiperparametrów, ale może zmniejszyć ogólną skuteczność zadania. Dzieje się tak, ponieważ domyślna strategia dostrajania wykorzystuje wyniki poprzednich prób do określania wartości w kolejnych próbach.
- search_algorithm: możesz ustawić algorytm wyszukiwania na siatkę, losowy lub domyślny (brak). Opcja domyślna stosuje optymalizację bayesowską do przeszukiwania przestrzeni możliwych wartości hiperparametrów i jest zalecanym algorytmem. Więcej informacji o tym algorytmie znajdziesz tutaj.
Po rozpoczęciu zadania możesz śledzić jego stan w interfejsie na karcie ZADANIA DOSTRAJANIA HIPERPARAMETRÓW.

Po zakończeniu zadania możesz wyświetlić i posortować wyniki prób, aby znaleźć najlepszą kombinację wartości hiperparametrów.

🎉 Gratulacje! 🎉
Dowiedziałeś się, jak używać Vertex AI do:
- Uruchamianie zadania dostrajania hiperparametrów z rozproszonym trenowaniem
Więcej informacji o poszczególnych częściach Vertex AI znajdziesz w dokumentacji.
8. Czyszczenie
Skonfigurowaliśmy notatnik tak, aby po 60 minutach bezczynności przekraczał limit czasu, więc nie musimy się martwić o zamykanie instancji. Jeśli chcesz ręcznie wyłączyć instancję, kliknij przycisk Zatrzymaj w sekcji Vertex AI Workbench w konsoli. Jeśli chcesz całkowicie usunąć notatnik, kliknij przycisk Usuń.

Aby usunąć zasobnik Storage, w menu nawigacyjnym w konsoli Cloud otwórz Storage, wybierz zasobnik i kliknij Usuń:
