상품 등록 카테고리 추천 모델 개발 과정

Blank(김선식)
번개장터 기술 블로그
14 min readApr 21, 2022

번개장터에는 상품을 등록할 수 있는 카테고리가 700개정도 있습니다. 사용자가 상품을 등록할 때마다 적절한 카테고리를 찾아야 한다면 서비스의 사용성이 떨어지기 때문에, 저희는 상품 등록 창에서 사용자가 입력한 상품 제목을 보고 등록 카테고리를 추천해주는 알고리즘을 오래 전에 개발해서 사용자에게 제공하고 있었습니다.

하지만 추천 결과가 부정확한 경우에도, 사용자는 상품을 등록할 카테고리를 일일이 찾기 번거롭기 때문에 이 부정확하게 추천된 카테고리를 그대로 사용하는 경우가 많았습니다. 예를 들어, 기존 알고리즘은 ‘나이키 농구화’를 등록하려는 사용자에게 기타(남성화) 카테고리를 추천해줬고, 그 결과 이 사용자는 농구 의류/잡화 카테고리가 별도로 있음에도 불구하고 이 상품을 기타(남성화) 카테고리에 등록하는 사례가 있었습니다. 이에 따라, 카테고리를 기준으로 상품을 탐색하는 사용자는 ‘상품이 왜 이렇게 뒤죽박죽이지’라는 인상을 갖게 되기 쉬웠습니다.

이 알고리즘을 개선하기 위해 2021년 4분기에 번개장터 데이터 팀은 Blank(김선식)와 Kyle(이준서)을 주축으로 연구 및 알고리즘 개발을 진행했습니다. 이 포스트는 알고리즘 개발 과정과 사용자를 대상으로 한 실제 성능 테스트 결과를 공유드리기 위해 작성하게 되었습니다.

기존 알고리즘의 문제점과 개선 방향

기존 알고리즘은 상품 제목이 입력되는 순서에 맞춰 제목 속 키워드를 인식하고, 그 키워드를 번개장터 상품 검색 엔진에 입력해서 출력된 상품들이 가장 많이 등록된 순으로 카테고리 추천을 제공했습니다. 이 방식은 상품 검색엔진만 구축되어 있다면 개발이나 유지보수에 대한 리소스를 추가할 필요 없이 상품 등록 카테고리 추천을 제공할 수 있다는 장점이 있지만, 상품이 많이 등록된 카테고리 위주로 추천을 제공한다는 단점이 있습니다.

일예로, 기존 모델이 ‘스타벅스’ 키워드에 대한 카테고리 추천을 커피 기프티콘 카테고리로 제공하는 이유는 ‘스타벅스’ 키워드를 번개장터 상품 검색 엔진에 입력했을 때 커피 기프티콘 카테고리에 등록된 상품이 가장 많이 조회되기 때문입니다. 이 예시만 봤을 때는 딱히 이상한 점이 없어 보입니다. 하지만 기존 모델에 ‘방탄 포카’ 키워드를 입력하면 보이그룹 포스터/화보 카테고리가 추천되는데, 이는 역시 사용자들이 이 키워드에 걸리는 상품들을 이 카테고리에 가장 많이 등록했기 때문입니다. 번개장터는 현재 스타굿즈 하위 카테고리로 팬시/포카 카테고리를 만들어 놓았기 때문에, 이 추천은 사실 틀린 추천입니다.

그렇기 때문에, 알고리즘이 인식할 수 있는 일부 키워드들에 가중치를 과도하게 부여하는 추천이 제공되지 않도록, 상품 제목에 있는 모든 단어들을 활용해서 추천을 제공할 수 있는 알고리즘이 필요했습니다. 또한, 카테고리 별로 등록된 상품들 개수의 영향력을 최소화해서, 상품 등록이 상대적으로 적은 카테고리들이 후보군에 포함된 추천이 제공될 수 있도록 해야 합니다.

데이터 수집

상품 제목이 A라고 입력되면 B 카테고리를 추천하라는 규칙을 모델에 학습시키기 위해서, 일정 기간동안 사용자가 등록한 상품의 제목과 해당 상품이 등록된 카테고리의 쌍으로 이루어진 데이터를 수집했습니다.

추천에서 제외할 카테고리 선정

먼저, 상품 등록이 잘 일어나지 않아 카테고리 추천에 대한 수요 자체가 적은 카테고리들을 추천 대상에서 제외했습니다. 이는 학습시킬 신경망 모델이 포함하고 있는 파라미터의 개수가 추천 대상이 되는 카테고리 개수에 비례해서 많아지기 때문입니다. 신경망 모델의 최종 용량과 사용자에게 카테고리를 추천하는데 필요한 연산의 양은 파라미터 개수에 비례해서 늘어납니다. 사용자들에게 몇 번 추천해주지도 못할 카테고리를 위해 이런 비용을 굳이 지불하는 것은 키우는 것은 비효율적이라고 판단했기 때문에 그런 카테고리들을 제외하게 되었습니다.

다음으로, 이질적인 상품이 등록될 수 있는 카테고리를 추천 대상에서 제외했습니다. 상품 제목에 대응되는 더 정확한 카테고리가 있어도, 이런 카테고리가 추천 목록에 포함되면 역선택이 일어날 수 있기 때문입니다. 예를 들어, ‘방탄소년단 포토카드’라는 제목에 ‘기타(보이그룹)’ 카테고리가 추천되면, 이 카테고리가 딱히 틀린 추천은 아니기 때문에 보이그룹 포토카드 카테고리가 있어도 이 카테고리를 선택하는 역선택이 발생할 수 있습니다.

카테고리 별 상품 개수 상한 설정

카테고리 별 상품 개수가 특정 카테고리에 치우쳐져 있다면 편향된 학습이 일어날 수 있습니다. 극단적인 예시로, A 카테고리에 전체 90%의 상품이 등록되고 나머지 카테고리에 10%의 상품이 등록된다면, 어떤 제목이 입력되도 A 카테고리만 추천해주는 알고리즘을 만들면 정확도가 90%인 알고리즘을 만들 수 있습니다. 앞서 언급했듯이 카테고리별로 등록된 상품들 개수의 영향력을 최소화해서 추천이 골고루 일어날 수 있도록 하는 것을 개선 방향으로 설정했기 때문에, 이런 편향적인 학습이 일어나지 않도록 카테고리 별 상품 개수를 제한했습니다. 카테고리 별 상품 개수 상한을 설정하는 아래 세 가지 전략들 중 하나를 정해 카테고리 별 상품 개수를 제한한 데이터로 모델을 학습시켰습니다.

  • none: 카테고리 별 상품 개수 상한을 정하지 않음(현상유지)
  • log: 카테고리 별 상품 개수 상한을 카테고리 별 상품 개수의 로그 값에 상수를 곱한 값으로 적용
  • uniform: 카테고리 별 상품 개수 상한을 10,000개로 일괄 적용

상한 설정 방법에 따라 카테고리 별 학습 데이터 상품 수 분포는 아래와 같이 표현되는 것을 확인했습니다. 스케일 비교를 시각적으로 보조하기 위해 10,000을 의미하는 까만 점선을 플랏에 각각 추가했습니다.

모델 학습

모델 적합에 앞서 모델 학습에 사용할 토크나이저와 아키텍쳐 후보들의 특징을 비교분석했습니다. 각 후보의 장단점을 염두에 두고, 고정된 데이터셋에 대한 성능을 평가해 적절한 아키텍쳐를 결정했습니다.

토크나이저

데이터를 통해 학습시킬 신경망 모델은 상품 제목을 그대로 입력받는 것이 아니라, 그 제목을 토큰이라는 작은 단위로 나눈 배열을 입력받습니다. 예를 들면, ‘나이키조던 백보드260’을 그대로 받는 것이 아니라 [‘나이키’, ‘조던’, ‘백보드’, ‘260’]이라는 배열을 입력으로 받습니다. 각 토큰은 자신과 대응되는 임베딩 벡터(float의 배열)로 변환되어 모델이 연산할 수 있는 형태가 되는데, 그렇기 때문에 제목을 토큰의 배열로 잘 분해시켜줄 수 있는 토크나이저를 선택하는 것이 중요합니다.

특정 상품 제목이 분류되어야 할 카테고리를 정하는 데에는 상품 제목 안에 있는 상품, 브랜드명과 같은 대명사들이 중요한 정보를 제공하는 경우가 많습니다. 그리고 이 대명사들은 트렌드에 따라 상품 제목에 새로 포함되기도 하고 더이상 쓰이지 않아 사라지기도 합니다. 그래서 번개장터 외부 텍스트로 미리 학습된 토크나이저보다는, 비교적 최근에 수집된 상품 제목들을 사용해 BPE, subword regularization같은 알고리즘으로 새로 학습시킬 수 있는 sentencpiece 토크나이저를 사용했습니다.

아키텍쳐

상품 제목을 분할한 토큰들의 배열에 대응하는 임베딩 벡터들의 배열(즉, 행렬)이 입력되었을 때, 신경망 모델은 미리 정의된 연산을 적용해 이 제목이 특정 카테고리에 해당할 가능성에 비례하는 점수를 계산합니다. 어떤 연산을 수행하는지가 아키텍쳐마다 다르고, 이번 프로젝트에서는 아래의 세 아키텍쳐를 후보로 정했습니다.

FastText

페이스북에서 이 논문을 통해 2016년에 공개한 아키텍쳐입니다. 이 아키텍쳐의 장점은 페이스북이 구현한 라이브러리를 사용해서 토크나이저, 임베딩 벡터들, 아키텍쳐 내 파라미터들을 간편하고 빠르게 학습시킬 수 있다는 것입니다. 그래서 개발 리소스를 크게 절약할 수 있고, 아웃풋도 bin파일 하나밖에 없어서 관리가 편하다는 장점도 있습니다. 하지만 동시에 이 라이브러리에 정의된 대로만 사용할 수 있기 때문에, 성능 개선 여지가 적다는 단점이 있습니다. 토큰 별 임베딩들의 평균을 구하고 여기에 행렬 곱 연산을 두 번밖에 거치지 않는데, 보통 이 연산을 여러 번 수행하는 아키텍쳐일수록 좋은 성능을 보이기 때문에 연산 횟수를 조정할 수 없다는 점은 단점입니다.

DAN

2015년에 이 논문을 통해 공개된 아키텍쳐입니다. 토큰 별 임베딩들의 평균을 상품 제목의 임베딩으로 사용한다는 점은 FastText와 같지만, tensorflow, pytorch와 같은 딥러닝 프레임워크를 사용해 앞서 언급한 행렬 곱 연산을 여러번 수행하도록 튜닝을 할 여지가 있어 FastText에 비해 나은 성능을 내는 모델을 만들 수 있다는 장점이 있습니다. 하지만 동시에 FastText 라이브러리가 주는 편리함은 포기해야 합니다. 토크나이저, 임베딩, 분류기 학습이 전부 각각 이루어지고, 이에 따라 실제 서빙을 위해 필요한 파일도 각각 따로 생성되기 때문에 FastText에 비해 관리가 다소 번거로워지기 때문입니다.

GRU

2014년에 이 논문을 통해 공개된 아키텍쳐입니다. 사실 위 아키텍쳐들과 같이 토큰 별 임베딩의 평균을 상품 제목의 임베딩으로 사용한다는 것은 토큰의 등장 순서를 무시한다는 것과 같습니다. 예를 들어, ‘나이키 조던 백보드 260’이라는 제목이 [‘나이키’, ‘조던’, ‘백보드’, ‘260’]로 토큰화된다고 했을 때, 4개 토큰 각각에 해당하는 임베딩들의 평균은 토큰의 순서가 [‘나이키’, ‘백보드’, ‘조던’, ‘260’]든 [‘백보드’, ‘나이키’, ‘260’, ‘조던’]든 같기 때문입니다. GRU는 이전에 입력된 토큰 임베딩에 연산을 수행한 결과를 다음 토큰에 대한 연산의 입력으로 사용하는 반복적인(recurrent) 연산을 수행하기 때문에 토큰의 순서 정보를 사용할 수 있다는 장점이 있습니다.

