Vertex AI Workbench: trenowanie modelu TensorFlow z użyciem danych z BigQuery

1. Omówienie

Z tego modułu dowiesz się, jak używać platformy Vertex AI Workbench do eksplorowania danych i trenowania modeli ML.

Czego się nauczysz

Poznasz takie zagadnienia jak:

  • Tworzenie i konfigurowanie instancji Vertex AI Workbench
  • Korzystanie z oprogramowania sprzęgającego Vertex AI Workbench
  • Trenowanie modelu na jądrze Vertex AI Workbench

Łączny koszt przeprowadzenia tego laboratorium w Google Cloud wynosi około 1 USD.

2. Wprowadzenie do Vertex AI

Ten moduł wykorzystuje 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 za pomocą AutoML i modele niestandardowe były dostępne za pomocą oddzielnych usług. Nowa oferta jest łączona w 1 interfejs API wraz z innymi nowymi usługami. Możesz też przenieść istniejące projekty do Vertex AI.

Vertex AI zawiera wiele różnych usług, które obsługują kompleksowe przepływy pracy związane z systemami uczącymi się. W tym laboratorium skupimy się na Vertex AI Workbench.

Vertex AI Workbench pomaga użytkownikom szybko tworzyć kompleksowe przepływy pracy oparte na notatniku dzięki głębokiej integracji z usługami danych (takimi jak Dataproc, Dataflow, BigQuery i Dataplex) oraz Vertex AI. Umożliwia badaczom danych łączenie się z usługami danych GCP, analizowanie zbiorów danych, eksperymentowanie z różnymi technikami modelowania, wdrażanie wytrenowanych modeli w środowisku produkcyjnym i zarządzanie MLOps w całym cyklu życia modelu.

3. Omówienie przypadku użycia

W tym module zapoznasz się ze zbiorem danych London Bicycles Hire (Wynajem rowerów w Londynie). Dane te zawierają informacje o podróżach rowerowych w ramach londyńskiego programu publicznego wypożyczania rowerów od 2011 r. Zacznij od zbadania tego zbioru danych w BigQuery za pomocą łącznika BigQuery w Vertex AI Workbench. Następnie wczytasz dane do Jupyter Notebook za pomocą pandas i wytrenujesz model TensorFlow, aby przewidzieć czas trwania przejażdżki rowerem na podstawie czasu jej trwania i dystansu.

W tym laboratorium do przekształcania i przygotowywania danych wejściowych do trenowania modelu używa się warstw wstępnego przetwarzania Kerasa. Ten interfejs API umożliwia wbudowywanie wstępnego przetwarzania bezpośrednio do grafu modelu TensorFlow, co zmniejsza ryzyko zniekształceń trenowania i wyświetlania przez zapewnienie, że dane treningowe i udostępniane są poddawane identycznemu przekształceniu. Pamiętaj, że od wersji TensorFlow 2.6 ten interfejs API jest stabilny. Jeśli używasz starszej wersji TensorFlow, musisz zaimportować symbol eksperymentu.

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 interfejs Compute Engine API

Przejdź do Compute Engine i wybierz opcję Włącz, jeśli nie jest jeszcze włączona.

Krok 2. 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 3. Utwórz instancję Vertex AI Workbench

W konsoli Cloud w sekcji Vertex AI kliknij Workbench:

Menu Vertex AI

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

Notebook_api

Po włączeniu kliknij ZARZĄDZANE NOTATKI:

Notebooks_UI

Następnie wybierz NOWY NOTATNIK.

new_notebook

Nadaj notatnikowi nazwę i w sekcji Permission (Uprawnienia) wybierz Service account (Konto usługi).

service_account

Kliknij Ustawienia zaawansowane.

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

enable_terminal

Pozostałe ustawienia zaawansowane możesz pozostawić bez zmian.

Następnie kliknij Utwórz.

Po utworzeniu instancji kliknij OTWÓRZ JUPYTERLAB.

enable_terminal

5. Przeglądanie zbioru danych w BigQuery

W instancji Vertex AI Workbench przejdź na lewą stronę i kliknij łącznik BigQuery w notatnikach.

