Vertex AI: Ajuste de hiperparâmetros

1. Visão geral

Neste laboratório, você usará a Vertex AI para executar um job de ajuste de hiperparâmetros para um modelo do TensorFlow. Embora este laboratório use o TensorFlow para o código do modelo, os conceitos também são aplicáveis a outros frameworks de ML.

Conteúdo do laboratório

Você aprenderá como realizar as seguintes tarefas:

  • Modificar código do aplicativo de treinamento para ajuste automático de hiperparâmetros
  • Configurar e iniciar um job de ajuste de hiperparâmetros na IU do Vertex AI
  • Configurar e lançar um job de ajuste de hiperparâmetros com o Vertex AI Python SDK

O custo total da execução deste laboratório no Google Cloud é de aproximadamente US$3.

2. Introdução ao Vertex AI

Este laboratório usa a mais nova oferta de produtos de IA disponível no Google Cloud. A Vertex AI integra as ofertas de ML do Google Cloud em uma experiência de desenvolvimento intuitiva. Anteriormente, modelos treinados com o AutoML e modelos personalizados eram acessíveis por serviços separados. A nova oferta combina os dois tipos em uma única API, junto com outros produtos novos. Você também pode migrar projetos existentes para a Vertex AI. Se você tiver algum feedback, consulte a página de suporte.

A Vertex AI inclui vários produtos diferentes para dar suporte a fluxos de trabalho integrais de ML. Este laboratório aborda os produtos destacados abaixo: Treinamento e Workbench.

Visão geral do produto Vertex

3. Configurar o ambiente

Para executar este codelab, você precisará de um projeto do Google Cloud Platform com o faturamento ativado. Para criar um projeto, siga estas instruções.

Etapa 1: ativar a API Compute Engine

Acesse o Compute Engine e selecione Ativar, caso essa opção ainda não esteja ativada. Você precisará dele para criar sua instância de notebook.

Etapa 2: ativar a API Container Registry

Navegue até o Container Registry e selecione Ativar. Use-o para criar um contêiner de job de treinamento personalizado.

Etapa 3: ativar a API Vertex AI

Navegue até a seção "Vertex AI" do Console do Cloud e clique em Ativar API Vertex AI.

Painel da Vertex AI

Etapa 4: criar uma instância do Vertex AI Workbench

Na seção Vertex AI do Console do Cloud, clique em "Workbench":

Menu da Vertex AI

Ative a API Notebooks se ela ainda não tiver sido ativada.

Notebook_api.

Após a ativação, clique em NOTEBOOK GERENCIADO:

IU do Notebooks

Em seguida, selecione NOVO NOTEBOOK.

new_notebook

Dê um nome ao notebook e clique em Configurações avançadas.

create_notebook

Em "Configurações avançadas", ative o encerramento inativo e defina o número de minutos como 60. Isso significa que o notebook será desligado automaticamente quando não estiver sendo usado.

idle_timeout

Em Segurança, selecione "Ativar terminal" se essa opção ainda não estiver ativada.

Enable_terminal

Você pode manter as outras configurações avançadas como estão.

Em seguida, clique em Criar. O provisionamento da instância levará alguns minutos.

Após a criação da instância, selecione Abrir o JupyterLab.

open_jupyterlab.

Na primeira vez que usar uma nova instância, você receberá uma solicitação para autenticar. Siga as etapas na IU para isso.

autenticar

4. Conteinerizar o código do aplicativo de treinamento

O modelo que você treinará e ajustará neste laboratório é um modelo de classificação de imagens treinado no conjunto de dados de cavalos ou humanos a partir dos Conjuntos de dados do TensorFlow.

Para enviar o job de ajuste de hiperparâmetros para a Vertex AI, coloque o código do aplicativo de treinamento em um contêiner do Docker e envie-o para o Google Container Registry. Com essa abordagem, é possível ajustar hiperparâmetros para um modelo criado com qualquer framework.

Para começar, no menu "Launcher", abra uma janela de terminal na instância do notebook:

Abrir terminal no notebook

Crie um diretório chamado horses_or_humans e use cd nele:

mkdir horses_or_humans
cd horses_or_humans

Etapa 1: criar um Dockerfile

A primeira etapa para inserir o código em contêiner é criar um Dockerfile. No Dockerfile, inclua todos os comandos necessários para executar a imagem. Ele instalará todas as bibliotecas necessárias, incluindo a biblioteca CloudML Hypertune, e definirá o ponto de entrada para o código de treinamento.

No seu terminal, crie um Dockerfile vazio:

touch Dockerfile

Abra o Dockerfile e copie o seguinte nele:

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

Esse Dockerfile usa a imagem do Docker do GPU Enterprise Contêiner do TensorFlow 2.7. Os contêineres de aprendizado profundo no Google Cloud vêm com muitos frameworks comuns de ML e ciência de dados pré-instalados. Após o download, o Dockerfile configura o ponto de entrada para o código de treinamento. Você ainda não criou esses arquivos. Na próxima etapa, você adicionará o código para treinar e ajustar o modelo.

Etapa 2: adicionar o código de treinamento de modelo

No seu terminal, execute o seguinte comando para criar um diretório para o código de treinamento e um arquivo Python em que você adicionará o código:

mkdir trainer
touch trainer/task.py

Agora você tem o seguinte no seu diretório horses_or_humans/:

+ Dockerfile
+ trainer/
    + task.py

Em seguida, abra o arquivo task.py que você acabou de criar e copie o código abaixo.

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 criar o contêiner, vamos analisar o código mais a fundo. Há alguns componentes específicos para o uso do serviço de ajuste de hiperparâmetros.

  1. O script importa a biblioteca hypertune. O Dockerfile da etapa 1 incluiu instruções para instalar o pip com essa biblioteca.
  2. A função get_args() define um argumento de linha de comando para cada hiperparâmetro que você quer ajustar. Neste exemplo, os hiperparâmetros que serão ajustados são a taxa de aprendizado, o valor do momento no otimizador e o número de unidades na última camada oculta do modelo, mas você pode testar outros. Em seguida, o valor transmitido nesses argumentos é usado para definir o hiperparâmetro correspondente no código.
  3. No final da função main(), a biblioteca hypertune é usada para definir a métrica que você quer otimizar. No TensorFlow, o método model.fit keras retorna um objeto History. O atributo History.history é um registro dos valores de perda e de métricas de treinamento em períodos sucessivos. Se você transmitir os dados de validação para model.fit, o atributo History.history também incluirá a perda de validação e os valores das métricas. Por exemplo, se você treinou um modelo por três períodos com dados de validação e forneceu accuracy como uma métrica, o atributo History.history será semelhante ao dicionário a seguir.
{
 "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
 ]

Se você quiser que o serviço de ajuste de hiperparâmetros descubra os valores que maximizam a precisão da validação do modelo, defina a métrica como a última entrada (ou NUM_EPOCS - 1) da lista val_accuracy. Depois, transmita essa métrica para uma instância do HyperTune. Você pode escolher a string que preferir para o hyperparameter_metric_tag, mas precisará usá-la novamente quando iniciar o job de ajuste de hiperparâmetros.

Etapa 3: criar o contêiner

No terminal, execute o seguinte para definir uma variável de ambiente para seu projeto, substituindo your-cloud-project pelo ID do projeto:

PROJECT_ID='your-cloud-project'

Defina uma variável com o URI da imagem do contêiner no Google Container Registry:

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

Em seguida, crie o contêiner executando a seguinte linha a partir da raiz do diretório horses_or_humans:

docker build ./ -t $IMAGE_URI

Por fim, envie-o para o Google Container Registry:

docker push $IMAGE_URI

Com o contêiner enviado para o Container Registry, está tudo pronto para iniciar um job de ajuste de hiperparâmetros de modelo personalizado.

5. Executar um job de ajuste de hiperparâmetros no Vertex AI

Este laboratório usa treinamento personalizado com um contêiner personalizado no Google Container Registry, mas também é possível executar um job de ajuste de hiperparâmetros com um contêiner pré-criado do Vertex AI.

Para começar, navegue até a seção Training na seção "Vertex" do Console do Cloud:

Menu do uCAIP

Etapa 1: configurar o job de treinamento

Clique em Criar para inserir os parâmetros do job de ajuste de hiperparâmetros.

  • Em Conjunto de dados, selecione Nenhum conjunto de dados gerenciado.
  • Em seguida, selecione Treinamento personalizado (avançado) como o método de treinamento e clique em Continuar.
  • Insira horses-humans-hyptertune (ou o nome que você quer atribuir ao modelo) em Nome do modelo
  • Clique em Continuar

Na etapa "Configurações do contêiner", selecione Contêiner personalizado:

Opção de contêiner personalizado

Na primeira caixa (Imagem do contêiner), insira o valor da variável IMAGE_URI da seção anterior. Ele precisa ser: gcr.io/your-cloud-project/horse-human:hypertune, com o nome do seu projeto. Deixe os outros campos em branco e clique em Continuar.

Etapa 2: configurar o job de ajuste de hiperparâmetros

Selecione Ativar ajuste de hiperparâmetros.

Hiperparâmetros

Configurar hiperparâmetros

Em seguida, você precisará adicionar os hiperparâmetros definidos como argumentos de linha de comando no código do aplicativo de treinamento. Ao adicionar um hiperparâmetro, primeiro é necessário informar o nome dele. Ele precisa corresponder ao nome do argumento que você transmitiu para argparse.

