테크매니아
Edge AI 모델 경량화 & 포팅 하면서 느낀 점 본문
서론
Edge AI를 3년 넘게 하면서 느낀 점을 짧은 글로 정리 하려고 한다. 느끼면서 지나쳤던 여러 생각들을 글로 정리 해 보고자 한다. Edge AI를 하는 여러 사람들이 이 글을 보이 도움이 되었으면 좋겠다.
NPU의 한계
NPU의 한계가 명확하다. NPU는 딥러닝 모델을 가속 실행하는 반도체를 의미한다. 반도체 특성상 설계와 생산에 많은 시간이 들기 때문에 필연적으로 내가 보는 NPU는 몇 년 전 기술에 머무는 느낌을 받는다. 실제로 지금 보이는 많은 NPU들은 몇 년 전에 나온 CNN기반의 백본 몇개를 타겟팅해서 설계됐기 때문에 쏟아져 나오는 최신 논문에서 제시하는 모델을 제대로 실행할 수 없다.
NPU 제조사들이 NPU와 함께 내놓는 SDK(소프트웨어)를 통해서 많은 Op를 지원하고 있지만 연구 속도를 완전히 따라가지 못하는 실정인 것 같다.
처음엔 ‘NPU가 무슨 이것도 못하나’ 싶었지만, 여기서 생기는 간극을 메꾸는게 결국 내가 할 일이였다. NPU가 완벽지 않고 오래된 딥러닝 모델에 타겟팅 되어서 설계되었기 때문에 이것을 인정하고 내가 거기에 맞춘다는 느낌으로 접근해야 한다.
모델에 대한 이해
처음 이 일을 할 때에는 단순히 모델을 시스템 관점에서 라이브러리 정도만 Edge Device에 포팅하면 된다고 생각 했지만 모델에 대한 이해가 많이 필요했다. 보통 만나는 오류 내용이 “백본 2번째 Conv뒤에 나오는 GeLU가 안된다.” 또는 “ViT에서 bmm은 5차원이상 지원하지 않는다.” 같은 식의 오류가 많기 때문에 모델을 제대로 모르면 문제를 해결하기 어렵다.
이런 문제를 해결하기 위해서 Conv뒤에 GeLU를 왜 썼는지, GeLU말고 다른걸 쓰면 안되는지, 그렇게 했을 때 학습 속도나 인식율 차이는 없는지, ViT에서 왜 5차원 bmm을 썼는지, 각 차원은 무엇을 뜻하는지, 차원별로 쪼갤수 있는지, 우회하려면 어떻게 해야 하는지 유추하고 실행하는 일이 대부분이다.
그래서 모델 자체에 대해서 기본적인 공부를 하고 들어가면 좋다. 나같은 경우에는 논문을 찾아보고 국내외 블로거나 유튜버를 통해 공부 했고, 모델을 잘 아는 동료에게 설명 듣기도 했다.
텐서에 대한 이해
위 내용과 비슷하지만 조금 더 디테일한 내용을 담는다. 모델보다 더 디테일하게 각 레이어마다 계산되는 텐서에 대해서 잘 알아야 한다. 처음에는 reshape이나 transpose가 어떻게 연산되는지 헷갈려서 실수도 많이 했고 시간 낭비도 많았다. 모델을 변환 하면서 그 모양을 바꾸는 경우가 많기 때문에 어느정도 머리속으로 4 차원 텐서까지 곱해지고 쪼개지고 돌아가는게 시뮬레이션이 되어야 한다. 그게 안되면 노트를 펴놓고 그림을 그려 보거나 다른 Python 인터프리터를 열어 놓고 실험 하면서 해야 한다.
경우에 따라서 모델을 Quantization 할 때 결과가 잘 안나온다면 어느 레이어에서 오차가 많이 발생하는지 모델의 weight나 출력값을 직접 확인해야 한다. SDK가 그냥 “2134번 node 다음에 죽었다.”라고 한다면 netron으로 모델을 열어서 그래프 앞뒤에 있는 Op와 텐서의 Shape을 보고 코드에 어떤 부분인지 유추해야 한다. 귀찮은 작업이긴 하지만 이런식의 노가다 작업이 많기 때문에 익숙해져야 한다.
Op에 대한 이해
Edge AI 모델 포팅 작업은 보통 이미 만들어진 모델(Torch나 TF로 개발)을 받아서 onnx로 “변환”하고, 이걸 NPU 제조사가 제공한 SDK를 통해서 중간 언어로 “변환”하고 이걸 다시 NPU에서 실행할 수 있는 모델로 “변환”하는 것을 뜻한다.
이 변환의 주체는 Op(오퍼레이터)이고, 각 변환 단계(Torch, onnx, 중간언어, NPU모델)에 따라 지원하는 Op의 종류가 다르기 때문에 이것을 맞춰주는 작업을 해야 한다.
가령, 특정 NPU에서 분산(variance)에 대한 Op가 없다면, 편차(standard) Op는 있는지, 몇 차원까지 지원하는지를 보고 편차를 이용해 분산을 만들어야 한다. 다른 예로, 특정 차원 이상의 conv가 안된다면 여러개의 conv로 쪼갠 다음에 concat 하는 식으로 우회해야 한다. 이런 상황에서 Op를 대체하고 새로 만들기 위해서 기본적으로 Op에 대해 이해하고 있어야 한다.
Op에 대해서는 아주 잘 알 필요는 없지만 내부적으로 어떻게 연산이 되는지 알고 있으면 좋다. 이것은 Torch나 TF가 오픈소스이기 때문에 이걸 참고해서 내부 구현이 어떻게 돼 있는지 보면 도움이 된다.
시간 절약
모델을 텐서와 Op 단위로 분석하는 일은 아주 넓고 깊은 모델을 현미경으로 보는 것과 같다. 코드의 내부의 내부의 내부까지 분석하다 보면 정신이 아득해지고 몇 시간이 지나면 내가 뭘 하고 있는지 잊고 무아지경으로 분석을 하게 되는데 이렇게 되면 효육적으로 일을 할 수 없다.
처음에 전체적으로 살펴보는 것을 제외하고 주제를 정하고 봐야 한다. “지금은 디코더 입력 텐서가 언제 바뀌는지 보는거야” 라는 식으로 주제를 정하고 실험해야 한다. 그리고 그 결과를 메모 하고, 코드에 주석을 자세히 남기면 좋다.
Edge AI 포팅 작업중 경량화 작업은 모델의 일부를 수정해서 기존 모델과 대비 얼마나 Acc를 유지 하면서 시간 성능이 얼마나 빨라지는지가 포인트다. 여기서 모델을 여러 방법으로 바꾸고 학습/실험/검증/테스트 하는 과정이 있는데 짧게는 몇 분에서 길게는 며칠씩 걸리기도 한다. 이것도 어느 상황에서 왜 한 어떤 실험인지 기록하고, commit하고, MLFlow를 이용해 메모 해 두면 같은 실험을 두 번 이상 하거나 실험을 해놓고 왜 했는지 되묻는 경우를 줄일 수 있다.
결론
Edge AI, 모델 경량화는 연구소에서 만들어진 인공지능 모델을 경제적으로 잘 서비스 할 수 있는 필수적이고 중요한 기술이라 생각한다. 개인적으로, 최적화 기술을 적용해 성능을 향상을 향상 시키는게 너무 재밌다. 놀고있는 자원 없이 성능을 (쥐어짜서) 더 좋은 모델을 더 잘 구현할 수 있도록 해야겠다.