무신사가 카테고리숍 추천을 하는 방법

MUSINSA tech
MUSINSA tech
Published in
14 min readMay 8, 2023

“무신사 추천순” 개선이야기

안녕하세요. 무신사 데이터프로덕트팀에서 데이터 사이언티스트로 일하고 있는 노설희입니다.

데이터프로덕트팀이라는 이름에서 알 수 있듯이, 저희 팀은 무신사에서 발생하는 데이터를 사용하여 모델 및 서비스를 만드는 일을 하고 있습니다. 이를 통해 유저들에게 더 나은 쇼핑 경험을 제공하고, 파트너 고객과 사내 구성원에게는 효율적으로 업무를 처리할 수 있도록 도움을 주고 있습니다.

이 글에서는 카테고리숍 상품 정렬에 ML 모델을 적용한 경험을 공유하고자 합니다. 무신사에서는 “숍”은 상품 리스트를 중심으로 여러 가지 정렬(추천순, 판매순, 높은 가격순 등)을 적용할 수 있는 공간을 의미합니다. 그 중에서도 카테고리숍은 각 카테고리(상의, 아우터 등등)를 누르면 이동하는 페이지입니다. 이 카테고리숍 내의 다양한 정렬옵션 중 이 글에서는 “무신사 추천순”이라는 정렬 기능을 개선한 경험에 대해 이야기해 보겠습니다.

카테고리숍은 무신사가 제공하는 다양한 상품 탐색 페이지 중에서, 비교적 많은 유저들이 방문하고 상품 탐색이 활발히 이루어지는 페이지인데요. 이런 이유 때문에, 유저 행동 로그 분석에서 중요한 의미가 있기도 합니다. 또한, 상품을 찾을 때 가장 먼저 방문하는 페이지로, 무신사의 아이덴티티를 표현하는 중요한 페이지입니다. 위와 같은 이유로 저희 팀에서는 카테고리숍에서 유저별로 맞춤화된 상품리스트를 제공한다면 그 임팩트가 가장 클 것으로 판단했습니다.

무신사 내 카테고리숍 페이지
[그림1] 카테고리숍 페이지

카테고리숍에 효율적인 정렬방법은 뭐가 있을까?

카테고리숍 페이지에 방문하는 유저는 상품 탐색의 목적이 있으면서도 스스로 무엇을 좋아하는지 모르는 경우가 많습니다. 그래서 이 페이지에서는 탐색 목적에 부합하면서도, 유저도 모르는 유저가 좋아할 만한 상품을 앞단에 보여줄 수 있으면 좋겠다고 생각했습니다. 그래서 카테고리숍 페이지는 검색과 추천 두 가지의 성격을 가진 페이지라고 정의하고 두 마리 토끼를 잡기 위해 유저의 인터랙션(클릭, 좋아요 등)이 많은 상품을 우선으로 보여줄 방법을 고민해보았습니다.

유저들의 인터랙션을 예측해서 보여준다면 인터랙션이 늘어날 뿐 아니라 최종적으로는 더 많은 구매까지 이어지는 선순환 구조를 만들 수 있을 것으로 생각했고, 유저의 행동을 효율적으로 예측할 방법을 찾던 중 ML모델을 적용해보면 좋을 것 같다는 생각이 들었습니다. 기존에는 페이지뷰, 구매 수 등의 데이터를 활용하여 상품에 스코어를 부여하고 이를 바탕으로 상품을 정렬하는 방식으로 서비스되고 있었는데요. 이 방식은 이전부터 잘 팔렸던 스테디셀러를 더 많이 보여주는 경향이 있었습니다. 또한, 모든 유저에게 동일한 상품 정렬을 보여주어 다양한 유저의 취향을 아우르지 못하는 한계점이 있었는데 이러한 부분을 개선할 수 있다고 생각했습니다.

이렇게 저희는 ML모델을 적용해 무신사의 정렬 종류 중 하나인 ‘무신사 추천순’ 을 개선해보기로 했는데요. 모델을 적용하는 과정에서 어떤 알고리즘을 적용할지, 어떤 유저를 대상으로 추천을 제공할지 고민한 과정과 테스트를 진행한 결과까지 모두 공유해보려 합니다.

