Obtén predicciones de un modelo de imágenes de TensorFlow previamente entrenado en Vertex AI

1. Descripción general

En este lab, usarás Vertex AI para obtener predicciones a partir de un modelo de clasificación de imágenes previamente entrenado.

Qué aprenderá

Aprenderás a hacer lo siguiente:

  • Importa un modelo de TensorFlow al Vertex AI Model Registry
  • Obtén predicciones en línea
  • Actualiza una función de TensorFlow Serving

El costo total de la ejecución de este lab en Google Cloud es de aproximadamente $1.

2. Introducción a Vertex AI

En este lab, se utiliza la oferta de productos de IA más reciente de Google Cloud. Vertex AI integra las ofertas de AA de Google Cloud en una experiencia de desarrollo fluida. Anteriormente, se podía acceder a los modelos personalizados y a los entrenados con AutoML mediante servicios independientes. La nueva oferta combina ambos en una sola API, junto con otros productos nuevos. También puedes migrar proyectos existentes a Vertex AI.

Vertex AI incluye muchos productos distintos para respaldar flujos de trabajo de AA de extremo a extremo. Este lab se enfocará en los productos que se destacan a continuación: Prediction y Workbench

Descripción general del producto Vertex

3. Descripción general del caso de uso

En este lab, aprenderás a tomar un modelo previamente entrenado de TensorFlow Hub y, luego, implementarlo en Vertex AI. TensorFlow Hub es un repositorio de modelos entrenados para una variedad de dominios de problemas, como incorporaciones, generación de texto, voz a texto, segmentación de imágenes y mucho más.

El ejemplo que se usa en este lab es un modelo de clasificación de imágenes MobileNet V1 previamente entrenado en el conjunto de datos de ImageNet. Cuando aprovechas los modelos listos para usar de TensorFlow Hub o de otros repositorios de aprendizaje profundo similares, puedes implementar modelos de AA de alta calidad para varias tareas de predicción sin tener que preocuparte por el entrenamiento de modelos.

4. Configura el entorno

Para ejecutar este codelab, necesitarás un proyecto de Google Cloud Platform que tenga habilitada la facturación. Para crear un proyecto, sigue estas instrucciones.

Paso 1: Habilita la API de Compute Engine

Ve a Compute Engine y selecciona Habilitar (si aún no está habilitada).

Paso 2: Habilita la API de Vertex AI

Navegue hasta la sección de Vertex AI en la consola de Cloud y haga clic en Habilitar API de Vertex AI.

Panel de Vertex AI

Paso 3: Crea una instancia de Vertex AI Workbench

En la sección Vertex AI de Cloud Console, haz clic en Workbench:

Menú Vertex AI

Habilita la API de Notebooks si aún no está habilitada.

Notebook_api

Una vez habilitada, haz clic en NOTEBOOKS ADMINISTRADOS (MANAGED NOTEBOOKS):

Notebooks_UI

Luego, selecciona NUEVO NOTEBOOK (NEW NOTEBOOK).

new_notebook

Asígnale un nombre al notebook y en Permiso (Permission), selecciona Cuenta de servicio (Service account).

create_notebook

Selecciona Configuración avanzada.

En Seguridad (Security), selecciona la opción “Habilitar terminal” (Enable terminal) si aún no está habilitada.

enable_terminal

Puedes dejar el resto de la configuración avanzada tal como está.

Luego, haz clic en Crear. La instancia tardará algunos minutos en aprovisionarse.

Una vez que se cree la instancia, selecciona ABRIR JUPYTERLAB (OPEN JUPYTERLAB).

open_jupyterlab

5. Registrar modelo

Paso 1: Sube el modelo a Cloud Storage

Haz clic en este vínculo para ir a la página de TensorFlow Hub del modelo MobileNet V1 entrenado con el conjunto de datos ImagNet.

Selecciona Download para descargar los artefactos del modelo guardados.

download_model

