Vertex AI: TensorFlow를 사용한 멀티 작업자 학습 및 전이 학습

1. 개요

이 실습에서는 Vertex AI를 사용하여 TensorFlow 모델을 위한 멀티 작업자 학습 작업을 실행합니다.

학습 내용

다음 작업을 수행하는 방법을 배우게 됩니다.

  • 다중 작업자 학습을 위한 학습 애플리케이션 코드 수정
  • Vertex AI UI에서 다중 작업자 학습 작업 구성 및 실행
  • Vertex SDK로 다중 작업자 학습 작업 구성 및 실행

Google Cloud에서 이 실습을 진행하는 데 드는 총 비용은 약 $5입니다.

2. Vertex AI 소개

이 실습에서는 Google Cloud에서 제공되는 최신 AI 제품을 사용합니다. Vertex AI는 Google Cloud 전반의 ML 제품을 원활한 개발 환경으로 통합합니다. 예전에는 AutoML로 학습된 모델과 커스텀 모델은 별도의 서비스를 통해 액세스할 수 있었습니다. 새 서비스는 다른 새로운 제품과 함께 두 가지 모두를 단일 API로 결합합니다. 기존 프로젝트를 Vertex AI로 이전할 수도 있습니다. 의견이 있는 경우 지원 페이지를 참고하세요.

Vertex AI에는 엔드 투 엔드 ML 워크플로를 지원하는 다양한 제품이 포함되어 있습니다. 이 실습에서는 아래에 강조 표시된 학습Workbench 제품에 중점을 둡니다.

Vertex 제품 개요

3. 사용 사례 개요

이 실습에서는 전이 학습을 사용하여 TensorFlow 데이터 세트cassava 데이터 세트에 대한 이미지 분류 모델을 학습시킵니다. 사용할 아키텍처는 Imagenet 데이터 세트에 사전 학습된 tf.keras.applications 라이브러리의 ResNet50 모델입니다.

분산 학습이 필요한 이유

단일 GPU가 있는 경우 TensorFlow가 이 액셀러레이터를 사용하여 추가 작업 없이 모델 학습 속도를 높입니다. 그러나 단일 머신 또는 여러 머신 (각각 여러 개의 GPU가 있을 수 있음)에서 여러 GPU를 사용하여 성능을 더욱 높이려면 여러 기기에서 계산을 실행하기 위한 TensorFlow 라이브러리인 tf.distribute를 사용해야 합니다. 기기란 TensorFlow가 작업을 실행할 수 있는 일부 머신의 CPU 또는 액셀러레이터(예: GPU 또는 TPU)를 의미합니다.

분산 학습을 시작하는 가장 간단한 방법은 여러 GPU 기기가 있는 단일 머신을 사용하는 것입니다. tf.distribute 모듈의 TensorFlow 배포 전략은 모든 GPU에서 데이터 배포 및 경사 업데이트의 조정을 관리합니다. 단일 호스트 학습을 마스터하고 더 확장하려는 경우 클러스터에 여러 머신을 추가하면 성능을 훨씬 더 높일 수 있습니다. CPU만 있거나 각각 하나 이상의 GPU가 있는 머신의 클러스터를 활용할 수 있습니다. 이 실습에서는 MultiWorkerMirroredStrategy를 사용하여 Vertex AI의 여러 머신에 TensorFlow 모델 학습을 배포하는 방법을 보여줍니다.

MultiWorkerMirroredStrategy는 몇 가지 코드 변경만으로 사용할 수 있는 동기식 데이터 동시 로드 전략입니다. 모델 사본은 클러스터의 각 기기에 생성됩니다. 후속 경사 업데이트는 동기 방식으로 진행됩니다. 즉, 각 작업자 기기는 입력 데이터의 서로 다른 슬라이스에서 모델을 정방향 및 역방향으로 전달합니다. 그런 다음 각 슬라이스에서 계산된 경사는 머신의 모든 기기와 클러스터의 모든 시스템에서 집계되고 AllReduce라는 프로세스를 통해 감소합니다 (일반적으로 평균). 그러면 최적화 도구에서 이렇게 줄어든 경사로 매개변수 업데이트를 수행하여 기기 동기화를 유지합니다. TensorFlow를 사용한 분산 학습에 대해 자세히 알아보려면 아래 동영상을 확인하세요.

4. 환경 설정하기

이 Codelab을 실행하려면 결제가 사용 설정된 Google Cloud Platform 프로젝트가 필요합니다. 프로젝트를 만들려면 여기의 안내를 따르세요.

1단계: Compute Engine API 사용 설정

아직 사용 설정되지 않은 경우 Compute Engine으로 이동하고 사용 설정을 선택합니다. 이것은 노트북 인스턴스를 생성하는 데 필요합니다.

2단계: Container Registry API 사용 설정

Container Registry로 이동하여 아직 사용 설정되지 않은 경우 사용 설정을 선택합니다. 이를 사용하여 커스텀 학습 작업을 위한 컨테이너를 생성합니다.

3단계: Vertex AI API 사용 설정

Cloud 콘솔의 Vertex AI 섹션으로 이동하고 Vertex AI API 사용 설정을 클릭합니다.

Vertex AI 대시보드

4단계: Vertex AI Workbench 인스턴스 만들기

Cloud 콘솔의 Vertex AI 섹션에서 'Workbench'를 클릭합니다.

Vertex AI 메뉴

Notebooks API를 아직 사용 설정하지 않은 경우 사용 설정합니다.

Notebook_api

사용 설정했으면 관리형 노트북을 클릭합니다.

Notebooks_UI

그런 다음 새 노트북을 선택합니다.

new_notebook

노트북 이름을 지정한 후 고급 설정을 클릭합니다.

create_notebook

고급 설정에서 유휴 상태 종료를 사용 설정하고 분을 60으로 설정합니다. 즉, 노트북을 사용하지 않을 때는 자동으로 종료되므로 불필요한 비용이 발생하지 않습니다.

idle_timeout

아직 사용 설정되지 않은 경우 보안에서 '터미널 사용 설정'을 선택합니다.

enable-terminal

다른 고급 설정은 모두 그대로 두면 됩니다.

그런 다음 만들기를 클릭합니다. 인스턴스를 프로비저닝하는 데 몇 분 정도 걸립니다.

인스턴스가 생성되면 JupyterLab 열기를 선택합니다.

open_jupyterlab

새 인스턴스를 처음 사용하는 경우 인증하라는 메시지가 표시됩니다. 진행하려면 UI의 단계를 따릅니다.

인증

5. 학습 애플리케이션 코드 컨테이너화

학습 애플리케이션 코드를 Docker 컨테이너에 넣고 이 컨테이너를 Google Container Registry로 푸시하여 이 학습 작업을 Vertex에 제출합니다. 이 방식을 사용하면 모든 프레임워크로 빌드된 모델을 학습시킬 수 있습니다.

시작하려면 런처 메뉴에서 노트북 인스턴스의 터미널 창을 엽니다.

노트북에서 터미널 열기

cassava라는 새 디렉터리를 만들고 여기로 디렉터리를 변경합니다.

mkdir cassava
cd cassava

1단계: Dockerfile 만들기

코드를 컨테이너화하는 첫 번째 단계는 Dockerfile을 만드는 것입니다. Dockerfile에는 이미지를 실행하는 데 필요한 모든 명령어가 포함됩니다. 필요한 모든 라이브러리를 설치하고 학습 코드의 진입점을 설정합니다.

터미널에서 빈 Dockerfile을 만듭니다.

touch Dockerfile

Dockerfile을 열고 다음을 복사합니다.

FROM gcr.io/deeplearning-platform-release/tf2-gpu.2-7

WORKDIR /

# 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에는 많은 수의 일반적인 ML 및 데이터 과학 프레임워크가 사전 설치된 상태로 제공됩니다. 해당 이미지를 다운로드한 후 이 Dockerfile은 학습 코드의 진입점을 설정합니다. 아직 이 파일을 만들지 않았습니다. 다음 단계에서 모델을 학습시키고 조정하기 위한 코드를 추가할 것입니다.

2단계: Cloud Storage 버킷 만들기

이 학습 작업에서는 학습된 TensorFlow 모델을 Cloud Storage 버킷으로 내보냅니다. 터미널에서 다음을 실행하여 프로젝트의 env 변수를 정의하고 your-cloud-project를 프로젝트의 ID로 바꿉니다.

PROJECT_ID='your-cloud-project'

다음으로, 터미널에서 다음을 실행하여 프로젝트에 새 버킷을 만듭니다.

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

3단계: 모델 학습 코드 추가

터미널에서 다음을 실행하여 학습 코드용 디렉터리와 코드를 추가할 Python 파일을 만듭니다.

mkdir trainer
touch trainer/task.py

이제 cassava/ 디렉터리에 다음이 포함됩니다.

+ Dockerfile
+ trainer/
    + task.py

다음으로, 방금 만든 task.py 파일을 열고 아래의 코드를 복사합니다. {your-gcs-bucket}은 방금 만든 Cloud Storage 버킷의 이름으로 바꿔야 합니다.

import tensorflow as tf
import tensorflow_datasets as tfds
import os


PER_REPLICA_BATCH_SIZE = 64
EPOCHS = 2

# TODO: replace {your-gcs-bucket} with the name of the Storage bucket you created earlier
BUCKET = 'gs://{your-gcs-bucket}/mwms'

def preprocess_data(image, label):
  '''Resizes and scales images.'''

  image = tf.image.resize(image, (300,300))
  return tf.cast(image, tf.float32) / 255., label


def create_dataset(batch_size):
  '''Loads Cassava dataset and preprocesses data.'''

  data, info = tfds.load(name='cassava', as_supervised=True, with_info=True)
  number_of_classes = info.features['label'].num_classes
  train_data = data['train'].map(preprocess_data,
                                 num_parallel_calls=tf.data.experimental.AUTOTUNE)
  train_data  = train_data.shuffle(1000)
  train_data  = train_data.batch(batch_size)
  train_data  = train_data.prefetch(tf.data.experimental.AUTOTUNE)

  # Set AutoShardPolicy
  options = tf.data.Options()
  options.experimental_distribute.auto_shard_policy = tf.data.experimental.AutoShardPolicy.DATA
  train_data = train_data.with_options(options)

  return train_data, number_of_classes


def create_model(number_of_classes):
  '''Creates and compiles pretrained ResNet50 model.'''

  base_model = tf.keras.applications.ResNet50(weights='imagenet', include_top=False)
  x = base_model.output
  x = tf.keras.layers.GlobalAveragePooling2D()(x)
  x = tf.keras.layers.Dense(1016, activation='relu')(x)
  predictions = tf.keras.layers.Dense(number_of_classes, activation='softmax')(x)
  model = tf.keras.Model(inputs=base_model.input, outputs=predictions)

  model.compile(
      loss='sparse_categorical_crossentropy',
      optimizer=tf.keras.optimizers.Adam(0.0001),
      metrics=['accuracy'])

  return model


def _is_chief(task_type, task_id):
  '''Helper function. Determines if machine is chief.'''

  return task_type == 'chief'


def _get_temp_dir(dirpath, task_id):
  '''Helper function. Gets temporary directory for saving model.'''

  base_dirpath = 'workertemp_' + str(task_id)
  temp_dir = os.path.join(dirpath, base_dirpath)
  tf.io.gfile.makedirs(temp_dir)
  return temp_dir


