Vertex AI: Ajuste de hiperparámetros

1. Descripción general

En este lab, usarás Vertex AI para ejecutar un trabajo de ajuste de hiperparámetros en un modelo de TensorFlow. Si bien en este lab se usa TensorFlow para el código del modelo, los conceptos también se aplican a otros frameworks de AA.

Qué aprenderá

Aprenderás a hacer lo siguiente:

  • Modificar el código de la aplicación de entrenamiento para el ajuste automatizado de hiperparámetros
  • Configurar y, luego, iniciar un trabajo de ajuste de hiperparámetros desde la IU de Vertex AI
  • Configurar y, luego, iniciar un trabajo de ajuste de hiperparámetros con el SDK de Vertex AI para Python

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

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. Para enviarnos comentarios, visita la página de asistencia.

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: Training y Workbench.

Descripción general del producto Vertex

3. Cómo configurar tu 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). La necesitarás para crear la instancia de notebook.

Paso 2: Habilita la API de Container Registry

Navega a Container Registry y selecciona Habilitar si aún no lo has hecho. Deberás usarla con el fin de crear un contenedor para tu trabajo de entrenamiento personalizado.

Paso 3: Habilita la API de Vertex AI

Navega hasta la sección Vertex AI en Cloud Console y haz clic en Habilitar API de Vertex AI (Enable Vertex AI API).

Panel de Vertex AI

Paso 4: 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, luego, haz clic en Configuración avanzada (Advanced settings).

create_notebook

En Configuración avanzada (Advanced settings), activa la opción Habilitar el cierre inactivo (Enable Idle Shutdown) y establece la cantidad de minutos en 60. Esto provocará que el notebook se cierre automáticamente cuando no esté en uso para que no se generen costos innecesarios.

idle_timeout

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 crea la instancia, selecciona Abrir JupyterLab (Open JupyterLab).

open_jupyterlab

La primera vez que uses una instancia nueva, se te solicitará que te autentiques. Sigue los pasos en la IU para hacerlo.

autenticar

4. Aloja en un contenedor el código de entrenamiento de la aplicación

El modelo que entrenarás y ajustarás en este lab es un modelo de clasificación de imágenes entrenado con el conjunto de datos de caballos o humanos de TensorFlow Datasets.

Para enviar este trabajo de ajuste de hiperparámetros a Vertex AI, deberás colocar el código de entrenamiento de la aplicación en un contenedor de Docker y enviar el contenedor a Google Container Registry. Con este enfoque, puedes ajustar los hiperparámetros para un modelo compilado con cualquier framework.

Para comenzar, en el menú Selector (Launcher), abre una ventana de terminal en tu instancia de notebook:

Abrir terminal en el notebook

Crea un directorio nuevo llamado horses_or_humans y ábrelo con el comando cd:

mkdir horses_or_humans
cd horses_or_humans

Paso 1: Crea un Dockerfile

El primer paso para alojar el código en un contenedor es crear un Dockerfile. En él, incluirás todos los comandos necesarios para ejecutar la imagen. Así, se instalarán todas las bibliotecas necesarias, incluida la CloudML Hypertune, y se configurará el punto de entrada para el código de entrenamiento.

En la terminal, crea un Dockerfile vacío:

touch Dockerfile

Abre el Dockerfile y copia lo siguiente:

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

Este Dockerfile usa la imagen de Docker TensorFlow Enterprise 2.7 GPU de los Contenedores de aprendizaje profundo. Los Contenedores de aprendizaje profundo de Google Cloud tienen instalados varios frameworks típicos del AA y ciencia de datos. Después de descargar esa imagen, este Dockerfile configura el punto de entrada para el código de entrenamiento. Aún no creas estos archivos; en el siguiente paso, agregarás el código para entrenar y ajustar el modelo.

Paso 2: Agrega el código de entrenamiento de modelos

En la terminal, ejecuta el siguiente comando para crear un directorio para el código de entrenamiento y un archivo de Python en el que agregarás el código.

mkdir trainer
touch trainer/task.py

Ahora, deberías tener lo siguiente en el directorio horses_or_humans/:

+ Dockerfile
+ trainer/
    + task.py

A continuación, abre el archivo task.py que acabas de crear y copia el código que aparece más abajo.

import tensorflow as tf
import tensorflow_datasets as tfds
import argparse
import hypertune

