Vertex AI: trenowanie wielu instancji roboczych i nauczanie transferowe z wykorzystaniem TensorFlow

1. Omówienie

W tym module użyjesz Vertex AI, aby uruchomić zadanie trenowania dla wielu instancji roboczych na potrzeby modelu TensorFlow.

Czego się nauczysz

Poznasz takie zagadnienia jak:

  • Modyfikowanie kodu aplikacji treningowej na potrzeby trenowania wielu instancji roboczych
  • Konfigurowanie i uruchamianie zadania trenowania wielu instancji roboczych w interfejsie Vertex AI
  • Konfigurowanie i uruchamianie zadania trenowania wielu instancji roboczych za pomocą pakietu SDK Vertex

Całkowity koszt uruchomienia tego modułu w Google Cloud wynosi około 5 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. W tym module skupimy się na wymienionych poniżej usługach: Szkolenia i Workbench.

Omówienie usługi Vertex

3. Omówienie przypadku użycia

W tym module dowiesz się, jak za pomocą uczenia się transferu wytrenować model klasyfikacji obrazów w zbiorze danych losu z zbiorów danych TensorFlow. Architektura, której użyjesz, to model ResNet50 z biblioteki tf.keras.applications wytrenowany w zbiorze danych Imagenet.

Dlaczego warto zorganizować szkolenie rozproszone?

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 na 1 maszynie lub na kilku komputerach (każda z potencjalnie większą liczbą procesorów graficznych), musisz użyć tf.distribute – biblioteki TensorFlow, która umożliwia wykonywanie obliczeń na wielu urządzeniach. Urządzenie to CPU lub akcelerator, np. GPU lub TPU, na maszynie, na której TensorFlow może uruchamiać operacje.

Najprostszym sposobem na rozpoczęcie trenowania rozproszonego jest pojedyncza maszyna z wieloma urządzeniami GPU. Strategia dystrybucji TensorFlow z modułu tf.distribute zarządza koordynacją dystrybucji danych i aktualizacjami gradientu we wszystkich procesorach graficznych. Jeśli masz już opanowane trenowanie na jednym hoście i chcesz jeszcze bardziej skalować rozwiązania, dodanie wielu maszyn do klastra może pomóc w osiągnięciu jeszcze większej wydajności. Możesz użyć klastra maszyn, które mają tylko procesor lub które mają co najmniej 1 GPU. W tym module omawiamy ten drugi przypadek i pokazujemy, jak za pomocą narzędzia MultiWorkerMirroredStrategy rozłożyć trenowanie modelu TensorFlow na wielu komputerach w Vertex AI.

MultiWorkerMirroredStrategy to synchroniczna strategia równoległości, której możesz używać, wprowadzając tylko kilka zmian w kodzie. Kopia modelu jest tworzona na każdym urządzeniu w klastrze. Kolejne aktualizacje gradientu będą odbywać się synchronicznie. Oznacza to, że każde urządzenie robocze 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 agregowane na wszystkich urządzeniach w maszynie i na wszystkich maszynach w klastrze. Następnie redukowane (zwykle do wartości średniej) w procesie nazywanym all-reduce. Optymalizator przeprowadza aktualizacje parametrów z tymi zredukowanymi gradientami, zapewniając synchronizację urządzeń. Aby dowiedzieć się więcej o trenowaniu rozproszonym za pomocą 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. Będzie Ci to potrzebne do utworzenia instancji notatnika.

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.

Panel Vertex AI

Krok 4. Utwórz instancję Vertex AI Workbench

W sekcji Vertex AI w konsoli Cloud kliknij Workbench:

Menu Vertex AI

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

Notebook_api

Po włączeniu kliknij ZARZĄDZANE NOTATKI:

Notebooks_UI

Następnie wybierz NOWY NOTATNIK.

new_notebook

Nadaj notatnikowi nazwę i kliknij Ustawienia zaawansowane.

create_notebook

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.

idle_timeout

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

enable_terminal

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.

