BLOG

Gluon data loader worker 활용하여 교육 성능 최대화하기
작성일: 2018-05-18

최근의 CPU 및 GPU 기술의 발전으로, 복잡하고 심도있는 신경망 모델을 몇 시간 동안만 교육하면 많은 최첨단 모델에 도달 할 수 있습니다. 그러나 처리량이 높은 시스템을 사용할 경우 각 반복작업 전에 처리 파이프 라인에 필요한 데이터를 준비해야 합니다. 처리 파이프 라인이 고갈되면 에포크(epoch) 당 시스템 시간과 관련하여 시스템 성능에 직접적인 영향을 미칩니다. 장기간의 교육은 연구의 더딘 발전과 높은 비용을 의미합니다. 따라서 최적화는 GPU를 사용하는 시스템뿐만 아니라 데이터 처리를 위해 CPU를 사용하는 시스템에서도 중요합니다.

 

 AWS의 데이터 파이프 라인

 

모델 교육을 위해 Amazon EC2 (Elastic Compute Cloud) 인스턴스를 사용하는 경우 종종 데이터가 S3 (Simple Storage Service) 버킷에 저장됩니다. 각 EC2 인스턴스는 로컬 파일 시스템으로 사용되는 Amazon Elastic Block Store (EBS) 볼륨에 연결됩니다. 하나의 공통 데이터 파이프 라인 패턴은 Amazon S3에서 시작하여 Amazon EBS로 이동한 다음 사전 처리를 위해 인스턴스 메모리로, 마지막으로 처리를 위해 GPU 메모리로 이동합니다.

 

 

 

Apache MXNet은 Amazon S3와의 직접 연결을 지원합니다. Amazon S3에서 Amazon EBS 로의 데이터 전송을 건너 뛰고 사전 처리를 위해 Amazon S3에서 인스턴스 메모리로 직접 이동한 다음 처리를 위해 GPU 메모리를 지원합니다. 이 기능에 대한 자세한 내용은 이 기술노트를 참조하십시오.

 

 

교육 성능을 극대화하려면 데이터 파이프 라인이 최소한 데이터 처리 속도만큼 빨라야 합니다. Amazon S3와 인스턴스 간의 데이터 링크는 네트워크 링크입니다. 올바른 인스턴스 유형을 선택하면 이 연결이 데이터 파이프 라인의 병목 현상이되지 않도록 할 수 있습니다. 많은 EC2 인스턴스는 10Gb 또는 25GB 네트워크 인터페이스로 향상된 네트워킹을 지원합니다.

 

EBS와 인스턴스 메모리 사이의 데이터 링크는 인스턴스 유형에 따라 초당 I / O (IOPS) 및 초당 500-4000 메가 비트 처리량 사이의 총 데이터 대역폭에 의해 조정됩니다. EBS 최적화 인스턴스를 사용하면 이 데이터 링크가 데이터 파이프 라인의 병목 현상이되지 않도록 할 수 있습니다. I / O 성능을 높이기 위한 또 다른 기술은 각 EC2 인스턴스에 연결된 여러 EBS 볼륨을 사용하는 것입니다. 이 페이지의 메모에는 데이터로드 최적화에 대한 유용한 팁이 들어 있습니다.

 

Apache MXNet은 비동기 엔진을 사용하여 이전 배치의 계산이 진행되는 동안 GPU 메모리에 데이터가 로드되도록 하여 GPU의 교육 성능을 극대화합니다. 이 고성능 교육 파이프 라인의 고갈을 방지하기 위해 사전 처리 된 데이터를 GPU 메모리로 전송할 수 있는 시간 내에 사용해야 합니다. gluon.data.DataLoader에는 이러한 병목 현상을 해결하기 위해 작업자를위한 메커니즘이 내장되어 있습니다. 이것은 이 블로그 게시물의 나머지 부분입니다.

 

gluon.data.DataLoader 는 Python의 다중 처리 패키지를 사용하여 데이터 처리와 병행하여 데이터 사전 처리를 수행하기 위해 작업자를 가속화합니다. 데이터 사전 프로세싱은 데이터 증가 (예를 들어, 랜덤 크롭, 스케일 및 이미지의 경우 미러) 및 데이터 컨디셔닝 (예를 들어, 상이한 특징들의 연결)을 포함 할 수 있습니다. 이 블로그 게시물에서 gluon.data.DataLoader의 작업자를 사용하는 것이 시스템 성능에 영향을 미칠 수 있음을 보여줍니다.

 

 

시스템 설정

 

이 게시물에서 사용하고있는 시스템은 Amazon EC2 p3.2xlarge 인스턴스이지만 개념은 GPU 및 멀티 코어 CPU 교육 모두에 적용됩니다. 이 글을 쓰고 있는 현재 MXNet의 최신 버전인  pip를 통해 설치된 MXNet 패키지 mxnet_cu90mkl 버전  1.0.0.post4를 사용하고 있습니다. 이 예시의 최소 필수 MXNet 버전은 버전 1.0.0입니다. 이 페이지에서 MXNet 설치에 대한 지침을 찾을 수 있습니다.

 

저는 EC2 인스턴스의 Amazon Machine Image (AMI)로 Deep Learning AMI (Ubuntu) Version 3.0 (ami-0a9fac70)을 사용합니다. 이 AMI를 작성할 당시에 AWS Marketplace에서 제공되는 최신 Deep Learning AMI입니다. 다음은 DLAMI를 시작하기 위한 링크입니다. 또는 MXNet이 사전 설치된 Amazon SageMaker 서비스를 사용할 수 있습니다.

 

MNIST 예시

 

첫번재로, 저는 DataLoader 작업자의 영향력을 보여주기 위해 MNIST 데이터 세트가 있는 간단한 컨볼루션 신경망을 사용합니다.

 

from __future__ import print_function

from time import time

import numpy as np

import mxnet as mx

from mxnet import nd, autograd, gluon

ctx = mx.gpu() if mx.test_utils.list_gpus() else mx.cpu()

 

 

컨볼루션 신경망을 정의하기

 

이제 간단한 2-layer 컨볼루션 네트워크를 gluon.nn를 사용하여 만들겠습니다.

 

num_fc = 512

num_outputs = 10

net = gluon.nn.HybridSequential()

with net.name_scope():

    net.add(gluon.nn.Conv2D(channels=20, kernel_size=5, activation=’relu’))

    net.add(gluon.nn.MaxPool2D(pool_size=2, strides=2))           

    net.add(gluon.nn.Conv2D(channels=50, kernel_size=5, activation=’relu’))

    net.add(gluon.nn.MaxPool2D(pool_size=2, strides=2))

    # The Flatten layer collapses all axes, except the first one, into one axis.

    net.add(gluon.nn.Flatten())

    net.add(gluon.nn.Dense(num_fc, activation=”relu”))

    net.add(gluon.nn.Dense(num_outputs))

 

 

MXNet 엔진이 최상의 성능을 위한 그래프 최적화를 수행 할 수 있도록 네트워크를 하이브리드화할 것입니다.

 

net.hybridize()

 

교육을 위해 Softmax cross entropy loss를 사용합니다.

softmax_cross_entropy = gluon.loss.SoftmaxCrossEntropyLoss()

 

정확도 테스트 위해 검토 루프 쓰기

 

def evaluate_accuracy(data_iterator, net):

    acc = mx.metric.Accuracy()

    for i, (data, label) in enumerate(data_iterator):

        predictions = nd.argmax(net(data.as_in_context(ctx)), axis=1)

        acc.update(preds=predictions, labels=label.as_in_context(ctx))

    return acc.get()[1]

 

DataLoader 및 변환 함수

 

transform() 함수는 데이터 사전 처리가 이루어지는 곳입니다. 이 예에서 전처리는 [0, 1] 범위로 정규화 된 입력 텐서의 치수를 재정렬하는 간단한 transpose() 연산입니다. 다른 응용 프로그램에서는 이미지 보강에 사용될 때와 같이 복잡하고 처리 집약적인 작업이 될 수 있습니다.

 

def transform(data, label):

    return nd.transpose(data.astype(np.float32), (2,0,1))/255, label.astype(np.float32)

 

def data_loader(train, batch_size, num_workers):

    dataset = gluon.data.vision.MNIST(train=train, transform=transform)

    return gluon.data.DataLoader(dataset, batch_size, shuffle=train, num_workers=num_workers)

 

트레이닝 루프

트레이닝 루프를 매우 심플하게, 하나의 에포크만을 사용하여 작성됩니다.

 

