추천 모델의 필요성
현재 진행중인 프로젝트에서 다른 유사 플랫폼과 비교하여 우리 플랫폼을 써야 할 이유가 필요했다.
여러가지 후보군들 중에 리뷰 기반 사용자 맞춤 추천 모델을 선택하였다.
단순히 인기 있는 가맹점을 보여주는 것을 넘어서, 사용자 본인도 잘 몰랐던 숨겨진 패턴이나 취향을 파악해 플랫폼 사용 만족도를 높이고자 한다.
가상의 사용자 'A씨'의 사례를 중심으로 설명해보겠다.
LSTM Model
가장 먼저 떠올린 아이디어는 이전 머신러닝 수업에서 직접 배우고 학습까지 시켜봤던 LSTM 모델이다.
A씨의 행동을 순서가 있는 순차 데이터(sequence)로 보고, 과거의 매장 방문 기록을 기반으로 다음의 방문할 매장을 예측하는 방식이다.
A씨가 [ a 갈비집(저녁) → b 카페(점심) → c 칼국수(저녁) → d 호프집(야식) ]과 같은 방문 순서를 거쳤다면,
이를 학습하여 그 다음 방문할 매장을 예측하는 방식의 설계이다.
LSTM으로 이 순서를 학습한 모델은 "칼국수집 다음에는 호프집에 갈 확률이 높다"와 같이 다음 방문 장소를 예측한다.
하지만 이 방법은 A씨를 만족시키기 힘들어 보인다.
1. "싫었어요"를 알지 못함
A씨가 c 칼국수집에 대해 맛이 없었다고 생각해 리뷰를 남겼어도, LSTM 모델은 그저 순차 방문 기록의 일부로만 학습힌다.
나중에 상황에 따라 A씨에게 c 칼국수집을 또 다시 추천할수도 있다.
2. 새로운 매장 추천의 부재
A씨는 새로운 맛집을 찾아가는 것을 좋아한다.
하지만, 이 모델은 과거 패턴에만 의존하기 때문에 새로운 맛집에 대한 추천이 어렵다.
3. 리뷰를 활용하지 못함
이 모델은 A씨가 자신의 소중한 시간을 들여 우리 플랫폼에 남긴 리뷰를 적절히 활용하지 못한다.
Two-Tower Model

