TensorFlow를 사용한 분산 훈련

TensorFlow.org에서 보기 Google Colab에서 실행하기 GitHub에서 소스 보기 노트북 다운로드하기

Overview

tf.distribute.Strategy는 여러 GPU, 여러 머신 또는 TPU에 훈련을 분산하는 TensorFlow API입니다. 이 API를 사용하면 코드를 최소한으로 변경하여 기존 모델 및 훈련 코드를 분산 처리할 수 있습니다.

tf.distribute.Strategy는 다음과 같은 주요 목표를 염두에 두고 설계되었습니다.

  • 쉬운 사용법과 연구원, 머신러닝 엔지니어 등 여러 사용자 세그먼트 지원
  • 즉시 뛰어난 성능을 제공
  • 전략 간 용이한 전환

Keras Model.fit과 같은 고수준 API를 사용하는 tf.distribute.Strategy뿐만 아니라 사용자 정의 훈련 루프를 사용해도 훈련을 분산할 수 있습니다(일반적으로 TensorFlow를 사용하는 모든 계산 포함).

TensorFlow 2.x에서는 프로그램을 긴급하게 실행하거나 tf.function을 사용하여 그래프에서 실행할 수 있습니다. tf.distribute.Strategy는 이러한 실행 모드를 모두 지원하지만 tf.function에서 가장 잘 작동합니다. Eager 모드는 디버깅 목적으로만 권장되며 tf.distribute.TPUStrategy에서는 지원되지 않습니다. 이 가이드는 훈련에 초점을 맞추고 있지만 다른 플랫폼에서 평가 및 예측을 분산하는 데에도 이 API를 사용할 수 있습니다.

TensorFlow의 기본 구성요소가 전략을 인식하도록 변경되었기 때문에 코드를 약간만 변경하면 tf.distribute.Strategy를 사용할 수 있습니다. 해당 항목으로는 변수, 레이어, 모델, 옵티마이저, 메트릭, 요약 및 체크포인트가 있습니다.

이 가이드에서는 다양한 유형의 전략과 다양한 상황에서 전략을 사용하는 방법에 대해 배우게 됩니다. 성능 문제를 디버그하는 방법을 알아보려면 TensorFlow GPU 성능 최적화 가이드를 확인하세요.

참고: 이 개념을 보다 깊이 이해하려면 심층 프레젠테이션(Inside TensorFlow: tf.distribute.Strategy)을 시청하세요. 이 동영상은 특히 자신만의 훈련 루프를 작성할 계획을 가진 분들께 권장합니다.

TensorFlow 설정하기

import tensorflow as tf
2022-12-14 21:30:22.985385: W tensorflow/compiler/xla/stream_executor/platform/default/dso_loader.cc:64] Could not load dynamic library 'libnvinfer.so.7'; dlerror: libnvinfer.so.7: cannot open shared object file: No such file or directory
2022-12-14 21:30:22.985508: W tensorflow/compiler/xla/stream_executor/platform/default/dso_loader.cc:64] Could not load dynamic library 'libnvinfer_plugin.so.7'; dlerror: libnvinfer_plugin.so.7: cannot open shared object file: No such file or directory
2022-12-14 21:30:22.985519: W tensorflow/compiler/tf2tensorrt/utils/py_utils.cc:38] TF-TRT Warning: Cannot dlopen some TensorRT libraries. If you would like to use Nvidia GPU with TensorRT, please make sure the missing libraries mentioned above are installed properly.

전략 유형

tf.distribute.Strategy는 다양한 축에 따른 여러 가지 사용 사례를 다룹니다. 현재는 일부 조합만 지원되며 다른 조합은 향후에 추가될 예정입니다. 일부 축에 대한 내용은 다음과 같습니다.

  • 동기식 및 비동기식 훈련: 데이터 병렬 처리로 훈련을 분산하는 두 가지 일반적인 방법입니다. 동기식 훈련에서 모든 작업자는 동기화된 입력 데이터의 다른 슬라이스에 대해 훈련하고 각 단계에서 그래디언트를 집계합니다. 비동기식 훈련에서 모든 작업자는 입력 데이터에 대해 독립적으로 훈련하고 변수를 비동기적으로 업데이트합니다. 일반적으로 동기식 훈련은 매개변수 서버 아키텍처를 통해 올 리듀스(all-reduce) 및 비동기삭(async)으로 지원됩니다.
  • 하드웨어 플랫폼: 하나의 머신에서 여러 GPU를 사용하도록 혹은 네트워크에서 여러 머신(각각 0개 이상의 GPU 포함)을 사용하도록 혹은 Cloud TPU를 사용하도록 훈련을 확장할 수 있습니다.

TensorFlow에는 이러한 사용 사례를 지원하는 MirroredStrategy, TPUStrategy, MultiWorkerMirroredStrategy, ParameterServerStrategy, CentralStorageStrategy 및 기타 전략이 있습니다. 다음 섹션은 TensorFlow의 각 시나리오에서 어떠한 항목이 지원되는지 설명합니다. 다음은 간략한 개요입니다.

훈련 API MirroredStrategy TPUStrategy MultiWorkerMirroredStrategy CentralStorageStrategy ParameterServerStrategy
Keras Model.fit 지원됨 지원됨 지원됨 실험 기능으로 지원 실험 기능으로 지원
사용자 정의 훈련 루프 지원됨 지원됨 지원됨 실험 기능으로 지원 실험 기능으로 지원
Estimator API 제한적인 지원 지원되지 않음 제한적인 지원 제한적인 지원 제한적인 지원

참고: 실험 기능으로 지원은 API가 호환성을 보장하지 않음을 의미합니다.

경고: Estimator 지원은 제한적입니다. 기본 훈련 및 평가는 실험기능으로 지원되며 스캐폴드와 같은 고급 기능은 구현되지 않습니다. 사용 사례가 적용되지 않는 경우 Keras 또는 사용자 정의 훈련 루프를 사용해야 합니다. 새 코드에는 Estimator를 사용하지 않는 것이 좋습니다. Estimator는 올바르게 작성하기가 더 어려운 v1.Session 스타일 코드를 실행하며 특히 TF 2 코드와 결합할 때 예기치 않게 작동하는 모습을 보일 수 있습니다. Estimator는 호환성 보장 대상에 해당하지만 보안 취약점 외에는 수정 사항이 제공되지 않습니다. 자세한 내용은 마이그레이션 가이드를 참조하세요.

MirroredStrategy

tf.distribute.MirroredStrategy는 하나의 머신으로 여러 GPU를 사용하여 작업을 수행하는 동기식 분산 훈련을 지원합니다. GPU 장치당 하나의 복제본을 생성합니다. 모델의 각 변수는 모든 복제본에서 미러링됩니다. 변수들은 다 함께 MirroredVariable이라는 단일 개념적 변수를 형성합니다. 모든 변수는 동일한 업데이트를 적용하며 서로 동기화된 상태를 유지합니다.

여러 장치에 변수의 변경사항을 전달하기 위해 효율적인 올 리듀스(all-reduce) 알고리즘을 사용합니다. 올 리듀스 알고리즘은 모든 장치의 텐서를 모은 다음 그 합을 구하고 다시 각 장비에 제공합니다. 이 통합된 알고리즘은 매우 효율적이기에 동기식의 오버헤드를 줄일 수 있습니다. 장치 간에 사용 가능한 통신 방법에 따라 다양한 올 리듀스 알고리즘과 구현이 있습니다. 기본적으로 NVIDIA Collective Communication Library(NCCL)를 올 리듀스 구현으로 사용합니다. 몇 가지 다른 옵션 중에서 선택하거나 직접 작성할 수 있습니다.

MirroredStrategy를 생성하는 가장 간단한 방법은 다음과 같습니다.

mirrored_strategy = tf.distribute.MirroredStrategy()
INFO:tensorflow:Using MirroredStrategy with devices ('/job:localhost/replica:0/task:0/device:GPU:0', '/job:localhost/replica:0/task:0/device:GPU:1', '/job:localhost/replica:0/task:0/device:GPU:2', '/job:localhost/replica:0/task:0/device:GPU:3')

이렇게 하면 TensorFlow에 표시되는 모든 GPU를 사용하고 NCCL을 장치 간 통신 수단으로 사용하는 MirroredStrategy 인스턴스가 생성됩니다.

머신에서 일부 GPU만 사용하려면 다음과 같이 하면 됩니다.

mirrored_strategy = tf.distribute.MirroredStrategy(devices=["/gpu:0", "/gpu:1"])
INFO:tensorflow:Using MirroredStrategy with devices ('/job:localhost/replica:0/task:0/device:GPU:0', '/job:localhost/replica:0/task:0/device:GPU:1')

장치 간 통신을 재정의하려면 tf.distribute.CrossDeviceOps의 인스턴스를 제공하여 cross_device_ops 인수를 사용하면 됩니다. 현재는 기본값인 tf.distribute.NcclAllReduce 이외에 tf.distribute.HierarchicalCopyAllReducetf.distribute.ReductionToOneDevice의 두 가지 옵션을 사용합니다.

mirrored_strategy = tf.distribute.MirroredStrategy(
    cross_device_ops=tf.distribute.HierarchicalCopyAllReduce())
INFO:tensorflow:Using MirroredStrategy with devices ('/job:localhost/replica:0/task:0/device:GPU:0', '/job:localhost/replica:0/task:0/device:GPU:1', '/job:localhost/replica:0/task:0/device:GPU:2', '/job:localhost/replica:0/task:0/device:GPU:3')

TPUStrategy

tf.distribute.TPUStrategy를 사용하면 Tensor Processing Units(TPU)에서 TensorFlow 훈련을 실행할 수 있습니다. TPU는 머신 학습 워크로드를 극적으로 가속화하도록 설계된 Google의 특수 ASIC입니다. TPU는 Google Colab, TPU Research Cloud, Cloud TPU에서 사용할 수 있습니다.

TPUStrategy는 분산 훈련 아키텍처의 측면에서 MirroredStrategy와 매우 유사하며 동기식 분산 훈련을 구현합니다. TPU는 TPUStrategy에서 사용되는 효율적인 올 리듀스 및 기타 집단 작업을 자체적으로 여러 TPU 코어에서 구현합니다.

TPUStrategy를 인스턴스화하는 방법은 다음과 같습니다.

참고: Colab에서 TPU 코드를 실행하려면 TPU를 Colab 런타임으로 선택해야 합니다. 전체 예제는 TPU 사용하기 가이드를 참조하세요.

cluster_resolver = tf.distribute.cluster_resolver.TPUClusterResolver(
    tpu=tpu_address)
tf.config.experimental_connect_to_cluster(cluster_resolver)
tf.tpu.experimental.initialize_tpu_system(cluster_resolver)
tpu_strategy = tf.distribute.TPUStrategy(cluster_resolver)

TPUClusterResolver 인스턴스는 TPU를 찾을 수 있도록 돕습니다. Colab에서는 이에 해당하는 인수를 지정할 필요가 없습니다.

Cloud TPU에서 사용하려는 경우:

  • tpu 인수에서 TPU 리소스의 이름을 지정해야 합니다.
  • 프로그램을 시작할 때 명시적으로 TPU 시스템을 초기화해야 합니다. 이 작업은 TPU를 계산에 사용하기 전에 필요합니다. TPU 시스템을 초기화하면 TPU 메모리도 지워지므로 상태 손실을 방지하기 위해 이 단계를 먼저 완료하는 것이 중요합니다.

MultiWorkerMirroredStrategy

tf.distribute.MultiWorkerMirroredStrategyMirroredStrategy와 매우 유사합니다. 이는 잠재적으로 여러 GPU가 있는 여러 작업자에 걸쳐 동기식 분산 훈련을 구현합니다. tf.distribute.MirroredStrategy와 유사하게 모든 작업자에 걸쳐 각 장치의 모델에 있는 모든 변수의 사본을 생성합니다.

MultiWorkerMirroredStrategy를 생성하는 가장 간단한 방법은 다음과 같습니다.