추천 모델을 적용해보자

모델을 적용하기로 했지만 무턱대고 모델을 선정할 수는 없었습니다. 모델의 방향성을 잡아야 했는데요. 고민하다보니 카테고리숍 추천순에서 개선할 수 있는 점들이 보였습니다.

  • 모든 유저에게 동일한 상품 리스트를 보여준다.
  • 다양한 상품을 판매하고 있지만 자주 노출되는 상품의 수가 매우 적다.

그래서 두 가지를 개선하는 쪽으로 모델 방향성을 잡아보았습니다.

  • 유저의 취향에 따라 다른 상품 리스트를 보여주자
  • 더 다양한 상품을 보여주자

먼저 유저의 취향에 따라 다른 무신사 추천순을 보여줄 방법을 고민했습니다.

처음에는 유저의 최신 로그 데이터를 통해 Sequential Model이나 그래프 기반의 추천모델을 적용해 유저별 개인화를 하고 싶었는데요. 이러한 모델을 사용한다면 위 두 가지 개선점을 모두 커버할 수 있다고 생각했기 때문입니다.

그렇지만 이 방식에는 또 다른 어려움이 있었습니다.

  • 유저 뿐 아니라 판매하고 있는 모든 상품에 대해 인덱싱을 해야 한다.
  • 유저별로 다른 추천순을 보여주는 방식의 서빙이 어렵다.

카테고리숍을 사용하는 유저도 많고, 수십만 개에 달하는 모든 상품에 대한 인덱싱 값을 갖고 있어야 해서 시간과 환경의 제약이 있었습니다. 또한, 모든 유저에게 단일한 추천순을 보여주고 있어서 서빙 구조도 바꿔야 했는데요. 내부적으로 Elasticsearch에서 인덱싱을 하고 그 값을 서빙하고 있어 실시간으로 스코어를 계산하고 업데이트 하기 쉽지 않은 구조였습니다. 그래서 유저별 개인화 대신 세그먼트 기반으로 유저를 나누고, 그에 따라 다른 정렬을 보여주는 방식을 선택했습니다.

다음으로 어떻게 유저에게 더 다양한 상품을 보여줄 수 있을지 고민을 했는데요.

저희는 “유저가 상품을 클릭한다”는 것을 “유저의 취향에 맞는 상품을 보여줬다”라고 가정했고, 따라서 유저의 상품 클릭을 극대화하는 방향으로 모델을 만들고 싶었습니다. 절대적인 클릭 수 대신 노출 대비 클릭한 횟수인 Click-Through Rate(이하 CTR)을 예측하면 이전에 자주 노출된 적은 없지만 유저가 많이 클릭한 상품도 상위 노출되면서 다양한 상품을 보여줄 수 있을 것이라고 생각했습니다. 그래서 저희는 CTR을 예측하는 모델을 적용하기로 했습니다.

무신사는 실시간으로 새로운 유저들이 유입되고 새로운 상품의 등록도 잦으며 품절 등의 이슈로 대상이 되는 상품이 사라지기도 합니다. 위에서 말씀드린 것처럼 카테고리숍에서는 유저의 행동(인터랙션)이 없는 상품들이 매우 많았죠. 그래서 새로운 유저나 상품에 대한 정보가 충분하지 않아 추천이 어려운 콜드 스타트(Cold Start) 문제가 생길 수밖에 없었습니다. 콜드 스타트 문제를 해결하면서도 유저의 정보나 상품의 정보가 잘 정의되어 있을 때 강점이 있는 CTR 예측 모델을 탐색했고 Deep FM(Deep Factorization Machine)모델을 선택했습니다. 이와 더불어 상품 메타를 포함한 양질의 무신사 데이터를 이용해서 feature를 더 강화하는 쪽으로 방향을 잡았습니다.

