정글 8기 나만무 : 수어지교 #3, 딥러닝 개론

우리 서비스의 딥러닝을 직접 맡은건 아니지만 설명은 할 수 있을정도가 되기위해 옆에서 열심히 보려고는 했다.. 설명을 들어보면 한 몫 기여 할 수 있지 않을까 생각했지만 내가 생각하고 추론하는 속도에 비해 원래 하던 사람이 Cursor 랑 같이 으쌰으쌰하는게 시도 하기엔 더 적합 한 것 같다. 하여튼, 이 글에선 내가 이해하고 있는 우리 개발의 딥러닝에 대한 이야기를 아는만큼 풀어보려고 한다. 



딥러닝 모델의 서비스 제공 과정

아쉽게도 나는 수차례 설명을 들었음에도 이것을 오 그렇구나 하고 당시엔 정말 잘 이해했지만, 완벽하게 설명 할 수가 없다. 후에도 언급하겠지만 현재 아는 선에서 대답을 해보겠다.

한 단어를 표현하는 각기 다른 영상을 교육시킨다. 즉, "컴퓨터"라는 단어를 표현하는 수어를 다양한 사람들이 같은 포즈로 액션 한 영상이 여러개 있으니 이 것을 "컴퓨터"라는 그룹에 묶어서 교육을 시킨다. 영상이 유의미한 결과치를 내기에는 양 자체가 모자랐다.

개인적으로 직접 찍은걸 교육 데이터로 쓰면 되지 않을까 생각을 했지만 우리 중에 수어 달인이 있진 않았기 때문에, 데이터가 오염될라 그런 부분은 입밖으로 나오진 못했다. 차후 설명하겠지만 기존의 데이터를 살짝 살짝 변형한 형태로 교육 데이터의 부피를 키워서 교육시키는데는 어찌저찌 성공했다.

그러면 분류 모델 한 개는 5-Class 분류 모델이 된다. 4개를 교육시켰잖아요 라고 하겠지만 그 4개에 해당되지 않는 "없음"을 포함하기 때문이다. 0이 자연수는 아니지만 0이 있음으로써 우린 없다는 개념을 표현할 수 있지 않은가. 그러니까 손가락 5개로 표현 할 수 있는 숫자는 6개라는 뜻이다.

 

 

한 영상을 모델이 학습하게 되는 과정을 간단히 읊어보면.. 1) CNN. 2) BiLSTM. 3) Dense 를 순서대로 적용한다.

  1. CNN | Convolutional Neural Network, 합성곱 신경망. 특징을 추출하는 단계이다.
    • 시계열 데이터에서, 짧은 시간의 구간 안에서 지역적이고 핵심적인 패턴을 찾아낸다. 영상에서 팔을 뻗는다고 가정을 해보자. 어깨가 들리는 순간, 팔꿈치가 펴지는 순간과 같은 미세한 특징들을 잡아낸다. 이렇게 하면 데이터의 복잡성을 줄이고, 의미있는 정보로 압축 할 수 있다고 한다.
  2. BiLSTM | Bidirectional Long Short-Term Memory, 양방향 장단기 메모리. 시간적 맥락을 파악한다.
    • 앞에서 추출된 핵심 특징들의 순서를 전달 받는다. LSTM은 데이터의 연관성을 학습하는데 특화되어 있다고 한다. 모션에 대한 데이터를 시간상의 순방향, 그리고 역방향으로도 모두 처리하기 때문에 특정 시점의 움직임의 맥락을 종합적으로 파악하는 것이다. 이 과정에서 팔을 뻗는 것의 목적이 무엇인지에 대한 파악이 가능해진다고 한다.
  3. Dense | Fully Connected Layer, 완전 연결 계층. 최종 분류를 진행하는 단계이다.
    • 앞 과정에서 일어나는 고차원적인 특징 정보를 받아서, 최종 결론을 내리게 된다. 이 때는 모든 내용들을 종합하여 어느 동작에 해당하는지 분류/예측 하게 된다.

 

 

이렇게 한 개의 "분류 모델"에는 총 4개의 수어를 교육 시키기로 결정 한 것은 이유가 있었다.

  • 우선 사용자에 요청에 따라 켜지고 꺼지는 과정이 나타나는데 UX를 해치지 않는 선에서의 부피 한계선은 4개 정도로 결론이 나왔다. 즉, 상식적인 로딩 내에서 해결하기 위함이었다.
  • 앞에서 설명했듯 카테고리 - 챕터 - 단어 단위로 구성된 우리 내용은 단어 n개를 한 개의 챕터로 규정했기 때문에 챕터 한 개를 실행하면서 한 개의 "분류 모델"이 실행되도록 매핑하는것을 처음에 설계했다. 하지만, 이 내용은 후에 바뀌게 된다..

 

분류 모델을 만드는 것도 의외로 효율적으로 이루어졌는데, 규모가 작다보니 로컬에서 교육하는게 가능했던 모양이었다. 그래서 퇴근전에 팀장이 만들어둔 스크립트를 틀어놓고, 카페인네이트까지 활성화하고 퇴근하곤 했다. 그렇게 아침에 오면 keras와 json 뭉치들이 생겨있고 이것들이 쓸만한지 검수를 하고 사용 여부를 판가르곤 했다. 이제와서 말하는 것은 누가 의도적으로 컴퓨터를 꺼놓고 갈라 무서웠던게 있다.

앞에서 이야기한대로 한 챕터에 대한 분류 요청(나 이 챕터 할래 요청)으로 인한 모델 실행, 그리고 분류까지 잘 되는 것을 확인했지만, 후반에 가서는 학습 계층에 대한 전반적인 수정으로 인해 한 챕터에 다중 모델이 들어가야 할 필요성이 생겼다. 이 부분이 앞에서 언급한 한 챕터당 한 모델이 매핑되지 못했던 이유이다.

즉, 한 챕터에 한 모델이었던 기존과 비교 할 때 n개의 단어가 있다면 최악의 경우엔 모델이 한 개씩만 분류를 맡아서 최대 n개가 실행 되는 상황이었다. 말이 최악이지만 그래도 할만은 했다.

  • 모델 자체의 준비시간은 어찌저찌 해보니까 한번에 준비시킬 수 있었다.
  • EC2 인스턴스에서 VRAM을 너무 많이 잡아놓고 있어서 모델을 세 개 이상 킬 수 없는 치명적 상황이 있었는데.. 이 옵션을 끄는걸 몇시간동안 헤매다가 찾아서, 19GB에 육박했던 모델당 VRAM의 비상식적인 사용을 500MB로 감소시키는 성과를 내서 다중 접속이 가능해졌다.
  • 기존에 켜져있는 모델이 있다면 다른 사람이 또 분류 요청을 한다고 해도 웹소켓 서버도 추가적인 cost를 지불하고 실행되는 것도 아니며 그대로 사용 할 수 있었다.

 

서버의 리소스는 제법 아낄 수 있는 여지가 다분했지만 문제는 클라이언트 입장에서의 전송 상황이었다. 클라이언트가 n개의 웹소켓 서버에 연결되어있는데 n개 모두에 신호를 보내면 단기적으로도 장기적으로도 구리다. 우린 이걸 꽤 기발한 방법이면서 상당히 근본적인 내용으로 해결 했는데, 해당 단어를 맡고있는 모델과 클라이언트만 정보를 주고 받는 mapper를 만들어서 사용했다. 일종의 교환원을 배치하는 셈. 

요정도로 작동과정까지 같이 보셨다.