하지만 동시에 이런 recurrent한 구조 때문에, 상품 제목에 대한 추천 결과를 제공하기 위해서는 그 제목 내 토큰의 개수만큼 행렬 곱 연산이 이루어져야 한다는 단점이 있습니다. 위 예시에서는 ‘나이키’를 받아 연산을 수행한 결과를 ‘조던’을 받아 수행하는 연산의 입력으로 사용하는 식으로 총 4번의 행렬 곱 연산을 반복해야 합니다. 이 연산을 상품 제목 내 모든 토큰에 대해 순차적으로 수행해야 하기 때문에, 카테고리 추천 한 번에 필요한 시간이 늘어나게 됩니다.

평가 결과

모델을 검증할 용도로 학습 데이터에서 분리시켜 놓은 데이터를 사용해서, 3가지 전처리 방법으로 정제한 데이터를 3가지 모델에 학습시킨 결과를 정리했습니다. 추천 성능을 평가할 척도는 Precision@k로 정했습니다. 참고로 Precision@k는 전체 검증 데이터 중에서, 상품 제목에 대한 k개의 추천 결과 중 상품 등록에 실제로 사용된 카테고리가 포함된 상품들의 비율을 의미합니다. 추천을 k개 제공했을 때의 추천 성공률이라고 해석할 수 있습니다.

먼저, 학습 데이터에서 분리시켜 놓은 검증용 데이터의 상품들 전체에 대한 Precision@2를 계산했습니다.

카테고리 별 상품 개수에 대한 전처리를 적용하지 않는 none 전략으로 획득한 데이터로 학습시킨 모델의 성능이 가장 좋은 것처럼 보이지만, 카테고리별로 계산한 Precision@2의 분포를 박스플랏으로 비교하면 다른 인사이트를 얻을 수 있습니다.

세 모델에서 모두 uniform 방식을 사용해 수집한 데이터로 훈련시킨 모델의 Precision@2 중앙값이 다른 전략을 사용했을 때보다 높거나 같지만, 1분위수와 4분위수 사이의 간격(박스의 세로 길이)은 항상 uniform 방식을 사용했을 때가 작았습니다. 이를 통해 여러 카테고리에서 보다 균등하게 좋은 추천을 제공하는 데이터 수집 방법은 uniform이라는 것을 알 수 있습니다.

다음으로는 모델 별 전체 Precision@4를 계산해 기록했습니다.

여기서도 수집되는 상품 데이터 수가 더 많은 none이나 log 방식이 uniform 방식보다 우수해 보이지만, 카테고리 별로 계산한 Precision@4의 박스플랏에서는 uniform 방식으로 수집한 데이터로 훈련시킨 모델이 여러 카테고리에서 균등하게 좋은 추천을 제공하고 있는 것을 확인할 수 있습니다.

토크나이저의 사전 크기가 정해져 있을 때, none이나 log방식으로 획득한 데이터로 토크나이저를 학습시키면 인기 카테고리에 등록되는 상품의 개수가 많기 때문에 비인기 카테고리의 단어 대신 등록되는 인기 카테고리의 단어 수가 함께 많아집니다. 이에 따라 상대적으로 비인기인 카테고리에 대한 정확도를 희생해 인기 카테고리에 대한 정확도가 개선됩니다. 전체 상품을 대상으로 계산한 Precision@2, Precision@4가 none, log에서 더 좋은 현상도 단순히 이러한 카테고리의 상품들이 많이 등록되다 보니 좋아진 것으로 이해할 수 있습니다.

일련의 실험 결과들을 통해, 아래와 같은 의사결정을 내렸습니다.

  1. 상대적으로 비인기인 카테고리에 대한 추천을 개선한다는 목적을 달성하기 위해서는, 카테고리 별 상품 개수 상한을 균일하게 유지해서 수집한 데이터(uniform)로 모델을 학습시키는 것이 가장 바람직하다.
  2. Precision@2, Precision@4 척도 측면에서 전처리 방법 선택과 관계없이 GRU가 다른 아키텍쳐보다 항상 좋은 성능을 보였기 때문에 GRU 아키텍쳐를 선택한다.

실제 사용자 피드백

위와 같은 결정 사항들을 반영해서 알고리즘을 구현했고, 이 알고리즘은 내부 검토를 거쳐 2022년 1월 26일에 일반 사용자들에게 배포되었습니다. 버전 업데이트 등을 통해 이 기능을 사용하게 된 사용자와 아닌 사용자들이 섞여 있는 기간(2022–01–26 ~ 2022–02–14)동안 수집된 로그를 사용해서, 기존 알고리즘과 신규 알고리즘의 사용률을 실제 사용자들을 대상으로 측정해서 비교했습니다.

