1. Omówienie
W tym module dowiesz się, jak używać Vertex AI do dostrajania hiperparametrów i trenowania rozproszonego. Chociaż w tym module do tworzenia kodu modelu używany jest TensorFlow, podane koncepcje mają też zastosowanie do innych platform ML.
Czego się nauczysz
Poznasz takie zagadnienia jak:
- Wytrenuj model za pomocą trenowania rozproszonego na niestandardowym kontenerze
- Przeprowadzaj wiele prób kodu trenowania na potrzeby automatycznego dostrajania hiperparametrów
Całkowity koszt uruchomienia tego modułu w Google Cloud wynosi około 6 USD.
2. Wprowadzenie do Vertex AI
W tym module wykorzystano najnowszą ofertę usług AI dostępną w Google Cloud. Vertex AI integruje ofertę systemów uczących się z całego Google Cloud, tworząc bezproblemowe środowisko programistyczne. Wcześniej modele wytrenowane z użyciem AutoML i modele niestandardowe były dostępne w oddzielnych usługach. Nowa oferta jest łączona w 1 interfejs API wraz z innymi nowymi usługami. Możesz też przenieść istniejące projekty 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 ML. Głównym tematem tego modułu są Szkolenia i Workbench.
3. Omówienie przypadku użycia
W tym module wykorzystasz dostrajanie hiperparametrów, aby odkryć optymalne parametry dla modelu klasyfikacji obrazów wytrenowanego na zbiorze danych „konie lub ludzie” ze zbiorów danych TensorFlow.
Dostrajanie hiperparametrów
Dostrajanie hiperparametrów za pomocą Vertex AI Training polega na uruchomieniu wielu prób aplikacji treningowej z wartościami dla wybranych hiperparametrów, ustawionymi w ramach określonych przez Ciebie limitów. Vertex AI śledzi wyniki każdej próby i wprowadza korekty w kolejnych.
Aby korzystać z dostrajania hiperparametrów w Vertex AI Training, musisz wprowadzić 2 zmiany w kodzie trenowania:
- Zdefiniuj argument wiersza poleceń w głównym module treningowym dla każdego hiperparametru, który chcesz dostroić.
- Użyj wartości przekazywanej w tych argumentach, aby ustawić odpowiedni hiperparametr w kodzie aplikacji.
Zdzielone szkolenie
Jeśli masz pojedynczy procesor graficzny, TensorFlow użyje tego akceleratora, aby przyspieszyć trenowanie modelu bez dodatkowych działań z Twojej strony. Jeśli jednak chcesz uzyskać dodatkowe korzyści dzięki używaniu kilku procesorów graficznych, musisz użyć interfejsu tf.distribute
, który jest modułem TensorFlow do przeprowadzania obliczeń na wielu urządzeniach.
W tym module używane są narzędzia tf.distribute.MirroredStrategy
, które możesz dodać do aplikacji treningowych, wprowadzając kilka zmian w kodzie. Ta strategia tworzy kopię modelu w każdym GPU na Twoim komputerze. Kolejne aktualizacje gradientu będą odbywać się synchronicznie. Oznacza to, że każdy procesor graficzny oblicza ruch do przodu i do tyłu przez model na innym wycinku danych wejściowych. Obliczone gradienty z każdego z tych wycinków są następnie zagregowane dla wszystkich układów GPU i uśredniane w procesie znanym jako all-reduce. Parametry modelu są aktualizowane za pomocą tych uśrednionych gradientów.
Nie musisz znać szczegółów, aby ukończyć ten moduł, ale jeśli chcesz dowiedzieć się więcej o tym, jak działa rozproszone trenowanie w TensorFlow, obejrzyj film poniżej:
4. Konfigurowanie środowiska
Aby uruchomić to ćwiczenia z programowania, musisz mieć projekt Google Cloud Platform z włączonymi płatnościami. Aby utworzyć projekt, postępuj zgodnie z tymi instrukcjami.
Krok 1. Włącz Compute Engine API
Przejdź do Compute Engine i wybierz opcję Włącz, jeśli nie jest jeszcze włączona.
Krok 2. Włącz Container Registry API
Otwórz Container Registry i wybierz Włącz, jeśli nie jest jeszcze włączony. Użyjesz go do utworzenia kontenera dla niestandardowego zadania trenowania.
Krok 3. Włącz interfejs Vertex AI API
Przejdź do sekcji Vertex AI w konsoli Cloud i kliknij Włącz interfejs Vertex AI API.
Krok 4. Utwórz instancję Vertex AI Workbench
W sekcji Vertex AI w konsoli Cloud kliknij Workbench:
Włącz Notebooks API, jeśli nie jest jeszcze włączone.
Po włączeniu kliknij ZARZĄDZANE NOTATKI:
Następnie wybierz NOWY NOTATNIK.
Nadaj notatnikowi nazwę i kliknij Ustawienia zaawansowane.
W sekcji Ustawienia zaawansowane włącz wyłączanie w trybie bezczynności i ustaw liczbę minut na 60. Oznacza to, że Twój notatnik automatycznie wyłączy się, gdy nie będzie używany, aby nie ponosić niepotrzebnych kosztów.
W sekcji Zabezpieczenia wybierz „Włącz terminal” , jeśli nie jest jeszcze włączona.
Inne 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 zobaczysz prośbę o uwierzytelnienie. W tym celu postępuj zgodnie z instrukcjami w interfejsie.
5. Pisanie kodu trenowania
Aby rozpocząć, w menu Menu z aplikacjami otwórz okno terminala w instancji notatnika:
Utwórz nowy katalog o nazwie vertex-codelab
i umieść w nim dysk CD.
mkdir vertex-codelab
cd vertex-codelab
Uruchom następujące polecenie, aby utworzyć katalog na kod trenowania i plik Pythona, w którym umieścisz kod:
mkdir trainer
touch trainer/task.py
W katalogu vertex-codelab
powinny znajdować się teraz te elementy:
+ trainer/
+ task.py
Następnie otwórz utworzony przed chwilą plik task.py
i wklej 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ę bliżej kodowi i składnikom specyficznym dla rozproszonego trenowania i dostrajania hiperparametrów.
Zdzielone szkolenie
- W funkcji
main()
tworzony jest obiektMirroredStrategy
. Następnie dodajesz zmienne modelu do zakresu strategii. Ten krok informuje TensorFlow, które zmienne powinny być powielone w GPU. - Wielkość wsadu jest skalowana w górę o
num_replicas_in_sync
. Skalowanie rozmiaru wsadu jest sprawdzoną metodą w przypadku korzystania ze strategii synchronicznego równoległości danych w TensorFlow. Więcej informacji możesz uzyskać tutaj.
Dostrajanie hiperparametrów
- Skrypt importuje bibliotekę
hypertune
. Później podczas tworzenia obrazu kontenera musimy zainstalować tę bibliotekę. - Funkcja
get_args()
definiuje argument wiersza poleceń dla każdego hiperparametru, który chcesz dostroić. W tym przykładzie dostrojone hiperparametry to szybkość uczenia się, wartość pędu w optymalizatorze i liczba jednostek w ostatniej ukrytej warstwie modelu. Możesz też eksperymentować z innymi. Wartość przekazywana w tych argumentach jest następnie używana do ustawienia odpowiedniego hiperparametru w kodzie (np. ustawlearning_rate = args.learning_rate
) - Na końcu funkcji
main()
bibliotekahypertune
służy do określenia danych, które chcesz optymalizować. W TensorFlow metoda Kerasmodel.fit
zwraca obiektHistory
. AtrybutHistory.history
zawiera zapis wartości strat trenowania i wartości wskaźników w kolejnych epokach. Jeśli przekażesz dane weryfikacyjne domodel.fit
, atrybutHistory.history
będzie też zawierać wartości utracone podczas weryfikacji i wskaźniki. Jeśli na przykład wytrenujesz model z 3 epokami z danymi do weryfikacji i podaszaccuracy
jako wskaźnik, atrybutHistory.history
bę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 wykrywała wartości maksymalizujące dokładność walidacji modelu, zdefiniuj wskaźnik jako ostatnią pozycję (lub NUM_EPOCS - 1
) na liście val_accuracy
. Następnie przekaż ten wskaźnik do instancji HyperTune
. Możesz wybrać dowolny ciąg dla hyperparameter_metric_tag
, ale trzeba będzie użyć go później, gdy uruchomisz zadanie dostrajania hiperparametrów.
6. Konteneryzowanie kodu
Pierwszym krokiem w konteneryzacji kodu jest utworzenie pliku Dockerfile. W pliku Dockerfile znajdziesz wszystkie polecenia potrzebne do uruchomienia obrazu. Zainstaluje wszystkie niezbędne biblioteki i skonfiguruje punkt wejścia dla kodu trenowania.
Krok 1. Zapisz plik Dockerfile
W terminalu sprawdź, czy jesteś w katalogu vertex-codelab
i utwórz pusty plik Dockerfile:
touch Dockerfile
W katalogu vertex-codelab
powinny znajdować się teraz te elementy:
+ Dockerfile
+ trainer/
+ task.py
Otwórz plik Dockerfile i skopiuj do niego poniższy plik:
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 wykorzystuje obraz Dockera GPU TensorFlow Enterprise 2.7. Kontenery do deep learningu w Google Cloud mają wstępnie zainstalowane wiele popularnych platform do uczenia maszynowego i platformy do badania danych. Po pobraniu tego obrazu plik Dockerfile konfiguruje punkt wejścia dla kodu trenowania.
Krok 2. Utwórz kontener
W terminalu uruchom to polecenie, aby zdefiniować zmienną env dla swojego projektu, pamiętając o zastąpieniu your-cloud-project
identyfikatorem projektu:
PROJECT_ID='your-cloud-project'
Zdefiniuj zmienną za pomocą identyfikatora 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 z poziomu głównego katalogu vertex-codelab
:
docker build ./ -t $IMAGE_URI
Na koniec wypchnij go do Google Container Registry:
docker push $IMAGE_URI
Krok 3. Utwórz zasobnik Cloud Storage
W zadaniu trenowania przekażemy ścieżkę do zasobnika przejściowego.
Aby utworzyć w projekcie nowy zasobnik, uruchom w terminalu to polecenie.
BUCKET_NAME="gs://${PROJECT_ID}-hptune-bucket"
gsutil mb -l us-central1 $BUCKET_NAME
7. Uruchom zadanie 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ć element worker_pool_specs
, który określa typ maszyny i obraz Dockera. Poniższa specyfikacja definiuje jedną maszynę z 2 procesorami graficznymi NVIDIA Tesla V100.
Musisz zastąpić zmienną {PROJECT_ID}
w image_uri
swoim projektem.
# 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 zoptymalizować. Klucz słownika to ciąg znaków przypisany do argumentu wiersza poleceń dla każdego hiperparametru, a wartość słownika to specyfikacja parametru.
W przypadku każdego hiperparametru musisz zdefiniować typ oraz granice wartości, które będzie próbować dostrajać usługa dostrajania. Hiperparametry mogą być typu liczba całkowita, liczba całkowita, kategorialne lub dyskretne. Jeśli wybierzesz typ Liczba podwójna lub Liczba całkowita, musisz podać wartość minimalną i maksymalną. Jeśli wybierzesz Kategorialne lub Dyskretne, musisz podać wartości. W przypadku typów Podwójna liczba i Liczba całkowita musisz też podać wartość Skalowanie. Więcej informacji o wybieraniu najlepszej skali 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)
}
Końcowa specyfikacja do zdefiniowania to metric_spec
, czyli słownik reprezentujący wskaźnik do optymalizacji. Kluczem słownika jest identyfikator hyperparameter_metric_tag
ustawiony w kodzie aplikacji treningowej, 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 typową specyfikację, która będzie używana do uruchamiania zadania w ramach każdej próby dostrajania hiperparametrów.
Musisz zastąpić zmienną {YOUR_BUCKET}
zasobnikiem utworzonym wcześniej.
# 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()
Pamiętaj o kilku argumentach:
- max_trial_count: musisz wyznaczyć górną granicę liczby wersji próbnych, w których usługa będzie działać. Większa liczba prób oznacza zwykle lepsze wyniki, ale występuje wtedy spadek zysków, po których dodatkowe testy mają znikomy wpływ na dane, które próbujesz zoptymalizować, lub nie mają ich wcale. Przed skalowaniem w górę najlepiej jest rozpocząć od mniejszej liczby prób i poznać wpływ wybranych hiperparametrów.
- Parallel_trial_count: jeśli korzystasz z równoległych prób, usługa udostępnia wiele klastrów przetwarzania trenowania. Zwiększenie liczby równoległych prób pozwala skrócić czas wykonywania zadania dostrajania hiperparametrów; ale może też zmniejszyć ogólną skuteczność zadania. Dzieje się tak, ponieważ domyślna strategia dostrajania wykorzystuje wyniki poprzednich prób do przypisania wartości w kolejnych próbach.
- algorytm_wyszukiwania: możesz ustawić algorytm wyszukiwania na siatkę, losowo lub domyślnie (Brak). Opcja domyślna stosuje optymalizację Bayesa do wyszukiwania przestrzeni możliwych wartości hiperparametrów i jest zalecanym algorytmem. Więcej informacji o tym algorytmie znajdziesz tutaj.
Po uruchomieniu zadania jego stan będzie można śledzić na karcie ZADANIA DOstrajania SAMOCHODU w interfejsie.
Po zakończeniu zadania możesz wyświetlić i posortować wyniki prób, aby odkryć najlepszą kombinację wartości hiperparametrów.
🎉 Gratulacje! 🎉
Wiesz już, jak używać Vertex AI do:
- Uruchamianie zadania dostrajania hiperparametrów z trenowaniem rozproszonym
Więcej informacji o różnych częściach Vertex AI znajdziesz w dokumentacji.
8. Czyszczenie
Skonfigurowaliśmy notatnik tak, aby przekraczał limit czasu po 60 minutach bezczynności, więc nie musimy się martwić wyłączeniem 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 na dane, w menu nawigacyjnym w konsoli Google Cloud otwórz Cloud Storage, wybierz swój zasobnik i kliknij Usuń: