문제해결

이 가이드에서는 Cloud TPU에서 자체 TensorFlow 모델을 실행하려는 사용자를 위한 문제해결 도움말을 제공합니다. Cloud TPU를 시작하는 방법에 관한 보다 일반적인 가이드는 빠른 시작 또는 MNIST 가이드를 참조하세요.

개요

Cloud TPU에서 TensorFlow 모델을 실행하기 위해 권장되는 전략은 TPUEstimator API를 사용하는 것입니다. 현재 TensorFlow의 Estimator API를 사용하는 경우 TPUEstimator로 전환하려면 일반적으로 코드 몇 줄만 변경하면 됩니다. 데이터를 TPUEstimator로 로드하는 데 권장하는 방법은 tf.data API를 사용하는 것입니다. TPUEstimatortf.data를 구현하는 실제 예시는 Cloud TPU에서 TPUEstimator API 사용의 MNIST 예시를 참조하세요. TPUEstimator로 MNIST 에스티메이터 포팅도 참조하세요.

모델을 TPUEstimator로 변환한 후 use_tpu=False 플래그가 설정된 상태에서 모델이 작동하는지 확인합니다. 이 플래그를 false로 설정하면 TensorFlow가 Estimator API로 돌아가고 TPU와 관련된 코드를 사용하지 않습니다. use_tpu=False가 설정된 상태에서 모델을 실행할 때 발생하는 모든 문제는 TPU와 관련이 없으므로 이 가이드에서 다루지 않습니다. 대신 TensorFlow 프로그래머 가이드를 참조하세요.

이론상 TPUEstimatoruse_tpu=False를 사용하여 성공적으로 실행되는 모델은 use_tpu=True를 설정하고 master가 TPU 서버 URL을 가리키도록 지정하는 것만으로 TPU에서 실행할 수 있습니다(일반적으로 클러스터 리졸버 사용). 그러나 TensorFlow 모델이 매우 복잡해질 수 있으며 TPU는 자체 실행 엔진을 사용하므로 TPU와 관련된 문제가 발생할 수 있습니다. 이러한 문제는 다음과 같은 광범위한 카테고리로 분류됩니다.

  1. 학습 스크립트를 TPU 서버에 전혀 연결할 수 없습니다.

  2. 모델 실행을 시도하면 TPU에서 오류가 반환됩니다.

  3. 모델 크기가 TPU 메모리에 맞지 않습니다.

  4. 모델을 TPU에서 실행하는 것은 가능하나 학습 속도가 예상만큼 빠르지 않습니다.

  5. 모델을 TPU에서 실행하는 것은 가능하나 TPU 학습 모델의 정확성이 CPU/GPU 학습 기준에 미치지 못합니다.

추가로 이 가이드에는 TPU에서 제공되는 일반적인 기능에 관한 FAQ가 포함되어 있습니다.

특정 유형의 신경망을 TPU로 포팅하는 방법에 대한 자세한 도움말은 Cloud TPU 가이드를 참조하세요.

TPU 서버 연결 문제

TPU에서 모델을 실행할 때 원격 TPU 서버 URL을 RunConfigmaster 매개변수에 전달해야 합니다. 내부적으로 TensorFlow는 이 서버와의 원격 tf.Session을 생성합니다. 이 섹션에서는 TPU 서버에 연결할 때 TensorFlow가 응답을 중단하거나 오류를 출력하는 상황을 해결하는 방법을 제공합니다. 모델이 큰 경우에는 TPU 그래프 컴파일 단계에 시간이 오래 걸릴 수 있으므로 응답을 중단했다고 결론을 내리기 전에 스크립트를 5분 이상 실행해보세요.

첫 번째 단계는 문제가 서버 자체에 있는지 또는 TensorFlow 학습 파이프라인에 있는지 확인하는 것입니다. 이 작업을 수행하려면 TPU 서버 URL을 사용하여 MNIST 가이드의 작업을 실행하고 올바르게 작동하는지 확인하세요. MNIST 가이드의 작업을 실행할 때에도 연결 문제가 발생하면 TPU 서버 문제인 것입니다. 이 경우에는 다음 단계를 수행하세요.

  1. 다음 명령어를 실행하여 사용 가능한 TPU를 나열합니다.

    (vm)$ gcloud compute tpus list
    

    MNIST 가이드에 나온 대로 zoneproject를 설정해야 할 수도 있습니다. 이렇게 하면 다음과 같은 출력이 표시됩니다.

    NAME       ZONE           ACCELERATOR_TYPE  NETWORK_ENDPOINT   NETWORK  RANGE          STATUS
    demo-tpu   us-central1-b  v2-8              10.240.1.2:8470    default  10.240.1.0  READY

  2. --tpu(위의 예시에서는 demo-tpu)에 올바른 값을 전달하는지, 그리고 이 TPU가 READY로 표시되는지 확인합니다. 또한 zoneproject가 다음을 사용하여 설정되었는지 확인합니다.

    (vm)$ gcloud config set project your-project-name
    
    (vm)$ gcloud config set compute/zone us-central1-b
    
  3. TPU가 READY로 표시되지 않거나 연결에 계속 문제가 발생하는 경우 gcloud compute tpus stop $TPU_SERVER_NAME && gcloud compute tpus start $TPU_SERVER_NAME을 사용하여 서버를 수동으로 다시 시작하세요. 위의 예시에서 $TPU_NAMEdemo-tpu입니다. 이 작업은 몇 분 정도 걸릴 수 있습니다.

  4. 위의 ... tpus list 명령어를 다시 실행하고 TPU가 READY 상태가 되기를 기다립니다. 이 작업은 몇 분 정도 걸릴 수 있습니다.

  5. MNIST 가이드를 다시 실행해 봅니다.

  6. MNIST 가이드 실행 문제가 지속되는 경우 도움 받기에 설명된 방법 중 하나를 통해 도움을 요청하세요.

