1. Visão geral
Neste laboratório, você vai usar a Vertex AI para executar um ajuste de hiperparâmetro no Vertex AI Training.
Este laboratório é parte da série de vídeos Protótipo para produção. Finalize o laboratório anterior antes de tentar este. Para saber mais, confira a série de vídeos complementar:
.
Conteúdo do laboratório
Você vai aprender a:
- modificar o código do aplicativo de treinamento para ajuste do hiperparâmetro automatizado;
- configurar e iniciar um job de ajuste de hiperparâmetro com o SDK da Vertex AI para Python.
O custo total da execução deste laboratório no Google Cloud é de aproximadamente US$ 1.
2. Introdução à 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 ambos em uma única API, com outros novos produtos. Você também pode migrar projetos para a Vertex AI.
A Vertex AI inclui vários produtos diferentes para dar suporte a fluxos de trabalho integrais de ML. Os produtos destacados abaixo são o foco deste laboratório: Treinamentos e Workbench.
3. Configurar o ambiente
Finalize as etapas no laboratório Como treinar modelos personalizados com a Vertex AI para configurar seu ambiente:
4. Faça a conteinerização do código do aplicativo de treinamento
Você vai enviar este job de treinamento para a Vertex AI adicionado o código do aplicativo de treinamento a um contêiner do Docker e enviando esse contêiner por push para o Google Artifact Registry. Com esta abordagem, você pode treinar e ajustar um modelo criado com qualquer framework.
Para começar, no menu de acesso rápido do notebook do Workbench que você criou nos laboratórios anteriores, abra uma janela do terminal.
Etapa 1: escrever código de treinamento
Crie um novo diretório chamado flowers-hptune
e coloque cd nele:
mkdir flowers-hptune
cd flowers-hptune
Execute o comando a seguir para criar um diretório destinado ao código de treinamento e a um arquivo Python em que você vai adicionar o código abaixo:
mkdir trainer
touch trainer/task.py
Agora você deve ter o seguinte no diretório flowers-hptune/
:
+ trainer/
+ task.py
Depois abra o arquivo task.py
que você acabou de criar e copie o código abaixo.
Você vai precisar substituir {your-gcs-bucket}
em BUCKET_ROOT
pelo bucket do Cloud Storage em que o conjunto de dados de flores está armazenado no laboratório 1.
import tensorflow as tf
import numpy as np
import os
import hypertune
import argparse
## Replace {your-gcs-bucket} !!
BUCKET_ROOT='/gcs/{your-gcs-bucket}'
# Define variables
NUM_CLASSES = 5
EPOCHS=10
BATCH_SIZE = 32
IMG_HEIGHT = 180
IMG_WIDTH = 180
DATA_DIR = f'{BUCKET_ROOT}/flower_photos'
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 create_datasets(data_dir, batch_size):
'''Creates train and validation datasets.'''
train_dataset = tf.keras.utils.image_dataset_from_directory(
data_dir,
validation_split=0.2,
subset="training",
seed=123,
image_size=(IMG_HEIGHT, IMG_WIDTH),
batch_size=batch_size)
validation_dataset = tf.keras.utils.image_dataset_from_directory(
data_dir,
validation_split=0.2,
subset="validation",
seed=123,
image_size=(IMG_HEIGHT, IMG_WIDTH),
batch_size=batch_size)
train_dataset = train_dataset.cache().shuffle(1000).prefetch(buffer_size=tf.data.AUTOTUNE)
validation_dataset = validation_dataset.cache().prefetch(buffer_size=tf.data.AUTOTUNE)
return train_dataset, validation_dataset
def create_model(num_units, learning_rate, momentum):
'''Creates model.'''
model = tf.keras.Sequential([
tf.keras.layers.Resizing(IMG_HEIGHT, IMG_WIDTH),
tf.keras.layers.Rescaling(1./255, input_shape=(IMG_HEIGHT, IMG_WIDTH, 3)),
tf.keras.layers.Conv2D(16, 3, padding='same', activation='relu'),
tf.keras.layers.MaxPooling2D(),
tf.keras.layers.Conv2D(32, 3, padding='same', activation='relu'),
tf.keras.layers.MaxPooling2D(),
tf.keras.layers.Conv2D(64, 3, padding='same', activation='relu'),
tf.keras.layers.MaxPooling2D(),
tf.keras.layers.Flatten(),
tf.keras.layers.Dense(num_units, activation='relu'),
tf.keras.layers.Dense(NUM_CLASSES, activation='softmax')
])
model.compile(optimizer=tf.keras.optimizers.SGD(learning_rate=learning_rate, momentum=momentum),
loss=tf.keras.losses.SparseCategoricalCrossentropy(),
metrics=['accuracy'])
return model
def main():
args = get_args()
train_dataset, validation_dataset = create_datasets(DATA_DIR, BATCH_SIZE)
model = create_model(args.num_units, args.learning_rate, args.momentum)
history = model.fit(train_dataset, validation_data=validation_dataset, epochs=EPOCHS)
# 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=EPOCHS)
if __name__ == "__main__":
main()
Antes de criar o contêiner, vamos analisar o código mais a fundo. Existem alguns componentes específicos para usar o serviço de ajuste de hiperparâmetros.
- O script importa a biblioteca
hypertune
. - A função
get_args()
define um argumento de linha de comando para cada hiperparâmetro a ser ajustado. No exemplo, os hiperparâmetros que serão ajustados são a taxa de aprendizado, o valor do momentum no optimizer e o número de unidades na última camada escondida do modelo, mas fique à vontade para testar outros. O valor transferido nesses argumentos é usado para definir o hiperparâmetro correspondente no código. - Ao final da função
main()
, a bibliotecahypertune
é usada para definir a métrica a ser otimizada. No TensorFlow, o métodomodel.fit
da Keras retorna um objetoHistory
. O atributoHistory.history
é um registro de valores de perda de treinamento e de valores de métricas em épocas sucessivas. Se você transmitir os dados de validação paramodel.fit
, o atributoHistory.history
vai incluir também valores de perda de validação e de métricas. Por exemplo, se você treinar um modelo para três épocas com dados de validação e informaraccuracy
como a métrica, o atributoHistory.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 acurácia da validação do modelo, defina a métrica como a última entrada (ou NUM_EPOCS - 1
) da lista val_accuracy
. Em seguida, transfira essa métrica para uma instância do HyperTune
. É possível escolher qualquer string para o argumento hyperparameter_metric_tag
, mas será preciso usar a string novamente, quando você iniciar o job de ajuste de hiperparâmetros.
Etapa 2: criar um Dockerfile
Para conteinerizar seu código, você precisa criar um Dockerfile. No Dockerfile, você vai incluir todos os comandos necessários para executar a imagem. Ele vai instalar todas as bibliotecas necessárias e configurar o ponto de entrada do código de treinamento.
No seu terminal, crie um Dockerfile vazio na raiz do diretório de flowers-hptune
.
touch Dockerfile
Agora você deve ter o seguinte no diretório flowers-hptune/
:
+ Dockerfile
+ trainer/
+ task.py
Abra o Dockerfile e copie o seguinte código nele. Você vai perceber que o Dockerfile é idêntico ao usado no primeiro laboratório, só que agora estamos instalando a biblioteca cloudml-hypertune.
FROM gcr.io/deeplearning-platform-release/tf2-gpu.2-8
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"]
Etapa 3: criar o contêiner
No Terminal, execute o comando a seguir e defina uma variável env para o projeto. Lembre-se de substituir your-cloud-project
pelo ID do projeto.
PROJECT_ID='your-cloud-project'
Defina um repositório no Artifact Registry. Vamos usar o que criamos no primeiro laboratório.
REPO_NAME='flower-app'
Defina uma variável com o URI da imagem do seu contêiner no Google Artifact Registry.
IMAGE_URI=us-central1-docker.pkg.dev/$PROJECT_ID/$REPO_NAME/flower_image_hptune:latest
Configure o Docker.
gcloud auth configure-docker \
us-central1-docker.pkg.dev
Agora execute o comando a seguir na raiz do diretório flower-hptune
para criar o diretório:
docker build ./ -t $IMAGE_URI
Por fim, envie por push para o Artifact Registry:
docker push $IMAGE_URI
Com o contêiner enviado por push para o Artifact Registry, agora está tudo pronto para você iniciar o job de treinamento.
5. Executar o job de ajuste de hiperparâmetro com o SDK
Nesta seção, você vai aprender a configurar e enviar o job de ajuste de hiperparâmetro usando a API Vertex Python.
Na tela de início, crie um notebook do TensorFlow 2.
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 o worker_pool_specs
, que especifica o tipo de máquina e a imagem do Docker. A especificação a seguir define uma máquina com duas GPUs NVIDIA Tesla V100.
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": "us-central1-docker.pkg.dev/{PROJECT_ID}/flower-app/flower_image_hptune:latest"
}
}]
Em seguida, defina o parameter_spec
, que é um dicionário que especifica os parâmetros que você quer otimizar. A chave de dicionário é a string atribuída ao argumento de linha de comando para cada hiperparâmetro e o valor do dicionário é a especificação de parâmetros.
Para cada hiperparâmetro, você precisa definir o tipo e os limites dos valores que o serviço de ajuste vai tentar. Os hiperparâmetros podem ser do tipo duplo, inteiro, categórico ou discreto. Se você selecionar o tipo "Duplo" ou "Inteiro", vai precisar fornecer um valor mínimo e máximo. E, se você selecionar "Categórico" ou "Discreto", vai ter que fornecer os valores. Para os tipos duplo e inteiro, você também precisa fornecer o valor de escalonamento. Saiba como escolher o melhor escalonamento neste vídeo
# 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 especificação final a ser definida é metric_spec
, que é um dicionário que representa a métrica a ser otimizada. A chave de dicionário é o hyperparameter_metric_tag
que você definiu no código do aplicativo de treinamento, e o valor é a meta de otimização.
# Dictionary representing metric 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'}
Depois de definir as especificações, crie um CustomJob, que é a especificação comum a ser usada para executar o job em cada um dos testes de ajuste de hiperparâmetro.
Será necessário substituir {YOUR_BUCKET}
pelo bucket que você criou anteriormente.
# Replace YOUR_BUCKET
my_custom_job = aiplatform.CustomJob(display_name='flowers-hptune-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='flowers-hptune-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()
Há alguns argumentos a serem observados:
- max_trial_count: será necessário estabelecer um limite para o número de testes que o serviço vai executar. Um número maior de testes geralmente leva a melhores resultados, mas haverá um ponto com retornos decrescentes. Depois dele, a execução de mais testes terá pouco ou nenhum efeito na métrica a ser otimizada. Uma prática recomendada é começar com um número menor de testes para ter noção do impacto dos hiperparâmetros escolhidos, antes de escalonar verticalmente.
- parallel_trial_count: se você usa testes em paralelo, o serviço provisiona vários clusters de processamento de treinamento. Aumentar o número de testes paralelos reduz o tempo necessário para a execução do job de ajuste de hiperparâmetros, mas isso pode reduzir a eficácia do job em geral. Isso ocorre devido à estratégia de ajuste padrão que usa os resultados de testes anteriores para informar a atribuição de valores em testes seguintes.
- search_algorithm: você pode definir o algoritmo de pesquisa como grade, aleatório ou padrão (nenhum). A opção padrão aplica a otimização bayesiana para pesquisar o espaço de possíveis valores de hiperparâmetros e é o algoritmo recomendado. Saiba mais sobre esse algoritmo aqui.
No console, você pode acompanhar o progresso do job.
Quando ele termina, você pode acessar os resultados de cada teste e saber qual conjunto de valores teve o melhor desempenho.
Parabéns! 🎉
Você aprendeu a usar a Vertex AI para:
- Executar um job de ajuste de hiperparâmetro automatizado.
Para saber mais sobre as diferentes partes da Vertex, consulte a documentação.
6. 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 "Parar" na seção "Vertex AI Workbench" do console. Se quiser excluir o notebook completamente, clique no botão "Excluir".
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":