open_jupyterlab

Przy pierwszym użyciu nowej instancji zobaczysz prośbę o uwierzytelnienie. W tym celu postępuj zgodnie z instrukcjami w interfejsie.

uwierzytelnij

5. Konteneryzowanie kodu aplikacji do trenowania

Prześlesz to zadanie treningowe do Vertex, umieszczając kod aplikacji treningowej w kontenerze Dockera i wypchając ten kontener do Google Container Registry. Dzięki temu podejściu możesz wytrenować model utworzony za pomocą dowolnej platformy.

Aby rozpocząć, w menu Menu z aplikacjami otwórz okno terminala w instancji notatnika:

Otwórz terminal w notatniku

Utwórz nowy katalog o nazwie cassava i znajdź do niego dysk CD:

mkdir cassava
cd cassava

Krok 1. Utwórz plik Dockerfile

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.

W terminalu utwórz pusty plik Dockerfile:

touch Dockerfile

Otwórz plik Dockerfile i skopiuj do niego poniższy plik:

FROM gcr.io/deeplearning-platform-release/tf2-gpu.2-7

WORKDIR /

# 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. Nie utworzono jeszcze tych plików – w następnym kroku dodasz kod do trenowania i dostrajania modelu.

Krok 2. Utwórz zasobnik Cloud Storage

W tym zadaniu treningowym wyeksportujesz wytrenowany model TensorFlow do zasobnika Cloud Storage. 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'

Następnie uruchom to polecenie w terminalu, aby utworzyć nowy zasobnik w projekcie.

BUCKET="gs://${PROJECT_ID}-bucket"
gsutil mb -l us-central1 $BUCKET

Krok 3. Dodaj kod trenowania modelu

W terminalu uruchom to polecenie, aby utworzyć katalog na kod trenowania i plik Pythona, w którym dodasz kod:

mkdir trainer
touch trainer/task.py

W katalogu cassava/ powinny znajdować się teraz te elementy:

+ Dockerfile
+ trainer/
    + task.py

Następnie otwórz utworzony przed chwilą plik task.py i skopiuj poniższy kod. Musisz zastąpić ciąg {your-gcs-bucket} nazwą utworzonego przed chwilą zasobnika Cloud Storage.

import tensorflow as tf
import tensorflow_datasets as tfds
import os


PER_REPLICA_BATCH_SIZE = 64
EPOCHS = 2

# TODO: replace {your-gcs-bucket} with the name of the Storage bucket you created earlier
BUCKET = 'gs://{your-gcs-bucket}/mwms'

def preprocess_data(image, label):
  '''Resizes and scales images.'''

  image = tf.image.resize(image, (300,300))
  return tf.cast(image, tf.float32) / 255., label


def create_dataset(batch_size):
  '''Loads Cassava dataset and preprocesses data.'''

  data, info = tfds.load(name='cassava', as_supervised=True, with_info=True)
  number_of_classes = info.features['label'].num_classes
  train_data = data['train'].map(preprocess_data,
                                 num_parallel_calls=tf.data.experimental.AUTOTUNE)
  train_data  = train_data.shuffle(1000)
  train_data  = train_data.batch(batch_size)
  train_data  = train_data.prefetch(tf.data.experimental.AUTOTUNE)

  # Set AutoShardPolicy
  options = tf.data.Options()
  options.experimental_distribute.auto_shard_policy = tf.data.experimental.AutoShardPolicy.DATA
  train_data = train_data.with_options(options)

  return train_data, number_of_classes


def create_model(number_of_classes):
  '''Creates and compiles pretrained ResNet50 model.'''

  base_model = tf.keras.applications.ResNet50(weights='imagenet', include_top=False)
  x = base_model.output
  x = tf.keras.layers.GlobalAveragePooling2D()(x)
  x = tf.keras.layers.Dense(1016, activation='relu')(x)
  predictions = tf.keras.layers.Dense(number_of_classes, activation='softmax')(x)
  model = tf.keras.Model(inputs=base_model.input, outputs=predictions)

  model.compile(
      loss='sparse_categorical_crossentropy',
      optimizer=tf.keras.optimizers.Adam(0.0001),
      metrics=['accuracy'])

  return model