MNIST 예시가 올바르게 실행되지만 모델이 여전히 응답을 중단한 상태라면 학습 파이프라인에 문제가 있을 가능성이 높습니다. 먼저 모델이 TPUEstimator API를 사용하고 있는지 확인하세요. 이 API는 복잡한 파이프라인을 처리할 뿐만 아니라 use_tpu 플래그를 사용하여 TPU와 비TPU 실행 간을 손쉽게 전환할 수 있게 해줍니다. TPUEstimator를 사용하는 방법의 몇 가지 예시는 TPU 가이드를 참조하세요. 모델에서 TPUEstimator API를 사용하면 use_tpu=False가 설정된 경우에 API가 올바르게 실행되는지 확인하세요. use_tpu=False가 설정된 경우에 모델이 제대로 실행되지 않으면 문제가 TPU와 관련이 없습니다.

일반적인 오류 디버깅

로컬 파일 시스템을 사용할 수 없는 경우

오류 메시지

InvalidArgumentError: Unimplemented: File system scheme '[local]' not implemented

세부정보

모든 입력 파일과 모델 디렉터리는 Cloud Storage 버킷 경로(gs://bucket-name/...)를 사용해야 하며 이 버킷은 TPU 서버에서 액세스할 수 있어야 합니다. 모든 데이터 처리 및 모델 체크포인트는 로컬 머신이 아닌 TPU 서버에서 수행됩니다. TPU에서 사용하기 위해 Cloud Storage를 적절하게 구성하는 방법은 Cloud Storage 버킷에 연결 가이드를 참조하세요.

tf.data.Dataset.cache()는 로컬 파일 시스템으로 캐시할 수 없음

오류 메시지

tensorflow.python.framework.errors_impl.UnimplementedError: File system scheme '[local]' not implemented (file: '[filename].lockfile')

세부정보

tf.data.DataSet은 캐시할 수 있습니다. .cache() 호출에는 두 가지 구현이 있습니다.

  1. 메모리에서 - 전달되는 인수가 없는 경우

  2. 파일 시스템에서 - 파일 경로가 인수로 전달되는 경우

Cloud TPU에서는 사용 가능한 메모리에 적합하다면 첫 번째 방법이 효과적이지만, 로컬 파일 시스템에 저장할 때 두 번째 방법은 효과가 없으며 위의 오류 메시지가 표시됩니다.

다음은 이 두 가지 상황을 보여주는 코드 스니펫입니다.

(1)
 import tensorflow as tf

def main():
  print('Hello world!')
  ds = tf.data.Dataset.range(10)
  ds = ds.cache()

runs to completion.

(2)
 import tensorflow as tf

def main():
  print('Hello world!')
  ds = tf.data.Dataset.range(10)
  ds = ds.cache('/tmp/foo')

generates the error.

API 가이드tf.data.Dataset.cache()에 대한 자세한 내용이 포함되어 있습니다.

지원되지 않는 데이터 유형

오류 메시지

TypeError: DataType is not a supported TPU infeed type.

세부정보

현재 TPU에서는 tf.float32, tf.int32, tf.bfloat16, tf.bool 데이터 유형만 지원됩니다. tf.uint8, tf.string, tf.int64와 같은 다른 일반적인 데이터 유형은 데이터 사전 처리 중에 지원되는 데이터 유형 중 하나로(TPUEstimatorinput_fn으로) 변환되어야 합니다. 다른 예시는 MNIST 가이드를 참조하세요. 하나의 예시로, MNIST의 이 코드 스니펫은 tf.uint8 바이트 시퀀스로 저장된 image 텐서를 tf.float32 텐서로 변환합니다.

image = tf.decode_raw(image, tf.uint8)
image = tf.cast(image, tf.float32)
image = tf.reshape(image, [784])

이 스니펫은 tf.int64로 저장된 label 텐서를 tf.int32 텐서로 변환합니다.

label = tf.cast(label, tf.int32)

지원되지 않는 동적 형태

오류 메시지

ValueError: shape [Shape] must have a fixed size for dimension d that is known at graph construction time.

세부정보

TPU에서 모델을 실행하기 위해 TensorFlow는 XLA 프레임워크를 사용하여 모델을 컴파일합니다. 이 컴파일 단계는 학습 속도와 메모리 사용량을 현저하게 개선하지만, 그래프의 모든 텐서 형태(차원 크기)가 정적이어야 하고 그래프 컴파일 시점에 해당 값이 정해져 있어야 합니다. 컴파일 시점에 형태가 결정되지 못한 경우에는 위와 같은 오류와 함께 TPU 컴파일이 실패합니다.

스트림에 남아있는 샘플 수가 배치 크기보다 작을 수 있으므로 동적 형태를 반환하는 일반적인 작업은 dataset.batch(batch_size)입니다. 따라서 TPU에서 학습할 때는 tf.contrib.data.batch_and_drop_remainder(batch_size)를 사용하세요. 그러면 모든 배치에 batch_size의 정적 형태가 포함되도록 파일에서 마지막 샘플 몇 개가 삭제됩니다. 예:

dataset = ...
dataset = dataset.apply(tf.contrib.data.batch_and_drop_remainder(batch_size))

사용 불가능한 TensorFlow 작업

오류 메시지

NotFoundError: No registered 'OpName' OpKernel for XLA_TPU_JIT devices compatible with node

세부정보

모델이 현재 TPU에서 제공되지 않는 TensorFlow 작업을 사용합니다.

이후 지원 계획 및 해결 방법에 대한 제안과 함께 TPU에서 사용 가능한 작업의 목록을 보려면 사용 가능한 TensorFlow 작업에 대한 가이드를 참조하세요.

메모리 부족 오류 메시지

오류 메시지

ResourceExhaustedError: Ran out of memory in memory space hbm; used: YYY; limit: 7.48G.

세부정보

각 Cloud TPU는 8개의 TPU 코어로 구성되어 있으며 각각 8GB의 RAM(또는 HBM: 높은 대역폭 메모리)을 가지고 있습니다. 이 메모리는 기울기 계산에 필요한 중간 결과 텐서와 가중치(변수) 텐서를 저장하는 데 사용됩니다. TPU RAM에 비해 모델이 너무 큰 경우에는 초기화가 실패하고 위의 오류 메시지가 출력됩니다. 자세한 도움말은 메모리 사용량 감소 섹션을 참조하세요.

CrossShardOptimizer 사용 안 함

오류 메시지

ValueError: CrossShardOptimizer must be used for model training on TPUs.

세부정보

TensorFlow Python API를 사용하여 모델을 정의할 때 사용자가 작성한 코드의 대부분은 TPU에 맞게 특수하게 처리할 필요가 없습니다. 가장 중요한 예외는 옵티마이저로, 이는 아래와 같이 tf.contrib.tpu.CrossShardOptimizer()로 래핑해야 합니다.

optimizer = tf.train.GradientDescentOptimizer(learning_rate=learning_rate)
if FLAGS.use_tpu:
  optimizer = tf.contrib.tpu.CrossShardOptimizer(optimizer)
train_op=optimizer.minimize(loss, tf.train.get_global_step())

각 Cloud TPU는 독립적인 처리 단위인 8개의 TPU 코어로 구성되어 있습니다. 각 학습 단계(예: 가중치 업데이트)에서 각 TPU 코어가 독립된 미니 배치의 데이터에 대해 정방향 전달 및 기울기 계산을 실행하면 모든 코어의 기울기가 서로 교환됩니다. 이는 대부분의 경우 하나의 대형 배치에서 경사를 계산하는 것과 수학적으로 동일합니다. 단, 일부 주의 사항에 대한 설명은 데이터 샤딩 이해를 참조하세요.

CrossShardOptimizer는 이러한 경사 교환을 담당하는 작업입니다. 기본적으로 CrossShardOptimizer는 코어 전체에서 평균 손실의 경사를 계산하지만 reduction=losses.Reduction.SUM을 전달하여 합계 손실을 계산하도록 구성할 수 있습니다.

TPU 서버에 연결할 수 없음

오류 메시지

An error was raised while a session was being created. This may be due to a preemption of a connected worker or parameter server. A new session is created.

세부정보

이 오류는 TensorFlow가 master로 전달되는 TPU 서버 URL에 연결할 수 없는 경우에 출력됩니다. 도움이 필요하면 TPU 서버 연결 문제에 대한 섹션을 참조하세요.

학습 도중 발생하는 오류

TPU에서 모델을 성공적으로 실행할 수 없는 경우 이와 관련된 모든 오류가 초기화 단계에서 파악되도록 설계되어 있습니다. 따라서 학습 도중에 모델이 실패하는 경우는 별로 없습니다. 이러한 문제가 발생한다면 대부분 데이터 사전 처리 함수에 문제가 있을 가능성이 가장 높습니다. 예를 들어 Dataset API를 사용하는 경우 일반적으로 dataset = dataset.repeat()을 호출해야 합니다. 그러지 않으면 데이터를 한 번 통과한 후 학습이 실패합니다. tf.while_loop()와 같은 동적 실행 작업도 입력 데이터에 의존하는 방식으로는 실패하기만 합니다. 드물게 허위 하드웨어 또는 네트워크 장애가 문제일 가능성도 있습니다.

실행 중단 문제

TPU 실행 도중 TensorFlow에 오류가 발생하는 경우, 스크립트가 셸로 돌아가지 않고 응답을 중단하는 것처럼 보이는 경우가 있습니다. 이 경우 키보드에서 CTRL+\를 눌러 SIGQUIT을 트리거하면 즉시 Python이 종료됩니다.

마찬가지로, TPU 실행 중에 CTRL+C를 누르면 TensorFlow가 즉시 종료되지는 않지만 대신 현재 반복 루프의 끝까지 기다렸다가 깔끔하게 종료됩니다. CTRL+\를 누르면 Python이 즉시 종료됩니다.

이런 식으로 종료한 후 TPU 서버에 다시 연결할 때 DeadlineExceededError와 같은 새로운 오류가 발생하면 명령어 gcloud compute tpus stop $TPU_SERVER_NAME && gcloud compute tpus start $TPU_SERVER_NAME을 사용하여 TPU 서버를 수동으로 재설정하세요. 여기서 $TPU_SERVER_NAMEgcloud compute tpus list 명령어의 첫 번째 열에서 가져옵니다.

메모리 사용량 감소

TPU에서 모델을 실행할 때 메모리 부족 오류가 발생하면 모델의 메모리 사용량을 줄이는 단계를 밟아야 합니다. 이 섹션에서는 메모리 문제의 몇 가지 근본 원인을 설명하고 문제를 해결하기 위한 가이드라인을 제공합니다.

모델 가중치가 많은 경우

메모리 문제의 가능한 원인

float32 모델 가중치에는 4바이트가 필요합니다. 이러한 가중치는 각 TPU 코어에서 복제됩니다. 따라서 가중치가 수억 개 정도 되는 모델은 TPU에 맞추기에 너무 클 수 있습니다.

메모리 사용량을 줄이는 방법

  1. 특정 옵티마이저에서 업데이트 통계를 저장하려면 가중치당 더 많은 메모리가 필요하기도 합니다. 특히 AdamOptimizerAdadeltaOptimizer에는 가중치당 8 바이트가 추가로 필요합니다. AdagradOptimizerMomentumOptimizer에는 가중치당 4바이트가 추가로 필요합니다. 표준 GradientDescentOptimizer는 최종 모델 정확성 측면에서 다른 옵티마이저만큼 성능이 좋지는 않지만 스토리지 공간이 추가로 필요하지는 않습니다. 실험용 AdafactorOptimizer는 추가 메모리가 거의 필요하지 않으며 Transformer 모델을 학습시킬 때 기준이 되는 Adam 옵티마이저 수준의 성능을 발휘합니다.
  2. 대부분의 가중치가 단어 임베딩인 경우 WordPiece와 같은 기술이 다양한 태스크에서 정확성을 높이는 동시에 어휘 크기를 현저하게 줄이는 것으로 나타났습니다.
  3. TensorFlow의 이후 출시 버전에서는 16비트 부동 소수점 가중치와 기울기에 대한 시험 지원이 포함되므로 요구되는 메모리양이 절반으로 줄어듭니다.

텐서 패딩이 과도한 경우

메모리 문제의 가능한 원인

TPU 메모리의 텐서에는 패딩이 적용되어 있습니다. 즉, TPU는 메모리에 저장된 텐서의 크기를 반올림하여 연산을 보다 효율적으로 수행합니다. 이 패딩은 하드웨어 수준에서 투명하게 발생하고 결과에 영향을 미치지 않습니다. 그러나 경우에 따라 패딩으로 인해 메모리 사용량 및 실행 시간이 현저하게 늘어날 수도 있습니다.

메모리 사용량을 줄이는 방법

TPU 소프트웨어는 메모리에 텐서를 배치하여 연산 효율성을 최대화하고 패딩을 최소화하려고 시도합니다. 이 메모리 레이아웃 프로세스는 복잡하지만 최적의 결과를 위해서는 모델이 다음과 같은 일반적인 원칙을 따라야 합니다. 메모리 오버헤드를 최소화하고 연산 효율성을 최대화하려면 다음 조건 중 하나를 충족해야 합니다.

  • 총 배치 크기는 64의 배수(TPU 코어당 8)이고 특징 차원은 128의 배수여야 합니다.

    또는

  • 총 배치 크기는 1,024의 배수(TPU 코어당 128)이고 특징 차원은 8의 배수여야 합니다.

1,024의 배치 크기 128의 배수인 특징 차원을 사용하면 효율성이 최대화됩니다(일부 모델에서는 가능하지 않을 수 있음). 명확하게 말해서 '특징 차원'은 완전 연결 레이어의 숨겨진 크기 또는 합성곱의 출력 채널 수를 의미합니다. 모든 레이어가 이 규칙을 따르는 것은 아니지만 특히 네트워크의 첫 번째와 마지막 레이어가 여기에 해당됩니다. 이는 정상적인 현상이며 대부분의 모델에는 일정 양의 패딩이 필요합니다.

배치가 너무 큰 경우

메모리 문제의 가능한 원인

CPU, GPU, TPU에서 신경망을 학습시킬 때 다음과 같은 두 작업에서 메모리 사용이 발생합니다.

  1. 가중치, 가중치 기울기, 모멘텀과 같은 옵티마이저별 통계 저장. 메모리 사용량은 모델의 가중치 수에 직접 비례하지만 배치 크기에는 비례하지 않습니다.
  2. 역방향 전달을 계산하는 데 필요한 정방향 전달의 중간 활성화 함수 저장. 메모리 사용량은 배치 크기, 레이어 크기, 레이어 수에 직접 비례합니다.

따라서 모델에서 필요한 메모리는 주로 배치 크기에 좌우됩니다.

메모리 사용량을 줄이는 방법

배치 크기를 메모리에 맞을 때까지 천천히 줄이면서 총 배치 크기가 64의 배수인지 확인하세요(코어별 배치 크기는 8의 배수여야 함). 배치 크기가 클수록 TPU에서 더 효율적입니다. 총 배치 크기가 1,024(코어당 128)이면 일반적으로 좋은 출발점입니다.

모델이 너무 큰 경우

메모리 문제의 가능한 원인

모델에서 필요로 하는 메모리는 그래프의 연산자 수(즉, 네트워크의 레이어 수)에 따라 크게 달라집니다. 이러한 저장용량 요구사항은 가중치 수와 별개입니다. 예를 들어 tf.nn.conv2d()와 같은 연산자의 경사를 계산하면 가중치를 저장하는 데 사용되는 메모리에 더해 메모리 사용량이 늘어날 수 있습니다.

TPU 엔진은 모델을 메모리에 맞추기 위해 전략적으로 특정 연산자를 다시 계산하려고 시도하지만(경사 체크포인트와 유사하게 재구체화라고 함) 항상 이렇게 할 수 있는 것은 아닙니다.

메모리 사용량을 줄이는 방법

소형 크기의 배치(예: 64)로도 TPU에서 모델을 실행할 수 없다면 레이어 수 또는 레이어 크기를 줄여보세요. TensorFlow의 이후 출시 버전은 TPU에서 '모델 동시 로드'를 지원하므로 다른 TPU 코어에서 서로 다른 부분의 모델을 실행하는 방법으로 Cloud TPU에서 훨씬 더 큰 모델을 실행할 수 있습니다.

학습 속도 개선

이 섹션에서는 TPU에서 모델을 성공적으로 실행할 수 있지만 학습 속도가 예상보다 느린 경우 속도를 높일 수 있는 방법을 설명합니다.

루프당 반복 횟수가 적은 경우

성능 문제 설명

TPUConfigiterations_per_loop 매개변수는 단일 '학습 루프'에서 TPU로 전송되는 데이터의 배치 수를 제어합니다. 각 학습 루프는 로컬 머신과 TPU 서버 간에 상당한 통신을 필요로 하므로 iterations_per_loop가 너무 작으면 학습 속도가 크게 느려질 수 있습니다.

모델에서 이 문제를 확인하는 방법

로깅 메시지 Enqueue next (X) batch(es) of data to infeed가 매우 자주(예를 들어 3초마다) 인쇄되는 경우에는 학습 루프에서 상당한 오버헤드가 발생할 수 있습니다.

해결 방법

iterations_per_loop를 더 큰 값으로 설정합니다. MNIST 가이드에서 이 값은 --iterations 플래그로 제어합니다. Enqueue next (X) batch(es) of data to infeed 메시지가 1분에 몇 번 이상 인쇄되지 않으면 현재 값이 충분한 것입니다. iterations_per_loop는 매우 큰 값으로 설정할 수 있으며, 로깅 메시지와 체크포인트가 루프의 끝에서만 발생할 수 있다는 단점이 있습니다.

입력 처리 병목 현상

성능 문제 설명

TPU가 특정한 데이터 청크를 기반으로 학습하는 동안 입력 처리 함수는 CPU에서 다음 데이터 청크를 준비합니다. 따라서 모델 함수보다 입력 함수에 소요되는 시간이 짧은 경우에는 입력 처리 비용이 사실상 0입니다. 그러나 모델 함수보다 입력 함수에 더 오랜 시간이 소요되는 경우에는 병목 현상이 발생합니다.

모델에서 이 문제를 확인하는 방법

Cloud TPU 도구: 입력 파이프라인 분석기의 안내에 따라 텐서보드에서 입력 파이프라인 분석을 살펴보세요.

이미지

입력 파이프라인 분석 페이지에는 입력 처리로 인해 모델에 병목 현상이 발생하는지를 한눈에 볼 수 있는 요약이 표시됩니다. 동일한 페이지에 오퍼레이션별 실행 시간이 표시되므로 문제가 있는 오퍼레이션을 정확히 찾아낼 수 있습니다.

해결 방법

Dataset API를 사용하여 데이터를 로드할 때 다음과 같은 몇 가지 완화 방법을 사용할 수 있습니다.

  1. 데이터를 TFRecord 파일에 tf.train.Example 구조의 모음으로 저장하고 TFRecordDataset를 사용하여 로드합니다. Dataset API 가이드 또는 ResNet 가이드에서 예시를 참조하세요.
  2. dataset.cache() 및/또는 dataset.prefetch()를 사용하여 입력 데이터를 버퍼링합니다. 이렇게 하면 병목 현상으로 인해 파일 액세스 속도가 산발적으로 느려지는 문제가 방지됩니다.
  3. dataset.map() 함수의 num_parallel_calls 매개변수를 지정하여 멀티스레드 map() 작업을 사용 설정합니다.
  4. 모든 학습의 매 세대마다 비용이 발생하도록 하지 말고 오프라인에서 1회 비용으로 값비싼 데이터 사전 처리를 수행하세요.

모든 입력 처리는 로컬 머신이 아닌 TPU 서버에 위치한 CPU에서 수행됩니다. 따라서 로컬 머신 속도는 요인에서 제외됩니다.

비행렬 곱셈 오퍼레이션이 너무 많이 발생하는 경우

성능 문제 설명

Cloud TPU는 매우 높은 속도로 행렬 곱셈과 합성곱을 수행할 수 있습니다. 대부분의 다른 TensorFlow 작업은 TPU에서 효율적으로 구현되지만, 이러한 작업은 다른 하드웨어에 비해 TPU의 주요 장점이 아닙니다. 따라서 TPU를 완전히 활용하려면 모델의 대부분이 행렬 곱셈이나 합성곱으로 이루어져 있어야 합니다.

모델에서 이 문제를 확인하는 방법

Cloud TPU 도구: 작업 프로필 가이드는 모델의 성능 프로필을 작업 유형별로 구분하여 생성하는 방법을 설명합니다. 일반적으로 대부분의 최신 신경망 아키텍처는 행렬 곱셈 및 합성곱으로 이루어져 있습니다.

해결 방법

모델에서 행렬 곱셈이 부족한 이유가 주로 다른 하드웨어의 학습 속도 문제 때문이었다면 속도 성능을 높이기 위해 TPU에서 이러한 모델을 다시 벤치마킹하는 것이 좋습니다. 행렬 곱셈 부족이 모델의 근본적인 속성 때문이라면 TPU가 최적의 하드웨어 선택이 아닐 수 있습니다.

텐서 패딩이 과도한 경우

성능 문제 설명

TPU는 계산 단위를 효율적으로 사용하기 위해 메모리의 텐서에 패딩을 적용합니다. 패딩은 메모리와 메모리 대역폭의 사용량을 늘릴 수 있습니다. 텐서 패딩 문제의 이해 및 해결을 위한 도움말은 텐서 패딩 섹션을 참조하세요.

배치 크기가 너무 작은 경우

성능 문제 설명

일반적으로 더 큰 배치를 사용할수록 TPU의 학습 속도(초당 샘플 수)가 빨라집니다.

모델에서 이 문제를 확인하는 방법

TPU가 64 크기에 도달할 때까지 텐서에 패드를 적용하므로 모든 모델의 배치 크기는 항상 64 이상(TPU 코어당 8)이어야 합니다. TPU 학습 시 최적의 배치 크기는 메모리 전송 및 패딩과 관련된 비효율성을 제거할 수 있는 1,024(TPU 코어당 128)입니다.

해결 방법

메모리에 적합하고 64의 배수인 가장 큰 배치 크기를 사용하는 것이 좋습니다. 이렇게 하는 가장 쉬운 방법은 1,024부터 시작하는 것입니다. 메모리 부족 오류가 발생하는 경우 모델이 성공적으로 실행될 때까지 배치 크기를 줄여보세요. 모델의 배치 크기를 변경하는 과정에서 동일한 모델 정확성을 유지하기 위해 학습률과 같은 기타 초매개변수를 조정해야 하는 경우도 있으나 상황에 따라 판단해야 합니다.

레이어 크기가 너무 작은 경우

성능 문제 설명

모델의 대부분을 행렬 곱셈이나 합성곱이 차지하는 경우에도 입력 텐서가 작으면 TPU가 최대 효율로 실행되지 않을 수 있습니다. 다른 하드웨어와 비교하자면 배치 크기와 레이어 크기가 모두 클 때(예: 차원이 512 이상인 경우) TPU가 가장 효율적으로 실행됩니다.

모델에서 이 문제를 확인하는 방법

일반적으로 레이어 크기가 128보다 작으면 TPU의 효율성이 떨어집니다. 128이 TPU 행렬 곱셈 단위의 기본 차원이기 때문입니다. 완전 연결 레이어의 경우 높은 효율성을 달성하려면 숨겨진 크기가 최소 512인 것이 좋습니다. 동일한 효율성 수준을 달성하기 위해서는 합성곱 레이어가 일반적으로 완전 연결형 레이어만큼 클 필요가 없습니다. 예를 들어 256 크기의 3×3 합성곱은 3×3×256=2,304이므로 2,048 크기의 완전 연결형 레이어와 비교해 비슷하거나 약간 높은 효율성을 달성합니다.

해결 방법

모델에 소형 레이어를 사용하는 주요 동기가 학습 속도 때문이라면 TPU에 더 큰 레이어를 사용하는 모델을 다시 벤치마킹하는 것이 좋습니다. 예를 들어 레이어의 출력 크기를 256에서 512로 늘리면 모델의 연산 속도가 2배더라도 늘어나는 학습 시간은 20%에 불과할 수 있습니다.

작업 수준 모델 프로파일링

성능 병목 현상을 식별하기 위해 작업 수준의 실행 시간과 메모리 사용량을 측정하면 유용한 경우가 많습니다. 이렇게 하는 방법에 대한 안내는
Cloud TPU 도구: Trace 뷰어 가이드를 참조하세요.

모델 정확성 저하 문제 디버깅

Cloud TPU 생태계의 목표 중 하나는 CPU 또는 GPU에서 현재 학습되고 있는 모든 모델을 TPU에서 학습시켰을 때 배치 크기 및 학습률과 같은 초매개변수를 약간 조정하는 것만으로 근접한 수준의 정확성을 실현하는 것입니다. 그러나 경우에 따라 TPU에서 모델을 학습시킬 때 정확성이 저하될 수 있습니다. 이러한 문제의 디버깅은 신경망 학습의 무작위적인 속성 때문에 매우 어려울 수 있습니다. 이 섹션에서는 모델을 TPU로 포팅할 때 모델 정확성이 저하되는 근본 원인을 정확히 찾아내는 방법을 제공합니다.

데이터 샤딩 이해(데이터 동시 로드)

TensorFlow의 주요 목표 중 하나는 각 작업이 CPU, GPU, TPU 중 어디에서 실행되든 거의 일치하는 결과를 생성하도록 만드는 것입니다. 단 여기에는 무작위 순서 지정 작업과 같은 예외가 있습니다. 일반적으로 TPU와 CPU에서 무작위 순서 지정이 아닌 작업의 출력에 큰 차이가 있으면 버그로 신고하세요.

그러나 학습 파이프라인의 경우 전체적으로 CPU/GPU에서의 학습과 TPU에서의 학습 간에는 상당한 차이가 있습니다. TPUEstimatoruse_tpu=False를 사용하는 경우 TensorFlow는 표준 실행 엔진을 사용합니다. 이 엔진은 단계당 하나의 배치로 학습됩니다. 그러나 실제 TPU에서 학습하는 경우 TensorFlow는 데이터 샤딩('동기 SGD를 통한 데이터 동시 로드'라고도 함)을 수행합니다. 그 이유는 각 Cloud TPU가 독립된 처리 단위로 작동하는 8개의 TPU 코어로 구성되어 있기 때문입니다. 따라서 학습의 각 단계마다 각 TPU 코어에서 데이터 배치 전달, 가중치 경사 계산, 경사 교환, 가중치 업데이트 계산이 차례대로 처리됩니다. 기본적으로는 여러 코어에서 손실의 평균을 계산하지만, 그 대신 CrossShardOptimizer의 매개변수를 변경하여 합계를 구할 수 있습니다.

모델의 총 손실은 독립된 샘플당 손실의 평균(또는 합계)으로 계산할 수 있고 이 절차는 하나의 대형 배치에 대한 학습과 수학적으로 일치합니다. 샘플별로 독립되지 않은 가장 일반적인 작업은 배치 정규화로, 각 코어별 배치에서 별도로 실행됩니다. 예를 들어 총 배치 크기가 128인 경우 코어별 배치 크기는 16이고 8개의 각 코어는 자체 16개 샘플에 대해 배치 정규화를 수행합니다. 일부의 경우 소형 배치에 대해 배치 정규화를 수행하면(예: 32 미만) 정확성이 저하되는 것으로 나타났습니다. 동일한 시나리오에서 TPU 학습 시 총 배치 크기는 클 수 있으므로(예: 256~1,024) 해당 크기의 배치는 큰 문제가 아닙니다. 그러나 배치 크기가 메모리에 맞추기에 너무 큰 경우 샤딩의 영향을 사례별로 평가해야 합니다.

분할에 따른 복잡성을 감안하여, 모델 정확성 저하를 디버그하는 첫 번째 단계는 확정된 단일 코어 TPU 학습을 실행하고 CPU/GPU에서 학습된 모델과 비교하는 것입니다. 일반적으로는 모델을 수렴 단계까지 학습시킬 필요가 없으므로 금방 수행할 수 있습니다.

확정적 학습

모델 정확성의 차이를 디버그하기 어려운 이유 중 하나는 모델이 학습될 때마다 TensorFlow가 서로 다른 가중치 초기화와 데이터 셔플링을 사용하기 때문입니다. 여러 번 실행했을 때 거의 일치하는 모델이 생성되도록 학습 절차를 확정하여 수정하는 것이 유익합니다. 이 섹션에서는 MNIST 가이드를 확정적으로 실행하는 방법을 보여줍니다.

  1. CPU에서 단일 단계를 실행하여 초기 체크포인트 파일을 생성합니다. 이 단계는 확정적인 가중치 초기화를 달성하기 위해 사용됩니다. 변수 초기화 도구를 시드하는 방식으로도 가능하지만 더 어렵습니다.
# Run training for 1 step to create an initial checkpoint.
python mnist_tpu.py \
  --use_tpu=False \
  --data_dir=${STORAGE_BUCKET}/data/ \
  --model_dir=${STORAGE_BUCKET}/init_output \
  --random_seed=12345 \
  --iterations=1
  --train_steps=1
  1. 무작위 시드를 사용하려면 입력 함수에서 데이터 무작위 섞기 함수를 수정하세요. 이 작업은 MNIST 가이드에서 이미 수행했을 수 있습니다. 입력 데이터 처리 작업은 항상 CPU에서 실행되기 때문에 이 방식이 효과가 있습니다. 모델 함수의 무작위 순서 지정 작업은 TPU와 CPU에서 확정적이지 않을 수 있습니다. 예:
# In the flag definitions
tf.flags.DEFINE_integer("batch_size", None, "Random seed for training")

# In the input_fn
if FLAGS.random_seed is not None:
dataset = dataset.shuffle(seed=FLAGS.random_seed)
  1. CPU에서 동일한 모델을 두 번 실행하여 확정적인 학습인지 확인합니다. 합리적인 수의 단계(예: 1,000)로 학습을 실행해야 합니다. 하지만 CPU에서는 속도가 매우 느릴 수 있기 때문에 수렴 단계까지 실행할 필요는 없습니다.

    CPU 학습을 단일 코어 TPU 학습과 비교하므로 단일 TPU 코어에 적합한 배치 크기를 사용하세요. 일반적으로 전체 배치 크기를 8로 나누면 됩니다. 텐서플로우는 실행 간에 완벽하게 동일한 확정성을 보장하지 않으나 손실은 거의 같아야 합니다.
# Copy the initial weights
gsutil mkdir ${STORAGE_BUCKET}/cpu_output_1
gsutil cp -f ${STORAGE_BUCKET}/init_output/* ${STORAGE_BUCKET}/cpu_output_1
gsutil mkdir ${STORAGE_BUCKET}/cpu_output_2
gsutil cp -f ${STORAGE_BUCKET}/init_output/* ${STORAGE_BUCKET}/cpu_output_2

# Run 1
python mnist_tpu.py \
  --use_tpu=False \
  --data_dir=${STORAGE_BUCKET}/data/ \
  --model_dir=${STORAGE_BUCKET}/cpu_output_1 \
  --batch_size=128 \
  --random_seed=12345 \
  --train_steps=2000 \
  --eval_steps=10

# Output 1
accuracy = 0.9910644, global_step = 1000, loss = 0.025323588

# Run 2
python mnist_tpu.py \
  --use_tpu=False \
  --data_dir=${STORAGE_BUCKET}/data/ \
  --model_dir=${STORAGE_BUCKET}/cpu_output_1 \
  --batch_size=128 \
  --random_seed=12345 \
  --train_steps=2000 \
  --eval_steps=10

# Output 2
accuracy = 0.9910644, global_step = 1000, loss = 0.025323414

단일 코어 TPU 학습

MNIST 가이드를 확정적으로 실행할 수 있다면 다음 단계는 TPU상의 CPU 학습 결과를 복제하여 단일 TPU 코어를 통해 데이터 분할과 관련된 문제인지, 아니면 TPU 실행 엔진 자체의 문제인지 확인하는 것입니다.

MNIST 가이드에서 단일 코어 학습 및 평가를 실행하는 방법은 다음과 같습니다.

# Use the same weight initialization as the CPU
gsutil cp -f ${STORAGE_BUCKET}/init_output/* ${STORAGE_BUCKET}/tpu_output

# Run training for 1000 steps
python mnist.py \
    --use_tpu=True \
    --master=$GRPC_SERVER \
    --train_file=${STORAGE_BUCKET}/data/train.tfrecords \
    --model_dir=${STORAGE_BUCKET}/tpu_output \
    --random_seed=12345 \
    --batch_size=128 \
    --train_steps=1000 \
    --eval_steps=10

  accuracy = 0.9910644, global_step = 1000, loss = 0.02514153

손실이 CPU 학습 모델과 정확히 일치하지 않더라도 비슷합니다. 내 모델과 비슷하지 않다면 TPU 실행 엔진에 버그가 있다는 의미일 수 있습니다. 버그 신고를 제출하기 전에 다음 내용을 다시 확인하세요.

  1. num_shards=1TPUConfig에 전달합니다.

  2. 모델 함수에 무작위 순서 지정 작업이 없으며 입력 함수의 모든 무작위 순서 지정 작업은 올바르게 시드됩니다.

  3. CPU 및 TPU 학습에 대해 동일한 초기 체크포인트 파일을 사용하고 있습니다.

다중 코어 TPU 학습 디버그

모델이 CPU 및 단일 코어 TPU에서 동일한 손실을 기록하는 경우 다음 중 하나가 문제일 수 있습니다.

(a) 다른 초기화 값으로 신경 모델을 학습시켰을 때 발생하는 자연적인 무작위 분산으로 인해 정확성이 저하됩니다.

(b) TPU의 데이터 샤딩과 관련된 문제로 인해 정확성이 저하됩니다.

(a) 문제인지 확인하려면 위와 같이 동일한 가중치 초기화 값을 사용하여 CPU/GPU 및 멀티코어 TPU에서 전체 모델을 다시 학습하는 것이 유용할 수 있습니다.

정확성 저하가 통계적으로 유의미하다는 확신이 들면 데이터 샤딩과 관련해 가장 가능성이 높은 문제는 다음과 같습니다.

  1. 모델이 샘플별 오류의 합계로 손실을 계산하는 경우 reduction=losses.Reduction.SUMCrossShardOptimizer에 전달하는 것이 좋습니다. 기본적으로 CrossShardOptimizer는 합계가 아닌 손실의 평균을 계산합니다.
  2. 모델이 배치 정규화를 사용하는 경우 총 배치 크기가 256 미만(예를 들어 코어별로 32 미만)이면 정확성이 낮아질 수 있습니다.
  3. 모델에 배치 수준의 손실 함수가 있으면 샤딩의 영향을 받습니다. 이러한 손실 함수는 일반적으로 특화되어 있습니다. 예를 들어 Karras et al. 2017은 생성적 적대 신경망(GAN)을 학습시킬 때 배치 분류자를 사용합니다.