대회를 시작하며 우리 팀의 목표는 **"1등"**이라고 했지만, 이보다는 상호 간에 학습을 하는 데 더 큰 목적이 있었다. 우리 팀을 담당하는 이정우 멘토님께서도 단순히 SOTA 모델을 가져와서 성능을 내는 데 의의가 있는 것이 아니라, 새로운 것을 배우는 데 목적이 있다고 조언해주셨다. 딥러닝 자체 코딩을 처음하는 캠퍼들도 몇 있었고, 나 자신도 CV 분야의 경험은 풍부하지 않기 때문에 이번 대회는 관련 경험과 지식을 향상시키기에 큰 도움이 되었다.
최대한 다양한 모델을 이해하고 시험해보며, 전이학습(transfer learning) 과정을 익히는 데 개인적인 목표가 있었다. 대학에서 기계학습 강좌를 수강하며 인공적으로 만들어진 데이터에 대해서는 우수한 성능을 낸 적이 있으나, 실제 데이터를 이용한 딥러닝 모델 구현은 처음이었다. 또한, 기존의 pre-trained 모델을 가져와서 훈련시키는 것 역시도 낯설었다.
그리고 딥러닝 프로젝트의 전반적인 파이프라인을 이해하는 것이 또다른 목표였다. 주피터 노트북이 아닌 .py 파일 형태로 하나의 프로젝트를 구성하는 것은 해보지 않았다. git을 이용해서 프로젝트를 관리하고 협업하며, 이를 효율적이고 효과적으로 진행하는 방법론을 발견하는 것은 앞으로 협업 과정에서 중요하다고 생각했다.
일단, 처음 시도한 것은 CV에서 현재 SOTA 모형인 ViT를 직접 구현하는 것이었다. Attention 구조로 이루어져 있으므로, 이를 잘 학습시킨다면 결과를 해석할 뿐만 아니라 fine-tuning에도 이용할 수 있을 것이라는 판단이었다. 부스트캠프에서 이전에 선택 과제로 주어졌던 코드를 바탕으로, layer의 깊이(depth)와 너비(width)를 유연하게 변경할 수 있도록 ViT 모듈을 처음부터 새롭게 구현했다. 이는 본인의 PyTorch 구현 능력을 끌어올리게 했고, ViT 동작 원리를 자세히 이해할 수 있도록 해줬다. 하지만 실제 ViT와 같은 구조로는 데이터 양이 절대적으로 부족해 학습이 불가능했고, 훨씬 얕은(shallow) 버전의 ViT를 만들어 훈련했을 때 f1-score = 0.576
, accuracy = 68.159
라는 준수한 성적을 얻을 수 있었다.
Shallow 버전의 ViT를 이용해 훈련한 결과
다만, 상기의 이유로 실제로 모델 구현에 활용하기 어렵다고 판단했고, 다음 선택한 것은 MTCNN이었다. MTCNN은 3.3백만 개의 얼굴 사진으로 훈련되었기 때문에, 마스크를 착용한 상태에서도 얼굴을 잘 찾아내는 특성을 보였다. 따라서 MTCNN의 convolution 레이어들의 훈련된 weights를 이용한다면, 마스크 착용 여부 분류를 잘해낼 것이라는 추측을 했다. MTCNN은 얼굴 crop 뿐만 아니라 landmark regression에도 사용되는데, 따라서 얼굴 윤곽과 눈, 코, 입 정보를 첫번째 convolution 레이어에서 잡아낸다는 사실을 출력값의 시각화를 통해 알 수 있었다. 이는 마스크 착용 여부 예측에 필수적인 정보였다.
가장 상단 convolution 레이어의 출력값 시각화 결과
실제로 정확도는 99%에 달했지만, 문제는 나이와 성별에 필요한 정보는 제거된 feature extraction을 진행한다는 것을 알게 되었다. 따라서 나이와 성별의 accuracy는 훈련을 통해서 일정 이상 좋아지지 않았다. 이후 convolution 레이어의 weight들을 다양하게 활용하는 방법을 고안하고 여러 실험들을 하였지만, 결과가 만족할만한 수준은 되지 않았다.
직접 그린 ResNet50과 EfficientNet b2의 구조
따라서 다음으로 진행된 것은 CV에서 SOTA pre-trained 모델을 불러와서, 마지막 FC 레이어를 교체한 채로 학습을 진행하는 것이었다. 이때, 본인은 ResNet50을 주로 실험했다가, 마감일에 EfficientNet이 잘 동작한다는 것을 확인하고, 이를 훈련시키는 것을 수행했다. 또한, 해당 아키텍처나 구조를 이해하기 위해 해당 논문을 다 읽고, 모델 구조를 직접 그려보며 피상적인 이해가 아닌 실질적 활용 수준의 이해까지 도달하고자 했다. 이러한 일련의 과정을 통해 전이학습이 어떻게 이루어지는 지 이해하고, 이때 고려해야하는 다양한 요소들을 배울 수 있었다.
Notion에 브레인스토밍을 할 수 있도록 칸반을 만들어, 대회 초기에 주로 활용하였다. 본인은 주로 시각화와 관련해 데이터를 grid 형태로 보여주는 함수 등을 작성하거나, 훈련 아이디어를 제공하며 팀원들에게 기여했다. 이러한 과정 속에서 다양한 의견들이 제시되었지만, 이를 모두 시험해보지 못한 것은 아쉬움이 남는다. 이후 팀워크를 끌어올리게 된 계기는 3~4회 정도 오프라인에서 모임을 가지게 되면서였다. 거리두기 제한으로 인해 두 팀으로 쪼개져서 별도의 장소에서 만나야 했지만, 온라인 협업에 비해 훨씬 의사소통이 용이하고 일이 빨리 진행된다는 장점이 있었다.
칸반 형태의 브레인스토밍 게시판
이러한 과정에서 본인은 주로 프로젝트가 어떠한 방향으로 나아가야 하고, 모델이 어떻게 개선될 수 있는지 의견을 제시하고 이를 실험했다. 예를 들어, 나이대/성별/마스크 세 카테고리에 대해서 전체를 18개의 클래스로 볼 것인지, 각각 3개, 2개, 3개의 클래스로 볼 것인지에 대한 논의가 있었다. 본인은 마스크 착용 여부는 나머지 둘에 대해 독립일 수 있으나, 나이대와 성별은 상호간에 종속적인 관계이리 것이라는 의견을 말했다. 따라서 MTCNN으로는 마스크 착용 여부를, 다른 CV 모델로는 나이와 성별을 알아내자는 아이디어를 제시하기도 했다. 하지만 추가적인 논의 과정에서 마스크 착용 여부 역시, 나이와 성별을 알아내는 데 종속적일 것이라는 데에 의견이 모아져, 18개의 클래스를 가진 multi-class classification 문제로 정의했다.