08.3 더 빠르게(딥러닝 고속화)
빅 데이터와 네트워크의 발전으로 딥러닝에서는 대량의 연산을 수행해야 합니다. 과거에는 주로 CPU가 계산을 담당했으나, CPU만으로 딥러닝을 처리하기는 부족한 게 현실입니다. 실제로 주위를 둘러보면 딥러닝 프레임워크 대부분은 GPUGraphics Processing Unit를 활용해 대량의 연산을 고속으로 처리할 수 있습니다. 최근 프레임워크에서는 학습을 복수의 GPU와 여러 기기로 분산 수행하기 시작했습니다. 이번 절에서는 딥러닝의 고속화에 관해 이야기해보려 합니다(참고로, 우리의 딥러닝 구현은 8.1절에서 마무리하고, GPU 대응 등 여기에서 설명하는 고속화는 적용하지 않습니다).
8.3.1 풀어야 할 숙제
딥러닝의 고속화 얘기를 시작하기 앞서, 딥러닝에서는 어떠한 처리에 시간이 소요되는지를 보겠습니다. [그림 8-14]는 AlexNet의 forward 처리(순전파)에서 각 층이 소비하는 시간을 원 그래프로 보여줍니다.
그림 8-14 AlexNet의 forward 처리 시 각 층의 시간 비율 : 왼쪽이 GPU, 오른쪽이 CPU를 사용한 경우. ‘conv’는 합성곱 계층, ‘pool’은 풀링 계층, ‘fc’는 완전연결 계층, ‘norm’은 정규화 계층이다.[26]

그림에서 보듯 AlexNet에서는 오랜 시간을 합성곱 계층에서 소요합니다. 실제로 합성곱 계층의 처리 시간을 다 더하면 GPU에서는 전체의 $95\%$, CPU에서는 전체의 $89\%$까지 달하지요! 그래서 합성곱 계층에서 이뤄지는 연산을 어떻게 고속으로 효율적으로 하느냐가 딥러닝의 과제입니다. [그림 8-14]는 추론 때의 결과지만, 학습 시에도 마찬가지로 합성곱 계층에서 많은 시간을 소비하게 됩니다.
NOTE_ 합성곱 계층에서 수행하는 연산은 “7.2 합성곱 계층“에서 설명했듯이, 결국 ‘단일 곱셈-누산’입니다. 그래서 딥러닝 고속화라는 주제는 대량의 ‘단일 곱셈-누산’을 어떻게 고속으로 효율적으로 계산하느냐는 것입니다.
8.3.2 GPU를 활용한 고속화
GPU는 원래 그래픽 전용 보드에 이용해왔습니다. 그러나 최근에는 그래픽 처리뿐 아니라 범용 수치 연산에도 이용합니다. GPU는 병렬 수치 연산을 고속으로 처리할 수 있으니, 그 압도적인 힘을 다양한 용도로 활용하자는 것이 GPU 컴퓨팅의 목적이죠. 이처럼 GPU로 범용 수치 연산을 수행하는 것을 GPU 컴퓨팅이라고 합니다.
딥러닝에서는 대량의 단일 곱셈-누산(또는 큰 행렬의 내적)을 수행해야 합니다. 이러한 대량 병렬 연산은 GPU의 특기죠(반대로 CPU는 연속적인 복잡한 계산을 잘 처리합니다). 그래서 딥러닝 연산에서는 GPU를 이용하면 CPU만 쓸 때보다 놀라울 정도로 빠르게 결과를 얻을 수 있습니다. 그렇다면 과연 GPU로 어느 정도까지 빨라지는지 예를 보여드리겠습니다. [그림 8-15]는 AlexNet의 학습 시간을 CPU와 GPU에서 비교한 결과입니다.
그림 8-15 AlexNet의 학습 시간을 ‘16코어 제온 CPU’와 엔비디아 ‘타이탄 GPU’에서 비교한 결과[27]