strategy = tf.distribute.MultiWorkerMirroredStrategy()
WARNING:tensorflow:Collective ops is not configured at program startup. Some performance features may not be enabled.
INFO:tensorflow:Single-worker MultiWorkerMirroredStrategy with local_devices = ('/device:GPU:0', '/device:GPU:1', '/device:GPU:2', '/device:GPU:3'), communication = CommunicationImplementation.AUTO

MultiWorkerMirroredStrategy에는 장치 간 통신에 사용할 수 있는 수집 연산 구현이 두 가지 있습니다. CommunicationImplementation.RINGRPC를 기반으로 하며 CPU와 GPU 모두를 지원합니다.
gRPC를 사용한 링 네트워크 기반의 수집 연산입니다. CommunicationImplementation.NCCL은 NCCL을 사용하고 GPU에서 최신의 성능을 제공하지만 CPU는 지원하지 않습니다. CollectiveCommunication.AUTO는 선택을 Tensorflow로 연기합니다. 지정하는 방법은 다음과 같습니다.

communication_options = tf.distribute.experimental.CommunicationOptions(
    implementation=tf.distribute.experimental.CommunicationImplementation.NCCL)
strategy = tf.distribute.MultiWorkerMirroredStrategy(
    communication_options=communication_options)
WARNING:tensorflow:Collective ops is not configured at program startup. Some performance features may not be enabled.
INFO:tensorflow:Single-worker MultiWorkerMirroredStrategy with local_devices = ('/device:GPU:0', '/device:GPU:1', '/device:GPU:2', '/device:GPU:3'), communication = CommunicationImplementation.NCCL

멀티 GPU 훈련과 비교하여 다중 작업자 훈련을 진행할 경우의 주요 차이점은 다중 작업자 설정입니다. 'TF_CONFIG' 환경 변수는 클러스터의 일부인 각 작업자에 클러스터 구성을 지정하는 TensorFlow의 표준 방법입니다. 이 문서의 TF_CONFIG 설정하기 섹션에서 자세히 알아보세요.

MultiWorkerMirroredStrategy에 대한 자세한 내용은 다음 튜토리얼을 참조하세요.

ParameterServerStrategy

매개변수 서버 훈련은 여러 머신에서 모델 훈련을 확장하는 일반적인 데이터 병렬 방식입니다. 매개변수 서버 훈련 클러스터는 작업자와 매개변수 서버로 구성되어 있습니다. 변수는 매개변수 서버에서 생성되며 각 단계에서 작업자가 읽고 업데이트합니다. 자세한 내용은 매개변수 서버 훈련 튜토리얼을 확인하세요.

TensorFlow 2에서 매개변수 서버 훈련은 tf.distribute.experimental.coordinator.ClusterCoordinator 클래스를 통해 센트럴 코디네이터 기반 아키텍처를 사용합니다.

이 구현에서 workerparameter server 작업은 코디네이터의 작업을 수신하는 tf.distribute.Server를 실행합니다. 코디네이터는 리소스를 생성하고, 훈련 작업을 발송하고, 체크포인트를 작성하고, 작업 실패를 처리합니다.

코디네이터에서 실행되는 프로그래밍에서 ParameterServerStrategy 객체를 사용하여 훈련 단계를 정의하고 ClusterCoordinator를 사용하여 원격 작업자에게 훈련 단계를 전달합니다. 이를 생성하는 가장 간단한 단계는 다음과 같습니다.

strategy = tf.distribute.experimental.ParameterServerStrategy(
    tf.distribute.cluster_resolver.TFConfigClusterResolver(),
    variable_partitioner=variable_partitioner)
coordinator = tf.distribute.experimental.coordinator.ClusterCoordinator(
    strategy)

ParameterServerStrategy에 대해 자세히 알아보려면 Keras Model.fit 및 사용자 정의 훈련 루프를 사용하는 매개변수 서버 훈련 튜토리얼을 확인하세요.

참고: TFConfigClusterResolver를 사용하는 경우 'TF_CONFIG' 환경 변수를 구성해야 합니다. 이는 MultiWorkerMirroredStrategy'TF_CONFIG'와 유사하지만 추가 주의 사항이 있습니다.

TensorFlow 1에서 ParameterServerStrategytf.compat.v1.distribute.experimental.ParameterServerStrategy 기호를 통해 Estimator에서만 사용할 수 있습니다.

참고: 이 전략은 현재 개발 중이므로 experimental입니다.

CentralStorageStrategy

tf.distribute.experimental.CentralStorageStrategy는 동기식 훈련도 수행합니다. 변수는 미러링되지 않고 대신 CPU에 배치되며 작업은 모든 로컬 GPU에 복제됩니다. GPU가 하나만 있는 경우 모든 변수와 연산이 해당 GPU에 배치됩니다.

다음을 수행하여 CentralStorageStrategy의 인스턴스를 생성합니다.

central_storage_strategy = tf.distribute.experimental.CentralStorageStrategy()
INFO:tensorflow:ParameterServerStrategy (CentralStorageStrategy if you are using a single machine) with compute_devices = ['/job:localhost/replica:0/task:0/device:GPU:0', '/job:localhost/replica:0/task:0/device:GPU:1', '/job:localhost/replica:0/task:0/device:GPU:2', '/job:localhost/replica:0/task:0/device:GPU:3'], variable_device = '/device:CPU:0'

이렇게 하면 보이는 모든 GPU와 CPU를 사용하는 CentralStorageStrategy 인스턴스가 생성됩니다. 복제본의 변수에 대한 업데이트는 변수에 적용되기 전에 집계됩니다.

참고: 이 전략은 현재 작업을 진행하고 있기에 experimental입니다.

Other strategies

위의 전략 외에도 tf.distribute API를 사용할 경우 프로토타이핑 및 디버깅에 유용할 수 있는 두 가지 기타 전략이 있습니다.

기본 전략

기본 전략은 명시적인 분산 전략이 범위에 없을 때 존재하는 분산 전략입니다. tf.distribute.Strategy 인터페이스를 구현하지만 그냥 통과하며 실제 분산 기능은 제공하지 않습니다. 예를 들어 Strategy.run(fn)은 단순히 fn을 호출합니다. 이 전략을 사용하여 작성한 코드는 전략 없이 작성한 코드와 똑같이 작동해야 합니다. 이를 "no-op"(무연산) 전략이라 생각할 수 있습니다.

기본 전략은 단일 항목(singleton)이며 더 이상 인스턴스를 만들 수 없습니다. 명시적 전략 범위 외부에서 tf.distribute.get_strategy를 사용하여 가져올 수 있습니다(명시적 전략 범위 내에서 현재 전략을 가져올 때 사용할 수 있는 API와 동일).

default_strategy = tf.distribute.get_strategy()

이 전략은 다음과 같은 두 가지 주요 목적을 달성하는 작업을 수행합니다.

  • 분산 인식 라이브러리 코드를 무조건으로 작성할 수 있습니다. 예를 들어 tf.keras.optimizers에서 tf.distribute.get_strategy를 사용하고 이 전략을 사용하여 그래디언트를 줄일 수 있습니다. 그러면 항상 Strategy.reduce API를 호출할 수 있는 전략 개체를 반환합니다.
# In optimizer or other library code
# Get currently active strategy
strategy = tf.distribute.get_strategy()
strategy.reduce("SUM", 1., axis=None)  # reduce some values
1.0
  • 라이브러리 코드와 유사하게 조건부 논리 없이 분산 전략을 사용하거나 사용하지 않고 최종 사용자의 프로그램을 작성하는 데 기본 전략을 사용할 수 있습니다. 다음은 이를 보여주는 예제 코드 조각입니다.
if tf.config.list_physical_devices('GPU'):
  strategy = tf.distribute.MirroredStrategy()
else:  # Use the Default Strategy
  strategy = tf.distribute.get_strategy()

with strategy.scope():
  # Do something interesting
  print(tf.Variable(1.))
INFO:tensorflow:Using MirroredStrategy with devices ('/job:localhost/replica:0/task:0/device:GPU:0', '/job:localhost/replica:0/task:0/device:GPU:1', '/job:localhost/replica:0/task:0/device:GPU:2', '/job:localhost/replica:0/task:0/device:GPU:3')
MirroredVariable:{
  0: <tf.Variable 'Variable:0' shape=() dtype=float32, numpy=1.0>,
  1: <tf.Variable 'Variable/replica_1:0' shape=() dtype=float32, numpy=1.0>,
  2: <tf.Variable 'Variable/replica_2:0' shape=() dtype=float32, numpy=1.0>,
  3: <tf.Variable 'Variable/replica_3:0' shape=() dtype=float32, numpy=1.0>
}

OneDeviceStrategy

tf.distribute.OneDeviceStrategy는 모든 변수와 계산을 지정한 단일 장치에 배치하는 전략입니다.

strategy = tf.distribute.OneDeviceStrategy(device="/gpu:0")

이 전략은 여러 면에서 기본 전략과 다릅니다. 기본 전략에서 변수 배치 논리는 분산 전략 없이 TensorFlow를 실행하는 것과 비교할 경우 변경되지 않은 상태로 유지됩니다. 그러나 OneDeviceStrategy를 사용하면 해당 범위에서 생성된 모든 변수가 지정한 장치에 명시적으로 배치됩니다. 또한 OneDeviceStrategy.run을 통해 호출한 모든 함수도 지정한 장치에 배치됩니다.

이 전략을 통해 분산된 입력을 지정한 장치로 미리 가져옵니다. 기본 전략에는 입력 분산이 없습니다.

기본 전략과 유사하게 이 전략은 실제로 여러 장치/머신에 분산하는 다른 전략으로 전환하기 전에 코드를 테스트하는 데 사용할 수도 있습니다. 이렇게 하면 기본 전략 이상의 분산 전략 머신만 실행하지만 MirroredStrategy 또는 TPUStrategy 등은 완전히 사용하지 않습니다. 전략이 없는 것처럼 동작하는 코드를 원하는 경우 기본 전략을 사용하세요.

지금까지 다양한 전략과 이를 인스턴스화하는 방법에 대해 배웠습니다. 다음 몇 가지 섹션은 훈련을 분산하는 데 사용할 수 있는 다양한 방법을 보여줍니다.

Keras Model.fit과 함께 tf.distribute.Strategy 사용하기

tf.distribute.StrategyKeras API 사양의 TensorFlow 구현인 tf.keras에 통합되었습니다. tf.keras는 모델을 빌드하고 훈련하는 고수준 API입니다. tf.keras 백엔드에 통합하면 Model.fit을 사용하여 Keras 훈련 프레임워크로 작성된 교육을 원활하게 분산할 수 있습니다.

코드에서 변경해야 하는 사항은 다음과 같습니다.

  1. 적절한 tf.distribute.Strategy의 인스턴스를 생성합니다.
  2. Keras 모델, 옵티마이저 및 메트릭 생성을 strategy.scope 안으로 이동합니다. 따라서 모델의 call(), train_step()test_step() 메소드에 있는 코드는 모두 가속기에서 배포되고 실행됩니다.

TensorFlow 분산 전략은 모든 Keras 모델 유형, 즉 순차형, 함수형, 서브 클래스를 지원합니다.

다음은 하나의 Dense 레이어를 가진 매우 간단한 Keras 모델에 이 작업을 수행하는 코드 조각입니다.

mirrored_strategy = tf.distribute.MirroredStrategy()

with mirrored_strategy.scope():
  model = tf.keras.Sequential([tf.keras.layers.Dense(1, input_shape=(1,))])

model.compile(loss='mse', optimizer='sgd')
INFO:tensorflow:Using MirroredStrategy with devices ('/job:localhost/replica:0/task:0/device:GPU:0', '/job:localhost/replica:0/task:0/device:GPU:1', '/job:localhost/replica:0/task:0/device:GPU:2', '/job:localhost/replica:0/task:0/device:GPU:3')
INFO:tensorflow:Reduce to /job:localhost/replica:0/task:0/device:CPU:0 then broadcast to ('/job:localhost/replica:0/task:0/device:CPU:0',).
INFO:tensorflow:Reduce to /job:localhost/replica:0/task:0/device:CPU:0 then broadcast to ('/job:localhost/replica:0/task:0/device:CPU:0',).
INFO:tensorflow:Reduce to /job:localhost/replica:0/task:0/device:CPU:0 then broadcast to ('/job:localhost/replica:0/task:0/device:CPU:0',).
INFO:tensorflow:Reduce to /job:localhost/replica:0/task:0/device:CPU:0 then broadcast to ('/job:localhost/replica:0/task:0/device:CPU:0',).

이 예제는 MirroredStrategy를 사용하기에 하나의 머신이 여러 GPU를 사용하는 경우에 실행할 수 있습니다. strategy.scope()는 훈련을 분산할 때 사용할 전략을 Keras에 표시합니다. 이 범위 내에서 모델/옵티마이저/메트릭을 생성하면 일반 변수 대신 분산 변수를 생성할 수 있습니다. 설정이 완료되면 평소처럼 모델을 맞출 수 있습니다. MirroredStrategy는 사용 가능한 GPU에서 모델의 훈련을 복제하고, 그래디언트를 집계하는 등의 작업을 수행합니다.

dataset = tf.data.Dataset.from_tensors(([1.], [1.])).repeat(100).batch(10)
model.fit(dataset, epochs=2)
model.evaluate(dataset)
2022-12-14 21:30:28.618723: W tensorflow/core/grappler/optimizers/data/auto_shard.cc:784] AUTO sharding policy will apply DATA sharding policy as it failed to apply FILE sharding policy because of the following reason: Found an unshardable source dataset: name: "TensorDataset/_2"
op: "TensorDataset"
input: "Placeholder/_0"
input: "Placeholder/_1"
attr {
  key: "Toutput_types"
  value {
    list {
      type: DT_FLOAT
      type: DT_FLOAT
    }
  }
}
attr {
  key: "_cardinality"
  value {
    i: 1
  }
}
attr {
  key: "metadata"
  value {
    s: "\n\017TensorDataset:0"
  }
}
attr {
  key: "output_shapes"
  value {
    list {
      shape {
        dim {
          size: 1
        }
      }
      shape {
        dim {
          size: 1
        }
      }
    }
  }
}
experimental_type {
  type_id: TFT_PRODUCT
  args {
    type_id: TFT_DATASET
    args {
      type_id: TFT_PRODUCT
      args {
        type_id: TFT_TENSOR
        args {
          type_id: TFT_FLOAT
        }
      }
      args {
        type_id: TFT_TENSOR
        args {
          type_id: TFT_FLOAT
        }
      }
    }
  }
}
Epoch 1/2
INFO:tensorflow:batch_all_reduce: 2 all-reduces with algorithm = nccl, num_packs = 1
INFO:tensorflow:Reduce to /job:localhost/replica:0/task:0/device:CPU:0 then broadcast to ('/job:localhost/replica:0/task:0/device:CPU:0',).
INFO:tensorflow:Reduce to /job:localhost/replica:0/task:0/device:CPU:0 then broadcast to ('/job:localhost/replica:0/task:0/device:CPU:0',).
INFO:tensorflow:Reduce to /job:localhost/replica:0/task:0/device:CPU:0 then broadcast to ('/job:localhost/replica:0/task:0/device:CPU:0',).
INFO:tensorflow:batch_all_reduce: 2 all-reduces with algorithm = nccl, num_packs = 1
INFO:tensorflow:Reduce to /job:localhost/replica:0/task:0/device:CPU:0 then broadcast to ('/job:localhost/replica:0/task:0/device:CPU:0',).
INFO:tensorflow:Reduce to /job:localhost/replica:0/task:0/device:CPU:0 then broadcast to ('/job:localhost/replica:0/task:0/device:CPU:0',).
 1/10 [==>...........................] - ETA: 41s - loss: 6.6755INFO:tensorflow:Reduce to /job:localhost/replica:0/task:0/device:CPU:0 then broadcast to ('/job:localhost/replica:0/task:0/device:CPU:0',).
10/10 [==============================] - 5s 5ms/step - loss: 4.7512
Epoch 2/2
10/10 [==============================] - 0s 4ms/step - loss: 2.1000
2022-12-14 21:30:34.012275: W tensorflow/core/grappler/optimizers/data/auto_shard.cc:784] AUTO sharding policy will apply DATA sharding policy as it failed to apply FILE sharding policy because of the following reason: Found an unshardable source dataset: name: "TensorDataset/_2"
op: "TensorDataset"
input: "Placeholder/_0"
input: "Placeholder/_1"
attr {
  key: "Toutput_types"
  value {
    list {
      type: DT_FLOAT
      type: DT_FLOAT
    }
  }
}
attr {
  key: "_cardinality"
  value {
    i: 1
  }
}
attr {
  key: "metadata"
  value {
    s: "\n\017TensorDataset:0"
  }
}
attr {
  key: "output_shapes"
  value {
    list {
      shape {
        dim {
          size: 1
        }
      }
      shape {
        dim {
          size: 1
        }
      }
    }
  }
}
experimental_type {
  type_id: TFT_PRODUCT
  args {
    type_id: TFT_DATASET
    args {
      type_id: TFT_PRODUCT
      args {
        type_id: TFT_TENSOR
        args {
          type_id: TFT_FLOAT
        }
      }
      args {
        type_id: TFT_TENSOR
        args {
          type_id: TFT_FLOAT
        }
      }
    }
  }
}
10/10 [==============================] - 2s 4ms/step - loss: 1.3042
1.3041685819625854

여기에서 tf.data.Dataset은 훈련 및 평가 입력을 제공합니다. NumPy 배열을 사용할 수도 있습니다.

import numpy as np

inputs, targets = np.ones((100, 1)), np.ones((100, 1))
model.fit(inputs, targets, epochs=2, batch_size=10)
Epoch 1/2
10/10 [==============================] - 0s 4ms/step - loss: 0.9282
Epoch 2/2
10/10 [==============================] - 0s 5ms/step - loss: 0.4103
<keras.callbacks.History at 0x7f9ce0051eb0>

Dataset 또는 NumPy를 사용하는 경우 제공된 입력의 각 배치가 여러 복제본에 균등하게 분할됩니다. 예를 들어 2개의 GPU와 함께 MirroredStrategy를 사용하는 경우 크기가 10인 각 배치는 2개의 GPU로 분할되어 각 단계에서 5개의 입력 예제를 수신하게 됩니다. 그러면 GPU를 추가할 때마다 각 에포크가 더 빠르게 훈련합니다. 일반적으로 가속기를 추가할 때 추가 계산 성능을 효과적으로 사용하기 위해 배치 크기를 늘리고 싶어할 것이며 모델에 따라 학습률을 다시 조정해야 할 수도 있습니다. 이러한 경우 strategy.num_replicas_in_sync를 사용하여 복제본의 수를 가져올 수 있습니다.

mirrored_strategy.num_replicas_in_sync
4
# Compute a global batch size using a number of replicas.
BATCH_SIZE_PER_REPLICA = 5
global_batch_size = (BATCH_SIZE_PER_REPLICA *
                     mirrored_strategy.num_replicas_in_sync)
dataset = tf.data.Dataset.from_tensors(([1.], [1.])).repeat(100)
dataset = dataset.batch(global_batch_size)

LEARNING_RATES_BY_BATCH_SIZE = {5: 0.1, 10: 0.15, 20:0.175}
learning_rate = LEARNING_RATES_BY_BATCH_SIZE[global_batch_size]

현재 지원되는 것은 무엇입니까?

훈련 API MirroredStrategy TPUStrategy MultiWorkerMirroredStrategy ParameterServerStrategy CentralStorageStrategy
Keras Model.fit 지원됨 지원됨 지원됨 실험 기능으로 지원 실험 기능으로 지원

예제 및 튜토리얼

다음은 Keras Model.fit과의 엔드 투 엔드 통합을 보여주는 튜토리얼 및 예제 목록입니다.

  1. 튜토리얼: Model.fitMirroredStrategy를 사용하는 훈련입니다.
  2. 튜토리얼: Model.fitMultiWorkerMirroredStrategy를 사용하는 훈련입니다.
  3. 가이드: Model.fitTPUStrategy 사용 예제를 포함합니다.
  4. 튜토리얼: Model.fitParameterServerStrategy를 사용하는 매개변수 서버 훈련입니다.
  5. 튜토리얼: Model.fitTPUStrategy를 사용하여 다수의 GLUE 벤치마크 작업의 BERT를 미세 조정합니다.
  6. 다양한 전략을 사용하여 구현한 최신 모델 컬렉션이 포함된 TensorFlow Model Garden 리포지토리입니다.

사용자 정의 훈련 루프와 함께 tf.distribute.Strategy 사용하기

위에서 설명한 것처럼 Keras Model.fit과 함께 tf.distribute.Strategy를 사용하려면 몇 줄의 코드만 변경하면 됩니다. 조금만 더 노력하면 사용자 정의 훈련 루프와 함께 tf.distribute.Strategy를 사용할 수도 있습니다.

Estimator 또는 Keras에서 가능한 것보다 더 많은 유연성과 훈련 루프 제어가 필요한 경우 사용자 정의 훈련 루프를 작성할 수 있습니다. 예를 들어 GAN을 사용할 때 각 라운드마다 다른 수의 생성기 또는 판별기 단계를 수행할 수 있습니다. 마찬가지로 고수준 프레임워크는 강화 학습 훈련에 적합하지 않습니다.

tf.distribute.Strategy 클래스는 사용자 정의 훈련 루프를 지원하는 코어 메서드 세트를 제공합니다. 이를 사용하려면 초기에 코드를 약간 재구성해야 할 수 있지만 일단 재구성을 완료하면 전략 인스턴스를 변경하는 방식으로 GPU, TPU 및 여러 시스템 간에 전환할 수 있게 됩니다.

다음은 이전과 동일한 Keras 모델을 사용하는 간단한 훈련 예제의 사용 사례를 보여주는 간단한 스니펫입니다.

먼저 전략 범위 내에서 모델과 최적화 프로그램을 생성합니다. 이렇게 하면 모델과 옵티마이저로 생성한 모든 변수가 미러링된 변수가 됩니다.

with mirrored_strategy.scope():
  model = tf.keras.Sequential([tf.keras.layers.Dense(1, input_shape=(1,))])
  optimizer = tf.keras.optimizers.SGD()

그런 다음 입력 데이터세트를 생성하고 tf.distribute.Strategy.experimental_distribute_dataset를 호출하여 전략에 따라 데이터세트를 분산합니다.

dataset = tf.data.Dataset.from_tensors(([1.], [1.])).repeat(1000).batch(
    global_batch_size)
dist_dataset = mirrored_strategy.experimental_distribute_dataset(dataset)
2022-12-14 21:30:36.253403: W tensorflow/core/grappler/optimizers/data/auto_shard.cc:784] AUTO sharding policy will apply DATA sharding policy as it failed to apply FILE sharding policy because of the following reason: Found an unshardable source dataset: name: "TensorDataset/_2"
op: "TensorDataset"
input: "Placeholder/_0"
input: "Placeholder/_1"
attr {
  key: "Toutput_types"
  value {
    list {
      type: DT_FLOAT
      type: DT_FLOAT
    }
  }
}
attr {
  key: "_cardinality"
  value {
    i: 1
  }
}
attr {
  key: "metadata"
  value {
    s: "\n\021TensorDataset:126"
  }
}
attr {
  key: "output_shapes"
  value {
    list {
      shape {
        dim {
          size: 1
        }
      }
      shape {
        dim {
          size: 1
        }
      }
    }
  }
}
experimental_type {
  type_id: TFT_PRODUCT
  args {
    type_id: TFT_DATASET
    args {
      type_id: TFT_PRODUCT
      args {
        type_id: TFT_TENSOR
        args {
          type_id: TFT_FLOAT
        }
      }
      args {
        type_id: TFT_TENSOR
        args {
          type_id: TFT_FLOAT
        }
      }
    }
  }
}

그런 다음 훈련의 한 단계를 정의합니다. tf.GradientTape를 사용하여 그래디언트를 계산하고 옵티마이저를 사용하여 이러한 그래디언트를 적용하여 모델의 변수를 업데이트합니다. 이 훈련 단계를 배포하려면 위에서 업데이트한 변수를 train_step 함수에 넣고 이전에 생성한 dist_dataset로부터 가져온 데이터세트 입력과 함께 tf.distribute.Strategy.run로 전달합니다.

loss_object = tf.keras.losses.BinaryCrossentropy(
  from_logits=True,
  reduction=tf.keras.losses.Reduction.NONE)

def compute_loss(labels, predictions):
  per_example_loss = loss_object(labels, predictions)
  return tf.nn.compute_average_loss(per_example_loss, global_batch_size=global_batch_size)

def train_step(inputs):
  features, labels = inputs

  with tf.GradientTape() as tape:
    predictions = model(features, training=True)
    loss = compute_loss(labels, predictions)

  gradients = tape.gradient(loss, model.trainable_variables)
  optimizer.apply_gradients(zip(gradients, model.trainable_variables))
  return loss

@tf.function
def distributed_train_step(dist_inputs):
  per_replica_losses = mirrored_strategy.run(train_step, args=(dist_inputs,))
  return mirrored_strategy.reduce(tf.distribute.ReduceOp.SUM, per_replica_losses,
                         axis=None)

위의 코드에서 주의해야 할 몇 가지 사항은 다음과 같습니다.

  1. tf.nn.compute_average_loss를 사용하여 손실을 계산했습니다. tf.nn.compute_average_loss는 예제당 손실을 합산하고 합산 값을 global_batch_size로 나눕니다. 이 계산의 결과는 각 복제본으로 그래디언트를 계산한 후 이를 합산하는 방식으로 복제본들의 결과를 집계하기 때문에 중요합니다.
  2. 또한 tf.distribute.Strategy.reduce API를 사용하여 tf.distribute.Strategy.run에서 반환한 결과를 집계했습니다. tf.distribute.Strategy.run은 전략의 각 로컬 복제본으로부터 입수한 결과를 반환하며 이 결과를 사용하는 방법에는 여러 가지가 있습니다. 사용자는 이를 reduce하여 집계된 값을 얻을 수 있습니다. tf.distribute.Strategy.experimental_local_results를 수행하여 결과에 포함된 값 목록을 로컬 복제본당 하나씩 가져올 수도 있습니다.
  3. 분산 전략 범위 내에서 apply_gradients를 호출하면 동작이 수정됩니다. 특히, 동기식 훈련 동안 각 병렬 인스턴스에 그래디언트를 적용하기 전에 그래디언트의 전체 복제본 합계를 수행합니다.

마지막으로 훈련 단계를 정의한 후에 다음과 같이 dist_dataset를 반복하고 루프에서 훈련을 실행할 수 있습니다.

for dist_inputs in dist_dataset:
  print(distributed_train_step(dist_inputs))
INFO:tensorflow:batch_all_reduce: 2 all-reduces with algorithm = nccl, num_packs = 1
INFO:tensorflow:batch_all_reduce: 2 all-reduces with algorithm = nccl, num_packs = 1
tf.Tensor(0.5699366, shape=(), dtype=float32)
tf.Tensor(0.5661711, shape=(), dtype=float32)
tf.Tensor(0.5624425, shape=(), dtype=float32)
tf.Tensor(0.55875045, shape=(), dtype=float32)
tf.Tensor(0.55509436, shape=(), dtype=float32)
tf.Tensor(0.55147403, shape=(), dtype=float32)
tf.Tensor(0.547889, shape=(), dtype=float32)
tf.Tensor(0.5443388, shape=(), dtype=float32)
tf.Tensor(0.5408232, shape=(), dtype=float32)
tf.Tensor(0.5373417, shape=(), dtype=float32)
tf.Tensor(0.533894, shape=(), dtype=float32)
tf.Tensor(0.53047955, shape=(), dtype=float32)
tf.Tensor(0.52709824, shape=(), dtype=float32)
tf.Tensor(0.52374953, shape=(), dtype=float32)
tf.Tensor(0.52043307, shape=(), dtype=float32)
tf.Tensor(0.5171485, shape=(), dtype=float32)
tf.Tensor(0.5138956, shape=(), dtype=float32)
tf.Tensor(0.51067394, shape=(), dtype=float32)
tf.Tensor(0.507483, shape=(), dtype=float32)
tf.Tensor(0.50432265, shape=(), dtype=float32)
tf.Tensor(0.5011925, shape=(), dtype=float32)
tf.Tensor(0.49809214, shape=(), dtype=float32)
tf.Tensor(0.4950213, shape=(), dtype=float32)
tf.Tensor(0.49197966, shape=(), dtype=float32)
tf.Tensor(0.48896685, shape=(), dtype=float32)
tf.Tensor(0.48598257, shape=(), dtype=float32)
tf.Tensor(0.4830265, shape=(), dtype=float32)
tf.Tensor(0.4800983, shape=(), dtype=float32)
tf.Tensor(0.47719774, shape=(), dtype=float32)
tf.Tensor(0.47432443, shape=(), dtype=float32)
tf.Tensor(0.47147804, shape=(), dtype=float32)
tf.Tensor(0.46865836, shape=(), dtype=float32)
tf.Tensor(0.46586505, shape=(), dtype=float32)
tf.Tensor(0.46309778, shape=(), dtype=float32)
tf.Tensor(0.46035624, shape=(), dtype=float32)
tf.Tensor(0.45764023, shape=(), dtype=float32)
tf.Tensor(0.45494938, shape=(), dtype=float32)
tf.Tensor(0.45228347, shape=(), dtype=float32)
tf.Tensor(0.44964224, shape=(), dtype=float32)
tf.Tensor(0.4470253, shape=(), dtype=float32)
tf.Tensor(0.4444325, shape=(), dtype=float32)
tf.Tensor(0.4418635, shape=(), dtype=float32)
tf.Tensor(0.4393181, shape=(), dtype=float32)
tf.Tensor(0.43679592, shape=(), dtype=float32)
tf.Tensor(0.43429682, shape=(), dtype=float32)
tf.Tensor(0.4318204, shape=(), dtype=float32)
tf.Tensor(0.42936656, shape=(), dtype=float32)
tf.Tensor(0.42693496, shape=(), dtype=float32)
tf.Tensor(0.4245254, shape=(), dtype=float32)
tf.Tensor(0.4221376, shape=(), dtype=float32)

위의 예제에서는 dist_dataset를 반복하여 훈련에 입력을 제공했습니다. NumPy 입력을 지원하기 위해 tf.distribute.Strategy.make_experimental_numpy_dataset도 제공됩니다. tf.distribute.Strategy.experimental_distribute_dataset를 호출하기 전에 이 API를 사용하여 데이터세트를 생성할 수 있습니다.

데이터를 반복하는 또 다른 방법은 명시적으로 반복기를 사용하는 것입니다. 전체 데이터세트를 반복하는 것과는 대조적으로 제공된 단계 수만큼 실행하려는 경우 이 작업을 수행할 수 있습니다. 이제 위의 반복구문이 수정되어 먼저 반복기를 만들면 다음에는 명시적으로 next를 호출하여 입력 데이터를 가져옵니다.

iterator = iter(dist_dataset)
for _ in range(10):
  print(distributed_train_step(next(iterator)))
tf.Tensor(0.41977128, shape=(), dtype=float32)
tf.Tensor(0.41742632, shape=(), dtype=float32)
tf.Tensor(0.41510245, shape=(), dtype=float32)
tf.Tensor(0.41279927, shape=(), dtype=float32)
tf.Tensor(0.41051674, shape=(), dtype=float32)
tf.Tensor(0.4082546, shape=(), dtype=float32)
tf.Tensor(0.40601254, shape=(), dtype=float32)
tf.Tensor(0.40379038, shape=(), dtype=float32)
tf.Tensor(0.40158793, shape=(), dtype=float32)
tf.Tensor(0.3994049, shape=(), dtype=float32)

여기서는 사용자 정의 훈련 루프를 분산하기 위해 tf.distribute.Strategy API를 사용하는 가장 간단한 사례를 다룹니다.

현재 지원되는 것은 무엇입니까?

훈련 API MirroredStrategy TPUStrategy MultiWorkerMirroredStrategy ParameterServerStrategy CentralStorageStrategy
사용자 정의 훈련 루프 지원됨 지원됨 지원됨 실험 기능으로 지원 실험 기능으로 지원

예제 및 튜토리얼

사용자 정의 훈련 루프와 함께 분산 전략을 사용하는 몇 가지 예제는 다음과 같습니다.

  1. 튜토리얼: 사용자 정의 훈련 루프 및 MirroredStrategy를 사용하는 훈련입니다.
  2. 튜토리얼: 사용자 정의 훈련 루프 및 MultiWorkerMirroredStrategy를 사용하는 훈련입니다.
  3. 가이드: TPUStrategy를 사용하는 사용자 정의 훈련 루프 예제를 포함합니다.
  4. 튜토리얼: 사용자 정의 훈련 루프와 ParameterServerStrategy를 사용하는 매개변수 서버 훈련입니다.
  5. 다양한 전략을 사용하여 구현한 최신 모델 컬렉션이 포함된 TensorFlow Model Garden 리포지토리입니다.

기타 주제

이 섹션에서는 여러 사용 사례와 관련된 몇 가지 주제를 다룹니다.

TF_CONFIG 환경 변수 설정하기

다중 작업자 훈련의 경우 앞서 언급했듯이 클러스터에서 실행하는 각 바이너리에 대해 'TF_CONFIG' 환경 변수를 설정해야 합니다. 'TF_CONFIG' 환경 변수는 클러스터를 구성하는 작업, 해당 주소 및 클러스터에서 각 작업의 역할을 지정하는 JSON 문자열입니다. tensorflow/ecosystem 리포지토리는 훈련 작업용 'TF_CONFIG'를 설정하는 Kubernetes 템플릿을 제공합니다.

'TF_CONFIG'에는 클러스터와 작업 등 두 가지 구성요소가 있습니다.

  • 클러스터는 작업자와 같이 서로 다른 유형의 작업으로 구성된 사전인 훈련 클러스터에 대한 정보를 제공합니다. 다중 작업자 훈련에는 일반 작업자가 수행하는 작업 외에 TensorBoard에 대한 체크포인트 저장 및 요약 파일 작성과 같은 약간의 더 많은 책임을 수행하는 작업자가 일반적으로 하나 있습니다. 이러한 작업자를 "수석" 작업자라고 하며 인덱스가 0인 작업자를 수석 작업자로 지정하는 것이 관례이며 실제로 이것은 tf.distribute.Strategy이 구현되는 방식입니다.
  • 반면에 작업은 현재 작업에 대한 정보를 제공합니다. 첫 번째 구성 요소 클러스터는 모든 작업자에 대해 동일하지만 두 번째 구성 요소 작업은 작업자마다 다르며 해당 작업자의 유형과 인덱스를 지정합니다.

'TF_CONFIG'의 예제는 다음과 같습니다.

os.environ["TF_CONFIG"] = json.dumps({
    "cluster": {
        "worker": ["host1:port", "host2:port", "host3:port"],
        "ps": ["host4:port", "host5:port"]
    },
   "task": {"type": "worker", "index": 1}
})

'TF_CONFIG'는 해당하는 호스트 및 포트와 함께 "cluster"에 3개의 작업자와 2개의 "ps" 작업이 있음을 지정합니다. "task" 부분은 "cluster", 즉 작업자 1(두 번째 작업자)에 현재 작업의 역할을 지정합니다. 클러스터의 유효한 역할은 "chief", "worker", "ps""evaluator"입니다. tf.distribute.experimental.ParameterServerStrategy를 사용하는 경우 외에는 "ps" 작업이 없어야 합니다.

무엇 향후 계획?

tf.distribute.Strategy는 현재 개발 중입니다. 사용해 보고 GitHub 문제를 사용하여 피드백을 제공해주세요.