카테고리 추천 성공 및 실패 정의

각 알고리즘을 평가할 척도는 전체 상품 등록 사건 중에서 제목을 입력해 카테고리 추천을 받은 사용자가 추천된 카테고리를 선택해서 상품을 등록하는 사건의 비중으로 정했습니다. 이를 측정하기 위해서는 상품을 등록한 사용자가 추천 카테고리를 선택해서 상품을 등록했는지(성공), 자신이 직접 카테고리 목록에서 등록할 카테고리를 탐색해서 상품을 등록했는지(실패)를 데이터로부터 파악해야 했습니다.

이를 위해, 먼저 한 사용자가 상품 등록창을 켜기 위해 하단메뉴의 ‘상품등록’ 버튼을 누르는 것부터 상품 등록을 완료하기 위해 상품 등록화면 하단의 ‘등록’ 버튼을 누르는 것까지의 로그 시퀀스를 분석 단위라고 정의했습니다. 그리고 한 분석 단위 안에서 카테고리를 고르는 사건들 중 추천된 카테고리를 누르는 사건이 가장 나중에 발생했으면 추천 성공, 카테고리 탐색창에서 찾은 카테고리를 누르는 사건이 가장 나중에 발생했으면 추천 실패라고 정의했습니다.

성능 평과 결과

먼저, 사용자가 각 추천 알고리즘이 제공한 카테고리 추천 결과를 선택해서 상품을 등록한 비율을 일별로 집계했습니다. 신규 알고리즘(CATREC)이 제공하는 추천 카테고리가 상품 등록에 실제로 사용되는 비율은 전체적으로 92%정도 되는 반면, 기존 알고리즘(SEARCH)이 제공하는 추천 카테고리가 상품 등록에 실제로 사용되는 비율은 전체적으로 73%정도 되는 것을 확인할 수 있었습니다.

또한, 추천 대상이 된 카테고리 각각에 해당하는 추천 알고리즘 사용률을 주 단위로 집계하고, 이 비율들의 분포를 박스플랏으로 나타냈습니다. 실험 단계에서 확인한 것과 같이, 기존 알고리즘(SEARCH)에 비해 신규 알고리즘(CATREC)이 다양한 카테고리를 정확하게 추천해 주고 있음을 확인할 수 있었습니다.

마무리

사실 상품 제목을 분류하는 등의 자연어 처리 태스크를 해결하기 위해 최근에는 BERT 계열의 아키텍쳐들이 가장 많이 활용되고 있습니다. 하지만 번개장터 상품 등록 화면에서 이 기능을 사용해 보시면 아실 수 있는 것처럼, 입력된 제목에 대한 카테고리 추천은 실시간으로 일어나기 때문에, 상품 등록 카테고리 추천 태스크에 대해서만큼은 텍스트에 대한 추천 결과를 반환하는 데까지 소요되는 시간이 짧은 아키텍쳐를 더욱 선호하고 있습니다. 앞서 공유드린 것처럼 GRU는 우수한 성능을 보이면서도 BERT에 비해 추천에 소요되는 시간이 짧다고 판단했기 때문에 최종적으로 선택하게 되었습니다.

저희도 번개장터 사용자로써 수많은 카테고리 목록에서 상품을 등록할 카테고리를 탐색하는 것보다 추천 카테고리를 사용하는 것이 훨씬 편합니다. 그럼에도 불구하고, 추천된 카테고리를 사용하지 못한다면 그것은 추천된 카테고리가 정확하지 않기 때문입니다. 그렇기 때문에 실제 사용자의 추천 카테고리 사용 비율이 73%에서 92%로 상승했다는 것은 저희에게 단순히 수치상의 변화 뿐만 아니라 저희가 사용자의 상품 등록 경험을 개선하는 데 기여를 했다는 의미가 있어서 뿌듯했습니다. 앞으로도 더 개선된 사용자 경험을 제공할 수 있도록 많이 고민하고, 더 노력하겠습니다.

--

--