Oprogramowanie sprzęgające BQ

Łącznik BigQuery umożliwia łatwe przeglądanie zbiorów danych BigQuery i wysyłanie do nich zapytań. Oprócz dowolnych zbiorów danych w projekcie, możesz je przeglądać, klikając przycisk Dodaj projekt.

przypiąć

W tym module użyjesz danych z publicznych zbiorów danych BigQuery. Przewiń w dół, aż znajdziesz zbiór danych london_bicycles. Ten zbiór danych zawiera 2 tabele: cycle_hirecycle_stations. Przyjrzyjmy się bliżej każdemu z nich.

london_bike_ds

Najpierw kliknij dwukrotnie tabelę cycle_hire. Tabela otworzy się na nowej karcie ze schematem tabeli oraz metadanymi, takimi jak liczba wierszy i rozmiar.

cycle_hire_ds

Jeśli klikniesz kartę Podgląd, zobaczysz próbkę danych. Wykonajmy proste zapytanie, aby sprawdzić, jakie są popularne podróże. Najpierw kliknij przycisk Utwórz zapytanie do tabeli.

cycle_hire_preview_ds

Następnie wklej ten kod do edytora SQL i kliknij Prześlij zapytanie.

SELECT
  start_station_name,
  end_station_name,
  IF(start_station_name = end_station_name,
    TRUE,
    FALSE) same_station,
  AVG(duration) AS avg_duration,
  COUNT(*) AS total_rides
FROM
  `bigquery-public-data.london_bicycles.cycle_hire`
GROUP BY
  start_station_name,
  end_station_name,
  same_station
ORDER BY
  total_rides DESC

W wynikach zapytania zobaczysz, że najpopularniejsze były wycieczki rowerowe do i ze stacji Hyde Park Corner.

journey_query_results

Następnie kliknij dwukrotnie tabelę cycle_stations, która zawiera informacje o każdej stacji.

Chcemy połączyć tabele cycle_hirecycle_stations. Tabela cycle_stations zawiera współrzędne geograficzne (lat/lon) każdej stacji. Na podstawie tych informacji oszacujesz odległość pokonaną podczas każdej podróży rowerowej, obliczając odległość między stacjami początkowymi i końcowymi.

Do wykonania tego obliczenia użyjesz funkcji geograficznych BigQuery. W szczególności musisz przekonwertować każdy ciąg szerokości i długości geograficznej na ST_GEOGPOINT i użyć funkcji ST_DISTANCE do obliczenia w metrach odległości między dwoma punktami w linii prostej. Użyjesz tej wartości jako przybliżonej odległości przebytej w każdej podróży rowerowej.

Skopiuj poniższe zapytanie do edytora SQL i kliknij Wyślij zapytanie. Zwróć uwagę, że w warunku JOIN są trzy tabele, ponieważ musimy złączyć tabelę stacji dwukrotnie, aby uzyskać szerokość i długość geograficzną zarówno stacji początkowej, jak i stacji końcowej cyklu.

WITH staging AS (
    SELECT
        STRUCT(
            start_stn.name,
            ST_GEOGPOINT(start_stn.longitude, start_stn.latitude) AS POINT,
            start_stn.docks_count,
            start_stn.install_date
        ) AS starting,
        STRUCT(
            end_stn.name,
            ST_GEOGPOINT(end_stn.longitude, end_stn.latitude) AS point,
            end_stn.docks_count,
            end_stn.install_date
        ) AS ending,
        STRUCT(
            rental_id,
            bike_id,
            duration, --seconds
            ST_DISTANCE(
                ST_GEOGPOINT(start_stn.longitude, start_stn.latitude),
                ST_GEOGPOINT(end_stn.longitude, end_stn.latitude)
            ) AS distance, --meters
            start_date,
            end_date
        ) AS bike
        FROM `bigquery-public-data.london_bicycles.cycle_stations` AS start_stn
        LEFT JOIN `bigquery-public-data.london_bicycles.cycle_hire` as b
        ON start_stn.id = b.start_station_id
        LEFT JOIN `bigquery-public-data.london_bicycles.cycle_stations` AS end_stn
        ON end_stn.id = b.end_station_id
        LIMIT 700000)