nome_da_taxa_de_aprendizado

Em seguida, você selecionará o tipo e os limites dos valores que o serviço de ajuste tentará. Se você selecionar o tipo "Duplo" ou "Inteiro", precisará fornecer um valor mínimo e máximo. E, se você selecionar "Categórica" ou "Diversa", precisará fornecer os valores.

tipo_de_taxa_de_aprendizadonome_da_taxa_de_aprendizado

Para os tipos duplo e inteiro, você também precisa fornecer o valor de escalonamento.

escala_de_taxa_de_aprendizado

Depois de adicionar o hiperparâmetro learning_rate, adicione os parâmetros para momentum e num_units.

Moment_config

numneruons_config

Configurar métrica

Depois de adicionar os hiperparâmetros, forneça a métrica que você quer otimizar e a meta. Precisa ser igual ao hyperparameter_metric_tag definido no aplicativo de treinamento.

métrica_configuração

O serviço de ajuste de hiperparâmetros do Vertex AI executará vários testes do aplicativo de treinamento com os valores configurados nas etapas anteriores. Você precisará estabelecer um limite superior para o número de testes que o serviço executará. Mais testes geralmente levam a melhores resultados, mas haverá um ponto de redução de retornos após o qual os testes adicionais terão pouco ou nenhum efeito sobre a métrica que você está tentando otimizar. É recomendável começar com um número menor de testes e ter uma ideia do impacto dos hiperparâmetros escolhidos antes de expandir para um grande número de testes.

Também será necessário definir um limite superior para o número de testes paralelos. Aumentar o número de testes em paralelo reduzirá o tempo de execução do job de ajuste de hiperparâmetros. mas isso pode reduzir a eficácia da vaga em geral. Isso ocorre porque a estratégia de ajuste padrão usa os resultados de testes anteriores para informar a atribuição de valores nos testes subsequentes. Se você fizer muitos testes em paralelo, haverá testes sem o benefício do resultado dos testes em execução.

Para fins de demonstração, é possível definir o número de testes em 15 e o máximo de 3. Você pode fazer experimentos com números diferentes, mas isso pode resultar em um tempo de ajuste mais longo e custos mais altos.

teste_configuração

A última etapa é selecionar "Padrão" como o algoritmo de pesquisa, que usará o Google Vizier para fazer a otimização bayesiana para o ajuste de hiperparâmetros. Saiba mais sobre esse algoritmo neste link.

configuração_do_algoritmo

Clique em Continuar.

Etapa 3: configurar a computação

Em Computação e preços, mantenha a região selecionada e configure o Pool de workers 0 da seguinte maneira.

Tipo de máquina

Clique em Iniciar treinamento para iniciar o job de ajuste de hiperparâmetros. Na seção "Training" do seu console, na guia HYPERPARAMETER TUNING JOBS, você verá algo semelhante a isto:

Jobs de hiperparam

Quando esse processo for concluído, você poderá clicar no nome do job e ver os resultados dos testes de ajuste.

Saída de hiperparâmetro

Parabéns! 🎉

Você aprendeu a usar a Vertex AI para:

  • iniciar um job de ajuste de hiperparâmetros para código de treinamento fornecido em um contêiner personalizado. Neste exemplo, você usou um modelo do TensorFlow, mas é possível treinar um modelo criado com qualquer framework usando contêineres personalizados.

Para saber mais sobre diferentes partes do Vertex, confira a documentação.

6. [Opcional] Usar o SDK do Vertex

A seção anterior mostrou como iniciar o job de ajuste de hiperparâmetros por meio da IU. Nesta seção, você verá uma maneira alternativa de enviar o job de ajuste de hiperparâmetros usando a API Vertex Python.

No acesso rápido, crie um notebook do TensorFlow 2.

new_notebook

Importe o SDK da Vertex AI.

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

Para iniciar o job de ajuste de hiperparâmetros, primeiro defina as especificações a seguir. Será necessário substituir {PROJECT_ID} no image_uri pelo seu projeto.

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

Em seguida, crie um CustomJob. Será necessário substituir {YOUR_BUCKET} por um bucket no seu projeto para preparo.

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

Em seguida, crie e execute o 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. Limpeza

Como configuramos o notebook para expirar após 60 minutos de inatividade, não precisamos nos preocupar em desligar a instância. Para encerrar a instância manualmente, clique no botão "Stop" na seção "Vertex AI Workbench" do console. Se quiser excluir o notebook completamente, clique no botão Excluir.

Interromper instância

Para excluir o bucket do Storage, use o menu de navegação do Console do Cloud, acesse o Storage, selecione o bucket e clique em "Excluir":

Excluir armazenamento