Deep FM에 대해 간단히 설명을 해보자면, 이름에서 알 수 있듯 Deep FM은 딥러닝 네트워크와 FM을 결합한 알고리즘입니다. FM과 Deep 영역 각각의 컴포넌트로 구성되고 FM 영역에서는 Low Order를 Deep영역에서는 High Order를 학습하게 되는데요. Low Order란 입력한 변수의 1개의 특성에 대해 가중치를 학습하는 것을 말합니다. 예를 들면, 상품의 가격 등 1개 변수의 특성이 갖는 개별적 중요도를 학습합니다. High Order란 두 개 이상의 변수에 대한 가중치를 학습하는데 상품의 가격과 카테고리, 유저의 나이 같은 변수들 사이의 복합적인 관계를 학습하는 것을 말합니다. 두 컴포넌트가 Input 데이터와 임베딩을 공유하기 때문에 더욱 효율적인 학습이 가능합니다. 따라서 Deep FM은 다양한 feature간 복잡한 상호작용을 학습할 수 있다는 점에서 활용 가능한 데이터들이 많은 무신사에서 적용하기 적합하다고 판단하여 테스트를 진행했습니다.

[그림2] DeepFM: A Factorization-Machine based Neural Network for CTR Prediction
[그림2] DeepFM: A Factorization-Machine based Neural Network for CTR Prediction

모델을 결정한 후 유저 세그먼트를 어떻게 나눌지 고민을 했는데요. 서빙을 할 수 있는 세그먼트의 수가 정해져 있어, 수는 적지만 강력한 효과가 있는 feature를 찾고 싶었습니다. 먼저 가장 직관적인 feature인 성/연령별로 세그먼트를 나누어 보았고 실제로 각 세그먼트에 따라 다른 상품을 선호하는 경향을 볼 수 있었습니다. 따라서 이 세그먼트를 베이스 라인으로 설계하여 진행하였습니다. 하지만 같은 세그먼트 내에서도 서로 다른 취향을 가진 유저가 있을 수 있을 것이라 생각했습니다. 만약 그렇다면 더욱 세분화된 기준으로 유저를 그루핑(grouping)해 각 그룹마다 다른 리스트를 보여주면 유저 반응이 좋을 것이라 생각했고, 추가적 실험을 통해 이를 확인하기로 했습니다. 그 방법 중 하나로 유저를 더 세분화 할 수 있는 feature를 탐색하기 시작했습니다.

첫번째로 유저의 메타 데이터에서 사용할만한 feature를 찾아보았는데요. 그 중 하나가 무신사의 회원 등급이었습니다. 무신사의 회원 등급은 누적 구매금액과 현재 포인트를 합산하여 부여합니다. 등급이 높을수록 무신사 서비스 내에서 활발한 인터렉션이 있고, 구매횟수도 높다는 의미죠.

등급이 높은 유저는 등급이 낮은 유저와는 다른 행동을 보였습니다.

  • 스테디셀러 상품보다는 신상품을 많이 클릭한다.
  • 카테고리숍보다는 브랜드숍과 기획전을 더 많이 본다.
  • 상대적으로 좋아요 수나 후기 수가 적은 상품을 많이 클릭한다.
    (많이 노출되는 상품보다는 취향에 따라 노출이 적은 상품들도 탐색하기 때문으로 해석합니다.)

회원등급은 유저를 나눌 수 있는 요소 중 하나라고 판단해 정량적, 정성적 결과를 확인한 후 모델을 개발해 서비스하였습니다.

두 번째로는 유저의 행동 기반 데이터를 사용해 보았는데요. 최근에 클릭한 상품과 브랜드로 유저를 클러스터링한다면 특정한 상품 혹은 브랜드를 선호하는 유저들끼리 나뉠 것이라는 가설을 세웠습니다. 1명의 유저가 각각 클릭한 상품 또는 브랜드를 합쳐 1개의 document를 만들고 TF-IDF를 적용 후 LDA를 사용하여 유저의 토픽(term)별 가중치를 구하고 그 결과를 Kmeans 클러스터링하였습니다.

임베딩 결과를 시각적으로 확인해보았을 때 상품보다는 브랜드를 사용한 클러스터가 더 잘 나뉘는 것을 확인할 수 있었습니다.

[그림3] 임베딩 결과를 시각적으로 구현한 그림으로, 상품보다는 브랜드를 사용한 클러스터가 더 잘 나뉘는 것을 확인할 수 있다는 자료
[그림3] 클러스터링 시각화 좌:브랜드, 우:상품