def write_filepath(filepath, task_type, task_id):
  '''Helper function. Gets filepath to save model.'''

  dirpath = os.path.dirname(filepath)
  base = os.path.basename(filepath)
  if not _is_chief(task_type, task_id):
    dirpath = _get_temp_dir(dirpath, task_id)
  return os.path.join(dirpath, base)


def main():
  # Create strategy
  strategy = tf.distribute.MultiWorkerMirroredStrategy()

  # Get data
  global_batch_size = PER_REPLICA_BATCH_SIZE * strategy.num_replicas_in_sync
  train_data, number_of_classes = create_dataset(global_batch_size)

  # Wrap variable creation within strategy scope
  with strategy.scope():
    model = create_model(number_of_classes)

  model.fit(train_data, epochs=EPOCHS)

  # Determine type and task of the machine from
  # the strategy cluster resolver
  task_type, task_id = (strategy.cluster_resolver.task_type,
                        strategy.cluster_resolver.task_id)

  # Based on the type and task, write to the desired model path
  write_model_path = write_filepath(BUCKET, task_type, task_id)
  model.save(write_model_path)

if __name__ == "__main__":
    main()

컨테이너를 빌드하기 전에 tf.distribute.Strategy API의 MultiWorkerMirroredStrategy를 사용하는 코드를 자세히 살펴보겠습니다.

코드에는 코드가 MultiWorkerMirroredStrategy와 작동하는 데 필요한 몇 가지 구성요소가 있습니다.

  1. 데이터를 샤딩해야 합니다. 즉, 각 작업자에게 전체 데이터 세트의 하위 집합이 할당됩니다. 따라서 각 작업자가 각 단계에서 겹치지 않는 데이터 세트 요소의 전역 배치 크기를 처리합니다. 이 샤딩은 tf.data.experimental.AutoShardPolicy를 통해 자동으로 발생하며 FILE 또는 DATA로 설정할 수 있습니다. 이 예에서 create_dataset() 함수는 AutoShardPolicyDATA로 설정합니다. Cassava 데이터 세트가 여러 파일로 다운로드되지 않았기 때문입니다. 그러나 정책을 DATA로 설정하지 않으면 기본 AUTO 정책이 적용되고 최종 결과는 동일합니다. 여기에서 MultiWorkerMirroredStrategy를 사용한 데이터 세트 샤딩에 관해 자세히 알아보세요.
  2. main() 함수에 MultiWorkerMirroredStrategy 객체가 생성됩니다. 다음은 전략 범위 내에 모델 변수 생성을 래핑합니다. 이 단계는 모든 복제본에서 미러링해야 하는 변수를 TensorFlow에 알려주는 중요한 단계입니다.
  3. 배치 크기는 num_replicas_in_sync에 의해 확장됩니다. 이렇게 하면 각 복제본이 각 단계에서 동일한 수의 예시를 처리합니다. TensorFlow에서 동기 데이터 동시 로드 전략을 사용할 때는 배치 크기를 확장하는 것이 좋습니다.
  4. 작업자마다 대상이 달라야 하므로 다중 작업자의 경우 모델을 저장하는 방법이 좀 더 복잡합니다. 최고 작업자는 모델을 원하는 모델 디렉터리에 저장하고, 다른 작업자는 모델을 임시 디렉터리에 저장합니다. 여러 작업자가 동일한 위치에 쓰지 않도록 하려면 이러한 임시 디렉터리가 고유해야 합니다. 저장에는 집합적 작업이 포함될 수 있습니다. 즉, 최고 작업자뿐만이 아니라 모든 작업자가 저장합니다. _is_chief(), _get_temp_dir(), write_filepath(), main() 함수에는 모두 모델을 저장하는 데 도움이 되는 상용구 코드가 포함되어 있습니다.

다른 환경에서 MultiWorkerMirroredStrategy를 사용한 경우 TF_CONFIG 환경 변수가 설정되어 있을 수 있습니다. Vertex AI는 TF_CONFIG을 자동으로 설정하므로 클러스터의 각 머신에서 이 변수를 정의할 필요가 없습니다.