def _is_chief(task_type, task_id):
  '''Helper function. Determines if machine is chief.'''

  return task_type == 'chief'


def _get_temp_dir(dirpath, task_id):
  '''Helper function. Gets temporary directory for saving model.'''

  base_dirpath = 'workertemp_' + str(task_id)
  temp_dir = os.path.join(dirpath, base_dirpath)
  tf.io.gfile.makedirs(temp_dir)
  return temp_dir


def write_filepath(filepath, task_type, task_id):
  '''Helper function. Gets filepath to save model.'''

  dirpath = os.path.dirname(filepath)
  base = os.path.basename(filepath)
  if not _is_chief(task_type, task_id):
    dirpath = _get_temp_dir(dirpath, task_id)
  return os.path.join(dirpath, base)


def main():
  # Create strategy
  strategy = tf.distribute.MultiWorkerMirroredStrategy()

  # Get data
  global_batch_size = PER_REPLICA_BATCH_SIZE * strategy.num_replicas_in_sync
  train_data, number_of_classes = create_dataset(global_batch_size)

  # Wrap variable creation within strategy scope
  with strategy.scope():
    model = create_model(number_of_classes)

  model.fit(train_data, epochs=EPOCHS)

  # Determine type and task of the machine from
  # the strategy cluster resolver
  task_type, task_id = (strategy.cluster_resolver.task_type,
                        strategy.cluster_resolver.task_id)

  # Based on the type and task, write to the desired model path
  write_model_path = write_filepath(BUCKET, task_type, task_id)
  model.save(write_model_path)

if __name__ == "__main__":
    main()

Zanim utworzysz kontener, przyjrzyjmy się dokładniej kodowi, który korzysta z dyrektywy MultiWorkerMirroredStrategy z interfejsu API tf.distribute.Strategy.

Kod musi zawierać kilka komponentów, które są niezbędne do współdziałania z MultiWorkerMirroredStrategy.

  1. Dane muszą zostać podzielone na fragmenty, co oznacza, że do każdej instancji roboczej zostanie przypisany podzbiór całego zbioru danych. Dlatego w każdym kroku każda instancja robocza będzie przetwarzać globalny rozmiar wsadu niepokrywających się elementów zbioru danych. Ta fragmentacja odbywa się automatycznie za pomocą parametru tf.data.experimental.AutoShardPolicy, który może mieć wartość FILE lub DATA. W tym przykładzie funkcja create_dataset() ustawia AutoShardPolicy na DATA, ponieważ zbiór danych kaskady nie jest pobierany w postaci wielu plików. Jeśli jednak nie ustawisz wartości DATA, uruchomi się domyślna zasada AUTO, dzięki czemu efekt będzie taki sam. Więcej informacji o dzieleniu zbiorów danych za pomocą MultiWorkerMirroredStrategy znajdziesz tutaj.
  2. W funkcji main() tworzony jest obiekt MultiWorkerMirroredStrategy. Następnie dodajesz zmienne modelu do zakresu strategii. Ten kluczowy krok informuje TensorFlow, które zmienne powinny być powielone w replikach.
  3. Wielkość wsadu jest skalowana w górę o num_replicas_in_sync. Dzięki temu każda replika przetworzy taką samą liczbę przykładów w każdym kroku. Skalowanie rozmiaru wsadu jest sprawdzoną metodą w przypadku korzystania ze strategii synchronicznego równoległości danych w TensorFlow.
  4. Zapisywanie modelu jest nieco bardziej skomplikowane w przypadku wielu instancji roboczych, ponieważ miejsce docelowe musi być różne dla każdej z tych instancji roboczych. Główna instancja robocza zapisze model w wybranym katalogu modelu, a pozostałe instancje robocze zapiszą model w katalogach tymczasowych. Takie katalogi tymczasowe muszą być unikalne, ponieważ dzięki temu wielu instancji roboczych nie będzie mogło zapisywać danych w tej samej lokalizacji. Zapis może obejmować operacje zbiorowe, co oznacza, że wszyscy pracownicy muszą ocalić, a nie tylko szefa. Funkcje _is_chief(), _get_temp_dir(), write_filepath() oraz main() zawierają stały kod, który pomaga zapisać model.

