Vertex AI: Điều chỉnh siêu tham số phân tán

1. Tổng quan

Trong phòng thí nghiệm này, bạn sẽ tìm hiểu cách sử dụng Vertex AI để điều chỉnh siêu tham số và huấn luyện phân tán. Mặc dù phòng thí nghiệm này sử dụng TensorFlow cho mã mô hình, nhưng các khái niệm này cũng áp dụng được cho các khung máy học khác.

Kiến thức bạn sẽ học được

Bạn sẽ tìm hiểu cách:

  • Huấn luyện mô hình bằng quy trình huấn luyện phân phối trên vùng chứa tuỳ chỉnh
  • Chạy nhiều bản dùng thử cho mã huấn luyện của bạn để điều chỉnh siêu tham số tự động

Tổng chi phí để chạy phòng thí nghiệm này trên Google Cloud là khoảng 6 USD.

2. Giới thiệu về Vertex AI

Phòng thí nghiệm này sử dụng sản phẩm AI mới nhất có trên Google Cloud. Vertex AI tích hợp các giải pháp học máy trên Google Cloud vào một trải nghiệm phát triển liền mạch. Trước đây, các mô hình được huấn luyện bằng AutoML và mô hình tuỳ chỉnh có thể truy cập được thông qua các dịch vụ riêng biệt. Dịch vụ mới kết hợp cả hai thành một API duy nhất, cùng với các sản phẩm mới khác. Bạn cũng có thể di chuyển các dự án hiện có sang Vertex AI. Nếu bạn có ý kiến phản hồi, vui lòng xem trang hỗ trợ.

Vertex AI có nhiều sản phẩm nhằm hỗ trợ quy trình học máy toàn diện. Phòng thí nghiệm này sẽ tập trung vào Đào tạoLàm việc.

Tổng quan về sản phẩm Vertex

3. Tổng quan về trường hợp sử dụng

Trong phòng thí nghiệm này, bạn sẽ sử dụng tính năng tinh chỉnh siêu tham số để khám phá các tham số tối ưu cho một mô hình phân loại hình ảnh được huấn luyện trên tập dữ liệu ngựa hoặc người từ Tập dữ liệu TensorFlow.

Điều chỉnh siêu tham số

Tính năng điều chỉnh siêu tham số bằng Vertex AI Training bằng cách chạy nhiều phiên bản thử của ứng dụng huấn luyện với các giá trị cho siêu tham số mà bạn đã chọn, được đặt trong giới hạn mà bạn chỉ định. Vertex AI theo dõi kết quả của mỗi lượt thử và điều chỉnh cho các lượt chạy thử tiếp theo.

Để sử dụng tính năng điều chỉnh siêu tham số bằng Vertex AI Training, bạn cần thực hiện 2 thay đổi đối với mã huấn luyện:

  1. Xác định đối số dòng lệnh trong mô-đun huấn luyện chính cho mỗi siêu tham số mà bạn muốn điều chỉnh.
  2. Sử dụng giá trị được truyền vào các đối số đó để đặt siêu tham số tương ứng trong mã của ứng dụng.

Đào tạo phân tán

Nếu bạn có một GPU, TensorFlow sẽ sử dụng trình tăng tốc này để tăng tốc quá trình huấn luyện mô hình mà bạn không cần làm gì thêm. Tuy nhiên, nếu muốn sử dụng nhiều GPU hiệu quả hơn nữa, bạn cần phải sử dụng tf.distribute. Đây là mô-đun của TensorFlow để chạy một phép tính trên nhiều thiết bị.

Phòng thí nghiệm này sử dụng tf.distribute.MirroredStrategy mà bạn có thể thêm vào các ứng dụng huấn luyện chỉ bằng một vài lần thay đổi mã. Chiến lược này sẽ tạo bản sao của mô hình trên từng GPU trên máy của bạn. Các lần cập nhật độ dốc tiếp theo sẽ diễn ra một cách đồng bộ. Tức là mỗi GPU tính toán lượt tiến và lùi thông qua mô hình trên một lát cắt khác của dữ liệu đầu vào. Sau đó, độ dốc được tính toán từ mỗi lát cắt này được tổng hợp trên tất cả các GPU và tính trung bình trong một quy trình gọi là all-reduce. Các tham số của mô hình được cập nhật bằng các độ dốc trung bình này.

Bạn không cần phải biết thông tin chi tiết để hoàn thành phòng thí nghiệm này, nhưng nếu bạn muốn tìm hiểu thêm về cách hoạt động của chương trình đào tạo phân tán trong TensorFlow, hãy xem video dưới đây:

4. Thiết lập môi trường

Bạn cần một dự án Google Cloud Platform đã bật tính năng thanh toán để chạy lớp học lập trình này. Để tạo một dự án, hãy làm theo hướng dẫn tại đây.

Bước 1: Bật Compute Engine API

Chuyển đến Compute Engine rồi chọn Enable (Bật) nếu bạn chưa bật tính năng này.

Bước 2: Bật Container Registry API

Chuyển đến Sổ đăng ký vùng chứa và chọn Bật nếu bạn chưa chọn. Bạn sẽ dùng mã này để tạo một vùng chứa cho công việc huấn luyện tuỳ chỉnh.

Bước 3: Bật Vertex AI API

Chuyển đến phần Vertex AI trong Cloud Console rồi nhấp vào Bật Vertex AI API.

Trang tổng quan Vertex AI

Bước 4: Tạo một thực thể Vertex AI Workbench

Trong mục Vertex AI trên Cloud Console, hãy nhấp vào Workbench:

Trình đơn Vertex AI

Bật API Notebooks nếu chưa bật.

Notebook_api

Sau khi bật, hãy nhấp vào SÁCH QUẢN LÝ SÁCH:

Notebooks_UI

Sau đó, chọn SÁCH LƯU Ý MỚI.

new_notebook

Đặt tên cho sổ tay của bạn, sau đó nhấp vào Cài đặt nâng cao.

create_notebook

Trong phần Advanced Settings (Cài đặt nâng cao), hãy bật chế độ tắt ở trạng thái rảnh và đặt số phút là 60 phút. Điều này có nghĩa là sổ tay của bạn sẽ tự động tắt khi không được sử dụng, do đó bạn không phải chịu các chi phí không cần thiết.

idle_timeout

Trong phần Bảo mật, hãy chọn "Enable terminal" (Bật thiết bị đầu cuối) nếu chưa được bật.

thiết bị đầu cuối bật

Bạn có thể giữ nguyên mọi chế độ cài đặt nâng cao khác.

Tiếp theo, hãy nhấp vào Tạo. Quá trình cung cấp thực thể này sẽ mất vài phút.

Sau khi tạo phiên bản, hãy chọn Open JupyterLab.

open_jupyterlab

Vào lần đầu tiên sử dụng một phiên bản mới, bạn sẽ được yêu cầu xác thực. Hãy làm theo các bước trong giao diện người dùng để thực hiện việc này.

xác thực

5. Viết mã huấn luyện

Để bắt đầu, trên trình đơn Trình chạy, hãy mở cửa sổ dòng lệnh trong thực thể sổ tay của bạn:

launcher_terminal

Tạo một thư mục mới có tên là vertex-codelab rồi cd vào thư mục đó.

mkdir vertex-codelab
cd vertex-codelab

Chạy lệnh sau để tạo thư mục cho mã huấn luyện và một tệp Python nơi bạn sẽ thêm mã:

mkdir trainer
touch trainer/task.py

Bây giờ, bạn sẽ có những nội dung sau trong thư mục vertex-codelab:

+ trainer/
    + task.py

Tiếp theo, hãy mở tệp task.py bạn vừa tạo và dán vào tất cả mã bên dưới.

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