그림과 같이 CPU에서는 40여 일이나 걸리지만 GPU로는 6일까지 단축되었습니다. 또, cuDNN이라는 딥러닝에 최적화된 라이브러리를 이용하면 더욱 빨라짐을 확인할 수 있습니다.
GPU는 주로 엔비디아와 AMD, 두 회사가 제공합니다. 두 회사의 GPU 모두 범용 수치 연산에 이용할 수는 있지만, 딥러닝과 더 ‘친한’ 쪽은 아직까지는 엔비디아입니다. 실제로 대부분의 딥러닝 프레임워크는 엔비디아 GPU에서만 혜택을 받을 수 있습니다. CUDA라는 엔비디아의 GPU 컴퓨팅용 통합 개발 환경을 사용하기 때문이죠. [그림 8-15]에 등장하는 cuDNN은 CUDA 위에서 동작하는 라이브러리로, 딥러닝에 최적화된 함수 등이 구현되어 있습니다.
NOTE_ 합성곱 계층에서 행하는 연산은
im2col을 이용해 큰 행렬의 내적으로 변환할 수 있었습니다. 이러한im2col의 방식은 GPU로 구현하기에도 적합합니다. GPU는 ‘작은’ 단위로 계산하기보다는 큰 덩어리를 한 번에 계산하는 데 유리하기 때문이죠. 즉,im2col로 거대한 행렬의 내적으로 한 번에 계산하여 GPU의 잠재력을 끌어내는 것입니다.
8.3.3 분산 학습
GPU로 딥러닝 연산을 꽤 가속할 수 있지만, 그래도 심층 신경망에서는 학습에 며칠 혹은 몇 주가 걸리기도 합니다. 그리고 지금까지 살펴본 것처럼 딥러닝은 많은 시행착오를 동반합니다. 뛰어난 신경망을 만들려면 시험을 수없이 반복해야 하고, 그러려면 1회 학습에 걸리는 시간을 최대한 단축하고 싶다는 요구가 필연적으로 생겨납니다. 그래서 딥러닝 학습을 수평 확장scale out하자는 아이디어 (즉, ‘분산 학습’)가 중요해지는 것입니다.
딥러닝 계산을 더욱 고속화하고자 다수의 GPU와 기기로 계산을 분산하기도 합니다. 최근에는 다수의 GPU와 컴퓨터를 이용한 분산 학습을 지원한 딥러닝 프레임워크들이 나타나고 있습니다. 그중에서도 구글의 텐서플로와 마이크로소프트의 CNTKComputational Network Toolkit는 분산 학습에 역점을 두고 개발하고 있습니다. 거대한 데이터센터의 저지연 · 고처리량low latency, high throughput 네트워크 위에서 이들 프레임워크가 수행하는 분산 학습은 놀라운 효과를 보이고 있습니다.
지니가 대형 관제소에서 여러 서버 랙에 꽂힌 수십 장의 GPU 카드들이 텐서플로 동기화 빔을 뿜어내며 하나의 거대 모델을 협동하여 초고속 학습하는 분산 처리 기법을 도로시에게 소개하고 있어요.
지니의 수평 확장 분산 학습 특강
- 지니: “도로시, 아무리 한 대의 GPU가 빨라도 초대형 언어 모델이나 고해상도 이미지 데이터셋을 훈련하기는 역부족이야. 그래서 수십, 수백 대의 GPU 서버를 기가비트 저지연 네트워크로 묶어 데이터를 분할 학습시키는 분산 학습(Distributed Learning) 스케일아웃 기술이 핵심 과제란다.”
- 도로시: “와! GPU가 100개 모이니까 7일이나 걸리던 작업이 단 3시간 만에 끝났네! 협동조합의 힘이 정말 대단하구나!”
분산 학습까지 더하면 어느 수준까지 고속화할 수 있을까요? [그림 8-16]은 텐서플로로 알아본 분산 학습의 효과입니다.
그림 8-16 텐서플로의 분산 학습 성능 : 가로는 GPU의 수, 세로는 GPU 1개일 때와 비교한 비율[28]

[그림 8-16]에서 보듯 GPU 수가 늘어남에 따라 학습도 빨라집니다. 실제로 여러 기기를 연결하여 GPU를 100개까지 사용하니 하나일 때보다 56배가 빨라졌습니다! 7일짜리 작업을 불과 3시간 만에 끝낸다는 것으로, 분산 학습의 놀라운 효과를 증명하고 있습니다.
분산 학습에서도 ‘계산을 어떻게 분산시키느냐’는 몹시 어려운 문제입니다. 컴퓨터 사이의 통신과 데이터 동기화 등, 쉽게 해결할 수 없는 문제를 얼마든지 끌어안고 있습니다. 그래서 이런 어려운 문제는 텐서플로 같은 뛰어난 프레임워크에 맡기는 것이 좋습니다. 여기에서는 분산 학습의 상세 내용은 다루지 않겠습니다. 분산 학습 관련 기술적인 내용은 텐서플로 기술 논문[29] 등을 참고하세요.
8.3.4 연산 정밀도와 비트 줄이기
계산 능력 외에도 메모리 용량และ 버스 대역폭 등이 딥러닝 고속화에 병목이 될 수 있습니다. 메모리 용량 면에서는 대량의 가중치 매개변수와 중간 데이터를 메모리에 저장해야 한다는 것을 생각해야 합니다. 버스 대역폭 면에서는 GPU(혹은 CPU)의 버스를 흐르는 데이터가 많아져 한계를 넘어서면 병목이 됩니다. 이러한 경우를 고려하면 네트워크로 주고받는 데이터의 비트 수는 최소로 만드는 것이 바람직합니다.
컴퓨터에서는 주로 64비트나 32비트 부동소수점 수를 사용해 실수를 표현합니다. 많은 비트를 사용할수록 계산 오차는 줄어듭니다만, 그만큼 계산에 드는 비용과 메모리 사용량이 늘고 버스 대역폭에 부담을 줍니다.
다행히 딥러닝은 높은 수치 정밀도(수치를 몇 비트로 표현하느냐)를 요구하지 않습니다. 이는 신경망의 중요한 성질 중 하나로, 신경망의 견고성에 따른 특성입니다. 예를 들어 신경망은 입력 이미지에 노이즈가 조금 섞여 있어도 출력 결과가 잘 달라지지 않는 강건함을 보여주죠. 이런 견고성 덕분에 신경망을 흐르는 데이터를 ‘퇴화’시켜도 출력에 주는 영향은 적습니다.
도로시가 뚱뚱한 64비트 소수 알갱이들을 가볍고 얇은 16비트 반정밀도 및 1비트 이진화(Binarized) 알갱이로 다이어트해서 가벼운 몸으로 병렬 통신 파이프를 고속 통과하도록 돕고 있어요.
도로시의 16비트 다이어트 감탄
- 도로시: “지니! 딥러닝은 노이즈에 강건(Robust)해서 소수점 자리가 조금 어긋나도 판단 결과에 거의 지장이 없대! 그래서 32비트나 64비트 대신 16비트 반정밀도(Half-precision)나 아예 0과 1로만 표현하는 1비트 이진화 신경망(BNN)을 쓰면 연산 대역폭과 메모리를 대폭 절약할 수 있어!”
- 지니: “정답이야! 이 수치 다이어트 덕분에 엣지 디바이스나 스마트폰 칩에서도 저전력으로 딥러닝 추론을 쌩쌩 실행할 수 있는 거지.”
컴퓨터에서 소수를 표현하는 방식으로 32비트 단정밀도single-precision와 64비트 배정밀도double-precision 부동소수점 등의 포맷이 있지만, 지금까지의 실험으로는 딥러닝은 16비트 반정밀도half-precision만 사용해도 학습에 문제가 없다고 알려져 있습니다.[30] 실제로 엔비디아의 최신 GPU인 파스칼Pascal 아키텍처는 이 포맷을 지원하여, 이제는 반정밀도 부동소수점이 표준적으로 이용되리라 생각합니다.
NOTE_ 엔비디아의 맥스웰Maxwell 세대 GPU는 반정밀도 부동소수점 수를 스토리지(데이터를 저장하는 기능)로 지원하고 있었지만, 연산 자체는 16비트로 수행하지 않았습니다. 이것이 파스칼 세대에 와서 연산 역시 16비트로 하기 시작하여, 이전 세대보다 2배 정도 빨라질 것으로 기대합니다.*
이 책은 지금까지 딥러닝을 구현하며 수치 정밀도에는 특별히 주의하지 않았습니다. 그럼 몇 가지를 짚어봅시다. 우선 파이썬에서는 일반적으로 64비트 배정밀도 부동소수점 수를 사용합니다. 하지만 넘파이는 16비트 반정밀도 부동소수점도 지원하며, 이를 사용해도 정확도가 떨어지지 않는 것을 쉽게 확인할 수 있습니다(단, 스토리지로서 16비트라는 틀이 있을 뿐 연산 자체는 16비트로 수행하지 않습니다). 관심 있는 분은 ch08/half_float_network.py를 참고하세요.
딥러닝의 비트 수를 줄이는 연구가 몇 가지 진행되고 있습니다. 최근에는 가중치와 중간 데이터를 1비트로 표현하는 **
토토가 귀여운 로봇 스마트 글래스를 착용해, 글래스 내부 경량화 칩셋(Inference Chip)이 실시간으로 눈앞의 사물들을 지연 없이 0.001초 만에 스캔하여 한글 라벨을 띄우는 모습을 지켜보고 있어요.
토토의 실시간 추론 감탄
- 토토: “왈왈! (글래스를 반짝이며) 실시간 사물 스캔 완료다 멍!”
- 도로시: “와! 이렇게 비트 다이어트를 거친 가벼운 경량 모델을 전용 엣지 추론 칩(NPU)에 올려두니까, 인터넷 연결이 없어도 카메라 화상 인식이 실시간으로 바로 실행되네! 신기해!”
* 옮긴이_ AMD GPU 역시 베가(VEGA) 모델부터는 반정밀도 연산을 지원합니다. 또한 게임 콘솔인 PS4 Pro뿐 아니라, <애플의 자체 제작 GPU 살펴보기>(http://macnews.tistory.com/5200)에 따르면 애플이 아이폰7에 처음 사용한 A10 퓨전 칩의 GPU도 반정밀도 연산을 지원합니다. 딥러닝이 생활 깊숙이 파고들면서 모바일 기기까지도 본격적인 딥러닝 대응을 시작했다는 방증일 것입니다.