SELECT * from STAGING

6. Trenowanie modelu ML na jądrze TensorFlow

Vertex AI Workbench ma warstwę zgodności z obliczeniami, która umożliwia uruchamianie jąder dla TensorFlow, PySpark, R itp. w ramach jednego notatnika. W tym module utworzysz notatnika z wykorzystaniem jądra TensorFlow.

Tworzenie ramki DataFrame

Po wykonaniu zapytania kliknij Kopiuj kod dla DataFrame. Dzięki temu możesz wkleić kod Pythona do notatnika, który łączy się z klientem BigQuery i wyodrębnia te dane jako DataFrame w pandas.

copy_for_df

Następnie wróć do Menu z aplikacjami i utwórz notatnik TensorFlow 2.

tf_kernel

W pierwszej komórce notatnika wklej kod skopiowany z Edytora zapytań. Powinien wyglądać mniej więcej tak:

# The following two lines are only necessary to run once.
# Comment out otherwise for speed-up.
from google.cloud.bigquery import Client, QueryJobConfig
client = Client()

query = """WITH staging AS (
    SELECT
        STRUCT(
            start_stn.name,
            ST_GEOGPOINT(start_stn.longitude, start_stn.latitude) AS POINT,
            start_stn.docks_count,
            start_stn.install_date
        ) AS starting,
        STRUCT(
            end_stn.name,
            ST_GEOGPOINT(end_stn.longitude, end_stn.latitude) AS point,
            end_stn.docks_count,
            end_stn.install_date
        ) AS ending,
        STRUCT(
            rental_id,
            bike_id,
            duration, --seconds
            ST_DISTANCE(
                ST_GEOGPOINT(start_stn.longitude, start_stn.latitude),
                ST_GEOGPOINT(end_stn.longitude, end_stn.latitude)
            ) AS distance, --meters
            start_date,
            end_date
        ) AS bike
        FROM `bigquery-public-data.london_bicycles.cycle_stations` AS start_stn
        LEFT JOIN `bigquery-public-data.london_bicycles.cycle_hire` as b 
        ON start_stn.id = b.start_station_id
        LEFT JOIN `bigquery-public-data.london_bicycles.cycle_stations` AS end_stn
        ON end_stn.id = b.end_station_id
        LIMIT 700000)

SELECT * from STAGING"""
job = client.query(query)
df = job.to_dataframe()

Na potrzeby tego modułu ograniczamy zbiór danych do 700 000, aby skrócić czas trenowania. Możesz jednak zmodyfikować zapytanie i eksperymentować z całym zbiorem danych.

Następnie zaimportuj potrzebne biblioteki.

from datetime import datetime
import pandas as pd
import tensorflow as tf

Uruchom podany niżej kod, aby utworzyć skrócony dataframe zawierający tylko kolumny potrzebne do wykonania części ćwiczenia dotyczącej uczenia maszynowego.

values = df['bike'].values
duration = list(map(lambda a: a['duration'], values))
distance = list(map(lambda a: a['distance'], values))
dates = list(map(lambda a: a['start_date'], values))
data = pd.DataFrame(data={'duration': duration, 'distance': distance, 'start_date':dates})
data = data.dropna()

Kolumna start_date to Python datetime. Zamiast używać w modelu bezpośrednio atrybutu datetime, utworzysz 2 nowe cechy, które wskazują dzień tygodnia i godzinę, w której miała miejsce przejażdżka rowerem.

data['weekday'] = data['start_date'].apply(lambda a: a.weekday())
data['hour'] = data['start_date'].apply(lambda a: a.time().hour)
data = data.drop(columns=['start_date'])

Na koniec przekonwertuj kolumnę czasu trwania z sekund na minuty, aby była bardziej zrozumiała.

data['duration'] = data['duration'].apply(lambda x:float(x / 60))

Sprawdź kilka pierwszych wierszy sformatowanego DataFrame. W przypadku każdej podróży rowerowej masz teraz dane o dniu tygodnia i godzinie, w której miała ona miejsce, a także o przejechanej odległości. Na podstawie tych informacji możesz spróbować przewidzieć, ile czasu zajęła podróż.