4단계: 컨테이너 빌드

터미널에서 다음을 실행하여 프로젝트의 env 변수를 정의하고 your-cloud-project를 프로젝트의 ID로 바꿉니다.

PROJECT_ID='your-cloud-project'

Google Container Registry에서 컨테이너 이미지의 URI로 변수를 정의합니다.

IMAGE_URI="gcr.io/$PROJECT_ID/multiworker:cassava"

Docker 구성

gcloud auth configure-docker

그런 다음 cassava 디렉터리의 루트에서 다음을 실행하여 컨테이너를 빌드합니다.

docker build ./ -t $IMAGE_URI

마지막으로 Google Container Registry에 푸시합니다.

docker push $IMAGE_URI

컨테이너가 Container Registry로 푸시되었으므로 이제 학습 작업을 시작할 준비가 되었습니다.

6. Vertex AI에서 다중 작업자 학습 작업 실행

이 실습에서는 Google Container Registry의 커스텀 컨테이너를 통한 커스텀 학습을 사용하지만 사전 빌드된 컨테이너로 학습 작업을 실행할 수도 있습니다.

시작하려면 Cloud 콘솔의 Vertex 섹션에서 학습 섹션으로 이동합니다.

uCAIP 메뉴

1단계: 학습 작업 구성

만들기를 클릭하여 학습 작업을 위한 매개변수를 입력합니다.

  • 데이터 세트에서 관리형 데이터 세트 없음을 선택합니다.
  • 그런 다음 학습 방법으로 커스텀 학습(고급)을 선택하고 계속을 클릭합니다.
  • 모델 이름multiworker-cassava (또는 원하는 모델 이름)을 입력합니다.
  • 계속을 클릭합니다.

컨테이너 설정 단계에서 커스텀 컨테이너를 선택합니다.

커스텀 컨테이너 옵션

첫 번째 상자(컨테이너 이미지)에 이전 섹션의 IMAGE_URI 변수 값을 입력합니다. 사용자 고유의 프로젝트 ID가 포함된 gcr.io/your-cloud-project/multiworker:cassava여야 합니다. 나머지 필드는 비워 두고 계속을 클릭합니다.

계속을 다시 클릭하여 H 초매개변수 단계를 건너뜁니다.

2단계: 컴퓨팅 클러스터 구성

Vertex AI는 다양한 유형의 머신 작업을 처리하기 위해 4개의 작업자 풀을 제공합니다.

작업자 풀 0은 기본, 최고, 스케줄러 또는 '마스터'를 구성합니다. MultiWorkerMirroredStrategy에서 모든 머신은 복제된 계산이 실행되는 물리적 머신인 작업자로 지정됩니다. 작업자가 되는 각 머신 외에도 체크포인트 저장 및 텐서보드에 요약 파일 쓰기와 같은 일부 추가 작업을 수행하는 작업자가 하나 있어야 합니다. 이 머신을 최고 작업자라고 합니다. 최고 작업자는 하나뿐이므로 작업자 풀 0의 작업자 수는 항상 1입니다.

컴퓨팅 및 가격 책정에서 선택한 리전을 그대로 두고 작업자 풀 0을 다음과 같이 구성합니다.

Worker_pool_0

작업자 풀 1에는 클러스터의 작업자를 구성합니다.

작업자 풀 1을 다음과 같이 구성합니다.

Worker_pool_1

이제 클러스터가 CPU 전용 머신 두 개를 보유하도록 구성되었습니다. 학습 애플리케이션 코드가 실행되면 MultiWorkerMirroredStrategy가 학습을 두 머신 모두에 배포합니다.

MultiWorkerMirroredStrategy에는 최고 및 작업자 태스크 유형만 있으므로 추가 작업자 풀을 구성할 필요가 없습니다. 그러나 TensorFlow의 ParameterServerStrategy를 사용하려면 작업자 풀 2에서 매개변수 서버를 구성합니다. 클러스터에 평가자를 추가하려면 작업자 풀 3에서 해당 머신을 구성합니다.