En la sección Cloud Storage de la consola de Google Cloud, selecciona CREAR.

create_bucket

Asigna un nombre a tu bucket y selecciona us-central1 como la región. Luego, haz clic en CREAR.

specify_bucket

Sube el modelo de TensorFlow Hub que descargaste al bucket. Primero, asegúrate de descomprimir el archivo TAR.

gcs_model

Tu bucket debería verse de la siguiente manera:

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

Paso 2: Importa el modelo al registro

Navega a la sección Registro de modelos de Vertex AI en la consola de Cloud.

model_registry

Selecciona IMPORTAR (IMPORT).

Selecciona Importar como modelo nuevo (Import as new model) y, luego, asígnale un nombre al modelo.

name_and_region

En Configuración del modelo, especifica el contenedor de TensorFlow compilado previamente más reciente. Luego, selecciona la ruta de acceso en Cloud Storage en la que almacenaste los artefactos del modelo.

select_container

Puedes omitir la sección Explicabilidad.

Luego, selecciona IMPORTAR.

Una vez que lo hagas, lo verás en el registro de modelos.

imported_model

6. Implementar el modelo

En el registro de modelos, selecciona los tres puntos que se encuentran a la derecha del modelo y haz clic en Implementar en el extremo (Deploy to endpoint).

deploy_model

En Define tu extremo, selecciona Crear extremo nuevo y, luego, asígnale un nombre.

En Configuración del modelo, establece la Cantidad máxima de nodos de procesamiento en 1 y el tipo de máquina en n1-standard-2; luego, deja el resto de la configuración tal como está. Luego, haz clic en IMPLEMENTAR.

endpoint_settings

Cuando se implementa, su estado cambiará a Implementado en Vertex AI.

deploy_status

7. Obtén predicciones

Abre el notebook de Workbench que creaste en los pasos de configuración. En el selector, crea un nuevo notebook de TensorFlow 2.

tf_nb

Ejecuta la siguiente celda para importar las bibliotecas necesarias.

from google.cloud import aiplatform

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

El modelo de MobileNet que descargaste de TensorFlow Hub se entrenó en el conjunto de datos de ImageNet. El resultado del modelo MobileNet es un número que corresponde a una etiqueta de clase en el conjunto de datos de ImageNet. Para traducir ese número en una etiqueta de cadena, deberás descargar las etiquetas de imagen.

# 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())

Para llegar al extremo, tienes que definir el recurso de extremo. Asegúrate de reemplazar {PROJECT_NUMBER} y {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}")

Puedes encontrar el número de proyecto en la página principal de la consola.

project_number

Y el ID de extremo en la sección Extremos de Vertex AI.

endpoint_id

A continuación, probarás tu extremo.

Primero, descarga la siguiente imagen y súbela a tu instancia.

test_image

Abre la imagen con PIL. Luego, cambia el tamaño y escala por 255. Ten en cuenta que el tamaño de imagen que espera el modelo se puede encontrar en la página de TensorFlow Hub del modelo.

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

A continuación, convierte los datos de NumPy en una lista para que se puedan enviar en el cuerpo de la solicitud HTTP.

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

Por último, realiza una llamada de predicción al extremo y, luego, busca la etiqueta de cadena correspondiente.

# 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. [Opcional] Usa TF Serving para optimizar las predicciones

Para ver ejemplos más realistas, te recomendamos que envíes la imagen directamente al extremo, en lugar de cargarla primero en NumPy. Esto es más eficiente, pero deberás modificar la función de entrega del modelo de TensorFlow. Esta modificación es necesaria para convertir los datos de entrada al formato que espera tu modelo.

Paso 1: Modifica la función de publicación

Abre un nuevo notebook de TensorFlow y, luego, importa las bibliotecas necesarias.

from google.cloud import aiplatform

import tensorflow as tf