또한 브랜드 클러스터에 속한 유저의 행동을 살펴본 결과, 몇 가지 분류 가능한 예시 그룹은 다음과 같습니다.

  • 자주 노출되는 인기 브랜드를 선호하는 그룹
  • 댄디하고 가격대가 있는 브랜드를 선호하는 그룹
  • 여성 브랜드를 주로 보는 그룹

베이스라인으로 설정한 성 연령 세그먼트에도 추가적으로 적용해 볼 수 있어 이 feature를 적용한다면 유저 취향에 맞는 상품 정렬을 제공할 수 있다고 생각했습니다.

좋은 모델과 feature를 선택하여 결과를 만들었지만 아쉬운 점도 있었는데요.

CTR을 예측하는 모델이다 보니 자칫 선정적인 상품이나 행사 상품 등 유인성 상품이 상위에 노출되는 결과가 있기도 했습니다. 이는 유저가 찾고자 하는 의도와 다른 결과라 판단하여 상품 정렬을 바로잡기 위한 필터 로직도 함께 적용 중입니다. 또한, 각각의 모델 아웃풋은 고객이 아직 접해보지 못한 상품을 더 보여줄 수 있도록 MAB 로직를 적용하였습니다. 이를 통해 콜드 스타트 문제를 해결하고 더 다양한 상품을 보여줄 수 있도록 했습니다.

바로 테스트를 해보자! A/B TEST

가설에 맞는 다양한 모델을 만들었다면 이제는 서빙만 남았는데요. 저희는 자체적으로 구성한 A/B 테스트 툴로 빠르게 결과를 확인하고 대응할 수 있습니다. 이 툴을 활용하여 1개의 결과만을 100% 서빙하는 것이 아니라 대조군과 여러 실험군(버킷)을 나누어 다양한 모델 결과를 서빙할 수 있습니다. 또한, 각 버킷의 비율은 실시간으로 변경 가능하고 버킷을 나누는 기준도 유저와 트래픽으로 선택할 수 있어 영역의 특성에 따라 적용할 수 있습니다. 또한, 메트릭도 함께 확인할 수 있기 때문에 쉽게 배포하고 또 제거할 수 있어 테스트하기가 매우 쉬웠습니다.

[그림4] 상의 추천 예시 화면
[그림4] 추천 예시

적용한 로직을 다시 한 번 정리해 보겠습니다.

  • 기존 로직 (A)
  • Deep FM + 성/연령별 세그먼트 (B)
  • Deep FM + 성/연령별 세그먼트 + 그룹 레벨 세그먼트 (B1)
  • Deep FM + 성/연령별 세그먼트 + 브랜드 세그먼트 (B2)

위 4가지 로직을 테스트한 결과 가장 많은 상승 폭을 보인 로직(B2) 기준 기존 로직(A) 대비 유저당 클릭 수가 43%, CTR도 18%, 상승한 것을 확인했습니다.

[그림5] 유저당 클릭 수가 43%, CTR도 18%, 상승한 것을 비교한 그래프
[그림5] CTR/ 유저당 클릭수

새롭게 추가한 로직에서 유저는 더 많은 상품을 보게 되었는데요. 저희가 의도한 대로 여러 상품이 더 많이 노출되고 더 많이 클릭 되는 경향을 볼 수 있었습니다. 짝짝짝!!

기존 로직과 새로운 로직의 A/B 테스트를 진행했고, CTR과 유저 당 클릭 수 등 다양한 지표를 대시보드로 확인할 수 있도록 구성했습니다. 결과적으로 유저를 세분화하고 취향에 맞는 상품을 보여주려 노력한 것이 효과가 있다는 걸 확인했습니다.

모델은 어떻게 만들고 관리할까?

좋은 결과를 내는 것도 물론 중요하지만, 가설에 따라 모델을 만들고 피드백 받는 과정을 쉽고 빠르게 할 수 있는 구조 역시 중요한데요. 모델을 만들고 그 결과를 모니터링하는 파이프라인을 확장성 있게 설계하여, 여러 모델을 빠르게 테스트 하고 최고의 모델을 선정할 수 있었습니다.