초매개변수 조정 작업을 시작하려면 학습 시작을 클릭합니다. 콘솔의 학습 섹션에서 학습 파이프라인 탭에 새로 실행한 작업이 표시됩니다.

학습 작업

🎉 수고하셨습니다. 🎉

Vertex AI를 사용하여 다음을 수행하는 방법을 배웠습니다.

  • 커스텀 컨테이너에서 제공되는 학습 코드에 대한 다중 작업자 학습 작업을 시작합니다. 이 예에서는 TensorFlow 모델을 사용했지만 커스텀 또는 기본 제공되는 컨테이너를 사용하여 모든 프레임워크로 빌드된 모델을 학습시킬 수 있습니다.

Vertex의 다른 부분에 대해 자세히 알아보려면 문서를 확인하세요.

7. [선택사항] Vertex SDK 사용

이전 섹션에서는 UI를 통해 학습 작업을 시작하는 방법을 알아보았습니다. 이 섹션에서는 Vertex Python API를 사용하여 학습 작업을 제출하는 다른 방법을 확인할 수 있습니다.

노트북 인스턴스로 돌아가서 런처에서 TensorFlow 2 노트북을 만듭니다.

new_notebook

Vertex AI SDK를 가져옵니다.

from google.cloud import aiplatform

다중 작업자 학습 작업을 시작하려면 먼저 작업자 풀 사양을 정의해야 합니다. 사양에서 GPU를 사용하는 것은 완전히 선택사항이며 이전 섹션과 같이 CPU 전용 클러스터를 원하는 경우 accelerator_typeaccelerator_count를 삭제할 수 있습니다.

# The spec of the worker pools including machine type and Docker image
# Be sure to replace {YOUR-PROJECT-ID} with your project ID.
worker_pool_specs=[
     {
        "replica_count": 1,
        "machine_spec": {
          "machine_type": "n1-standard-8", "accelerator_type": "NVIDIA_TESLA_V100", "accelerator_count": 1
        },
        "container_spec": {"image_uri": "gcr.io/{YOUR-PROJECT-ID}/multiworker:cassava"}
      },
      {
        "replica_count": 1,
        "machine_spec": {
          "machine_type": "n1-standard-8", "accelerator_type": "NVIDIA_TESLA_V100", "accelerator_count": 1
        },
        "container_spec": {"image_uri": "gcr.io/{YOUR-PROJECT-ID}/multiworker:cassava"}
      }
]

다음으로, CustomJob를 만들고 실행합니다. 스테이징을 위해 {YOUR_BUCKET}을 프로젝트의 버킷으로 바꿔야 합니다. 앞서 만든 동일한 버킷을 사용할 수 있습니다.

# Replace YOUR_BUCKET
my_multiworker_job = aiplatform.CustomJob(display_name='multiworker-cassava-sdk',
                              worker_pool_specs=worker_pool_specs,
                              staging_bucket='gs://{YOUR_BUCKET}')

my_multiworker_job.run()

콘솔의 학습 섹션에서 커스텀 작업 탭에 학습 작업이 표시됩니다.

커스텀 작업

8. 정리

노트북이 유휴 시간 60분 후에 타임아웃되도록 구성했으므로 인스턴스를 종료할 필요가 없습니다. 인스턴스를 수동으로 종료하려면 콘솔의 Vertex AI Workbench 섹션에서 중지 버튼을 클릭합니다. 노트북을 완전히 삭제하려면 '삭제' 버튼을 클릭합니다.

인스턴스 중지

스토리지 버킷을 삭제하려면 Cloud 콘솔의 탐색 메뉴를 사용하여 스토리지로 이동하고 버킷을 선택하고 '삭제'를 클릭합니다.

스토리지 삭제