Learning
Mixed Precision Training 이라는 기술은 모델의 파라미터를 32-bit가 아닌 16-bit로 표현하여 배치 사이즈를 늘리고, 그에 따라 학습 속도를 빠르게 할 수 있는 기술입니다. 더불어, 이 과정에서 발생할 수 있는 문제를 Adaptive 방식으로 해결하는 과정과 나아가 Automatic Mixed Precision(AMP)이 뭔지 다루도록 하겠습니다.
혹시 논문부터 읽고 싶으신 분은 Mixed Precision Training을 다룰 논문 링크를 참고하세요.
Single Precision(Floating Point 32, FP32)는 과연 딥러닝 학습에서 양보할 수 없는 선일까? 만약 Half Precision(Floating Point 16, FP16)을 활용할 수 있다면 모델 학습에 필요한 메모리도 줄이고, 연산도 가속시킬 수 있습니다. 물론 그렇게 학습된 모델의 성능이 FP32와 비교해서 크게 떨어지지 않아야겠죠.
단순하게 보면 모델의 파라미터를 32-bit에서 16-bit로 줄인 것 뿐이지만, 이 기술은 아래 세가지 측면을 고려했을 때 정말 획기적이라고 말할 수 있습니다.
저는 특히 2, 3번이 인상적이었는데요, 그 이유는 특정 모델이나 연산에 국한하지 않고 범용적으로 적용될 수 있으니 이산화탄소 발생으로 인한 환경 파괴를 크게 줄일 수 있기 때문입니다. 더욱이 요즘은 GPT, 특히 ChatGPT로 대표되는 많은 초거대 AI 모델이 득세하고 있기 때문에 그것들을 학습할 때 사용하는 자원이 천문학적임을 고려한다면 Mixed Precision의 중요성은 이루 말할 수 없을 것 같습니다.
생각해보면 파라미터를 32-bit에서 16-bit로 줄여 숫자의 표현 정밀도를 낮춰 연산량을 줄이고 학습 속도를 높일 수 있다면 처음부터 16-bit로 하면 되는게 아닐까? 하는 생각을 할 수 있습니다.
그래서 살펴본 아래 자료에서 대답을 찾을 수 있습니다. 아래 그림은 NVIDIA Technical Blog에서 실험한 Object Detection에서 유명한 SSD(Single Shot Multibox Detector)모델의 파라미터가 가진 gradient의 분포입니다.
그림의 빨간색 선을 기준으로 왼쪽은 FP16으로는 표현할 수 없는 숫자 범위이고 오른쪽은 FP16으로 표현 가능한 수의 범위입니다. 절반 이상의 gradient가 FP16으로는 표현할 수 없기 때문에 FP16으로 학습을 한다면 많은 정보가 소실될 것으로 유추할 수 있습니다.
이것은 bit 수에 따른 수의 표현 범위가 크게 차이나기 때문인데요, “bit 수가 절반이 된다고 뭐가 그렇게 차이나겠어?”라고 생각하시는 분은 아래의 자료를 보시면 금방 이해하실 수 있습니다.
32-bit와 16-bit는 위의 그림처럼 표현할 수 있는 범위가 극명하게 차이를 보입니다.
혹시나 16-bit도 모자라 8-bit, 4-bit로 학습할 수 있지 않을까하는 욕심은 과유불급…
때문에 FP16을 활용해서 메모리와 속도의 이점을 가져가고 싶지만 위와 같은 문제로 Fully Designed to FP16 모델은 성능 저하가 명백해 보입니다. 이를 막기 위해 Mixed Precision이 제안되었습니다.
참고로 C에서는 FP16을 지원하지 않기 때문에 CPython 기반인 Numpy를 활용해도 16-bit / 32-bit 속도 차이가 없다는 내용이 보고된 바 있습니다. 오히려 16-bit가 더 느려졌다는 내용도 있었지만 이 부분은 해결된 것으로 보입니다.
이름처럼 모든 파라미터를 FP32로 하지도, FP16으로 하지도 않습니다. 두 타입을 넘나들며 학습을 수행하게 되며 논문에서 소개된 그림은 아래와 같습니다.
그런데 Scaling factor S가 너무 크거나 작으면 곱하고 나누는 과정에서 Inf 또는 NaN이 발생할 수 있습니다. 이 세상엔 너무나 많은 모델이 있고 실험 환경이 있는데, S를 늘 같은 값으로 정해 학습하는 것은 좋은 방법이 아닌 것 같죠.
다만 생각할 수 있는 것은 gradient의 최댓값이 65,504 (FP16의 최댓값)을 넘지 않도록 설계하는 것입니다. 따라서 초기 S를 크게 설정하되 iteration이 지나서 학습에 문제가 발생하면 S를 키우거나 줄이거나 하는 방법을 선택하면 좋을 것 같고 우리는 이 방법을 Adaptive라고 표현할 수 있겠습니다. 그리고 이걸 알고리즘으로 설명하면,
FP32로 표현된 FP32 Master weights를 저장해둔다
S의 초기값을 큰 수로 설정한다
매 iteration 마다 아래를 수행:
backprop해서 얻은 weight gradient를 S로 나눈다
Gradient clipping, weight decay를 포함하여 weight update 수행
만약 최근 N iteration 동안 inf 또는 NaN이 발생하지 않았다면 S값을 증가시킨다
영어를 그대로 옮겼지만 쉽게 이해할 수 있습니다. 단지 Inf 또는 NaN이 발생했을 경우 S를 키우거나 줄인다는 점이 추가되었습니다.
왜 S값을 키우나요?
Mixed Precision을 이용해서 학습했을 경우 성능의 저하는 없고 throughput은 1~5배 증가한 것을 실험을 통해 확인할 수 있습니다.
보고된 숫자는 표에 나와있고, 제 의견을 덧붙이자면
NVIDIA의 자료를 살펴보면 Mixed Precision에 AllowList, DenyList, InterList가 구분되어 있는 것을 알 수 있습니다.
왜 이런 구분이 있는 것일까? 원문과 함께 살펴보겠습니다.
How is AllowList/DenyList/InferList determined? What are the corresponding ops that are in each list?
주목할 점은 DenyList인데, 먼저 이것을 두 분류로 나눠보면
Non-linear는 log 또는 e 등의 지수연산이 들어가기 때문에 쉽게 FP16의 표현 범위를 넘어갈 것으로 예상할 수 있습니다. 따라서 Mixed Precision 적용 시 형변환을 하면 성능 저하가 발생할 것이 뚜렷합니다.
하지만 Linear는 조금 가능성이 낮아보이는데, 왜냐하면 단순 사칙연산에 해당하기 때문입니다. 그래도 생각해보자면 L1 Loss는 mean 또는 sum 연산이 옵션으로 존재하는데, 아마도 Large mini-batch를 가정했을 때 성능 저하가 발생할 것으로 예상할 수 있습니다 (많은 수를 더하는 과정에서 범위를 벗어날 수 있기 때문이라고 이해했습니다).
What is Automatic Mixed Precision (AMP) and how can it help with training my model?
정리하자면 Mixed Precision을 쉽게 적용할 수 있게끔 프레임워크 차원에서 제공하는 것을 의미합니다.
오늘 Mixed Precision에 대해 소개드렸는데, 이 기술은 데이터헌트를 포함한 모든 AI 서비스를 제공하는 회사에게 매우 중요한 내용이라고 생각합니다. 그 이유는 딥러닝 모델을 학습할 때 비용적, 시간적 자원이 정말 많이 들어가기 때문입니다. 대충 어림계산을 해도 모델 학습에 필요한 시간을 절반으로 줄일 수 있다면 그것에 필요한 물적 비용 또한 절반이 되고, 서비스 개발 속도도 큰 폭으로 개선시킬 수 있습니다.
때문에 데이터헌트에서도 Mixed Precision을 활용해서 모델을 연구개발하고 있으며, 앞으로도 이 분야에서 이루어지는 최신 연구들을 follow up 할 예정입니다.
다음에는 PyTorch에서 AMP를 어떻게 사용하는가에 대해 Automatic Mixed precision package 를 바탕으로 실습하는 시간을 가져보도록 하겠습니다.
https://arxiv.org/pdf/1710.03740.pdf
https://hoya012.github.io/blog/Mixed-Precision-Training/
https://arxiv.org/pdf/2208.06064.pdf
https://pytorch.org/blog/what-every-user-should-know-about-mixed-precision-training-in-pytorch/
https://www.khronos.org/opengl/wiki/Small_Float_Formats
https://pytorch.org/docs/stable/amp.html