[그림6] 추천 시스템 구조를 나타낸 그림
[그림6] 추천시스템 구조

저희가 빠르게 테스트할 수 있었던 건 다양한 환경이 잘 구축되었기 때문인데요. 다양한 원천의 데이터로부터 모델을 학습하고 서빙하기 위해 Airflow, AWS, GCP등 다양한 환경을 활용하고 있습니다. 물리적 제약이 없는 클라우드 환경에서 주로 작업이 이루어지기 때문에 비교적 환경적 제약이 적은 편입니다. 또한, 다양한 소스에서 필요한 데이터를 쉽게 가져와 전처리할 수 있도록 데이터 관리가 되어 있어 학습에 필요한 데이터를 효율적으로 처리할 수 있습니다.

가설에 따라 서로 다른 모델 인풋으로 학습 데이터와 추론 데이터를 여러 벌 만들어 구성하고 추가적으로 알고리즘, feature, 하이퍼파라미터 등도 다르게 설정하여 다양한 관점의 A/B 테스트를 진행할 수 있는 환경 역시 구성되어 있습니다.

이번 프로젝트에서는 추론 데이터 생성과 모델 학습 과정을 데이터브릭스에서 진행했는데요. GPU를 포함한 클러스터를 다양한 모델의 학습에 적정한 크기로 사용하여 리소스 낭비 없이 진행할 수 있었습니다. 또한, 병렬로 처리할 수 있어 다양한 모델을 여러 벌 학습할 수 있어 시간도 아낄 수 있었고 작업 중인 클러스터의 크기도 필요에 따라 손쉽게 변경할 수 있어서 더욱 편리했습니다. 데이터브릭스에서도 Airflow처럼 디펜던시 있는 작업을 연결하는 파이프라인을 구성할 수 있는데, 모두 UI로 간단히 사용할 수 있습니다. 모델 학습 시 다양한 파라미터와 메트릭 결과도 UI로 확인할 수 있어 모델 버전 관리도 수월하게 할 수 있었습니다.

이 외에도 모델 테스트를 노트북 환경에서 작업하면서 코드 레벨로 공유할 수 있어 협업하기 편했는데 하나의 노트북 내에서 Python, Scala, SQL 등 여러 언어를 사용할 수 있었던 점도 좋았습니다.

이번 기회를 통해 다시 한번 환경 구축해주신 데이터플랫폼팀 분들께 감사드립니다! :)

마치며

지금까지 저희의 고민을 해결한 과정에 대해서 공유해보았는데요. 지속해서 카테고리숍에서 유저들이 더 좋아할 만한 상품을 보여줄 수 있도록 또 다른 문제들을 정의하고 해결 방법을 찾아가며 고도화할 예정입니다. 카테고리숍 추천 외에도 재미있는 다양한 과제들을 풀어나가고 있습니다. (무신사 내에는 상품을 코디할 때 도움이 될 수 있도록 하는 코디 콘텐츠(코디맵, 코디숍)들이 있는데 이러한 콘텐츠를 추천해 주는 코디추천, 다양한 기획전 및 할인, 신상 소식을 전하는 배너들을 개개인의 취향에 따라 순서를 보여주는 배너 개인화 등등 이외에도 많아요!) 팀원들과 함께 고민하며 풀어나가고 있지만, 해결해야 하는 문제는 아직도 많습니다.

추천에 관심이 있으신 분, 패션을 좋아하시는 분, 문제를 발견하고 해결하는 것을 좋아하는 분, 이 글을 재미있게 읽으신 분들 모두 모두 언제든지 데이터 프로덕트팀에 지원해주세요! 긴 글 읽어주셔서 감사합니다.

PS. 마지막으로 함께 고생해주신 저희 팀원분들 (무엇이든 물어보는 최영민님, 항상 든든한 이원지님, 믿고 가는 최두석님, 에러 해결사 남상준님, 멘탈 지킴이 김준호님, 분위기 메이커 최두섭님, 똑쟁이 막냉이 정승휴님), 검색서비스실, 탐색경험팀, 그 외에 함께 해주신 분 모두 모두 감사합니다!

--

--