A씨의 패턴이나 취향을 제대로 알기 위해 다양한 다른 방법을 찾아보았다.
그중 가장 합리적이라고 생각한 방식은, 추천 시스템에 널리 쓰이는 Two-Tower 딥러닝 모델이다.
Two-Tower 모델의 장점은 아래와 같다.
1. 독립 구조
User tower와 Item tower를 각각 학습시키므로, 한쪽 데이터만 바뀌어도 나머지를 재학습할 필요가 없다.
예를 들어, 새로운 유저가 추가되어도 Item tower는 그대로 사용 가능하다.
2. 입력 feature의 유연성 및 확장성
각 타워에는 서로 다른 종류의 feature를 인풋으로 넣을 수 있고, feature를 자유롭게 추가/제거할 수 있다.
결국 각 타워의 최종 output은 차원이 같은 고차원 벡터이기 때문이다.
3. 빠른 추천 속도
Item Tower의 출력은 사전에 계산하여 저장해두기 때문에, User Tower의 인풋만 들어오면 빠르게 처리하여 유사도를 계산할 수 있다.
이 모델은 User Tower와 Item Tower 두 개로 나뉜다.
User Tower는 A씨의 대한 정보를, Item Tower는 매장에 대한 정보를 각각 고차원 벡터값으로 변환한다.
그리고 이 두 벡터가 얼마나 가까운지(유사도)를 계산하여 A씨가 특정 식당을 좋아할 확률을 예측하는 방식이다.
이 구조를 통해 A씨의 정보와 많은 식당들의 정보를 효율적으로 처리할 수 있다.
이제 각 타워에 어떤 정보를 넣어야 A씨의 취향과 패턴에 맞는 추천을 잘 할 수 있을지 고민해보아야 한다.
설계 1. (폐기)
첫 번째 설계는 A씨가 쓴 리뷰의 내용에 집중하였다.
- User Tower: A씨의 ID, 식당 방문 시간
- Item Tower: 식당의 ID, content_vector (A씨가 남긴 리뷰를 벡터화한 값)
- 로직: A씨가 남긴 리뷰의 벡터와 유사한 내용을 가진 다른 식당을 추천하고, A씨가 부정적 리뷰를 남긴 곳은 추후 제외한다.
하지만 이 설계에는 결함이 존재했다.
아래 사례를 통해 살펴보자.
만약 A씨가 파스타가게 X에 방문 후, 아래와 같이 부정적 리뷰를 남겼다고 생각해보자.
"오일 파스타를 시켰는데, 면이 너무 불어있었고 해산물에 비린내가 났어요."
이 모델은 "오일 파스타", "해산물"이라는 키워드를 학습한다.
그리고, 다른 식당들의 정보에서 "오일 파스타", "해산물"이라는 단어가 자주 언급되는 식당 Y를 A씨에게 추천해준다.
모델은 'A씨가 해산물 오일 파스타를 싫어한다'는 취향을 이해(학습)하지 못하고, 언급했다는 사실에 집중해 좋지 않은 추천을 한 것이다.
(content_vector는 의미를 내포하지 않고, 리뷰 자체를 벡터화한 값에 불과하기 때문이다)
설계 2. (채택)
설계 1의 결함을 해결하고자, 모델이 A씨의 선호 자체를 배우도록 학습 방식을 변경했다.
- User Tower: A씨의 ID, time_features(방문 시간을 요일, 주말 여부 등 세부 feature로 세분화한 것)
- Item Tower: 식당의 ID, Category
- 로직: 리뷰의 '내용'이 아닌 '긍정/부정' 여부를 정답(Label)으로 사용하여 학습한다.
만약 A씨가 평일 점심시간에 쌀국수집 Z에 방문 후, 아래와 같이 긍정적 리뷰를 남겼다고 생각해보자.
"국물이 엄청 진하고 맛있어요!"
이 모델은 아래와 같은 과정으로 학습과 추천을 진행할 것으로 예상된다.
- 모델이 이 리뷰가 '긍정'이라는 라벨을 확인한다.
- '점심시간의 A씨'를 나타내는 사용자 벡터와, '아시안/면요리' 카테고리에 속하는 'Z 쌀국수집'의 아이템 벡터를 서로 가깝게 만들도록 학습한다.
- 이제 모델은 "A씨는 점심시간에 아시안 또는 면요리 종류를 좋아하는구나!" 라는 A씨의 취향과 행동 패턴을 학습하게 된다.
- 다음번에 A씨가 점심시간에 맛집을 찾을 때, 모델은 쌀국수집 Z와 벡터 공간에서 가장 유사도가 높은 다른 맛있는 쌀국수집이나 라멘집 등을 추천해준다.
이 과정은 초기 목표였던 "사용자의 취향과 패턴에 따른 맞춤 추천 기능"에 부합하게 된다.
개발 계획
채택한 설계 2를 바탕으로한 아래와 같이 딥러닝 모델의 개발 순서를 계획하였다.
0. 모델 선정 및 설계 (현재)
1. 데이터 전처리
- 개발 환경 구축
- 세부 시간 feature 생성
- KcELECTRA(예정)를 이용한 선호 여부 라벨링
- 학습 데이터, 테스트 데이터 분할 및 저장
2. 모델 구조 설계 및 구현
- 데이터 파이프라인 구축
- User Tower, Item Tower 클래스 구현
3. 모델 학습 및 평가
- 모델 컴파일 및 학습
- 테스트 데이터셋을 이용한 성능 평가
4. 배포 준비 (Item Vector 사전 계산)
- 학습된 Item Tower를 이용해 모든 가게의 벡터 생성
- FAISS 인덱스 구축 및 저장
5. 실시간 추천 API 구현
- 서버 구성
- 모델 및 FAISS 인덱스 로드
- API 엔드포인트 생성
6. API 로직 완성 및 최종 테스트
- User Vector 생성 → FAISS 검색 → 결과 반환 로직 구현
- 통합 테스트