Pamiętaj, że jeśli używasz interfejsu MultiWorkerMirroredStrategy w innym środowisku, możliwe, że masz skonfigurowaną zmienną środowiskową TF_CONFIG. Vertex AI automatycznie ustawia TF_CONFIG za Ciebie, nie musisz więc definiować tej zmiennej na każdym komputerze w klastrze.

Krok 4. 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/multiworker:cassava"

Skonfiguruj Dockera

gcloud auth configure-docker

Następnie utwórz kontener, uruchamiając to polecenie z poziomu głównego katalogu cassava:

docker build ./ -t $IMAGE_URI

Na koniec wypchnij go do Google Container Registry:

docker push $IMAGE_URI

Po przekazaniu kontenera do Container Registry możesz rozpocząć zadanie trenowania.

6. Uruchamianie zadania trenowania dla wielu instancji roboczych w Vertex AI

W tym module korzystasz z trenowania niestandardowego za pomocą niestandardowego kontenera w Google Container Registry, ale możesz też uruchomić zadanie trenowania za pomocą gotowych kontenerów.

Zacznij od sekcji Trenowanie w sekcji Vertex w konsoli Cloud:

Menu uCAIP

Krok 1. Skonfiguruj zadanie trenowania

Kliknij Utwórz, aby wpisać parametry zadania treningowego.

  • W sekcji Zbiór danych wybierz Brak zarządzanego zbioru danych.
  • Następnie wybierz Trenowanie niestandardowe (zaawansowane) jako metodę trenowania i kliknij Dalej.
  • W polu Nazwa modelu wpisz multiworker-cassava (lub inną nazwę modelu)
  • Kliknij Dalej.

W kroku „Ustawienia kontenera” wybierz Kontener niestandardowy:

Opcja kontenera niestandardowego

W pierwszym polu (Obraz kontenera) wpisz wartość zmiennej IMAGE_URI z poprzedniej sekcji. Powinien to być: gcr.io/your-cloud-project/multiworker:cassava i identyfikator Twojego projektu. Pozostałe pola pozostaw puste i kliknij Dalej.

Pomiń krok Hhyperparameters, ponownie klikając Continue (Dalej).

Krok 2. Skonfiguruj klaster obliczeniowy

Vertex AI udostępnia 4 pule instancji roboczych do obsługi różnych typów zadań maszyn.

Pula instancji roboczych 0 konfiguruje instancję główną, główną, algorytm szeregowania lub instancję główną. W MultiWorkerMirroredStrategy wszystkie maszyny są oznaczone jako instancje robocze, czyli fizyczne maszyny, na których są wykonywane zreplikowane obliczenia. Oprócz tego, że każda maszyna jest maszyną roboczą, musi istnieć jeszcze jedna instancja robocza, która wykonuje dodatkowe czynności, takie jak zapisywanie punktów kontrolnych i zapisywanie plików podsumowania w TensorBoard. Ta maszyna jest nazywana główną. Istnieje tylko 1 główna instancja robocza, więc liczba instancji roboczych w puli instancji roboczych 0 zawsze będzie wynosić 1.

W sekcji Obliczenia i ceny pozostaw wybrany region bez zmian i skonfiguruj Pula instancji roboczych 0 w ten sposób:

Worker_pool_0

Pula instancji roboczych 1 to miejsce, w którym konfigurujesz instancje robocze klastra.

Skonfiguruj pulę instancji roboczych 1 w ten sposób:

Worker_pool_1

