Uzyskiwanie prognoz z wytrenowanego modelu obrazów TensorFlow w Vertex AI

1. Przegląd

W tym laboratorium dowiesz się, jak za pomocą Vertex AI uzyskiwać prognozy z wytrenowanego modelu klasyfikacji obrazów.

Czego się dowiesz

Poznasz takie zagadnienia jak:

  • Importowanie modelu TensorFlow do rejestru modeli Vertex AI
  • Uzyskiwanie prognoz online
  • Aktualizowanie funkcji udostępniania TensorFlow

Całkowity koszt ukończenia tego laboratorium w Google Cloud wynosi około 1 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.

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 wyróżnionych poniżej usługach: PrognozyWorkbench.

Omówienie usługi Vertex

3. Omówienie przypadku użycia

W tym laboratorium dowiesz się, jak pobrać wytrenowany model z TensorFlow Hub i wdrożyć go w Vertex AI. TensorFlow Hub to repozytorium wytrenowanych modeli do różnych zastosowań, takich jak wektory dystrybucyjne, generowanie tekstu, zamiana mowy na tekst, segmentacja obrazów i inne.

W tym module użyjemy modelu klasyfikacji obrazów MobileNet V1, który został wstępnie wytrenowany na zbiorze danych ImageNet. Korzystając z gotowych modeli z TensorFlow Hub lub innych podobnych repozytoriów deep learning, możesz wdrażać wysokiej jakości modele ML do wielu zadań prognozowania bez konieczności trenowania modeli.

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 Vertex AI API

Otwórz sekcję Vertex AI w konsoli Cloud i kliknij Włącz interfejs Vertex AI API.

Panel Vertex AI

Krok 3. Tworzenie instancji Vertex AI Workbench

W sekcji Vertex AI w konsoli Cloud 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 NOTATNIKI:

Notebooks_UI

Następnie wybierz NOWY NOTEBOOK.

new_notebook

Nadaj nazwę notatnikowi, a w sekcji Uprawnienia wybierz Konto usługi.

create_notebook

Kliknij Ustawienia zaawansowane.

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

enable_terminal

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

Następnie kliknij Utwórz. Udostępnienie instancji zajmie kilka minut.

Po utworzeniu instancji kliknij OTWÓRZ JUPYTERLAB.

open_jupyterlab

5. Zarejestruj model

Krok 1. Prześlij model do Cloud Storage

Kliknij ten link, aby przejść na stronę TensorFlow Hub z modelem MobileNet V1 wytrenowanym na zbiorze danych ImageNet.

Kliknij Pobierz, aby pobrać zapisane artefakty modelu.

download_model

W sekcji Cloud Storage w konsoli Google Cloud kliknij UTWÓRZ.

create_bucket

Nadaj zasobnikowi nazwę i wybierz region us-central1. Następnie kliknij UTWÓRZ.

specify_bucket

Prześlij do zasobnika pobrany model z TensorFlow Hub. Najpierw rozpakuj plik.

gcs_model

Twój zasobnik powinien wyglądać mniej więcej tak:

imagenet_mobilenet_v1_050_128_classification_5/
  saved_model.pb
  variables/
    variables.data-00000-of-00001
    variables.index

Krok 2. Importowanie modelu do rejestru

W konsoli Cloud otwórz sekcję Vertex AI Rejestr modeli.

model_registry

Kliknij IMPORT.

Kliknij Zaimportuj jako nowy model, a potem wpisz nazwę modelu.

name_and_region

W sekcji Ustawienia modelu podaj najnowszy gotowy kontener TensorFlow. Następnie wybierz ścieżkę w Cloud Storage, w której są przechowywane artefakty modelu.

select_container

Możesz pominąć sekcję Wyjaśnienie.

Następnie kliknij IMPORT.

Po zaimportowaniu model pojawi się w rejestrze modeli.

imported_model

6. Wdrażanie modelu

W rejestrze modeli kliknij 3 kropki po prawej stronie modelu i wybierz Wdróż w punkcie końcowym.

deploy_model

W sekcji Zdefiniuj punkt końcowy wybierz Utwórz nowy punkt końcowy, a następnie nadaj mu nazwę.

W sekcji Ustawienia modelu ustaw Maksymalną liczbę węzłów obliczeniowych na 1, a typ maszyny na n1-standard-2. Pozostałe ustawienia pozostaw bez zmian. Następnie kliknij WDRAŻAJ.

endpoint_settings

Po wdrożeniu stan wdrożenia zmieni się na Wdrożono w Vertex AI.

deploy_status

7. Pobieraj prognozy

Otwórz notatnik Workbench utworzony w krokach konfiguracji. W programie uruchamiającym utwórz nowy notatnik TensorFlow 2.

tf_nb

Uruchom poniższą komórkę, aby zaimportować niezbędne biblioteki.

from google.cloud import aiplatform

import tensorflow as tf
import numpy as np
from PIL import Image

