김동현
김동현
Apr 10, 2018 · 9 min read

안녕하세요.
스타일쉐어에서 백엔드 개발을 하고 있는 김동현입니다.

작년 11월 스타일쉐어에서 뷰티에 관련된 사진들을 따로 모아서 보여줄 피드.
바로 뷰티피드 라는 것을 만들었습니다. 하지만 피드를 만드는 과정이 순탄치 만은 않았는데요.

그간의 과정과 얻었던 경험들을 공유하고자 합니다.

들어가기에 앞서

혹시 설명을 하다 보면 스타일쉐어에서만 사용되는 단어가 있을 수 있다는 생각이 들어 단어에 대한 공유를 먼저 드리고자 합니다.

스타일쉐어에서는 이를 “피드”라 칭합니다.
스타일쉐어에서는 이를 “스타일”이라 칭합니다.

여러 가지 카테고리 중에서 왜 뷰티인가요?

기존의 서비스에서는 유저들이 올리는 스타일에 대한 카테고리가 없어서 유저들이 보고 싶어 하는 스타일들을 쏙쏙 뽑아서 보여줄 수 없는 상황이었지만 “내가 보고 싶은 것들만 볼 수 있었으면 좋겠다”라는 유저들의 니즈는 계속 올라가고 있었습니다.

서비스 특성상 1020 유저들이 많이 있었고 하루 동안 올라오는 스타일에 대해서 사람이 직접 카테고리를 하나하나 나눠봤을 때 가장 활발하게 대화가 이루어지고 반응이 좋고 충성도도 높은 카테고리가 바로 뷰티였습니다.

뷰티만이라도 따로 보여줄 수 있도록 해보자

그럼 어떻게 뷰티에 관련된 게시물들을 뽑아낼 건가요?

올라오는 스타일들 중에서 뷰티라는 속성을 찾아내어 분류하는 방법으로 두 가지의 제안이 나왔습니다.

1. 사람이 직접 뽑아낸다.
2. 요즘 뜨고 있는 딥러닝을 이용해서 뽑아낸다.

처음엔 사람이 직접 모니터링 해볼까? 라는 이야기가 나왔었습니다.
당장이라도 시작 할 수 있다는 점과 높은 정확도를 가졌다는 장점이 있기 때문이였죠.
하지만 주말 관계없이 4000~6000개씩 올라오는 스타일들을 상시 모니터링하고 모두 검토해야 하는 상황이 너무 막막하게 느껴졌습니다. 관련 업무를 하시는 분의 업무 만족도는 낮을 것이 당연하기도 했지만 그럴만한 인적자원이 충분하지 않았습니다.

그래서 요즘 뜨고 있는 딥러닝을 이용해보자는 방향으로 일이 진행되었습니다. 게다가 요즘 딥러닝으로 Image Classification 하는데에 있어서 정확도가 사람을 넘어섰다는 이야기도 결정에 한몫을 했답니다.

딥러닝으로 분류하기로 결정했다! 근데 트레이닝 셋은?

딥러닝을 하시는 분들이 애용하는 사이트인 캐글만 가보아도 문제와 트레이닝 셋이 잘 정리되어있기에 개발자는 어떻게 하면 잘 예측할 수 있을까에 대한 고민만 했으면 되었었습니다. 하지만 당연하게도 실제 필드에서 처리해야 하는 문제와 그에 대한 트레이닝 셋은 존재하지 않았습니다.

우선 딥러닝으로 분류하기로 결정을 하였으니 서비스에서 뷰티라는 카테고리 안에 넣을 소카테고리를 나누었고 다음과 같았습니다.

* 눈 화장 관련
* 입술 화장 관련
* 얼굴 화장 관련
* 헤어
* 화장품
* 발색
* 네일

그래도 태양 아래 새로운 것은 없다 라는 말처럼 비슷한 것들이 존재할까 하고 찾아보았으나…

https://www.kaggle.com/openfoodfacts/openbeautyfacts

http://www.antitza.com/makeup-datasets.html

ㅇ…없잖아?!

그렇습니다. 공개된 것은 없던 새로운 것이었습니다. 위의 소카테고리들을 모으는 방법을 모색해야 했습니다.

