In [ ]:
#@title Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
|
|
|
Note: 이 문서는 텐서플로 커뮤니티에서 번역했습니다. 커뮤니티 번역 활동의 특성상 정확한 번역과 최신 내용을 반영하기 위해 노력함에도 불구하고 공식 영문 문서의 내용과 일치하지 않을 수 있습니다. 이 번역에 개선할 부분이 있다면 tensorflow/docs-l10n 깃헙 저장소로 풀 리퀘스트를 보내주시기 바랍니다. 문서 번역이나 리뷰에 참여하려면 docs-ko@tensorflow.org로 메일을 보내주시기 바랍니다.
Note: tf.distribute
API와 함께 추정기를 사용할 수는 있지만, tf.distribute
와 함께 케라스(Keras)를 사용하는 것을 추천합니다. 케라스를 사용한 다중 워커(Multi-worker) 훈련을 봐주세요. tf.distribute.Strategy
를 추정기와 사용하는 것은 부분적으로만 지원하고 있습니다.
이 튜토리얼은 tf.estimator
와 함께 분산 다중 워커 훈련을 하기 위하여 tf.distribute.Strategy
를 어떻게 사용하는지 살펴봅니다. tf.estimator
를 사용하여 코드를 작성하고 있고, 고성능의 장비 한 대로 다룰 수 있는 것보다 더 큰 작업을 하는 데에 관심이 있으시다면 이 튜토리얼이 알맞습니다.
시작하기 전에, 텐서플로로 분산 훈련하기를 먼저 읽어주세요. 다중 GPU 훈련 튜토리얼도 관련이 있습니다. 이 튜토리얼과 같은 모델을 사용합니다.
In [ ]:
import tensorflow_datasets as tfds
import tensorflow as tf
tfds.disable_progress_bar()
import os, json
이 튜토리얼은 텐서플로 데이터셋(TensorFlow Datasets)의 MNIST 데이터셋을 사용합니다. 코드 내용은 다중 GPU 훈련 튜토리얼과 유사하지만 큰 차이점이 하나 있습니다. 바로 추정기를 써서 다중 워커 훈련을 할 때는 데이터셋을 워커 숫자대로 나누어 주어야 모델이 수렴합니다. 입력 데이터는 워커 인덱스로 샤딩(shard)합니다. 그러면 각 워커 프로세스가 데이터셋을 1/워커 수
만큼씩 겹치지 않게 나누어 갖습니다.
In [ ]:
BUFFER_SIZE = 10000
BATCH_SIZE = 64
def input_fn(mode, input_context=None):
datasets, info = tfds.load(name='mnist',
with_info=True,
as_supervised=True)
mnist_dataset = (datasets['train'] if mode == tf.estimator.ModeKeys.TRAIN else
datasets['test'])
def scale(image, label):
image = tf.cast(image, tf.float32)
image /= 255
return image, label
if input_context:
mnist_dataset = mnist_dataset.shard(input_context.num_input_pipelines,
input_context.input_pipeline_id)
return mnist_dataset.map(scale).cache().shuffle(BUFFER_SIZE).batch(BATCH_SIZE)
훈련을 수렴시키기 위한 또 다른 방법으로 각 워커에서 데이터셋을 제각기 다른 시드 값으로 셔플하는 것도 있습니다.
다중 GPU 훈련 튜토리얼과 비교할 때 가장 큰 차이 중 하나는 다중 워커를 설정하는 부분입니다. TF_CONFIG
환경 변수는 클러스터를 이루는 각 워커에 클러스터 설정을 지정하는 표준 방법입니다.
TF_CONFIG
에는 cluster
와 task
라는 두 가지 구성요소가 있습니다. cluster
는 전체 클러스터, 다시 말해 클러스터에 속한 워커와 파라미터 서버에 대한 정보를 제공합니다. task
는 현재 작업에 대한 정보를 지정합니다. 이 예제에서는 작업의 type
이 worker
이고, 작업의 index
는 0
입니다.
예를 들기 위하여, 이 튜토리얼에서는 두 개의 워커를 localhost에 띄울 때의 TF_CONFIG
를 보여드리겠습니다. 실제로는 각 워커를 다른 장비에서 띄울 텐데, 실제 IP 주소와 포트를 할당하고, 그에 맞게 TF_CONFIG를 지정해야 합니다. 예를 들어, 각 장비의 작업 index
가 달라야 합니다.
주의: 아래 코드를 코랩에서 실행하지 마십시오. 텐서플로 런타임이 주어진 IP와 포트로 gRPC 서버를 띄우려고 할 텐데, 아마도 실패할 것입니다.
os.environ['TF_CONFIG'] = json.dumps({
'cluster': {
'worker': ["localhost:12345", "localhost:23456"]
},
'task': {'type': 'worker', 'index': 0}
})
훈련을 위하여 레이어와 옵티마이저, 손실 함수를 정의하세요. 이 튜토리얼에서는 다중 GPU 훈련 튜토리얼과 비슷하게 케라스 레이어로 모델을 정의합니다.
In [ ]:
LEARNING_RATE = 1e-4
def model_fn(features, labels, mode):
model = tf.keras.Sequential([
tf.keras.layers.Conv2D(32, 3, activation='relu', input_shape=(28, 28, 1)),
tf.keras.layers.MaxPooling2D(),
tf.keras.layers.Flatten(),
tf.keras.layers.Dense(64, activation='relu'),
tf.keras.layers.Dense(10)
])
logits = model(features, training=False)
if mode == tf.estimator.ModeKeys.PREDICT:
predictions = {'logits': logits}
return tf.estimator.EstimatorSpec(labels=labels, predictions=predictions)
optimizer = tf.compat.v1.train.GradientDescentOptimizer(
learning_rate=LEARNING_RATE)
loss = tf.keras.losses.SparseCategoricalCrossentropy(
from_logits=True, reduction=tf.keras.losses.Reduction.NONE)(labels, logits)
loss = tf.reduce_sum(loss) * (1. / BATCH_SIZE)
if mode == tf.estimator.ModeKeys.EVAL:
return tf.estimator.EstimatorSpec(mode, loss=loss)
return tf.estimator.EstimatorSpec(
mode=mode,
loss=loss,
train_op=optimizer.minimize(
loss, tf.compat.v1.train.get_or_create_global_step()))
Note: 이 예제에서는 학습률이 고정되어있습니다. 하지만 실제로는 전역 배치 크기에 따라 학습률을 조정해야 할 수 있습니다.
모델을 훈련하기 위하여 tf.distribute.experimental.MultiWorkerMirroredStrategy
의 인스턴스를 사용하세요. MultiWorkerMirroredStrategy
는 모든 워커의 각 장비에, 모델의 레이어에 있는 모든 변수의 복사본을 만듭니다. 이 전략은 CollectiveOps
라는 수집을 위한 통신용 텐서플로 연산을 사용하여 그래디언트를 모으고, 변수들의 값을 동일하게 맞춥니다. 텐서플로로 분산 훈련하기에 이 전략에 대한 더 자세한 내용이 있습니다.
In [ ]:
strategy = tf.distribute.experimental.MultiWorkerMirroredStrategy()
In [ ]:
config = tf.estimator.RunConfig(train_distribute=strategy)
classifier = tf.estimator.Estimator(
model_fn=model_fn, model_dir='/tmp/multiworker', config=config)
tf.estimator.train_and_evaluate(
classifier,
train_spec=tf.estimator.TrainSpec(input_fn=input_fn),
eval_spec=tf.estimator.EvalSpec(input_fn=input_fn)
)
이제 모델과 tf.distribute.Strategy
로 만든 다중 워커를 사용할 수 있는 추정기가 있습니다. 다중 워커 훈련 성능을 최적화하려면 다음과 같은 방법을 사용해 보십시오.
tf.float
타입으로 바꾸세요. 공식 ResNet 모델의 예제에서 어떻게 변환하는지 볼 수 있습니다.집합 통신 구현을 사용하세요: MultiWorkerMirroredStrategy
는 여러 가지 집합 통신 구현을 제공합니다.
RING
은 장비 간 통신을 위하여 gRPC를 써서 링 네트워크 기반의 집합 통신을 구현한 것입니다.NCCL
은 Nvidia의 NCCL을 사용하여 수집 연산을 구현한 것입니다. AUTO
는 런타임이 알아서 고르도록 합니다.어떤 집합 구현이 가장 좋은지는 GPU의 숫자와 종류, 클러스터 장비 간 네트워크 연결 등에 따라 다를 수 있습니다. 런타임 자동 선택을 오버라이드하려면, MultiWorkerMirroredStrategy
생성자의 communication
인자에 적절한 값을 주면 됩니다. 예를 들어 communication=tf.distribute.experimental.CollectiveCommunication.NCCL
과 같이 주면 됩니다.
tf.keras.estimator.model_to_estimator
API를 이용하여 추정기 모델로 변환합니다.