data.head()

data_head

Zanim utworzysz i trenować model, musisz podzielić dane na zestawy treningowy i weryfikacyjny.

# Use 80/20 train/eval split
train_size = int(len(data) * .8)
print ("Train size: %d" % train_size)
print ("Evaluation size: %d" % (len(data) - train_size))

# Split data into train and test sets
train_data = data[:train_size]
val_data = data[train_size:]

Tworzenie modelu TensorFlow

Utwórz model TensorFlow za pomocą interfejsu Keras Functional API. Do wstępnego przetwarzania danych wejściowych użyjesz interfejsu Keras preprocessing layers API.

Podana niżej funkcja pomocnicza utworzy tf.data.Dataset z ramki danych pandas.

def df_to_dataset(dataframe, label, shuffle=True, batch_size=32):
  dataframe = dataframe.copy()
  labels = dataframe.pop(label)
  ds = tf.data.Dataset.from_tensor_slices((dict(dataframe), labels))
  if shuffle:
    ds = ds.shuffle(buffer_size=len(dataframe))
  ds = ds.batch(batch_size)
  ds = ds.prefetch(batch_size)
  return ds

Użyj tej funkcji, aby utworzyć 2 funkcje tf.data.Dataset: jedną do trenowania, a drugą do walidacji. Mogą się wyświetlić ostrzeżenia, ale możesz je zignorować.

train_dataset = df_to_dataset(train_data, 'duration')
validation_dataset = df_to_dataset(val_data, 'duration')

W modelu użyjesz tych warstw wstępnej obróbki:

  • Warstwa normalizacji: wykonuje normalizację cech wejściowych z uwzględnieniem poszczególnych cech.
  • Warstwa wyszukiwania liczb całkowitych: zamienia wartości liczbowe w wartości liczbowe indeksów.
  • Warstwa kodowania kategorii: zamienia atrybuty typu kategoria o typie liczbowym w gęste reprezentacje typu one-hot, multi-hot lub TF-IDF.

Pamiętaj, że tych warstw nie można trenować. Zamiast tego ustawiasz stan warstwy przetwarzania wstępnego, udostępniając ją danych treningowych za pomocą metody adapt().

Poniższa funkcja utworzy warstwę normalizacji, której możesz użyć w funkcji odległości. Stan ustawisz przed dopasowaniem modelu, używając metody adapt() na danych treningowych. Spowoduje to obliczenie średniej i wariacji, które zostaną użyte do normalizacji. Później, gdy przekażesz do modelu zbiór danych do weryfikacji, ta sama średnia i wariancja obliczone na podstawie danych treningowych zostaną użyte do skalowania danych do weryfikacji.

def get_normalization_layer(name, dataset):
  # Create a Normalization layer for our feature.
  normalizer = tf.keras.layers.Normalization(axis=None)

  # Prepare a Dataset that only yields our feature.
  feature_ds = dataset.map(lambda x, y: x[name])

  # Learn the statistics of the data.
  normalizer.adapt(feature_ds)

  return normalizer

Podobnie, podana niżej funkcja tworzy kodowanie kategorii, którego użyjesz w przypadku funkcji godziny i dnia tygodnia.

def get_category_encoding_layer(name, dataset, dtype, max_tokens=None):
  index = tf.keras.layers.IntegerLookup(max_tokens=max_tokens)

  # Prepare a Dataset that only yields our feature
  feature_ds = dataset.map(lambda x, y: x[name])

  # Learn the set of possible values and assign them a fixed integer index.
  index.adapt(feature_ds)

  # Create a Discretization for our integer indices.
  encoder = tf.keras.layers.CategoryEncoding(num_tokens=index.vocabulary_size())

  # Apply one-hot encoding to our indices. The lambda function captures the
  # layer so we can use them, or include them in the functional model later.
  return lambda feature: encoder(index(feature))

Następnie utwórz część modelu, która jest wstępnie przetwarzana. Najpierw utwórz warstwę tf.keras.Input dla każdej z funkcji.

