Vertex AI:超参数调节

1. 概览

在本实验中,您将使用 Vertex AI,为 TensorFlow 模型运行超参数调节作业。虽然本实验使用 TensorFlow 构建模型代码,但这些概念也适用于其他机器学习框架。

学习内容

您将了解如何:

  • 修改训练应用代码以进行自动超参数调节
  • 通过 Vertex AI 界面配置和启动超参数调节作业
  • 使用 Vertex AI Python SDK 配置并启动超参数调节作业

在 Google Cloud 上运行此实验的总费用约为 3 美元。

2. Vertex AI 简介

本实验使用的是 Google Cloud 上提供的最新 AI 产品。Vertex AI 将整个 Google Cloud 的机器学习产品集成到无缝的开发体验中。以前,可通过单独的服务访问使用 AutoML 训练的模型和自定义模型。新产品与其他新产品结合在一起,形成了一个 API。您还可以将现有项目迁移到 Vertex AI。如果您有任何反馈,请参阅支持页面

Vertex AI 包含许多不同的产品,可支持端到端机器学习工作流。本实验将重点介绍下列产品:培训Workbench

Vertex 产品概览

3.设置环境

您需要一个启用了结算功能的 Google Cloud Platform 项目才能运行此 Codelab。如需创建项目,请按照此处的说明操作。

第 1 步:启用 Compute Engine API

转到 Compute Engine,然后选择启用(如果尚未启用)。创建笔记本实例时需要用到此文件。

第 2 步:启用 Container Registry API

转到 Container Registry,然后选择启用(如果尚未启用)。您将使用此文件为您的自定义训练作业创建容器。

第 3 步:启用 Vertex AI API

转到 Cloud Console 的 Vertex AI 部分,然后点击启用 Vertex AI API

Vertex AI 信息中心

第 4 步:创建 Vertex AI Workbench 实例

在 Cloud Console 的 Vertex AI 部分中,点击 Workbench:

Vertex AI 菜单

启用 Notebooks API(如果尚未启用)。

Notebook_api

启用后,点击 MANAGED NOTES(代管式笔记本):

Notebooks_UI

然后选择新建笔记本

新笔记本

为您的笔记本命名,然后点击高级设置

create_notebook

在“高级设置”下,启用空闲关停,并将分钟数设置为 60。这意味着,当您的笔记本处于未使用状态时,会自动关停,以免产生不必要的费用。

idle_timeout

安全下方,选择“启用终端”(如果尚未启用)。

Enable_terminal

其他所有高级设置无需更改即可。

接下来,点击创建。预配实例需要几分钟时间。

创建实例后,选择打开 JupyterLab

open_jupyterlab

首次使用新实例时,系统会要求您进行身份验证。为此,请按照界面中的步骤操作。

身份验证

4.将训练应用代码容器化

您在本实验中需要训练和调整的模型是基于 TensorFlow 数据集中的马或人数据集训练的图片分类模型。

如需将训练应用代码放入 Docker 容器并将其推送到 Google Container Registry,您需要将此超参数调节作业提交到 Vertex AI。使用此方法,您可以为使用任何框架构建的模型调整超参数。

首先,在“启动器”菜单中,在笔记本实例中打开终端窗口:

在笔记本中打开终端

新建一个名为 horses_or_humans 的目录,并放入该目录:

mkdir horses_or_humans
cd horses_or_humans

第 1 步:创建 Dockerfile

将代码容器化的第一步是创建 Dockerfile。在 Dockerfile 中,您将添加运行映像所需的所有命令。它将安装所有必要的库(包括 CloudML Hypertune 库)并设置训练代码的入口点。

在终端中创建一个空的 Dockerfile:

touch Dockerfile

打开 Dockerfile 并将以下内容复制到其中:

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

此 Dockerfile 使用 Deep Learning Container TensorFlow Enterprise 2.7 GPU Docker 映像。Google Cloud 上的 Deep Learning Containers 预安装了许多常见的机器学习和数据科学框架。下载该映像后,此 Dockerfile 会为训练代码设置入口点。您尚未创建这些文件 - 在下一步中,您将添加用于训练和调整模型的代码。

第 2 步:添加模型训练代码

从终端运行以下命令,为训练代码创建一个目录,以及要在其中添加代码的 Python 文件:

mkdir trainer
touch trainer/task.py

您的 horses_or_humans/ 目录中现在应包含以下代码:

+ Dockerfile
+ trainer/
    + task.py

接下来,打开您刚刚创建的 task.py 文件,并复制下面的代码。

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

在构建容器之前,让我们深入了解一下代码。有一些组件专门用于使用超参数调节服务。

  1. 该脚本会导入 hypertune 库。请注意,第 1 步中的 Dockerfile 包含对 pip 安装此库的说明。
  2. get_args() 函数为每个要调节的超参数定义命令行参数。在本示例中,将要调整的超参数为学习速率、优化器的动量值以及模型最后一个隐藏层中的单元数,但您可以随意尝试其他参数。然后,在这些参数中传递的值将用于在代码中设置相应的超参数。
  3. main() 函数的末尾,hypertune 库用于定义您要优化的指标。在 TensorFlow 中,keras model.fit 方法会返回 History 对象。History.history 属性用于记录连续周期中的训练损失值和指标值。如果您将验证数据传递给 model.fitHistory.history 属性也将包含验证损失和指标值。例如,如果您使用验证数据训练了三个周期的模型,并提供了 accuracy 作为指标,则 History.history 属性将类似于以下字典。
{
 "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
 ]

