2018년 1월 11일 목요일

Deep Learning Multi Host & Multi GPU Architecture #2 - Keras 를 이용한 Scale Up, Horovod 를 이용한 Scale Out 성능 비교

Deep Learning Multi Host, Multi GPU 를 사용하고, BigData Scale 데이타를 처리하며, Auto Scale Out 확장 까지 고려한 아키텍처 구성에 대하여 연재 중이다.

개요는 이곳에서 확인 가능하다. [아키텍처 주안점 및 설계를 위한 고찰 : https://hoondongkim.blogspot.kr/2018/01/deep-learning-multi-host-multi-gpu.html ]

오늘은 두번째로, High Level 딥러닝 프레임워크 인 Keras 를 이용한 GPU Scale Up. 그리고 Horovod 를 이용한 Multi Host GPU Scale Out 의 성능에 대한 비교를 해보도록 하겠다.

우선 Tensorflow 나 pyTorch 나 CNTK , Caffe2 등에서 이미 GPU 나 Host 에 대한 확장을 이미 지원하고 있는데, 이러한 실험이 무슨 의미가 있는지 의아할 듯 하여, 그 의미에 대하여 다시 언급해 보도록 하겠다.
  1. 기존 Deep Learning 프레임워크에서의 Low  Level 병렬 수행 최적화 코드를 별도로 구현해야 하는 수고를 덜 수 있다.
    1. Keras 의 경우 Multi GPU 를 지원하기 시작한지 불과 3달도 체 지나지 않았다. 2017년 10월 경 버전 2.0.9 부터 지원되기 시작했다.
    2. 하지만, Keras는 단 1줄로 Multi GPU Scale Up 이 된다. (Horovod 와 함께 Keras 를 함께 실험한 이유이기도 하다.)
  2. Multi Host 는 훨씬 복잡하다.
    1. Keras 의 경우 Multi Host 는 아직 지원하지 않는 한계가 있다.
    2. Multi GPU Scale Up 은 8 GPU 가 Max 이다. 즉, BigData Scale 확장을 위해서는 Multi Host 도 동원해야 한다.
    3. Keras등은 자체적으로는 Multi Host 를 지원하지 않는데, Multi Host 까지 최소의 노력으로 사용가능 하도록 구성하기 위해서는 tensorflowOnSpark 나 Horovod, elephas 등을 이용해야 한다. 
  3. 개발 생산성 뿐 아니라, 성능 까지 더 좋았으면 한다.
    1. Horovod (made by Uber ) 의 official 페이지에는 Horovod 개발 배경을 다음과 같이 설명하고 있다.
    2. 이런 언급도 있다.
이제 위에서 언급된 (1) 병렬 코딩에 있어서의 개발생산성 , (2) 수행 시간 단축 효과가 어느 정도 인지 확인 해 보자. (맛보기 정도의 예제이기는 하지만, 느낌을 공유 하고자 한다.)

테스트는 아래 환경에서 수행되었다.
1. GPU Scale Up Test
=> Azure DSVM Image NC-Series .
=> K80 GPU.
=> Tensorflow + Keras
2. GPU Scale Out Test
=> Azure Batch AI Cluster with NC-Series vm.
=> K80 GPU.
=> Tensorflow + Keras + Horovod + Azure Batch AI

  1. Keras 를 이용한 Multi GPU Scale Up 코드
    1. 아래 코드 1줄이면 된다.
    2. 위에서 사용한 메소드를 호출하기 위해 필요한 package import 는 아래처럼 해주면 된다.
    3. 여기서 매우매우 유의해야 할 점이 있다.
      1. Keras 는 Multi GPU 사용 시 epoch 가 나눠져서 수행되는 것과 유사하게 동작한다.
      2. 즉, Epoch 를 GPU 갯수로 나누는 코드 적용이 필요하다.
      3. 이론적으로는 이 경우 GPU 갯수가 2배가 되면, Training 속도가 2배 빨라져야 할 것이다. 그러나, 실험을 해보면 그정도 까지 개선되지는 않는다. 그것은 GPU 가 증가 시 GPU 간 Data 의 동기화 Copy 등에 부가적인 Overhead 가 소요되기 때문이다.
  2. Keras 를 이용한 Multi GPU Scale Up 성능 비교
    1. General 한  LSTM 모델이다. 실험을 위해 Training Data Size 는 줄여놓은 모델이다.
    2. GPU 1개 (NC6)
      1. 150초 정도가 소요되었다.
    3. GPU 2개 (NC6)
      1. 127초가 소요되었다.
      2. 그리고 약간 성능도 개선되었다.
      3. 이 시점의 nvidia GPU 사용량은 다음과 같다.
      4. 위 처럼 2번째 GPU 는 보편적으로 Fully 일하지는 못한다. (그러나, 모델 및 알고리즘에 따라 그 양상에는 차이가 있었다.)
    4. GPU 4개 (NC12)
      1. 82초가 소요 되었다.
      2. 성능도 좀더 향상 되었다.
      3. GPU 갯수와 성능과의 관계는 뒤에서 다시 언급 토록 하겠다.
  3. Horovod 를 이용한 Multi GPU Scale Out 코드
    1. Keras 의 Scale Up 코드 만큼 심플하지는 않지만, Horovod 의 경우도 몇줄 코드만으로 Deep Learning 을 Multi Host 로 Scale Out 가능하다. 중요한 것은 Keras와 달리 Scale Up 도 되고, Scale Out 도 된다는데 있다.
    2. import 패키지
      1. import horovod.keras as hvd
    3. horovod init 코드
      1. hvd.init()
    4. Process 당 GPU 하나씩 할당하기 위한 코드
      1. config = tf.ConfigProto()
      2. config.gpu_options.allow_growth = True
      3. config.gpu_options.visible_device_list = str(hvd.local_rank())
      4. K.set_session(tf.Session(config=config))
    5. Epoch 분산 용으로 변경
      1. EPOCH = 200.0
      2. epochs = int(math.ceil(EPOCH / hvd.size()))
    6. Optimizer 분산용으로 변경
      1. opt = optimizers.Adadelta(1.0 * hvd.size())
    7. Callbacks 추가
      1. hvd.callbacks.BroadcastGlobalVariablesCallback(0)
    8. 아래는 위 코드 Example 이다.
      1. epoch 를 본 예에서는 직접 입력하였다. 이후 Optimizer 와 Callbacks 관련 2줄만 각각 model compile 과 model fit 전에 수행해 주면 된다.
  4. Horovod 를 이용한 Multi Host Scale Out 성능비교
    1. Node 1개
      1. Jupyter 를 통해 Azure Batch AI 클러스터 위로 Training Job 을 구동하였다.
      2. Node 1개에서 166초가 소요되었다. 
    2. Node 2개
      1. Node 2개 에서 멀티 Host 모드로 수행하자 아래처럼 로그가 2번씩 찍힌다.
      2. Horovod Cluster Size 가 2가 되자 initial epoch가 200 이었지만, 각 노드별 병렬 epoch 는 100으로 줄었다.
      3. 143초로 수행시간이 단축 되었다.
    3. Node 4개
      1. Horovod 는 계속 NC6 으로도 병렬 확장 테스트가 가능하나, Keras Scale Up 과의 비교를 위해 , 이 시점에 NC12로 바꾸었다. 왜냐하면, Scale Up 의 경우 NC6 은 GPU 2개 까지밖에 지원하지 않아서, GPU 4개를 테스트하는 시점 NC12로 바꾸었었기 때문이다. 
      2. 동일한 테스트를 위해 이시점은 NC12 이미지 4대에서의 테스트 이다. 각 멀티 노드에서 GPU 는 1개씩만 사용하였다.
      3. 즉, 4 Host * 1 GPU = 4GPU 환경이다.
      4. 예상했던 것처럼 로그가 4번씩 나오고 있다.
      5. 수행속도는 89초로 줄어 들었다.
[결론]

Keras 의 Scale Up과 Horovod 의 Scale Out 모두 Epoch 를 나눠가졌다. 이런 양상은 TensorflowOnSpark 와는 조금 다른 양상이다. TensorflowOnSpark 는 Epoch 를 나눠갖지 않고, Multi Node 의 Multi Job 들이 Mini Batch 를 1/N 로 나눠 갖는다. 각 특성이 갖는 양상에 따른 차이도 그 차이점을 고려해볼만 한 주제인듯 하다.(향후 시간이 허락한다면 이 부분도 파 보도록 하겠다.)

우선 오늘 실험해본 내용의 종합 결과는 아래와 같다.


앞에서도 언급 했던 것처럼 Keras 를 사용하면, Tensorflow Backend 의 GPU Scale Up 은 우선 매우 매우 쉽다. 성능 또한, 기본적인 initial time 을 제외 하고는 어느정도 선형적인 증가를 보여 준다. 좀 더 특이한 양상이 발견되었던 점은, (적은 양의 데이타에서 특히) GPU 갯수가 늘어나자 좀더 성능이 빨리 좋아지는 양상이 발견되었다는 점이다. 이는 앙상블 효과 처럼 보인다. 그리고, 마치 가끔 Mini Batch Size 를 키웠더니, 정확도가 오히려 개선되었을 때와 비슷한 양상이다.(일반적으로 그 반대가 더 많지만...) 모든 weight 의 실시간 공유가 꼭 좋은것 만은 아니다. 4개의 독립적인 GPU 가 어느정도는 독자적인 local minigma 를 찾고, 각 GPU 가 1번씩 epoch 가 끝났을때, 지연 동기화를 하게 되면, local minigma 에 빠질 확률이 훨씬 줄어들기 때문에, 분산 지연 weight 동기화가 오히려 training 에 긍정의 효과를 준 것으로 보여진다.

Horovod 를 통한 Scale Out 형태의 GPU 확장은 예상 했던 것 처럼, Scale Up 모드보다는 무거운 연산임이 실험을 통해서도 확인 되었다. 노드 갯수가 작을때에는 Single Node 의 멀티 GPU 보다 더 느린 양상을 보였다. 이는 노드갯수가 4개 정도로 늘어나면 큰 차이가 나지 않는다. (이 곳에 언급하진 않았지만, 노드 갯수가 많아질수록 성능은 역전된다.) 즉, Horovod 시나리오는 좀더 BigData Scale Deep Learning 에 가깝다. 

Production 시스템에서 Training Data 가 쌓이고, 그 크기가 점점 커지기 시작하면, 점점 training 전에 전처리 단계에서 부터, 1대 머신의 물리 Disk 를 모두 동원해도 감당이 안될 정도로 Data가 커지는 경우가 있다. 이 경우 Scale Out 시나리오에서는 해당 노드에 간단하게 Hadoop 정도를 설치해주면, 데이타는 복수 Node 에 펼쳐져 저장되게 되고, Disk IO 는 분산되어, 훨씬 성능도 좋아진다. ( Tensorflow 의 공식 github 에는 이러한 경우를 위해hadoop 에 저장된 Training Data를 핸들링 할 수 있는 Hadoop Connector 유틸리티가 제공되고 있다. Spark Connector 도 있다. TensorflowOnSpark 는 내부적으로 해당 유틸리티를 활용하고 있다.) Data 의 크기는 크지 않지만, Disk IO 를 20~30배 이상 성능적으로 개선해보고자 할때는 Hadoop 대신에 해당 노드에 Spark 나 Tachyon (이름이 바뀌긴 했으나, original 이름으로 더 알려진) 이나, Apache ignite 를 설치하고 수행할 수도 있다.

위 실험에서도 알 수 있는것처럼, 데이타의 크기가 1대의 머신에 담을 수 있는 크기이고, GPU는 8개 미만만 사용해도 되는 수준이라고 한다면, Scale Up 이 더 유리하다. ( Deep Learning Infra 설계시 참고하기 바란다. 작은 데이타는 1Node 4GPU 가 1GPU 4Node 보다 성능이 더 좋음을 위해서 보여 준 바 있다.)

하지만, Scale Up 은 Nvidia 의 dependency 로 대부분의 Deep Learning 프레임워크들이 8개 까지만 지원하는 경우가 많다. 하지만, Scale Out 은 그런 한계를 극복 할 수 있다. Horovod 는 그래서, 1대 Node 에 GPU 를 4개씩 꼳아서 8대를 클러스터로 묶어서 수행하는 경우 Scale Up 과 Scale Out 의 성능을 동시에 활용할 수 있다. 즉, 그 경우 4*8 = 32개 GPU 를 사용할 수 있다. Keras 는 8개가 한계 이지만, Horovod 그리고, Horovod + Cloud PaaS (본 실험에서는 이 부분을 Azure batch AI 를 이용했다.) 를 사용하는 경우 수백대 이상 까지도 Node 및 GPU를 동원하여, 분산 Training 의 장점을 몇번의 클릭으로 수행 해 볼 수 있다.

Keras 는 1줄 코드 수정으로 Scale Up 이 되었지만,  Horovod 는 6~8 줄 정도의 수정이 필요하였다. 하지만, 익숙해지면, 1분안에 적용 가능한 수준이었다. 때문에, 발생산성 향상은 검증되었다고 본다.

Horovod  의 위키에는 다양한 Horovod 성능 수치 비교자료들이 존재한다. 아래는 그중에 어떤 사용자의 경험을 보여주는 성능비교 수치이다. Scale Out 이 아닌 Scale Up 의 경우에도 8개 GPU 이상일때는 Horovod 방식이 성능이 더 잘 나오는 것을 표현해주고 있다. 내가 했던 실험 데이타 또한 처음에는 Horovod 가 느리다가 Node 4개를 기점으로 역전되는 모양을 보여주었었다.

Scale Out 부분에 있어서도, 대부분의 벤치마크 자료나, 대다수의 비교 자료에서 Horovod 는 Tensorlfow 에서 자체적으로 제공하는 Parameter Server 를 활용한 방식 보다, 수행 속도 측면에서 성능이 더 잘 나오는 것을 확인 해 볼 수 있다.

즉, 성능 적인 개선도 검증되었다고 여겨진다.


개발이 훨씬 쉬워지면서 성능이 뒤쳐지지 않는다면... 아키텍처링 입장에서는 마다할 이유가 없다.


댓글 없음:

댓글 쓰기