def train(num_workers):

    mx.random.seed(1)

    epochs = 1

 

    train_data = data_loader(train=True, batch_size=64, num_workers=num_workers)

    test_data = data_loader(train=False, batch_size=64, num_workers=num_workers)

 

    # Initialize parameters randomly

    net.collect_params().initialize(mx.init.Xavier(magnitude=2.24), ctx=ctx, force_reinit=True)

    trainer = gluon.Trainer(net.collect_params(), ‘sgd’, {‘learning_rate’: .1})

 

    train_start = time()

    for e in range(epochs):

        for data, label in train_data:

            data = data.as_in_context(ctx)

            label = label.as_in_context(ctx)

            # Wait for completion of previous iteration to

            # avoid unnecessary memory allocation

            nd.waitall()

            with autograd.record():

                output = net(data)

                loss = softmax_cross_entropy(output, label)

            loss.backward()

            trainer.step(data.shape[0])

    nd.waitall()

    eval_start = time()

    test_accuracy = evaluate_accuracy(test_data, net)

    eval_end = time()

    print(“{} workers: train duration {:.4}, eval duration {:.4}, test accuracy {:.2}”.format(

        num_workers, eval_start – train_start, eval_end – eval_start, test_accuracy))

 

이제 우리는 DataLoader에 다른 작업자를 사용하여 실험할 것입니다. 0 workers는 사전 처리 단계가 기본 Python 프로세스에서 수행되고 작업자 프로세스가 사전 처리를 병렬로 수행하는 데 사용되지 않는다는 것을 의미합니다. 일반적으로 시스템의 사용 가능한 CPU 코어 수를 초과하여 작업자 수를 늘리지 않는 것이 좋습니다.

 

for workers in range(0, 10, 2):

    train(num_workers=workers)

 

0 workers: train duration 12.96, eval duration 4.154, test accuracy 0.98

2 workers: train duration 6.167, eval duration 2.499, test accuracy 0.98

4 workers: train duration 4.04, eval duration 2.589, test accuracy 0.98

6 workers: train duration 3.765, eval duration 2.61, test accuracy 0.98

8 workers: train duration 3.94, eval duration 2.666, test accuracy 0.98

 

수치에서 알 수 있듯이 근로자 수가 증가하면 성과가 크게 향상됩니다. 그러나 최적의 수의 작업자에 도달하면 운영 체제의 Context 전환 오버 헤드가 추가되어 성능이 약간 떨어집니다.

 

 

I / O 병목 현상을 식별하는 팁

 

I / O 병목 현상의 일반적인 증상은 GPU와 CPU 모두의 활용도가 낮습니다. I / O가 교육의 병목인지 판단하는 가장 쉬운 방법은 파이프 라인에서 데이터의 사전 처리를 제거하는 것입니다. 성능이 향상되지 않으면 I / O가 병목 현상입니다.

 

그러나 I / O 병목 현상은 디스크 I / O 또는 GPU I / O 일 수 있습니다. GPU의 I / O 병목 현상은 디스크 읽기를 제거하고 GPU에 동일한 데이터 배치를 재로딩함으로써 측정 할 수 있습니다. 성능이 향상되지 않으면 시스템 병목 현상은 GPU I / O입니다. 이는 교육이 주어진 배치 크기에서 최고 성능으로 작동하고 배치 크기를 늘려 처리량을 향상시킬 수 있음을 의미합니다. 그러나 디스크 읽기에 대한 종속성을 제거하여 성능이 향상되면 디스크 I / O가 병목 현상입니다. 앞에서 설명한 기술 조합을 사용하여 시스템 성능을 향상시킬 수 있습니다.

 

 

결론

 

이 블로그 게시물에서 설명했듯이 직원의 수는 시스템 성능에 큰 영향을 줄 수 있습니다. 각 설정의 최적 수는 배치 크기 및 하드웨어 구성은 물론 데이터에서 수행되는 전처리 유형에 따라 다릅니다. 작업자가 처리 엔진을 따라 잡을 수 있게 된 후 추가 작업자를 추가하면 불필요한 운영 체제 컨텍스트 전환으로 인해 성능이 약간 저하됩니다. 새로운 교육 일부터 시작하여 다른 수의 근로자를 자유롭게 시험하고 실험에 최적의 성능을 제공하는 근로자 수를 선택하세요. 항상 적은 수의 직원 대신 더 많은 직원을 선택하여 처리 엔진이 결코 고갈되지 않도록 해야 합니다. 잠재적인 디스크 I / O 병목 현상을 염두에 두어야 합니다.

 

원문 URL: https://aws.amazon.com/ko/blogs/machine-learning/maximize-training-performance-with-gluon-data-loader-workers/

** 메가존 TechBlog는 AWS BLOG 영문 게재글중에서 한국 사용자들에게 유용한 정보 및 콘텐츠를 우선적으로 번역하여 내부 엔지니어 검수를 받아서, 정기적으로 게재하고 있습니다. 추가로 번역및 게재를 희망하는 글에 대해서 관리자에게 메일 또는 SNS페이지에 댓글을 남겨주시면, 우선적으로 번역해서 전달해드리도록 하겠습니다.