NUM_EPOCHS = 10
BATCH_SIZE = 64

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

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

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

  # Create distribution strategy
  strategy = tf.distribute.MirroredStrategy()

  # Get data
  GLOBAL_BATCH_SIZE = BATCH_SIZE * strategy.num_replicas_in_sync
  train_data, validation_data = create_dataset(GLOBAL_BATCH_SIZE)

  # Wrap variable creation within strategy scope
  with strategy.scope():
    model = create_model(args.num_units, args.learning_rate, args.momentum)

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

Hãy tìm hiểu sâu hơn về mã này và kiểm tra các thành phần cụ thể cho quá trình huấn luyện phân phối và điều chỉnh siêu tham số.

Đào tạo phân tán

  1. Trong hàm main(), đối tượng MirroredStrategy được tạo. Tiếp theo, bạn kết hợp việc tạo các biến mô hình trong phạm vi của chiến lược. Bước này sẽ cho TensorFlow biết những biến nào nên được phản chiếu trên các GPU.
  2. Kích thước lô được num_replicas_in_sync tăng tỷ lệ. Việc điều chỉnh quy mô kích thước lô là một phương pháp hay nhất khi sử dụng chiến lược tính song song dữ liệu đồng bộ trong TensorFlow. Bạn có thể tìm hiểu thêm tại đây.

Điều chỉnh siêu tham số

  1. Tập lệnh này nhập thư viện hypertune. Sau này, khi xây dựng hình ảnh vùng chứa, chúng ta sẽ cần đảm bảo đã cài đặt thư viện này.
  2. Hàm get_args() xác định một đối số dòng lệnh cho mỗi siêu tham số mà bạn muốn điều chỉnh. Trong ví dụ này, các siêu tham số sẽ được điều chỉnh là tốc độ học, giá trị động lượng trong trình tối ưu hoá và số lượng đơn vị trong lớp ẩn cuối cùng của mô hình, nhưng vui lòng thử nghiệm với các đơn vị khác. Sau đó, giá trị được truyền vào các đối số đó sẽ được dùng để đặt siêu tham số tương ứng trong mã (ví dụ: đặt learning_rate = args.learning_rate)
  3. Ở cuối hàm main(), thư viện hypertune được dùng để xác định chỉ số mà bạn muốn tối ưu hoá. Trong TensorFlow, phương thức Keras model.fit trả về một đối tượng History. Thuộc tính History.history là một bản ghi gồm các giá trị chỉ số và giá trị tổn thất huấn luyện trong các khoảng thời gian bắt đầu của hệ thống liên tiếp. Nếu bạn chuyển dữ liệu xác thực đến model.fit, thuộc tính History.history cũng sẽ bao gồm tổn thất xác thực và các giá trị chỉ số. Ví dụ: nếu bạn đã huấn luyện một mô hình cho 3 khoảng thời gian bắt đầu của hệ thống bằng dữ liệu xác thực và cung cấp accuracy làm chỉ số, thì thuộc tính History.history sẽ có dạng như trong từ điển sau.
{
 "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
 ]

Nếu muốn dịch vụ điều chỉnh siêu tham số khám phá các giá trị giúp tối đa hoá độ chính xác xác thực của mô hình, bạn cần xác định chỉ số đó là mục nhập cuối cùng (hoặc NUM_EPOCS - 1) của danh sách val_accuracy. Sau đó, hãy truyền chỉ số này đến một thực thể của HyperTune. Bạn có thể chọn bất kỳ chuỗi nào mình thích cho hyperparameter_metric_tag, nhưng sẽ cần sử dụng lại chuỗi đó sau khi bắt đầu công việc điều chỉnh siêu tham số.

6. Vùng chứa mã

Bước đầu tiên trong việc chứa mã là tạo Dockerfile. Trong Dockerfile, bạn sẽ thêm tất cả các lệnh cần thiết để chạy hình ảnh. Thư viện này sẽ cài đặt tất cả thư viện cần thiết và thiết lập điểm truy cập cho mã huấn luyện.

Bước 1: Viết Dockerfile

Trên Terminal, hãy đảm bảo bạn đang ở thư mục vertex-codelab và tạo một Dockerfile trống:

touch Dockerfile

Bây giờ, bạn sẽ có những nội dung sau trong thư mục vertex-codelab:

+ Dockerfile
+ trainer/
    + task.py

Mở Dockerfile và sao chép nội dung sau đây vào đó:

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 này sử dụng hình ảnh Docker GPU cho TensorFlow Enterprise 2.7 của Deep Learning Container. Các vùng chứa học sâu trên Google Cloud được cài đặt sẵn nhiều khung phổ biến của công nghệ học máy và khoa học dữ liệu. Sau khi tải hình ảnh đó xuống, Dockerfile này sẽ thiết lập điểm nhập cho mã huấn luyện.

Bước 2: Tạo vùng chứa

Trên cửa sổ dòng lệnh, hãy chạy lệnh sau để xác định một biến env cho dự án của bạn, nhớ thay thế your-cloud-project bằng mã dự án của bạn:

PROJECT_ID='your-cloud-project'

Xác định một biến bằng URI của hình ảnh vùng chứa của bạn trong Google Container Registry:

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

Định cấu hình Docker

gcloud auth configure-docker

Sau đó, hãy tạo vùng chứa bằng cách chạy lệnh sau từ gốc của thư mục vertex-codelab:

docker build ./ -t $IMAGE_URI

Cuối cùng, hãy đẩy địa chỉ email này đến Google Container Registry:

docker push $IMAGE_URI

Bước 3: Tạo một bộ chứa Cloud Storage

Trong công việc huấn luyện, chúng ta sẽ chuyển đường dẫn đến một bộ chứa thử nghiệm.

Chạy dòng sau trong Terminal để tạo một bộ chứa mới trong dự án.

BUCKET_NAME="gs://${PROJECT_ID}-hptune-bucket"
gsutil mb -l us-central1 $BUCKET_NAME

7. Khởi chạy công việc điều chỉnh siêu tham số

Bước 1: Tạo công việc huấn luyện tuỳ chỉnh bằng tính năng điều chỉnh siêu tham số

Trên trình chạy, hãy mở một Sổ tay TensorFlow 2 mới.

new_notebook

Nhập SDK Vertex AI Python.

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

Để chạy công việc điều chỉnh siêu tham số, trước tiên, bạn cần xác định worker_pool_specs. Lớp này sẽ chỉ định loại máy và hình ảnh Docker. Thông số kỹ thuật sau đây xác định một máy có hai GPU NVIDIA Tesla V100.

Bạn cần thay thế {PROJECT_ID} trong image_uri bằng dự án của mình.

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

Tiếp theo, hãy xác định parameter_spec. Đây là từ điển chỉ định các tham số mà bạn muốn tối ưu hoá. Khoá từ điển là chuỗi bạn đã chỉ định cho đối số dòng lệnh cho mỗi siêu tham số và giá trị từ điển là thông số kỹ thuật của tham số.

Đối với mỗi siêu tham số, bạn cần xác định Loại cũng như các giới hạn cho các giá trị mà dịch vụ điều chỉnh sẽ thử. Siêu tham số có thể thuộc loại Kép, Số nguyên, Phân loại hoặc Rời rạc. Nếu chọn loại Double hoặc Integer, bạn cần cung cấp giá trị tối thiểu và tối đa. Nếu chọn Phân loại hoặc Rời rạc, bạn cần cung cấp các giá trị. Đối với các loại Số nguyên và Kép, bạn cũng cần cung cấp giá trị Tỷ lệ. Bạn có thể tìm hiểu thêm về cách chọn thang đo tốt nhất trong video này.

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

Thông số kỹ thuật cuối cùng cần xác định là metric_spec, là từ điển đại diện cho chỉ số cần tối ưu hoá. Khoá từ điển là hyperparameter_metric_tag mà bạn đặt trong mã xử lý ứng dụng huấn luyện và giá trị là mục tiêu tối ưu hoá.

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

Sau khi xác định các thông số, bạn sẽ tạo một CustomJob. Đây là thông số phổ biến dùng để chạy công việc của bạn trong mỗi lượt thử điều chỉnh siêu tham số.

Bạn cần thay thế {YOUR_BUCKET} bằng bộ chứa mà bạn đã tạo trước đó.

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

Sau đó, hãy tạo và chạy HyperparameterTuningJob.

hp_job = aiplatform.HyperparameterTuningJob(
    display_name='horses-humans',
    custom_job=my_custom_job,
    metric_spec=metric_spec,
    parameter_spec=parameter_spec,
    max_trial_count=6,
    parallel_trial_count=2,
    search_algorithm=None)

hp_job.run()

Có một số đối số cần lưu ý:

  • max_trial_count: Bạn cần phải đặt giới hạn trên về số lượt dùng thử mà dịch vụ sẽ chạy. Nhiều thử nghiệm hơn thường dẫn đến kết quả tốt hơn, nhưng sẽ có điểm lợi nhuận giảm dần, sau đó các thử nghiệm bổ sung có ít hoặc không ảnh hưởng đến chỉ số mà bạn đang cố gắng tối ưu hoá. Bạn nên bắt đầu với số lượng nhỏ thử nghiệm và tìm hiểu tác động của siêu tham số đã chọn trước khi mở rộng quy mô.
  • Duet_trial_count: Nếu bạn sử dụng phiên bản dùng thử song song, dịch vụ sẽ cung cấp nhiều cụm xử lý huấn luyện. Việc tăng số lượng phiên bản thử song song sẽ giúp giảm thời gian thực hiện công việc điều chỉnh siêu tham số cần thiết; tuy nhiên, nó có thể làm giảm hiệu quả của công việc nói chung. Điều này là do chiến lược điều chỉnh mặc định sử dụng kết quả của các lần thử trước để thông báo việc chỉ định giá trị trong các lần thử tiếp theo.
  • search_algorithm: Bạn có thể đặt thuật toán tìm kiếm thành lưới, ngẫu nhiên hoặc mặc định (Không có). Lựa chọn mặc định áp dụng phương pháp tối ưu hoá Bayes để tìm kiếm không gian của các giá trị siêu tham số có thể có và là thuật toán được đề xuất. Bạn có thể tìm hiểu thêm về thuật toán này tại đây.

Sau khi công việc bắt đầu, bạn sẽ có thể theo dõi trạng thái trong giao diện người dùng trong thẻ HYPER parameters TUNING JOBS.

HP_job

Sau khi công việc hoàn tất, bạn có thể xem và sắp xếp kết quả của các lượt thử để khám phá tổ hợp giá trị siêu tham số tốt nhất.

HP_results

🎉 Xin chúc mừng! 🎉

Bạn đã tìm hiểu cách sử dụng Vertex AI để:

  • Chạy công việc điều chỉnh siêu tham số bằng quy trình huấn luyện phân phối

Để tìm hiểu thêm về các phần khác nhau của Vertex AI, hãy xem tài liệu này.

8. Dọn dẹp

Vì đã định cấu hình sổ tay hết thời gian chờ sau 60 phút ở trạng thái rảnh, nên chúng ta không cần phải lo lắng về việc tắt thực thể. Nếu bạn muốn tắt thực thể theo cách thủ công, hãy nhấp vào nút Dừng trên phần Vertex AI Workbench của bảng điều khiển. Nếu bạn muốn xoá hoàn toàn sổ tay, hãy nhấp vào nút Xoá.

xóa

Để xoá Bộ chứa Storage, hãy sử dụng trình đơn Điều hướng trong Cloud Console, duyệt đến Bộ nhớ, chọn bộ chứa rồi nhấp vào Xoá:

Xoá bộ nhớ