Model MobileNet pobrany z TensorFlow Hub został wytrenowany na zbiorze danych ImageNet. Dane wyjściowe modelu MobileNet to liczba odpowiadająca etykiecie klasy w zbiorze danych ImageNet. Aby przekształcić tę liczbę w etykietę tekstową, musisz pobrać etykiety obrazów.

# Download image labels

labels_path = tf.keras.utils.get_file('ImageNetLabels.txt','https://storage.googleapis.com/download.tensorflow.org/data/ImageNetLabels.txt')
imagenet_labels = np.array(open(labels_path).read().splitlines())

Aby dotrzeć do punktu końcowego, musisz zdefiniować zasób punktu końcowego. Pamiętaj, aby zastąpić zmienne {PROJECT_NUMBER}{ENDPOINT_ID}.

PROJECT_NUMBER = "{PROJECT_NUMBER}"
ENDPOINT_ID = "{ENDPOINT_ID}"

endpoint = aiplatform.Endpoint(
    endpoint_name=f"projects/{PROJECT_NUMBER}/locations/us-central1/endpoints/{ENDPOINT_ID}")

Numer projektu znajdziesz na stronie głównej konsoli.

project_number

oraz identyfikator punktu końcowego w sekcji Punkty końcowe w Vertex AI.

endpoint_id

Następnie przetestuj punkt końcowy.

Najpierw pobierz ten obraz i prześlij go do instancji.

test_image

Otwórz obraz za pomocą biblioteki PIL. Następnie zmień rozmiar i skalę o 255. Rozmiar obrazu oczekiwany przez model znajdziesz na stronie modelu w TensorFlow Hub.

IMAGE_PATH = "test-image.jpg"
IMAGE_SIZE = (128, 128)