如果您希望超参数调节服务发现使模型的验证准确率最大化的值,则可以将指标定义为 val_accuracy 列表的最后一个条目(或 NUM_EPOCS - 1)。然后,将此指标传递给 HyperTune 的实例。您可以为 hyperparameter_metric_tag 选择任何字符串,但稍后在启动超参数调节作业时,将需要再次使用该字符串。

第 3 步:构建容器

在终端中,运行以下命令为项目定义一个环境变量,确保将 your-cloud-project 替换为您的项目 ID:

PROJECT_ID='your-cloud-project'

使用 Google Container Registry 中容器映像的 URI 定义变量:

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

然后,从 horses_or_humans 目录的根目录下运行以下命令来构建容器:

docker build ./ -t $IMAGE_URI

最后,将其推送到 Google Container Registry:

docker push $IMAGE_URI

将容器推送到 Container Registry 后,您便可以启动自定义模型超参数调节作业。

5. 在 Vertex AI 上运行超参数调节作业

本实验通过 Google Container Registry 中的自定义容器使用自定义训练,但您也可以通过 Vertex AI 预构建容器来运行超参数调节作业。

首先,转到 Cloud Console 的“顶点”部分中的训练部分:

uCAIP 菜单

第 1 步:配置训练作业

点击创建,输入超参数调节作业的参数。

  • 数据集下,选择无代管式数据集
  • 然后选择自定义训练(高级)作为训练方法,并点击继续
  • 输入 horses-humans-hyptertune(或您希望调用模型的任何名称)作为模型名称
  • 点击继续

在“容器设置”步骤中,选择自定义容器

自定义容器选项

在第一个框(容器映像)中,输入上一部分中的 IMAGE_URI 变量的值。它应该是:gcr.io/your-cloud-project/horse-human:hypertune(您自己的项目名称)。将其余字段留空,然后点击继续

第 2 步:配置超参数调节作业

选择启用超参数调节

超参数

配置超参数

接下来,您需要将已在训练应用代码中设为超参数的超参数添加进去。添加超参数时,您首先需要提供名称。此名称应与您传递给 argparse 的参数名称一致。

学习速率名称

然后,您要选择调整服务类型的值以及所属的范围。如果您选择“双精度”或“整数”类型,则需要提供最小值和最大值。如果您选择“分类”或“离散”选项,则需要提供相应的值。

学习速率类型学习速率名称

对于 Double 和 Integer 类型,您还需要提供 Scaling 值。

学习速率比例

添加 learning_rate 超参数后,为 momentumnum_units 添加参数。

Momentum_config

numneruons_config

配置指标

添加超参数后,接下来您需要提供要优化的指标以及目标。它应该与您在训练应用中设置的 hyperparameter_metric_tag 相同。

metric_config

Vertex AI 超参数调整服务将使用您在上一步配置的值运行训练应用的多个试验。您需要设置服务运行的试验次数的上限。实验轮次通常可以带来更好的效果,但回报率会下降,在此之后,其他轮次的试验对您想要优化的指标几乎没有或没有影响。最佳做法是先减少试验次数,并了解在超大量试验之前所选超参数的影响程度。

您还需要设置并行试验的次数上限。增加并行试验的次数将减少超参数调节作业运行所需的时间;但会降低作业的整体效率。这是因为默认调整策略使用先前试验的结果告知后续试验的赋值。如果您同时运行过多实验轮次,就会开始进行试验,并且没有获得正在进行的实验结果。

出于演示目的,您可以将试验次数设置为 15,将并行试验数量上限设置为 3。您可以尝试不同的数字,但这可能会导致调整时间更长,费用也更高。

试验配置

最后一步是选择“默认”作为搜索算法,该算法将使用 Google Vizier 对超参数调节进行贝叶斯优化。您可以在此处详细了解此算法

controller_config

点击继续

第 3 步:配置计算

计算和价格中,保持所选区域不变,并按以下方式配置工作器池 0

机器类型

点击开始训练以启动超参数调节作业。在控制台的“训练”部分内的超参数调节作业标签页下,您会看到如下内容:

超参数作业

完成后,您将能够点击作业名称,并查看调整试验的结果。

超参数输出

🎉? 恭喜!🎉

您学习了如何使用 Vertex AI 执行以下操作:

  • 启动自定义容器中提供的用于训练代码的超参数调节作业。您在本示例中使用了 TensorFlow 模型,但可以使用自定义容器训练使用任何框架构建的模型。

如需详细了解 Vertex 的不同部分,请参阅文档

6.[可选] 使用 Vertex SDK

上一部分介绍了如何通过界面启动超参数调节作业。在本部分中,您将看到另一种使用 Vertex Python API 提交超参数调节作业的方法。

在启动器中创建一个 TensorFlow 2 笔记本。

新笔记本

导入 Vertex AI SDK。

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

如需启动超参数调节作业,您需要先定义以下规范。您需要将 image_uri 中的 {PROJECT_ID} 替换为您的项目。

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

接下来,创建一个 CustomJob。您需要将 {YOUR_BUCKET} 替换为项目中的存储分区以进行暂存。

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

然后,创建并运行 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. 清理

因为我们将笔记本配置为在 60 分钟空闲后超时,所以我们不必担心关停实例。如果您要手动关停实例,请点击控制台的 Vertex AI Workbench 部分中的“停止”按钮。如果您想完全删除笔记本,请点击“删除”按钮。

停止实例

如需删除存储分区,请使用 Cloud Console 中的“导航”菜单,转到“存储”,选择您的存储分区,然后点击“删除”:

删除存储空间