Search
💼

첫 직장, 가우디오랩에서의 8개월

Intro : 소마를 마무리하며

작년 소프트웨어 마에스토로 11기를 마치고 회고를 작성하지도 않았으면서 지금와서 무슨 회골까 싶지만, 사실상 회사 업무가 소마의 연장선이기도 했고 첫 직장생활에서의 경험을 글로 작성해야 할 것 같아서 이렇게 남기게 되었다. (물론, 생각보다 인수인계가 일찍 끝나서 시간이 남게된 것도 영향이 크다 ~_~)
1학년 때, 대학교 공지글에 인턴 관련 내용이 있어서 바로 지원을 하고 최종합격까지 했었는데, 1학년이라는 이유로 처우협의 중 사전에 공지된 내용보다 금액을 많이 깎기도 하였고(?) 주말근무까지 해야한다는 이야기를 듣고 인턴을 포기했던 경험이 있다. 이 때 이후로 '아 그때 그래도 그냥 인턴 경험이나 해볼껄'하는 아쉬움도 있었고, 그 때문에 2학년 이후로는 실제 회사에서의 업무를 해보고 싶다는 생각이 매우 크게 들었다.
그리고 2학년때 우연히도 소프트웨어 마에스트로에 합격하게 되었고, 이 때 개인적인 목표로 소마가 끝나면 바로 인턴을 지원할 수 있을 정도로 실력을 쌓기 위해 ML Engineering에 대해서 다양한 것들을 시도하고자 하였다. AWS Lambda를 이용해서 서버리스로 ML서빙을 구현하기도 했고, TorchServe, TFServing등 잘 패킹된 라이브러리들로 만든 모델을 서빙해보기도 했었다. 또한, 소마 자율멘토링때 죽도록 들었던 쿠버네티스를 직접 써보고 싶어서 AWS EKS로 이것저것 가지고 놀아보기도 했고, Message Queue의 요청량에 따라서 자동으로 Node와 Pod를 늘이고 줄이는 아키텍처를 실제로 구현해보기도 했다.(쏘카 블로그가 많은 도움이 되었다..! : https://tech.socarcorp.kr/data/2020/03/10/ml-model-serving.html) 주제가 주제인터라 실시간으로 피아노의 소리를 듣고 어떤 음인지 맞추는것도 구현하기 위해 On-Device ML도 구현해보았다. 이런 경험을 소마 보고서에 녹여낼 수 있었고, 능력자들인 프론트엔드를 맡아준 인성이형과 백엔드를 맡아준 하균형 덕분에 Banju앱을 실제 사용 가능한 MVP로 완성시킬 수 있었다. 사실 소마를 시작할때는 "내 실력에 무슨 인증이얏...!" 하고 인증은 꿈도 못꾸고 (주변에 무서운 팀들이 많더라...) 내가 좋아하는거나 완성시키고자 했었는데, 의외로 심사평이 매우 좋았고, 덕분에 소마 11기 인증까지 받게 되었다.
Banju가 AppStore에 올라간 모습.
소마는 재밌었고, 그 안에서 만났던 다른 연수생이나 멘토님들 한분한분이 소중했다. 그리고, 소마가 끝날무렵 나는 처음에 목표로 했었던 실제 회사에서의 인턴생활을 해보고 싶어 회사들을 알아보았고, 마침 프로그래머스 윈터캠프가 그때 진행되어 회사 5군데를 지원하게 되었다. 그중 4개는 ML리서치 관련된 직군으로 지원을 했었고, 나머지 1개는 지금까지 다녔던 가우디오랩을 지원하게 되었다. 특이했던건, 가우디오랩이 채용하고 있던 직군은 ML직군이 아닌, Vue를 스택으로 하는 Front-End 직군이었던 것이다.

가우디오랩

사실 지금까지 Front-End관련된 개발이라곤 React로 만들어본 몇가지 토이프로젝트 말고는 거의 없었다. 하지만, 음악 및 오디오와 관련된 일을 해보고싶기도 했고, 여러가지 이유로(?) 가우디오랩이 마음에 끌렸다. 그렇게 해서 가우디오랩에도 이력서를 제출하게 되었는데, 나는 Front-End 관련 스택이 없었기에 별다른 기대를 하고있지는 않았다. ML리서쳐 직군으로 지원했던 회사들이 하나둘 다 떨어지기 시작했고, 나는 가우디오랩 역시 떨어질 것이라 예상하고, 마음을 접고 있었다. 그러다가 기술면접을 진행하자는 연락을 받게 되었고, 나는 최대한 빠르게 면접을 보고싶은 생각에 최대한 빠른 날짜로 면접일정을 설정했다. 하지만, 알고보니 그 날짜가 안타깝게도 소마 최종보고서 제출날이었어서 결국에 전날에 밤을 새게 되었고, 비몽사몽한 상태로 가우디오랩 면접을 볼 수밖에 없었다. 면접 전에 나는 당연히 Vue와 관련된 내용으로 면접이 이루어질 것 같아 급하게나마 공식문서를 좀 읽고 갔는데, 실제로는 그렇지 않았다. 알고봤더니 회사 내에는 AI팀이 있었고, 팀을 이끌고계신 CSO분인 밴(Ben)이 내 이력서를 보시고나서 AI직군으로 면접을 보면 어떻겠냐고 여쭤보셨다. 내 입장에서는 당연히 OK였고, 지금까지 AI과 관련된 프로젝트 경험들을 설명하면서 면접을 원활하게 진행할 수 있었다. 면접을 진행해보니, 일단 첫인상으로는 회사 내부가 카페처럼 굉장히 이뻐서 편안한(?) 기분이 들었고, 함께 면접을 봐주셨던분들도 굉장히 친절하셨어서 함께 일할때 편안하게 일할 수 있다는 생각이 들었다. 그래서 꼭 다녀보고싶다는 생각이 있었고, 이후 임원면접까지 진행하여 최종적으로 가우디오랩에 입사할 수 있었다. 소마가 11월 26일정도에 끝났는데, 빨리 입사하고 싶어서 바로 그 다음주인 12월 1일부터 입사를 하겠다고 연락을 드렸다.

첫 업무, 그리고 인턴으로의 3개월

인턴때 일했던 사무실 자리, 이후 무빙데스크로 바뀌었다..!

On-Device 모델 서빙

입사 이후, 사내에 정리되어 있던 온보딩 프로세스를 밟고, 입사 동기인 듀이(Dewey)와 함께 회사 Product에 대한 설명들을 들으며 회사에 빠르게 적응할 수 있었다. 그리고, 밴과 함께 앞으로의 업무 방향에 대해 논의를 하였는데, 인턴기간 3개월동안 첫 1개월에는 Android에서의 서빙을, 그 다음에는 iOS, 그리고 서버로의 서빙을 하는게 어떻겠냐라고 여쭈어보셨고, 나는 소마에서는 맛만 봤었던 On-Device 서빙을 더 파보고 싶어서 그렇게 업무 방향을 결정하게 되었다. 그렇게 첫번째 업무가 주어지게 되었고, PyTorch로 구현된 모델을 모바일에 서빙하는 것을 구현하기 시작했다.
구현에 제약사항이 몇가지 있었는데, 첫 번째는 오디오가 들어올 때 한 Frame씩 처리해서 실시간으로 그 Frame에 대한 결과를 내보내야 했고, 두 번째는 기존에 있던 사내의 다른 Audio Product와 엮기 위해서는 C++로 구현해야했던 점이었다. 이 두가지 모두 나에겐 처음 시도해보는 것이라 어려움이 많았지만, 그래도 새로이 도전해보는게 재미있었다. 가장 빠르게 구현할 수 있었던 방법은 PyTorch로 구현된 모델이기 때문에 PyTorch Mobile을 시도해보는 것이었다. (https://pytorch.org/mobile/home/) PyTorch에서는 libtorch라는 C++ 라이브러리를 제공하고, 이 라이브러리 안에 있는 torch::jit::script를 통해 모바일에서 C++을 통해 모델을 서빙할 수 있다. 간단하게는 아래와 같은 코드로 서빙이 될 수 있는 것이다.
auto mModule = torch::jit::load(path); std::vector<torch::jit::IValue> inputTensors; inputTensors.emplace_back( torch::from_blob(inputData.data(), {shape1, shape2, shape3, shape4})); auto output = mModule.forward(inputTensors).toTensor();
C++
복사
Torch모델은 변환이 간단하여 연구팀에서 사용하고 있는 모델을 바로 모바일로 서빙할 수 있다는 장점이 있었다. 하지만, PyTorch Mobile는 정식 릴리즈가 된지 얼마 되지 않았었고, Vulkan이나 NNAPI 등을 통해 하드웨어 가속을 받을 수 있다고는 하지만 아직 베타단계에 머물러있었어서 이전에 소마에서 올려보았던 TensorFlow Lite를 올려보고자 했었다. TensorFlow Lite 모델을 서빙하기 위해서는 당연하게도 TensorFlow로 작성된 모델이 필요했다. 모델 변환을 해본적이 없어서 구글링을 하던 중, 'onnx_tf(https://github.com/onnx/onnx-tensorflow/)'라는 것을 찾을 수 있었다. PyTorch모델은 자체적으로 ONNX backend를 통해 ONNX 모델로 변환할 수가 있는데, 이렇게 변환한 모델을 onnx_tf를 통해 TensorFlow SavedModel 포맷으로 변환한 뒤, 이 모델을 TFLite 모델로 변환할 수가 있었다. 하지만, 이러한 방식은 onnx_tf로 ONNX모델을 TF모델로 변환하는 과정에서 1. 지원하지 않는 Operator들이 굉장히 많았으며, 2. 벤치마킹을 진행해보니 오히려 PyTorch Mobile보다 느린 Inference Time을 보여주었다. 따라서, ONNX 모델을 변환하기보다는, 직접 TensorFlow 모델을 작성한 뒤 그 모델을 TFLite로 변환하여서 Inference Time을 측정해 보아야겠다고 판단하였다. 그래서, 기존에 있던 PyTorch 모델을 그대로 TensorFlow로 이전하는 작업을 시작하였다.
모델의 변환 과정은 그렇게 어렵진 않았다. 예를 들어서 torch에서의 nn.Linear 와 같은 경우 tensorflow의 layers.Dense 등으로 바꾸어주는 등, 공식문서를 보고 그대로 옮겨갈 수 있었다. (조심해야했었던 것은 BatchNormalization의 eps값이 torch에서는 1e-05가 기본값이었는데, tf에서는 1e-04가 기본값이었다!) 이렇듯 모델 변환과정은 별로 복잡하지는 않았는데, Weight, 즉 모델이 학습한 파라미터들을 옮겨가는 것이 조금 고생이었다. 전에는 TF나 Torch의 내부 동작과정을 열어보지는 않았어서 좀 하는데 애를 많이 먹긴 했지만, 우연히 관련된 내용으로 그때 욱재님이 작성하신 스캐터랩의 블로그 글이 올라왔었다. (https://blog.pingpong.us/torch-to-tf-tf-to-torch/) 이 블로그에서는 하나의 모듈에 대해서 TF와 Torch에서 어떻게 서로 Weight을 옮겨가야 하는지, 그리고 옮겨갈때 주의해야하는 점들이 나와있었다. 대표적으로 Torch의 nn.Linear 와 TF의 layers.Dense 의 weight(kernel)은 서로 Transpose를 해주어야 같아지거나, GRU에서 Update Gate와 Reset Gate커널의 위치가 바뀌어야하는 등 TF/Torch의 내부 구현을 보아야 변환할 수 있는 내용들이 많이 있었다. 이 블로그가 이후 업무에 많은 도움이 되어서 LSTM등을 옮길때도 내부 구현을 참고하여서 성공적으로 옮겨갈 수 있었고, 한 모델에 대해서 Torch에서 TF모델로 모든 Weight을 자동으로 옮겨갈 수 있도록 하는 코드를 작성해낼 수 있었다. 이렇게 변환된 모델은 아래와 같이 TFLite Interpreter 코드를 통해서 서빙될 수 있었다. (참고 : https://www.tensorflow.org/lite/api_docs/cc/class/tflite/interpreter)
auto model = tflite::FlatBufferModel::BuildFromFile("path/to/model"); auto resolver = tflite::ops::builtin::BuiltinOpResolver(); std::unique_ptr<tflite::Interpreter> interpreter; tflite::InterpreterBuilder(*model, resolver)(&interpreter, 4); interpreter->AllocateTensors(); auto inputTensor = interpreter->typed_input_tensor<float>(0); auto outputTensor = interpreter->typed_output_tensor<float>(0); std::copy(inputVector.begin(), inputVector.end(), inputTensor); interpreter->Invoke();
C++
복사
변환을 진행하고나서 다양한 최적화 방법들을 시도해 보았고, Dynamic Quantization/Static Quantization과 같이 바로 적용해볼 수 있는 방법, Operater Fusing으로 Linear-ReLU나 BatchNorm-Linear 등을 하나의 Operator로 합쳐주는 방법을 시도해 보았는데, 아무래도 오디오를 다루는 분야다 보니 Quantization을 진행하면 출력 결과물의 성능이 악화되는 것을 확인할 수 있었다. (그러나 생각보다 크게 악화는 안되어서, 나중에 Quantization Aware Training을 통해 해결할 수 있지 않을까? 생각은 했다.) 또한, GPU나 NNAPI를 통해서 하드웨어 가속을 시도해 보았으나, 해당 가속을 받을 수 있는 Operator들이 굉장히 적어, LSTM이나 GRU와 같은 Recurrent 네트워크들은 하드웨어의 가속을 받을 수 없었다. 심지어 NNAPI에서는 지원하지 않는 Operator가 있으면 CPU로 Fallback되는데, 이때 직접 CPU로 Inference하는 것보다 더 느렸다. 그래서 CPU로밖에 Inference를 진행할 수밖에 없었는데, 그나마 TensorFlow Lite가 Inference Time이 PyTorch Mobile보다는 2~30%정도 빨랐던 것 같다.
이후에, TFLite/PyTorch에만 한정되는 것이 아닌, alibaba의 MNN(https://github.com/alibaba/MNN)이나, 삼성에서 제공하는 딥러닝 서빙 라이브러리도 시도를 해보았었다. alibaba의 MNN은 굉장히 가볍고, Inference Time이 말도 안되게 빨랐었다. 하지만, 그만큼 출력물의 품질은 좋지 않았다. 삼성에서 제공하는 라이브러리는 시도도 못해보았던 것이, 중간에 개발이 중단되어서 TF1.x밖에 지원을 하지 않았다...
모바일에서 딥러닝을 서빙하는 것 말고도, 다양한 오디오 처리를 위한 코드들을 만져볼 수 있었다. 사내에서 사용되는 오디오 처리를 위한 필터들도 내 코드에 직접 적용시켜보면서 그동안 사용했던 가상악기나 각종 플러그인이 이런식으로 구현되었구나 하는 생각이 들며 신기하고 재미있었다. 딥러닝 모델 서빙을 구현할 때도 오디오를 Spectrogram으로 처리하기 위해서 C++로 직접 STFT를 구현해볼 필요가 있었는데, 그동안 librosa로만 사용해서 '아 이렇게 변환이 되는구나~'만 느꼈던 것을 직접 구현해볼 수 있었던 좋은 경험이었다.

PRML 스터디

PRML 영문판과 한글판. 한글판이 더 난해하다 :(
사실, Software Engineer로 입사하여서 Research회의에 참여하지 않아도 되었지만, 내 개인적인 욕심으로 오디오 분야로 연구를 진행해보고 싶어서 입사할때부터 매주 참여하였다. (물론, 밴이 리서치회의에 참여할 의사를 여쭤보셨고, 나는 당연히 참여하겠다고 했다) 오디오 분야의 연구는 처음이기도 하고, 딥러닝에 대해서도 아직 모르는 부분이 많아서 Follow Up할 수 있는 자료가 필요했고, 리서치회의 끝자락에 PRML을 공부한 내용을 다른 리서쳐분들에게 검증받는(?!) 좋은 기회를 얻을 수 있었다.
PRML을 고르게 된건 리서치회의에서 VAE 관련된 내용이 언급된 적이 있었고, 해당 부분을 공부하다가 머리가 깨질 것 같아서 관련 내용을 공부하고자 고르게 되었다. 2월 초부터 스터디를 진행하였는데, 앞부분 내용부터 굉장히 어려웠다. 베이지안 Framework를 뇌가 잘 받아들이지를 못한다 그렇게 매주 스터디를 진행하다가... 개강하고 나서는 이쪽 공부에 힘을 쏟기가 어려워 드문드문하다가 결국 스터디를 중단했다 여유로워진 지금 다시 PRML을 보고 있다...

MLOps 스터디

1월달에 팀 내에서 GPU서버를 대량으로 구매하면서, 이전에는 말로만 들어보았던 Kubeflow등 MLOps 관련된 부분을 적용시켜보고 싶었다. 처음에는 Kubeflow를 GPU서버에 대해서 Training을 하나로 관리할 수 있는 플랫폼의 성격이 강하다고 오해를(?) 했어서 직접 설치하여 Kubeflow에 대해서 스터디를 진행했다. 하지만, 파면 팔수록 이 Kubeflow라는 친구는 단순히 Training환경을 관리하기 위함이 아닌, 딥러닝을 위한 Pipelining을 다루는 도구라는 것을 알 수 있었다. Pipelining은 꾸준히 추가되는 Dataset들을 계속 Training을 시켜서 모델의 전처리부터 배포까지 자동화할때 큰 시너지를 발휘한다. 하지만, 오디오 연구의 특성상, 그리고 아직 초기 연구단계에서는 데이터셋이 꾸준히 들어오지 않는다. Kubeflow Pipeline을 이용하기 위해서는 Training 코드를 Dockerize하여 Kubernetes환경에 올려야 하는데, 이 과정이 리서쳐들에게는 굉장한 병목으로 다가올 수가 있었다. (디버깅이 힘들다/데이터셋을 매번 복사해야한다 등등..) 따라서, 리서치 팀에서의 MLOps에 대한 요구사항을 다시 분석하였고, 모델의 Version관리와 메타데이터 태깅, 그리고 Dataset의 관리라는 문제를 해결하기 위해 꾸준히 각광받고 있던 오픈소스인 MLflow(https://github.com/mlflow/mlflow)와 DVC(https://github.com/iterative/dvc)를 찾아보게 되었고, 해당 부분을 직접 적용시키게 되었다. 초기 리서치팀에서 이런 운영에 대한 부분을 생각하는 것은 굉장히 어려운 문제라는 것을 느꼈다

헬게이트 오픈, 35시간 근무와 17학점의 공존 (feat. 정형수 교수님)

병특을 위해 4급인 후배를 데려왔을 때 만든 짤. 후배님 고생이 많습니다 ㅠㅠㅠ

왜 학교를 병행하게 되었나

사실 가우디오랩에 입사할때는 "어 여기 전문연구요원도 잘 되니까 산업기능요원도 잘 되지 않을까??"하는 가벼운 마음이었던 것 같다. 그래서 병특에 대해서도 기다리면 되겠지라는 마음으로 있었고, 그러다가 회사 내외에서 산업기능 요원에 대해 잘 아시는 분들과 이야기를 나누고, 다양한 서칭을 해보면서(정교라는 사이트가 가장 도움이 많이 된다! http://www.jungkyo.com) 산업기능요원 제도의 엄격한 조건을 하나하나 알아갈 수 있었다. 우선, 현역 대학생은 산업기능요원 편입을 위해서는 관련 학과 2년 이상을 수료해야 하며, 정보처리기능사가 아닌 정보처리 산업기사 자격증을 필요로 한다. (기능사 괜히땄...) 또한, 6월에 정기적으로 신청하는 산업기능요원 현역 T.O.는 3순위인 내가 들어갈 수 있는 자리가 아닌, 특성화고를 졸업한 학생들을 우선으로 배정되며, 말이 우선이지 현역 대학생에게는 아에 자리가 나지 않는다 한다. 현역 대학생이 산업기능요원으로 편입하기 위해서는 결국에는 보충역 3명을 모아오는 일명 드래곤볼 제도(공식적으로는 인센티브 T.O.라 부른다)나, 10월에 근로우수업체에게 배정되는 재배정 제도밖에 없었다. 그래서 그때 1차 우울기가 찾아오게 된다. 올해 말 병특을 시작할 수 있을 것으로 가볍게만 여겼던 것이 2년은 더 기다리게 된 상황이 온 것이다....! 그래서 우선은 소마로 인해서 1학기 휴학을 하였기 때문에 3학년 1학기로 억지로 월반복학을 신청하였다. 행복회로로 돌렸던 것은 1월에 신청하는 보충역 선발을 위한 업체신청을 한 뒤에, 10월 재배정을 받아서 최대한 빨리 복무를 시작하는 것이었다. 하지만 그마저 5월달에 병역 업체에서 떨어지게 되어 2차 우울기가 찾아오게 된다...

학업) 운영체제, 컴퓨터구조론, 그리고 DSP

정형수교수님 운영체제 피아자. 1학기를 갈갈갈갈...
3학년 1학기 과목으로는 운영체제, 컴퓨터구조론, 테크노경영학, 한사봉, 오토마타 및 계산이론, 그리고 융합전자공학부과목인 DSP를 신청했다. 업무를 진행하며 개인적으로도 DSP를 공부해야할 필요성을 느꼈고, 학점과 연결이 되면 공부를 하지 않을까 하는 무책임한 생각에 DSP를 신청하게 되었다. DSP에 대해서 많은 것들을 기대했지만.. 실상 수업은 그리 많은 내용을 다루지는 않았다. 몇주동안 Sampling Theorem과 Aliasing현상에 대해서만 반복을 했고, 실제 필터설계는 기말고사쯤 조금 다루었다. 수업을 들으면서 차라리 DSP 수업을 듣느니, 유튜브 혁펜하임같은 영상을 보는게 더 얻는게 많겠다는... 생각을 했었다. 수업 자체는 따라가기 쉬웠고, 심지어 매트랩 실습은 주어진 필터를 직접 설계해보는 것이 아닌, 2학년 1학기 과목인 객체지향 프로그래밍처럼 조교분이 코드를 영상에 캡처해서 올리고, 그거를 받아적는게 다였다(...). 심지어 시험은 모두 레포트로 대체되었다. 그래서 DSP 성적을 잘 받았냐 물어보면... ㅎㅎㅎㅎ 채점기준을 모르겠다.
무엇보다 이번학기는 운영체제가 가장 큰 발목을 잡았다. 학기를 시작하기 전에는 35시간 근무를 통해 나머지 5시간동안 실시간 강의 내용을 최대한 그 시간에 이해하고, 퇴근 후에는 녹화강의들을 돌려보면서 공부를 한다는 생각이었다. 실제로 학기 초 과제가 별로 없을때는 이런식으로 공부가 잘 되는 것 같았고, 동아리회장일까지 수행할 수 있을 정도로 생활패턴이 잡혀가는듯 했다. 하지만, 형수님의 명성답게 바로 프로젝트 과제가 쏟아지게 되었고, 처음에는 주말만 버리나 싶었지만, 프로젝트 중반이 될수록 반차를 쓰지 않고는 도저히 다른 공부를 할 수 없을 것 같았다. 프로젝트는 xv6(https://github.com/mit-pdos/xv6-public)코드를 바탕으로 MLFQ+Stride 스케줄러, Light Weight Process(Thread)구현, 그리고 File System을 수정하는 것이었다. 스케줄러 구현에서는 xv6코드를 처음 보고 어디부터 시작해야할지 막막했고, LWP 구현에서는 끊임없는 Trap에러가 괴롭혔다. 그래서 결국에는... 과제를 위해서 휴가를 태웠다. 휴가를 태우고 카페에서 다른 동기들과 모여서 어떻게 구현할지에 대해서 논의했었고(여기까진 괜찮다 하셨다!), 그 덕분에 기한 내에 과제를 잘 완수할 수 있었다. 굉장히 힘들었던 과목이었던 만큼 운영체제가 뇌에서 떠나지 않는 것 같았다.
그렇게 학기를 마무리했고, 운영체제와 컴퓨터 구조론은 좋은 성적을 거두었지만, 예상하지 못했던 DSP와 테크노경영학을 망치면서 그 결과 전공학점은 전학기 대비 상승했지만 교양 학점이 떨어지게 되었다. 이대로 더 학교 다니다가는 학점이 계속 떨어질것만 같았다(ㅠㅠ) 이번학기 학업과 업무를 함께 해보며, 사실상 그 양쪽 어떤것도 깊게 파볼 수 없었던 것 같다.

업무) Android Demo App 개발 : 기획부터 개발까지

학업과 업무를 병행하기가 쉽지는 않았지만, 그래도 내가 하고싶은 일이다 보니 버틸 수 있었던 것 같다. 사내의 기술을 활용해서 고객사에게 보내줄 Demo App을 기획하는 Task를 주셨고, 3월 초에는 이 프로젝트를 어떻게 진행할지 설계를 하였다. 다른분이 사업개발을 맡아주시고, 나는 기술적인 내용들을 주로 다루었는데, 일단 이 기술이 필요한 이유를 정의한 뒤, 그 이유에 맞는 기능들을 구성하고 MVP0, MVP1, MVP2로 나누어서 Demo App 개발을 기획하였다. 이후, 다른 분들과 커뮤니케이션을 진행하며 계획을 다질 수 있었고, 3월 말부터는 Android를 우선으로 개발을 시작하였다.
React Native로 UI를 만드는 것은 해보았지만, 안드로이드 네이티브 앱을 주어진 Zeplin 디자인에 맞추어서 개발하는 것은 처음이라 좀 어색하긴 했지만, 회사에서 원래 안드로이드를 담당하던 바론(Baron)과 커뮤니케이션을 하면서 UI관련 부분은 완성시킬 수 있었다. 또한, MVVM 디자인패턴을 따르기 위해서 뷰와 관련 로직을 분리하고자 노력했는데, RecyclerView의 애니메이션을 다루는 부분에 있어서 로직을 나누는 데에 좀 어려움이 있었다. 실시간으로 마이크를 통해 오디오를 받는 것도 구현하기 위해서 'Oboe(https://github.com/google/oboe)'라는 구글의 C++기반 네이티브 오디오처리 라이브러리도 처음으로 써보았다. 구현한 기능을 iOS에서도 테스트해보기 위해 AudioUnit을 직접 구현해보기도 했다. iOS와 안드로이드 양쪽에서 동일 기능을 구현해낼 수 있었고, 만든 테스트앱을 가지고 집에서 혼자 불러보며 놀기도 했다.
그렇게 해서 총 2개월의 기간동안 데모앱을 완성시켰고, 이전에 못했던 딥러닝 서빙 관련 최적화를 진행해보았다. Torch와 TF에서 결과물의 성능이 어떻게 정량적으로 달라지는지 SDR를 측정해 보았고, 그 결과 Torch에서 TF로 이전시 결과물의 성능이 크게 떨어진다는 것을 알 수 있었다. 아직 원인파악은 하지 못한 상태다 (못 들어줄 만큼은 아닌데, 수치상으로는 많이 떨어졌다.)

날벼락 : 2022년부터 산업기능요원 현역 편입 폐지

결국에 터질게 터졌다. 내년부터 현역의 산업기능요원 편입이 금지된다. 이미 나는 올해 병특을 시작하기는 글렀고, 내년에 시작해야했던 상황에서 그거마저 병무청이 희망을 가로채간 것이다. 3차 우울기가 찾아왔다. AI팀을 이끄시는 밴과 함께 관련 내용을 이야기했고, 결론은 학교를 계속 회사와 병행하면서 대학원 이후에 전문연구요원을 가우디오에서 진행한다, 또는 편입 가능한 업체로의 빠른 이직 두가지의 선택지만 남게 되었다. 현재 이 공고가 뜬 이상 나와 같이 내년의 병특을 기다리던 현역들이 분명히 다른 업체의 문을 두드리고 있을 것이고, 나 역시 조급한 마음에 원티드를 통해 산업기능요원 편입이 가능한 업체들을 전부 찾아서 지원하였다.
사실 저 공고가 6월 중순쯤에 올라왔는데, 그때 시험기간으로 바쁠 때여서 저 일로 정신을 소모할 힘이 없었다. 그래서 따로 이직준비는 하지 못하고 무작정 업체를 지원하였는데, 대부분 업체들이 이미 내부에 대기자가 있거나, 특성화고만 편입 가능한 티오가 존재하는 등 확정적으로 병특을 시작할 수 있는 업체들은 없었다. 그러다가 갑자기 스캐터랩이 생각났고, 스캐터랩에 지원서를 넣었다.

스캐터랩으로의 이직

채용 프로세스는 과정은 굉장히 길었는데, 기간은 짧았다. 프로그래머스 코테를 시작으로 NLP 기술과제, 기술면접과 온사이트 면접(문화면접)으로 이루어졌다. 코테의 경우 문제공개는 안되지만 생각보다 쉽게 나왔다. 메일이 온 그날 저녁에 코테는 빨리 해치우고, 그 뒤로 NLP기술과제에 대한 안내메일을 받을 수 있었다. NLP기술과제는 말그대로 주어진 NLP 데이터셋을 바탕으로 해당 데이터셋을 가장 잘 학습할 수 있는 모델을 만들고, 이에 대한 보고서까지 제출하는 과제였다. 어떤 분야였는지 역시 언급할수는 없다만, 사실 본인은 NLP분야가 처음이기도 했지만, NLP도메인의 지식이 막 그렇게 많지 않아도 되는 분야의 과제가 주어졌었다. 여러가지 모델들을 시도해 보았었고, 해당 부분을 모두 정리해서 총 25페이지 가량의 PPT로 정리해서 제출할 수 있었다. 얼마 지나지 않아 면접 관련 메일을 받을 수 있었고, 최대한 빠른 기간에 채용프로세스를 마치고 싶은 생각에 가장 빠른 날짜를 선택하였다.
면접은 기술면접과 라이브코딩으로 나누어졌다. 기술면접은 기본적인 CS질문과 ML의 기초 지식과 관련된 질문들로 구성되었다. 전날에 LSTM이나 어텐션과 관련된 부분을 더 자세하게 보고갔던터라 들어오는 질문들에 대해서 자신있게 이야기할 수 있었다. 이후 있는 온사이트 면접에서는 이런저런 내가 어떻게 개발을 좋아하게 되었는지에 대해 설명하였다.
그리고, 합격메일을 받을 수 있었다.

정리

사실상 작년 6월부터 소마를 진행하고, 논스톱으로 지금까지 달려왔던 터라 지금 1년이 정말 정신없었다. 소마는 내가 개발하는 이유에 대해서 목표를 세울 수 있도록 도와주었고, 다양한 멘토분들과 연수생들과 네트워킹을 하며 인맥을 넓힐 수 있는 좋은 기회가 되었다. 가우디오랩에서 첫 직장생활을 하면서, 물론 개발측면에서도 온디바이스 머신러닝을 파볼 수 있는 좋은 경험이 되었지만, 인간적인 측면에서도 너무 좋은분들과 함께 일할 수 있어 행복했던 시간이었던 것 같다. 일도 재밌지만, 퇴근 후 간간히 소규모의 인원으로 열리는 우도주막(?) 술자리도 매번 재밌었고, 좋은 추억으로 남게된 것 같다. 회사를 다니면서 많이 의지하게 된 밴에게 무한의 감사를 드리고, 이외에 함께한 다른 분들도 나와 함께해주셔서 수고 너무 많으셨다고 말씀드리고 싶다.
이제 이직하는 회사는 한번도 해본적이 없는 분야인 NLP를 다루는 회사이다. 내 궁극적인 목표는 MIR기술을 통해서 무언가 내가 재미있어할만 하면서도 모두에게도 재미있는 사업을 해보는건데, 그 디딤돌로 NLP분야에 대해서 도전을 해보려 한다.
모두 감사합니다 ;)