NUM_EPOCHS = 10


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():
  '''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(64)

  # Create validation dataset
  validation_data = data['test'].map(preprocess_data)
  validation_data  = validation_data.batch(64)

  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()
  train_data, validation_data = create_dataset()
  model = create_model(args.num_units, args.learning_rate, args.momentum)
  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()

Antes de crear el contenedor, analicemos el código en detalle. Hay algunos componentes que son específicos para el uso del servicio de ajuste de hiperparámetros.

  1. La secuencia de comandos importa la biblioteca hypertune. Ten en cuenta que el Dockerfile del paso 1 incluía instrucciones para instalar la biblioteca mediante pip.
  2. La función get_args() define un argumento de la línea de comandos para cada hiperparámetro que deseas ajustar. En este ejemplo, los hiperparámetros que se ajustarán son la tasa de aprendizaje, el valor de impulso en el optimizador y la cantidad de unidades en la última capa oculta del modelo, pero puedes experimentar con otros. El valor que se pasa en dichos argumentos luego se usa para configurar el hiperparámetro correspondiente en el código.
  3. Al final de la función main(), se usa la biblioteca hypertune para definir la métrica que quieres optimizar. En TensorFlow, el método model.fit de Keras muestra un objeto History. El atributo History.history es un registro de los valores de pérdida de entrenamiento y de valores de métricas en ciclos sucesivos. Si pasas datos de validación a model.fit, el atributo History.history también incluirá valores de métricas y pérdida de validación. Por ejemplo, si entrenaste un modelo durante tres ciclos con datos de validación y proporcionaste accuracy como métrica, el atributo History.history se verá como el siguiente diccionario.
{
 "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
 ]

Si quieres que el servicio de ajuste de hiperparámetros descubra qué valores maximizan la exactitud de la validación del modelo, debe definir la métrica como la última entrada (o NUM_EPOCS - 1) de la lista val_accuracy. Luego, pasa esta métrica a una instancia de HyperTune. Puedes elegir la cadena que desees para hyperparameter_metric_tag, pero deberás volver a usarla más adelante cuando inicies el trabajo de ajuste de hiperparámetros.

Paso 3: Compila el contenedor

Desde tu terminal, ejecuta lo siguiente para definir una variable de entorno para tu proyecto y asegúrate de reemplazar your-cloud-project con el ID de tu proyecto:

PROJECT_ID='your-cloud-project'

Define una variable con el URI de la imagen de contenedor en Google Container Registry:

IMAGE_URI="gcr.io/$PROJECT_ID/horse-human:hypertune"

Configura el Docker.

gcloud auth configure-docker

Luego, ejecuta el siguiente comando para compilar el contenedor desde la raíz de tu directorio horses_or_humans:

docker build ./ -t $IMAGE_URI

Por último, envía el contenedor a Google Container Registry:

docker push $IMAGE_URI

Ahora que enviaste el contenedor a Container Registry, puedes iniciar el trabajo de ajuste de hiperparámetros para un modelo personalizado.

5. Ejecuta un trabajo de ajuste de hiperparámetros en Vertex AI.

En este lab, se usa un entrenamiento personalizado con un contenedor personalizado en Google Container Registry, pero también puedes ejecutar un trabajo de ajuste de hiperparámetros con un contenedor creado previamente de Vertex AI.

Para comenzar, ve a Entrenamiento (Training) de la sección de Vertex de la consola de Cloud.

Menú de uCAIP

Paso 1: Configura el trabajo de entrenamiento

Haga clic en Crear para ingresar los parámetros del trabajo de ajuste de hiperparámetros.

  • En Conjunto de datos, selecciona No hay ningún conjunto de datos administrado.
  • Selecciona Entrenamiento personalizado (avanzado) como método de entrenamiento y haz clic en Continuar.
  • Ingresa horses-humans-hyptertune (o el nombre que quieras asignarle a tu modelo) en Nombre del modelo.
  • Haga clic en Continue.

En el paso Configuración del contenedor, selecciona Contenedor personalizado (Custom container):

Opción de contenedor personalizado

En la primera casilla (Imagen de contenedor), ingresa el valor de la variable IMAGE_URI de la sección anterior. Debería ser gcr.io/your-cloud-project/horse-human:hypertune, con el nombre de tu proyecto. Deja el resto de los campos en blanco y haz clic en Continuar.

Paso 2: Configura el trabajo de ajuste de hiperparámetros

Selecciona Enable hyperparameter tuning.

Hiperparámetros

Configura los hiperparámetros

A continuación, deberás agregar los hiperparámetros que configuraste como argumentos de la línea de comandos en el código de entrenamiento de la aplicación. Cuando agregues un hiperparámetro, primero deberás proporcionar el nombre. Este debe coincidir con el nombre del argumento que pasaste a argparse.

learning_rate_name

Luego, seleccionarás el tipo y los límites de los valores que intentará el servicio de ajuste. Si seleccionas el tipo doble o número entero, deberás proporcionar un valor mínimo y uno máximo. Además, si seleccionas categórico o discreto, debes proporcionar los valores.

learning_rate_typelearning_rate_name

Para los tipos doble y número entero, también deberás proporcionar el valor de escalamiento.

learning_rate_scale

Después de agregar el hiperparámetro learning_rate, agrega parámetros para momentum y num_units.

momentum_config

numneruons_config

Configura la métrica

Después de agregar los hiperparámetros, deberás proporcionar la métrica que deseas optimizar y el objetivo. Debe ser el mismo que el hyperparameter_metric_tag que configuraste en la aplicación de entrenamiento.

metric_config

El servicio de ajuste de hiperparámetros de Vertex AI ejecutará múltiples pruebas de tu aplicación de entrenamiento con los valores que configuraste en los pasos anteriores. Deberás establecer un límite superior para la cantidad de pruebas que ejecutará el servicio. Si se realizan más pruebas, se obtendrán mejores resultados, pero habrá un punto en el que habrá menos resultados y las pruebas adicionales tendrán un efecto nulo o muy bajo en la métrica que intentas optimizar. Se recomienda comenzar con una cantidad más pequeña de pruebas para tener una idea del impacto de los hiperparámetros elegidos antes de aumentar a una gran cantidad de pruebas.

También deberás establecer un límite superior para la cantidad de pruebas paralelas. Si las aumentas, se reducirá el tiempo que tarda el trabajo de ajuste de hiperparámetros en completarse; sin embargo, esta acción puede reducir su eficacia general. Esto se debe a que la estrategia de ajuste predeterminada utiliza los resultados de pruebas anteriores para asignar los valores en las pruebas posteriores. Si ejecutas demasiadas pruebas en paralelo, algunas no se beneficiarán de los resultados de las que ya están en curso.

Para efectos de demostración, puedes establecer la cantidad de pruebas en 15 y la cantidad máxima de pruebas paralelas en 3. Puedes experimentar con distintas cantidades, aunque esto puede aumentar el tiempo de ajuste y el costo.

trial_config

El último paso consiste en seleccionar Predeterminado como el algoritmo de búsqueda, el cual usará Google Vizier para realizar la optimización bayesiana del ajuste de hiperparámetros. Puedes obtener más información sobre este algoritmo aquí.

algorithm_config

Haz clic en Continuar.

Paso 3: Configura el procesamiento

En Procesamiento y precios, no cambies la región seleccionada y configura Grupo de trabajadores 0 de la siguiente manera.

Tipo de máquina

Haz clic en Comenzar entrenamiento para iniciar el trabajo de ajuste de hiperparámetros. En la sección Entrenamiento de la consola, en la pestaña TRABAJOS DE AJUSTE DE HIPERPARÁMETROS, verás algo como esto:

Trabajos de hiperparámetros

Cuando termine, podrás hacer clic en el nombre del trabajo y ver los resultados de las pruebas de ajuste.

Resultado del hiperparámetro

🎉 ¡Felicitaciones! 🎉

Aprendiste a usar Vertex AI para hacer lo siguiente:

  • Iniciar un trabajo de ajuste de hiperparámetros para entrenar el código de un contenedor personalizado. En este ejemplo, usaste un modelo de TensorFlow, pero puedes entrenar un modelo creado con cualquier framework a través de contenedores personalizados.

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

6. Use el SDK de Vertex (opcional)

En la sección anterior, se mostró cómo iniciar el trabajo de ajuste de hiperparámetros con la IU. En esta sección, verás una forma alternativa de enviar el trabajo de ajuste de hiperparámetros con la API de Vertex Python.

En el Selector (Launcher), crea un notebook de TensorFlow 2.

new_notebook

Importa el SDK de Vertex AI.

from google.cloud import aiplatform
from google.cloud.aiplatform import hyperparameter_tuning as hpt

Para iniciar el trabajo de ajuste de hiperparámetros, primero debes definir las siguientes especificaciones. Deberás reemplazar {PROJECT_ID} en el image_uri con tu proyecto.

# 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": 1
    },
    "replica_count": 1,
    "container_spec": {
        "image_uri": "gcr.io/{PROJECT_ID}/horse-human:hypertune"
    }
}]


# Dictionary 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'}

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

A continuación, crea un CustomJob. Deberás reemplazar {YOUR_BUCKET} por un bucket de tu proyecto para la etapa de pruebas.

# Replace YOUR_BUCKET
my_custom_job = aiplatform.CustomJob(display_name='horses-humans-sdk-job',
                              worker_pool_specs=worker_pool_specs,
                              staging_bucket='gs://{YOUR_BUCKET}')

Luego, crea y ejecuta HyperparameterTuningJob.

hp_job = aiplatform.HyperparameterTuningJob(
    display_name='horses-humans-sdk-job',
    custom_job=my_custom_job,
    metric_spec=metric_spec,
    parameter_spec=parameter_spec,
    max_trial_count=15,
    parallel_trial_count=3)

hp_job.run()

7. Realiza una limpieza

Debido a que configuramos el notebook para que se agote el tiempo de espera después de 60 minutos de inactividad, no tenemos que preocuparnos 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