# Create a Keras input layer for each feature
numeric_col = tf.keras.Input(shape=(1,), name='distance')
hour_col = tf.keras.Input(shape=(1,), name='hour', dtype='int64')
weekday_col = tf.keras.Input(shape=(1,), name='weekday', dtype='int64')

Następnie utwórz warstwy normalizacji i kodowania kategorii, przechowując je na liście.

all_inputs = []
encoded_features = []

# Pass 'distance' input to normalization layer
normalization_layer = get_normalization_layer('distance', train_dataset)
encoded_numeric_col = normalization_layer(numeric_col)
all_inputs.append(numeric_col)
encoded_features.append(encoded_numeric_col)

# Pass 'hour' input to category encoding layer
encoding_layer = get_category_encoding_layer('hour', train_dataset, dtype='int64')
encoded_hour_col = encoding_layer(hour_col)
all_inputs.append(hour_col)
encoded_features.append(encoded_hour_col)

# Pass 'weekday' input to category encoding layer
encoding_layer = get_category_encoding_layer('weekday', train_dataset, dtype='int64')
encoded_weekday_col = encoding_layer(weekday_col)
all_inputs.append(weekday_col)
encoded_features.append(encoded_weekday_col)

Po zdefiniowaniu warstw wstępnego przetwarzania możesz zdefiniować resztę modelu. Skonkatenujesz wszystkie wejściowe cechy i przekażesz je do gęstej warstwy. Warstwą wyjściową jest pojedyncza jednostka, ponieważ jest to problem regresji.

all_features = tf.keras.layers.concatenate(encoded_features)
x = tf.keras.layers.Dense(64, activation="relu")(all_features)
output = tf.keras.layers.Dense(1)(x)
model = tf.keras.Model(all_inputs, output)

Na koniec skompiluj model.

model.compile(optimizer = tf.keras.optimizers.Adam(0.001),
              loss='mean_squared_logarithmic_error')

Po zdefiniowaniu modelu możesz zwizualizować architekturę

tf.keras.utils.plot_model(model, show_shapes=True, rankdir="LR")

keras_model

Warto zauważyć, że w przypadku tego prostego zbioru danych ten model jest dość skomplikowany. Jest on przeznaczony do celów demonstracyjnych.

Przeprowadź 1 epokę, aby sprawdzić, czy kod działa.

model.fit(train_dataset, validation_data = validation_dataset, epochs = 1)

Trenowanie modelu z wykorzystaniem GPU

Następnie trenuj model przez dłuższy czas i użyj przełącznika sprzętowego, aby przyspieszyć trenowanie. Vertex AI Workbench umożliwia zmianę sprzętu bez wyłączania instancji. Dodając GPU tylko wtedy, gdy jest to potrzebne, możesz obniżyć koszty.

Aby zmienić profil sprzętowy, w prawym górnym rogu kliknij typ maszyny i wybierz Modyfikuj sprzęt.

modify_hardware

Wybierz Podłącz GPU i wybierz procesor graficzny NVIDIA T4 Tensor Core.

add_gpu

Skonfigurowanie sprzętu potrwa około 5 minut. Po zakończeniu procesu trenowania modelu potrwa to jeszcze chwilę. Jak widać, każda epoka zajmuje teraz mniej czasu.

model.fit(train_dataset, validation_data = validation_dataset, epochs = 5)

🎉 Gratulacje! 🎉

Dowiedz się, jak używać Vertex AI Workbench do:

  • Przeglądaj dane w BigQuery
  • Wczytywanie danych do Pythona za pomocą klienta BigQuery
  • Wytrenuj model TensorFlow z użyciem warstw przetwarzania wstępnego Keras i GPU

Więcej informacji o różnych elementach Vertex AI znajdziesz w dokumentacji.

7. Czyszczenie

Notebook został skonfigurowany tak, aby wyłączał się po 60 minutach bezczynności, więc nie musisz się martwić zamykaniem instancji. Jeśli chcesz ręcznie wyłączyć instancję, w konsoli Vertex AI Workbench kliknij przycisk Zatrzymaj. Jeśli chcesz całkowicie usunąć zeszyt, kliknij przycisk Usuń.

usuń