im = Image.open(IMAGE_PATH)
im = im.resize(IMAGE_SIZE
im = np.array(im)/255.0

Następnie przekonwertuj dane NumPy na listę, aby można było je wysłać w treści żądania HTTP.

x_test = im.astype(np.float32).tolist()

Na koniec wywołaj punkt końcowy, aby uzyskać prognozę, a potem wyszukaj odpowiednią etykietę tekstową.

# make prediction request
result = endpoint.predict(instances=[x_test]).predictions

# post process result
predicted_class = tf.math.argmax(result[0], axis=-1)
string_label = imagenet_labels[predicted_class]

print(f"label ID: {predicted_class}")
print(f"string label: {string_label}")

8. [Opcjonalnie] Używanie TF Serving do optymalizacji prognoz

Aby uzyskać bardziej realistyczne przykłady, prawdopodobnie lepiej będzie wysłać sam obraz bezpośrednio do punktu końcowego, zamiast najpierw wczytywać go do NumPy. Jest to bardziej wydajne, ale musisz zmodyfikować funkcję obsługi modelu TensorFlow. Ta modyfikacja jest potrzebna do przekształcenia danych wejściowych w format oczekiwany przez model.

Krok 1. Zmodyfikuj funkcję wyświetlania

Otwórz nowy notatnik TensorFlow i zaimportuj niezbędne biblioteki.

from google.cloud import aiplatform

import tensorflow as tf

Zamiast pobierać zapisane artefakty modelu, tym razem załadujesz model do TensorFlow za pomocą funkcji hub.KerasLayer, która opakowuje model TensorFlow SavedModel jako warstwę Keras. Aby utworzyć model, możesz użyć interfejsu Keras Sequential API z pobranym modelem TF Hub jako warstwą i określić kształt danych wejściowych modelu.

tfhub_model = tf.keras.Sequential(
    [hub.KerasLayer("https://tfhub.dev/google/imagenet/mobilenet_v1_050_128/classification/5")]
)
tfhub_model.build([None, 128, 128, 3])

Określ URI utworzonego wcześniej zasobnika.

BUCKET_URI = "gs://{YOUR_BUCKET}"
MODEL_DIR = BUCKET_URI + "/bytes_model"

Gdy wysyłasz żądanie do serwera prognozowania online, jest ono odbierane przez serwer HTTP. Serwer HTTP wyodrębnia żądanie prognozy z treści żądania HTTP. Wyodrębnione żądanie prognozy jest przekazywane do funkcji obsługi. W przypadku gotowych kontenerów prognozowania Vertex AI treść żądania jest przekazywana do funkcji obsługi jako tf.string.

Aby przekazać obrazy do usługi prognozowania, musisz zakodować skompresowane bajty obrazu w formacie Base64, co zabezpiecza treść przed modyfikacją podczas przesyłania danych binarnych przez sieć.

Wdrożony model oczekuje danych wejściowych w postaci surowych (nieskompresowanych) bajtów, dlatego musisz zadbać o to, aby dane zakodowane w formacie Base64 zostały przekonwertowane z powrotem na surowe bajty (np. JPEG), a następnie wstępnie przetworzone w taki sposób, aby spełniały wymagania modelu. Dopiero wtedy można je przekazać jako dane wejściowe do wdrożonego modelu.

Aby rozwiązać ten problem, zdefiniuj funkcję udostępniania (serving_fn) i dołącz ją do modelu jako krok przetwarzania wstępnego. Dodajesz dekorator @tf.function, aby funkcja udostępniania była połączona z modelem bazowym (zamiast z procesorem).

CONCRETE_INPUT = "numpy_inputs"


def _preprocess(bytes_input):
    decoded = tf.io.decode_jpeg(bytes_input, channels=3)
    decoded = tf.image.convert_image_dtype(decoded, tf.float32)
    resized = tf.image.resize(decoded, size=(128, 128))
    return resized


@tf.function(input_signature=[tf.TensorSpec([None], tf.string)])
def preprocess_fn(bytes_inputs):
    decoded_images = tf.map_fn(
        _preprocess, bytes_inputs, dtype=tf.float32, back_prop=False
    )
    return {
        CONCRETE_INPUT: decoded_images
    }  # User needs to make sure the key matches model's input


@tf.function(input_signature=[tf.TensorSpec([None], tf.string)])
def serving_fn(bytes_inputs):
    images = preprocess_fn(bytes_inputs)
    prob = m_call(**images)
    return prob


m_call = tf.function(tfhub_model.call).get_concrete_function(
    [tf.TensorSpec(shape=[None, 128, 128, 3], dtype=tf.float32, name=CONCRETE_INPUT)]
)

tf.saved_model.save(tfhub_model, MODEL_DIR, signatures={"serving_default": serving_fn})

Gdy wysyłasz dane do prognozowania jako pakiet żądania HTTP, dane obrazu są kodowane w formacie Base64, ale model TensorFlow przyjmuje dane wejściowe numpy. Funkcja obsługi będzie konwertować dane z formatu base64 na tablicę NumPy.

W przypadku żądania prognozy musisz kierować je do funkcji obsługującej zamiast do modelu, więc musisz znać nazwę warstwy wejściowej funkcji obsługującej. Możemy uzyskać tę nazwę z sygnatury funkcji obsługującej.

loaded = tf.saved_model.load(MODEL_DIR)

serving_input = list(
    loaded.signatures["serving_default"].structured_input_signature[1].keys()
)[0]
print("Serving function input name:", serving_input)

Krok 2. Zaimportuj do rejestru i wdroż

W poprzednich sekcjach pokazaliśmy, jak zaimportować model do Vertex AI Model Registry za pomocą interfejsu. W tej sekcji znajdziesz alternatywny sposób korzystania z pakietu SDK. Pamiętaj, że jeśli wolisz, możesz nadal korzystać z interfejsu.

model = aiplatform.Model.upload(
    display_name="optimized-model",
    artifact_uri=MODEL_DIR,
    serving_container_image_uri="us-docker.pkg.dev/vertex-ai/prediction/tf2-cpu.2-8:latest",
)

print(model)

Model możesz też wdrożyć za pomocą pakietu SDK zamiast interfejsu.

endpoint = model.deploy(
     deployed_model_display_name='my-bytes-endpoint',
     traffic_split={"0": 100},
     machine_type="n1-standard-4",
     accelerator_count=0,
     min_replica_count=1,
     max_replica_count=1,
   )

Krok 3. Przetestuj model

Teraz możesz przetestować punkt końcowy. Ponieważ zmodyfikowaliśmy funkcję obsługi, tym razem możesz wysłać obraz bezpośrednio (zakodowany w formacie base64) w żądaniu, zamiast najpierw wczytywać go do NumPy. Umożliwi to również wysyłanie większych obrazów bez przekraczania limitu rozmiaru prognoz Vertex AI.

Ponowne pobieranie etykiet obrazów

import numpy as np
labels_path = tf.keras.utils.get_file('ImageNetLabels.txt','https://storage.googleapis.com/download.tensorflow.org/data/ImageNetLabels.txt')
imagenet_labels = np.array(open(labels_path).read().splitlines())

Zakoduj obraz w formacie Base64.

import base64

with open("test-image.jpg", "rb") as f:
    data = f.read()
b64str = base64.b64encode(data).decode("utf-8")

Wywołaj prognozę, podając nazwę warstwy wejściowej funkcji obsługującej, którą zdefiniowaliśmy wcześniej w zmiennej serving_input.

instances = [{serving_input: {"b64": b64str}}]

# Make request
result = endpoint.predict(instances=instances).predictions

# Convert image class to string label
predicted_class = tf.math.argmax(result[0], axis=-1)
string_label = imagenet_labels[predicted_class]

print(f"label ID: {predicted_class}")
print(f"string label: {string_label}")

🎉 Gratulacje! 🎉

Dowiedziałeś się, jak używać Vertex AI do:

  • Hostowanie i wdrażanie wstępnie wytrenowanego modelu

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

9. Czyszczenie

Zarządzane notatniki Vertex AI Workbench mają funkcję wyłączania w przypadku braku aktywności, więc nie musimy się martwić o wyłączenie 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 Storage, w menu nawigacyjnym w konsoli Cloud otwórz Storage, wybierz zasobnik i kliknij Usuń:

Usuń miejsce na dane