Klaster jest teraz skonfigurowany tak, aby mieć 2 maszyny tylko z procesorem. Po uruchomieniu kodu aplikacji do trenowania MultiWorkerMirroredStrategy rozdziela trenowanie na obie maszyny.

MultiWorkerMirroredStrategy ma tylko typy zadań głównego i instancji roboczej, więc nie trzeba konfigurować dodatkowych pul instancji roboczych. Jeśli jednak używasz biblioteki ParameterServerStrategy TensorFlow, serwery parametrów musisz skonfigurować w puli instancji roboczych 2. Jeśli chcesz dodać do klastra oceniającego, musisz skonfigurować tę maszynę w puli instancji roboczych 3.

Kliknij Rozpocznij trenowanie, aby uruchomić zadanie dostrajania hiperparametrów. W sekcji Szkolenia w konsoli na karcie POTOKI SZKOLENIOWE zobaczysz nowo uruchomione zadanie:

Zadania trenowania

🎉 Gratulacje! 🎉

Wiesz już, jak używać Vertex AI do:

  • Uruchom zadanie trenowania dla wielu instancji roboczych na potrzeby kodu trenowania podanego w kontenerze niestandardowym. W tym przykładzie użyto modelu TensorFlow, ale możesz wytrenować model utworzony za pomocą dowolnej platformy za pomocą niestandardowych lub wbudowanych kontenerów.

Więcej informacji o różnych częściach Vertex znajdziesz w dokumentacji.

7. [Opcjonalnie] Użyj pakietu Vertex SDK

W poprzedniej sekcji pokazaliśmy, jak uruchomić zadanie trenowania za pomocą interfejsu użytkownika. W tej sekcji zobaczysz alternatywny sposób przesyłania zadania treningowego za pomocą interfejsu Vertex Python API.

Wróć do instancji notatnika i utwórz notatnik TensorFlow 2 za pomocą Menu z aplikacjami:

new_notebook

Zaimportuj pakiet Vertex AI SDK.

from google.cloud import aiplatform

Aby uruchomić zadanie trenowania dla wielu instancji roboczych, musisz najpierw zdefiniować specyfikację puli instancji roboczych. Pamiętaj, że użycie GPU w specyfikacji jest całkowicie opcjonalne i możesz usunąć accelerator_type i accelerator_count, jeśli chcesz używać klastra tylko z CPU (jak pokazano w poprzedniej sekcji).

# The spec of the worker pools including machine type and Docker image
# Be sure to replace {YOUR-PROJECT-ID} with your project ID.
worker_pool_specs=[
     {
        "replica_count": 1,
        "machine_spec": {
          "machine_type": "n1-standard-8", "accelerator_type": "NVIDIA_TESLA_V100", "accelerator_count": 1
        },
        "container_spec": {"image_uri": "gcr.io/{YOUR-PROJECT-ID}/multiworker:cassava"}
      },
      {
        "replica_count": 1,
        "machine_spec": {
          "machine_type": "n1-standard-8", "accelerator_type": "NVIDIA_TESLA_V100", "accelerator_count": 1
        },
        "container_spec": {"image_uri": "gcr.io/{YOUR-PROJECT-ID}/multiworker:cassava"}
      }
]

Następnie utwórz i uruchom CustomJob. Musisz zastąpić obiekt {YOUR_BUCKET} zasobnikiem na potrzeby testowania w projekcie. Możesz użyć tego samego zasobnika, który został utworzony wcześniej.

# Replace YOUR_BUCKET
my_multiworker_job = aiplatform.CustomJob(display_name='multiworker-cassava-sdk',
                              worker_pool_specs=worker_pool_specs,
                              staging_bucket='gs://{YOUR_BUCKET}')

my_multiworker_job.run()

W sekcji Szkolenia w konsoli na karcie NIESTANDARDOWE ZADANIA zobaczysz swoje zadanie trenowania:

Zadania niestandardowe

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ń.

Zatrzymaj instancję

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

Usuń miejsce na dane