T academy ASAC 빅데이터 분석가 4기 과정에서 최종 프로젝트로 진행한 프로젝트입니다.
형식적인 프로젝트 내용 정리는 깃헙에서 했기 때문에 블로그에서는 그 과정에서 있었던 소소한 고민들을 기록해두는게 어떨까 생각해서 정리해보려고 합니다.
(깃헙 주소: https://github.com/newdatajaam/Domestic-Tourism-Search-System-with-Multimodal)
프로젝트 개요
- 프로젝트 명: 멀티모달을 활용한 유사도 기반 국내 관광 정보 검색 시스템(A similarity-based domestic tourism information search system using multimodal)
- 기간 : 2024.03.05 ~ 2024.05.20
- 팀원 : 신재함, 이현수, 장서연, 한은경
프로젝트 및 팀 구성 배경
ASAC 빅데이터 분석가 과정의 최종 프로젝트는 현직자 멘토님들과 팀을 구성해서 주제를 정하는 식으로 결정됩니다.
멘토님의 성향이나 상황에 따라서 주제가 아예 정해져 있는 경우도 있고, 큰 틀만 잡혀있는 상태로 세부 주제는 팀원 간 회의를 통해 결정하는 경우도 있습니다. 저희 조는 후자의 경우로, 멘토님께서 멀티모달을 활용한 영상분석 서비스라는 큰 틀이 있었던 상태로 팀이 구성되었고 후에 회의를 거쳐 지금의 프로젝트를 진행하게 되었습니다.
저를 포함한 팀원들의 경우 이미지 모델에 대한 기초적인 지식만 있었던 상태고, 자연어 처리(NLP)나 임베딩과 관련된 지식들이 거의 없어서 스터디를 병행하며 프로젝트를 진행하기로 했습니다. 그리고 기존의 영상분석 서비스 단계까지 가기엔 시간적으로나 역량적으로나 많이 부족하다고 판단하여 시간이 되면 영상까지 진행하되 일단은 이미지 분석까지 진행하자는 결론을 나왔습니다.
세부 주제는 자료조사와 회의를 거쳐서 진행이 되었는데요. 현실적인 측면에서 데이터가 따로 없었던 상황이라 데이터를 구할 수 있는 범위 내에서 주제를 선정하게 되었습니다. 크게 3가지 후보가 있었는데요.
- 멀티모달 관련 논문인 HowTo100M이라는 데이터 셋을 활용하기 (https://www.di.ens.fr/willow/research/howto100m/)
- AIHub에서 제공하는 미디어 영상 관련 멀티모달 자료 (https://www.aihub.or.kr/aihubdata/data/view.do?currMenu=&topMenu=&aihubDataSe=data&dataSetSn=57)
- DACON에서 진행한 한국관광공사 데이터를 활용한 경진대회 데이터 (https://dacon.io/competitions/official/235978/overview/description)
저희는 그 중에서 3번 데이터를 활용하기로 했습니다. 그 이유는 주제 회의 과정에서 관광 여행지 추천과 관련된 주제가 나왔었는데, 해당 데이터를 활용해서 텍스트-이미지의 활용성을 극대화할 수 있겠다고 생각했습니다. 일반적으로 여행가고 싶다는 생각은 이미지나 영상등의 시각적 자료를 통해 드는 경우가 많은데요. 관련 검색 자체는 텍스트로 하게 되는 경우가 많아서 만약 정확한 정보는 모르는데 사진이나 영상 속 관광지를 찾고 싶다거나, 비슷한 장소를 알고 싶다고 생각했을 때 도움이 될 수 있는 서비스가 있으면 좋겠다고 생각했습니다.
또한 한국관광공사에서 제공하는 데이터라 국내 관광지의 범위에서만 진행할 수 있었지만 해외 사진을 집어넣어서 유사한 국내 관광지를 찾을 수 있게 도움을 주는 방식도 꽤나 재밌고 유익할 것 같다고 생각했습니다.
프로젝트 진행과정
세부적인 진행과정에 앞서 짧게 설명하자면, 저희 프로젝트는 먼저 비정형 데이터인 텍스트와 이미지 데이터를 하나의 벡터 형태로 변환하는 임베딩 과정을 거칩니다. 그리고 두 벡터값을 하나의 벡터 공간안에 투영시키는 조인트 임베딩 과정을 통해 두 데이터가 하나의 데이터다를 학습시키는 단계로 진행합니다.
예를들어 숭례문 사진이 있고 숭례문에 대한 설명이 있는 텍스트 자료가 있으면 컴퓨터가 이해할 수 있도록 사진과 텍스트를 벡터라는 숫자 형태로 변형하고, 그 사진과 텍스트 벡터가 똑같이 숭례문과 관련된 데이터라고 컴퓨터에게 알려주기 위해서 그 원본 숫자 값을 훼손하지 않고 다른 공간에서 그 두 정보를 짝꿍으로 엮어준다고 생각하시면 됩니다.
1. 데이터 구성 및 전처리에 대한 고민
먼저 데이터는 아래 사진과 같이 ID, 이미지 경로, 텍스트, 카테고리 대-중-소분류로 구성이 되어있는 약 17000여개의 데이터 입니다. 경진대회 용이라 train 셋과 test 셋 파일이 따로 있었지만 test 셋에서는 카테고리 관련 라벨링 데이터가 없어서 프로젝트를 진행하는 과정에서 사용하기 어렵다고 판단하여 train.csv 파일만 사용하기로 했습니다.
이미지 데이터는 csv파일의 ID값과 동일한 파일 이름으로 jpg형식으로 제공하고 있었습니다.
먼저 스터디를 진행하면서 데이터를 가지고 다양하게 연습을 했고, 그 과정에서 어디까지 어떻게 전처리 할 것인지에 대한 고민이 있었지만, 팀원들 전체가 자연어 처리에 대한 깊은 이해가 부족한 단계였고, 또한 임베딩 한 후에 텍스트와 이미지 임베딩을 거쳤을 때 어떤 식으로 영향을 미칠지 예상할 수가 없어서 최소한의 전처리 단계만 거치는 식으로 진행했습니다. (이 당시에 얘기했을 때만 해도 일단 결과를 먼저 확인하고 다시 해보자였지만, 시간 관계상 다시 돌아올 수가 없었습니다. 그래서 초반에 데이터에 대한 고민에 시간이 정말정말정말 많이 드는구나 또 한번 느꼈습니다 ㅠ)
그래서 기본적으로 텍스트는 특수 기호들을 제거하고, 이미지 파일은 사이즈 변형 정도만 하는 식으로 진행되었습니다.
추후에 발표하고 피드백 받는 과정에서 이런 고민들이 조금 더 필요하지 않았나라고 평가를 받았는데 그 부분에 대해서는 스스로도 너무 아쉽다는 생각을 하고 있습니다.
몇 가지 아쉬웠던 점을 꼽아보자면, 텍스트 데이터 길이 차이에 대한 전처리라던가, 카테고리 불균형에 대한 전처리, 의미적인 면에서 불용어 처리라던지 등이 있습니다. 이 부분들에 대한 고민들을 적용하기가 어려웠던 점을 조금 변명해보자면 데이터 셋 자체가 17000여개로 너무 적어서 그렇기도 했고, 추가적인 데이터를 구하고자 하는데도 한계가 있어서 였습니다. 자세한 이야기는 진행단계에 따라서 이어서 해보겠습니다.
2. 텍스트 임베딩
자연어 처리와 관련된 공부를 처음으로 조금 자세하게 했지만 결국 비슷한 관광지와 관련된 정보를 찾아내는게 목적이었기 때문에 어떤 것을 기준으로 '두 글이 유사하냐'를 판단할 것인지에 대한 고민이 필요했습니다. 하나하나 결과를 비교하며 판단하기는 한계가 있으니 저희는 그 기준을 일단 '카테고리'로 분류된 라벨링이 일치하는가로 두었습니다.
'역사 관광지'와 관련된 내용이면 결국 단어가 비슷하더라도 같은 '역사 관광지'를 카테고리로 가지고 있는 문장의 단어들이어야 하니까요. 그래서 카테고리에 대한 검색 결과를 확인하는 것이다 보니 유사도(=검색 결과 순위)가 높을 수록 가중치를 부여해서 판단하는 식으로 weigted average precision을 메인 기준으로, accuracy는 보조 기준으로 판단하였습니다. 그리고 정량적인 기준을 카테고리로 두고, 정성적으로는 몇 가지 쿼리를 랜덤하게 던져서 유사한지 최종 판단하는 식으로 진행했습니다.
이 부분도 조금 부족하지 않았나 싶지만 어떤 식으로 해결했어야 하는지는 잘 모르겠더라고요. 저희가 가진 역량 안에서의 최선의 결정을 했던 것 같습니다.
모델은 크게 doc2vec 알고리즘과 BERT 모델을 비교했습니다.
from gensim.models import doc2vec
doc2vec은 gensim에서 제공하는 모듈을 활용했고, vector_size, worker, window, epoch등 파라미터 들을 변형하면서 비교하는 식이었습니다. 물론 기준은 위에서 설명한 weigted average precision, accuracy, 정성적 평가 입니다.
BERT의 경우는 한국어에 특화된 KoBERT에서 사전학습 모델을 가져와서 저희 데이터를 학습시키는 방식으로 진행했습니다. 파인튜닝도 시도해봤는데 결과적으로는 잘 안되었습니다. 그리고 카테고리에 따라 결과를 확인하는 식이다보니 분류 형식으로 진행했는데 결국엔 해당 데이터를 임베딩 하는 데이터로 활용해야 하다보니 그것으로 특화된 SBERT 모델도 적용해서 진행했습니다. SBERT는 Sentence-BERT로 BERT의 문장 임베딩의 성능을 우수하게 개선시킨 모델입니다.
최종적으로는 SBERT 사전 학습 모델에 적용시킨 모델이 가장 좋은 성능이 나온다고 판단하여 해당 모델을 사용했습니다. 사전학습 모델은 https://sbert.net/docs/sentence_transformer/pretrained_models.html SBERT 홈페이지에 명시된 것과 Hugging-Face에서 가져올 수 있는 모델 몇가지를 비교 분석하였습니다.
멘토님께서 자연어 처리는 상황에 따라 어떤 모델이 성능이 좋을지 모르고, 오히려 doc2vec과 같은 모델은 아닌 알고리즘이 성능이 더 우수한 경우도 많다고 하셔서 다양하게 시도해보고 확인해봤지만 저희의 데이터는 사전 학습 모델이 더 괜찮은 결과를 보여서 의외라고 생각했습니다.
3. 이미지 임베딩
앞서 전처리 과정에서 카테고리간에 불균형 처리를 제대로 못해서 아쉬웠다고 간단하게 언급했었는데요. 이미 기존 데이터 간의 카테고리 분포 차이가 너무 컸던 데다가 대분류 6개, 중분류 18개, 소분류128개로 대분류로 이미지 분류 모델을 돌리면 성능이 떨어지고 중분류, 소분류를 사용하면 과적합 되는 경향이 강했었습니다. 그래서 내부적으로 데이터를 재정의 재조합하는 과정을 거치긴 했었습니다.
재정의와 재분류를 진행했지만 여전히 차이가 조금 심하다고 생각했습니다. 그리고 이 단계에서도 시간이 꽤나 걸렸습니다. 하나하나 라벨링을 손 보기에는 어려우니 기존의 분류를 재조합하거나 큰 카테고리를 세부적으로 나누고 너무 작은건 합치는 수준이었는데 데이터 양도 고려해야하고 의미적으로도 '얘는 굳이 분류해야하나?', '이 카테고리는 어떻게 나눠야하지?' 등의 많은 회의들이 있었습니다.
여전히 분포간의 차이가 어느정도 있었지만 그렇다고 데이터를 일부 삭제하는 등의 처리는 학습량 자체가 더 떨어진다고 생각해서 11개의 새로운 카테고리 선에서 마무리 하였습니다. 실제로 중분류로 이미지 분류 모델의 accuracy가 0.3 정도 수준이었는데 그나마 11개의 저희가 세운 기준으로는 0.4-0.5선으로 향상이 이뤄지긴 해서 여기서 더 진행하진 않았던 것도 있었습니다. 그 후에는 파인튜닝을 거치면서 개선시키자는 의견이었습니다.
모델을 결정하는데 있어서는 vgg19에 대해 하드코딩하는 방법, ImageNet 데이터셋으로 학습한 사전학습모델(vgg19, Resnet50, Densnet201) base모델과 파인 튜닝 진행한 모델을 비교했습니다.
Loss도 분류와 관련된어서는 categorical_crossentropy가 대표적으로 사용되지만, Triplet loss 방식도 있다고 팀원이 논문에서 확인하여 그 부분에 대한 실험도 진행했지만 시간상 최종적으로 비교하지는 못했습니다. 회의할 때 담당 팀원의 말로는 layer 단계가 넘어가면서 dimension문제가 있었다는 것 같았는데, 아무래도 아직 저희가 병아리 수준이다보니 너무 많은 욕심을 부리지는 않는 것으로 했습니다.
결론적으로는 사전학습 모델 중에서는 Densnet201 모델을 파인튜닝 진행한 모델의 성능이 가장 좋아서 해당 모델로 결정했습니다. Densent201모델 자체는 1920차원을 가지고 있어서 꽤나 큰 차원을 가지고 있다보니 SBERT모델의 벡터 차원인 768차원에 맞춰서 차원을 변경하는 작업을 추가로 진행하여 적용하였습니다. 다행히 성능 자체에는 큰 차이나 변화가 없었습니다.
4. 조인트 임베딩
텍스트 임베딩 결과와 이미지 임베딩 결과, 벡터 값들의 분포가 다르기 때문에 이대로 그냥 사용하기엔 무리가 있습니다. 그래서 조인트 임베딩이라는 과정을 거쳐 두 각 모달(Modal)의 분포도를 맞춰줄 필요가 있습니다.
멀티모달을 적용하는 방식에는 두 가지 임베딩 방식이 있는데, 저희는 오른쪽의 coordinated representation 방식을 적용하였습니다.
그 이유는 왼쪽의 방식은 두 벡터 값을 하나의 벡터 값으로 결합하는 방식이기 때문에 추후에 이미지 관련 검색이나 텍스트 관련 검색을 따로 처리할 수가 없어서 두 가지 모달(modal) 따로 적용하여 추론이 가능한 방식인 해당 방식을 선택했습니다.
이 때 새로운 공간에 투영하더라도 비슷한 결과들은 비슷한 위치에 있을 수 있도록 학습 시켜야 하므로 학습의 기준을 세우는 과정이 필요합니다. 조인트 임베딩 단계에서는 이를 pair를 설정한다고 하는데요. 가까워져야할 벡터 값들은 positive pair로, 멀어져야할 벡터 값들은 negative pair로 설정해야 합니다.
positive pair는 간단하게 X번 사진과 X번 텍스트가 가까운 위치에 투영 되게 하는 식으로 설정하고,
negative pair는 카테고리가 다른 X번 사진과 Y번 텍스트는 멀어지게 투영하는 방식으로 설정했습니다.
이 과정에서도 어떤 방식이 최선의 결과를 나타낼지 다양하게 조정하면서 진행했습니다. postive pair에서 기준을 같은 카테고리에 있으면 가까워지게 추가적으로 설정한다던지, negative pair의 경우의 수를 더 많이 줘서 멀어질땐 확실하게 멀어지게 한다던지, 학습량(epoch)을 늘려서 더 확실하게 한다던지 등이 있습니다.
저만 보려고 적으면서 한거라 꽤나 지저분하지만 이런식으로 비교하면서 혼자서만 한 40-50개 모델을 돌려본 것 같습니다. 다른 팀원들이 돌린 것 까지하면 거의 7-80개를 확인했을지도,, 다행히 모델 자체는 벡터값을 투영하는 방식이라 평균적으로 한번에 30분 정도(epoch 100기준) 걸리는 것 같습니다. 코랩에서 한번에 돌릴때 3-4개씩 돌리니 어떻게든 되더라고요...
초반 목표는 기존에 지정한 11개 카테고리 분류 모델에서 조인트 임베딩 단계 학습을 거칠 때 소분류(128개)까지 더 디테일한 분류까지도 가능하지 않을까 실험도 했었는데 기존 모델의 결과들이 너무 망가져서 성능이 너무 떨어졌었습니다. 그래서 조인트 임베딩도 11개 분류 성능을 확인하는 단계로 마무리하여 최종 모델을 선정하였습니다.
프로젝트 결과
시간에 쫓겨서 급급하게 마무리하느라(최종 발표라는 마감기한이 있다보니) 발표 당시에는 기존 단순 텍스트 모델, 이미지 모델 대비 멀티모달을 활용한 모델이 얼마나 더 좋은 성능을 나타냈는가 수치적으로 확인하지 못했는데요. 발표때는 아래와 같이 시각적으로 각 모델의 결과가 어떻게 되었는지 보여드리는 식으로 마무리 했었습니다.
아무래도 이런 부분에서 조금 부족한 것 같아서 프로젝트가 끝나고 정리하는 과정에서 추가적으로 비교를 해봤고요.
이렇게 비교하는게 맞는지 모르겠지만 동일한 쿼리를 던졌을 때 각각의 모델에서 얻을 수 있는 accuracy와 weigeted precision의 결과를 비교했습니다. 각각의 모달을 따로 사용했을 때 대비 멀티모달을 활용한 모델이 몇 퍼센트 더 카테고리를 잘 맞추고 있는지 평균을 낸 결과입니다.
아무래도 이미지 성능이 많이 떨어지는 편이었어서 향상도가 더 높게 보이는데, 조인트 임베딩 거치면서 이미지 모델이 텍스트 모델의 영향을 받아서 성능이 조금 더 올라간 것인가 조심스럽게 예상해봅니다.
개인적인 후기
10주라는 시간이 너무 부족할 정도로 진짜 정신없이 지나갔던 것 같습니다. 오히려 주제가 해야할 것이 많다보니 짧은 시간에 배우는 양이 훨씬 많아서 좋았습니다(할때 당시는 죽을것 같았지만). 그래도 뭔가 공부하고 해냈다라는 그 성취감은 되게 만족스럽더라고요. 물론 아쉬웠던 점들도 분명히 많았지만 이런 것들은 차차 더 경험하면서 배워가면 되는 것이니까요.
어쩌다보니 제가 팀장을 맡아서 진행을 했었는데, 다들 똑같이 모르고 해야할 일은 많다보니 그 과정에서 힘들었던 건 분명하게 있었던 것 같습니다. 역할 분담은 어떻게 하고, 각자 작업하다보니 얼마만큼 진행되었는지, 어디서 어떤 문제가 있어서 어떤거를 다같이 의논해야할지 의사소통하는 능력도 조금 길렀던 것 같습니다.
그리고 결국 그 과정들을 이해하고 공유하고 하려면 제가 더 많은 것을 공부하고 알고 있어야 하더라고요. 그냥 단순하게 이미지 담당, 텍스트 담당, 조인트 담당 이런식으로 나누면 될거라고 생각했는데 그 과정에서 필요한 조율들은 누군가가 결정을 내리고 '여기가 이런 문제가 있으니 저기가 이런식으로 조금 조정해주자!' 라는식으로 맥락을 이해하고 결정을 고민해야하는 순간들이 있었던 것 같습니다.
이걸로 모든 과정이 끝이 났지만 이제 시작이라는 생각이 들었습니다. (실제로 취업준비도..)
그래도 한 걸음씩 화이팅해보겠습니다!