En lugar de descargar los artefactos del modelo guardado, esta vez cargarás el modelo en TensorFlow con hub.KerasLayer, que une un modelo guardado de TensorFlow como una capa de Keras. Para crear el modelo, puedes usar la API secuencial de Keras con el modelo de TF Hub descargado como una capa y especificar la forma de la entrada para el modelo.

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])

Define el URI para el bucket que creaste anteriormente.

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

Cuando envías una solicitud a un servidor de predicción en línea, un servidor HTTP recibe la solicitud. El servidor HTTP extrae la solicitud de predicción del cuerpo del contenido de la solicitud HTTP. La solicitud de predicción extraída se reenvía a la función de publicación. Para los contenedores de predicción compilados con anterioridad de Vertex AI, el contenido de la solicitud se pasa a la función de entrega como un tf.string.

Para pasar imágenes al servicio de predicción, deberás codificar los bytes de imagen comprimidos en base 64, lo que protege el contenido de modificaciones mientras se transmiten datos binarios a través de la red.

Dado que el modelo implementado espera que los datos de entrada sean bytes sin procesar (sin comprimir), debes asegurarte de que los datos codificados en Base 64 se vuelvan a convertir en bytes sin procesar (p. ej., JPEG) y, luego, se procesen previamente para que coincidan con los requisitos de entrada del modelo, antes de pasarlos como entrada al modelo implementado.

Para resolver este problema, debes definir una función de publicación (serving_fn) y adjuntarla al modelo como un paso de procesamiento previo. Agregas un decorador @tf.function para que la función de publicación se combine con el modelo subyacente (en lugar de hacerlo en una CPU).

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})

Cuando envías datos para la predicción como un paquete de solicitud HTTP, los datos de la imagen están codificados en base64, pero el modelo de TensorFlow recibe una entrada de NumPy. Tu función de publicación realizará la conversión de base64 a un array numpy.

Cuando realizas una solicitud de predicción, debes enrutar la solicitud a la función de entrega en lugar del modelo, por lo que debes conocer el nombre de la capa de entrada de la función de entrega. Podemos obtener este nombre de la firma de la función de publicación.

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)

Paso 2: Importa al registro y, luego, realiza la implementación

En las secciones anteriores, viste cómo importar un modelo a Vertex AI Model Registry a través de la IU. En esta sección, verás una forma alternativa de usar el SDK. Ten en cuenta que, si lo prefieres, puedes usar la IU aquí.

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)

También puedes implementar el modelo con el SDK, en lugar de la IU.

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,
   )

Paso 3: Prueba el modelo

Ahora puedes probar el extremo. Como modificamos la función de publicación, esta vez puedes enviar la imagen directamente (codificada en base64) en la solicitud en lugar de cargarla primero en NumPy. Esto también te permitirá enviar imágenes más grandes sin alcanzar el límite de tamaño de las predicciones de Vertex AI.

Vuelve a descargar las etiquetas de la imagen

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())

Aplica la codificación en Base64 a la imagen.

import base64

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

Realiza una llamada de predicción y especifica el nombre de la capa de entrada de la función de entrega que definimos antes en la variable 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}")

🎉 ¡Felicitaciones! 🎉

Aprendiste a usar Vertex AI para hacer lo siguiente:

  • Aloja y, luego, implementa un modelo previamente entrenado

Para obtener más información sobre las distintas partes de Vertex, consulte la documentación.

9. Limpieza

Debido a que los notebooks administrados de Vertex AI Workbench tienen una función de cierre por inactividad, no necesitas preocuparte por cerrar la instancia. Si quieres cerrar la instancia de forma manual, haz clic en el botón Detener (Stop) en la sección Vertex AI Workbench de la consola. Si quieres borrar el notebook por completo, haz clic en el botón Borrar (Delete).

Detener instancias

Para borrar el bucket de almacenamiento, en el menú de navegación de la consola de Cloud, navega a Almacenamiento, selecciona tu bucket y haz clic en Borrar (Delete):

Borrar almacenamiento