위에서 언급했듯이 잉여 인적자원이 없었기 때문에 몇만 개의 데이터를 모을만한 데이터를 모으는 일은 저를 포함해서 개발자 2명이서 진행을 했었습니다.

라벨링 노가다, 그걸 하기엔 시간이 없는 걸?

데이터 셋이 준비되어 있지 않은 상태였고 라벨링을 붙이며 충분한 데이터를 만들기에는 시간이 충분하지 않았습니다.

시간을 덜 들이고 많은 데이터를 뽑아내기 위해서 스타일에 있는 설명글을 사용하여 Classification 모델을 만드는 것은 어떨까 하는 판단을 하였어요.

그래서 이미지 모델을 만들기 위한 첫 번째 스텝으로 단어 벡터를 먼저 만드는 것으로 학습의 준비를 시작합니다.

단어 벡터를 만들기 위한 첫 단계로 konlpy 내의 트위터(현재는 Okt) 형태소 분석기를 사용하여 어간 추출을 하였습니다. 하지만 데일리룩의 경우에는 데일리 + 룩 으로 분리하는 등 신조어 또는 브랜드 명칭에 대해서 원하는 결과를 보여주지 못했습니다.

이를 해결하고자 신조어와 브랜드 명칭을 수집하여 사용자 단어를 만들었습니다.

(사용자 단어 사전을 만든 후에는 customized_konlpy 를 사용하여 사전을 적용하였어요.)

이렇게 만들어진 형태소 분석기를 사용하여 명사만을 추출한 후 Word2Vec에 넣어 간단하게 단어 벡터를 만든 후 KMeans를 돌려서 비슷한 벡터를 가진 단어 클러스터를 만들었는데요.

K의 값을 조절해가며 최대한 다양하고 비슷한 단어들이 묶일 수 있도록 하여 클러스터를 만들었습니다.

KMeans 클러스터 속 내용을 확인하며 라벨 맵을 만들었어요.

클러스터 속 단어들은 생각보다 괜찮게 비슷한 단어들이 오밀조밀 잘 모여있었습니다.

이러한 작업을 진행했던 이유는 우리가 모르는 단어들에 대해서도 잘 대응하기 위함이었어요.

위의 Label Map과 KMeans Cluster 속 단어를 활용하여 스타일의 설명에 데이터 라벨링을 하기 시작했습니다.

이를 바탕으로 좀 더 많은 스타일의 라벨을 만들어 내기 위해서 description 안에 있는 단어들의 평균 벡터와 라벨을 이용해서 KNN Classifier를 만들었습니다.

이렇게 만들어진 텍스트 분류기를 통해서 여타 스타일에 대해서도 라벨링을 진행하였고 스타일에 있는 이미지에도 같은 라벨을 붙여 이미지 라벨링 데이터를 만들어내었습니다.

위의 작업으로 대략 30만 장이 넘는 라벨링 된 이미지를 뽑아내었고 생각보다 빠르게 소 카테고리마다 2만 장 이상의 라벨 데이터를 만들 수 있었어요.

이 중에서 이렇게 만들어진 데이터 중에서도 각 소 카테고리별로 유저 댓글과 좋아요를 많이 받은 스타일의 TOP 10k 를 뽑았습니다.유저가 많이 좋아하고 반응을 한 데이터는 좀 더 많은 정보를 가지고 있을 것이고, 게시글을 분류하기에 충분한 정보가 들어있을 것이라는 가정이였어요.

이렇게 만들어진 데이터 / 총 12만장에 달하는 이미지 데이터에 data augmentation을 진행했어요. 1주 정도의 시간을 들인 것 치고는 많은 정보를 얻을 수 있었던 것 같아요.

이렇게 만들어진 데이터를 pre-trained 된 vgg16을 바탕으로 전이학습을 통해서 이미지 분류 모델을 만들어내었습니다. DL의 완성은 결국 데이터라는 말을 새삼 다시 한 번 더 느꼈는데요. bottleneck feature와 fully connected layer을 추가해서 조정하니 생각보다 괜찮은 모델을 얻을 수 있었습니다

적용은 어떻게 하죠..?

이렇게 만들어낸 이미지 모델을 실제 서비스에 적용해야 하는 순간이 왔습니다.

이후에 새로운 모델들이 만들어질 수 있다는 가정을 두고 머신러닝 모델을 자유롭게 업데이트하며 결괏값을 반환해 줄 수 있게 해야 편할 것이라는 생각을 했습니다.

우선은 Flask + Celery로 아래와 같이 머신러닝 서버를 구성하였습니다.

위와 같은 흐름으로 스타일쉐어 서비스에서 비동기로 분류된 정보를 가져가는 방식을 채택하였습니다.

Celery에 모델을 올려서 분류를 하도록 처리하였는데요. 모델의 revision 관리는 s3를 통해서 하였습니다.

최신 모델에 대한 정보(model.json)과 label에 대한 정보와 file hash, weights의 정보와 file hash를 lastest에 저장하였어요.

celery가 올라올 때마다 weights_version, label_version을 검사하여 모델 적용하는 과정을 가볍게 가져갔습니다.

여기에 더불어서 CPU로도 0.n 초가 나오는 모델이 있는가 하면 GPU를 사용해야 하는 무거운 모델들도 있었는데요.

이를 대응하기 위해서 Rabbitmq에서 가벼운 모델을 사용해야 하는 분류 큐와 무거운 모델을 사용하는 분류 큐를 만들었습니다.

이렇게 하니 CPU 인스턴스와 GPU 인스턴스 한대로도 충분한 성능을 보여주었습니다.

GPU 머신에서는 celery의 pool을 solo로 하여 GPU 점유를 온전히 할 수 있게 처리하였습니다.

이렇게 분류된 정보를 RDB에 저장하는 것을 끝으로 스타일쉐어에 올라오는 스타일 데이터에 대한 라벨링을 하고 웹서비스에서 1분 주기로 라벨 정보를 가져오도록 처리하였어요.

그래서 결국 뷰티 피드는…

성.공.적.

다행히도 잘 마무리되었습니다. 화자 되고 있는 딥러닝 기술을 실제로 사용해볼 수 있어서 좋았고 팀원들도 이게 되는구나, 다른 것도 해볼 수 있겠다 라는 피드백을 많이 받았고 저 또한 개발을 하면서도 이게 된다고? 하는 반응이 제일 많았던 것 같습니다. 물론 앞으로 모델을 계속 개선해나가야겠지만요.

사실 딥러닝을 거의 처음 공부하는 수준에 가까웠고 초반에 우왕좌왕 하기도 많이 했었는데 믿고 기다려줬던 스타일쉐어 팀원 분들 덕분에 잘 마무리될 수 있었던 것 같습니다.

앞으로는

변해가는 상황에 대응하기 위해서 꾸준한 모델 업데이트가 필요할텐데요.

이러한 방법으로 sage maker와 같은 머신러닝 플랫폼을 사용하는 것을 고려하고 있습니다.

끝으로

스타일쉐어에서는 더 많은 사람들이 더 쉽게 자신만의 멋을 찾아갈 수 있는 방법을 찾아가고 있습니다. 이러한 길에 관심이 있으시다면 스타일쉐어에 놀러 오셔서 이야기 해보아요 😄

StyleShare Notion 을 통해 회사를 구경해보세요 😏 그리고 같이 걷고 싶으신 분이 계시다면 그 관심을 저희가 알 수 있게 언제든지 join+dev@stylesha.re 로 알려주세요 :)

StyleShare

안녕하세요, 스타일쉐어 팀원들이 작업하다 짬내서 적는 블로그입니다 :-) 새로운 세대를 위한 더 나은 쇼핑 여정을 만들어나가는 과정에서 겪는 저희의 다양한 경험을 공유합니다. 그리고 저희와 문제해결 과정에 함께하실 좋은 분들과 만나고 싶습니다. join@stylesha.re

김동현

Written by

김동현

피할 수 있다면 피하자

StyleShare

안녕하세요, 스타일쉐어 팀원들이 작업하다 짬내서 적는 블로그입니다 :-) 새로운 세대를 위한 더 나은 쇼핑 여정을 만들어나가는 과정에서 겪는 저희의 다양한 경험을 공유합니다. 그리고 저희와 문제해결 과정에 함께하실 좋은 분들과 만나고 싶습니다. join@stylesha.re

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade