← 목록으로

‘로컬’ 슈퍼 앱에서 장기 유저 모델링은 어떻게 달라질까?

‘로컬’ 슈퍼 앱에서 장기 유저 모델링은 어떻게 달라질까?

요약

안녕하세요! 당근 ML Foundation 팀에서 ML Engineer로 일하고 있는 Hawke와 Ben.Kim이에요. 저희 팀은 개인화 추천 개선을 위한 “기반 기술”을 만드는 역할을 하고 있어요. 이 글에서는 유저의 장기 행동 로그를 Transformer로 학습해 유저 임베딩을 만들고, 홈피드·광고 등 다양한 추천 모델에 적용해 큰 폭의 온라인 지표 개선을 달성한 여정을 공유하려고 해요.

왜 장기 유저 모델링이 필요할까?

추천 시스템에서 “유저가 지금 무엇을 원하는지”는 최근 행동에서 잘 드러나요. 하지만 서비스를 운영하다 보면 최근 행동만으로는 답하기 어려운 질문들을 계속 마주치게 돼요.

1. 단기 히스토리에 담기지 않는 지속 취향과 반복 관심사는 어떻게 반영할까요?

매 겨울 패딩이나 방한용품을 반복해서 검색하는 유저, 이사철마다 부동산 매물을 탐색하는 유저가 있어요. 최근 로그만으로는 이런 패턴이 드러나지 않아요.

2. 여러 버티컬을 넘나드는 유저의 관심사는 어떻게 파악할까요?

부동산에서 매물을 탐색하는 유저가 중고거래에서 가구·가전을 검색하고, 동네생활에서 이사 후기를 찾는 경우가 있어요. 하나의 관심사가 장기간에 걸쳐 여러 버티컬에 나타나는데, 일부 지면의 최근 데이터만 사용하면 이런 연결을 잡기 어려워요.

3. 추천이 만든 노출 로그만 학습하면 생기는 selection bias를 장기 관점에서 완화할 수 있을까요?

짧은 기간의 로그만 학습하면 “모델이 보여준 것만 다시 학습하는” 순환에 빠질 수 있어요. 장기 로그를 활용하면 여러 세대의 모델과 다양한 맥락에서 발생한 액션을 함께 보게 되어 이 순환을 완화할 여지가 있어요.

하지만 추천 모델에 히스토리를 더 길게 넣으면 단순히 해결되는 문제가 아니에요. 예를 들어, 랭킹 모델은 지연(latency)에 민감해 실시간 입력을 무한정 늘리기 어렵고, 히스토리를 길게 가져갈수록 계산량과 인프라 복잡도가 급격히 커져요. 결국 긴 기간의 데이터를 넣는 것 + 잘 배울 수 있도록 설계하는 것 + 서빙할 수 있게 만드는 것, 이 세 가지를 함께 풀어야 하는 문제예요.

Pinterest, Meta, ByteDance 등에서도 장기 히스토리 활용이 추천 성능에 큰 개선을 준 사례가 이미 보고되고 있었어요. 저희도 이 방향으로 가보기로 했어요.

우리가 택한 방향: 장기 유저 임베딩을 ‘공통 피처’로 만들자

저희가 선택한 접근 방식은 이래요. 장기 히스토리는 별도의 user encoder가 오프라인에서 학습하고 추론하고, 다운스트림 모델(홈피드 랭킹, 후보 모델, 광고 랭킹)은 이를 “공통 유저 피처”로 받아 쓰는 구조예요.

이 방식의 장점은 세 가지예요.

  1. 다운스트림 모델은 장기 히스토리를 직접 들고 있지 않아도 돼요. 지연과 복잡도를 관리하기 쉬워요.
  2. User encoder는 데이터와 컴퓨팅 스케일을 독립적으로 키울 수 있어요. 다운스트림 모델을 건드리지 않고 user encoder만 스케일업하거나 실험할 수 있어서 실험 속도가 빨라지고, 모델 크기와 학습 데이터를 자유롭게 확장할 수 있어요.
  3. 한 번 만든 임베딩을 여러 지면에서 재사용할 수 있어요. 홈피드, 후보 모델, 광고 등 다양한 곳에서 동일한 유저 임베딩을 사용해요.

물론 이 구조에도 한계가 있어요.

  1. user encoder는 수백억 건의 로그와 큰 Transformer로 학습되어 다운스트림 모델보다 훨씬 풍부한 표현력을 가지고 있지만, 다운스트림 모델은 이를 고정된 하나의 피처 벡터로만 받아쓰기 때문에 그 표현력이 충분히 전달되지 못해요.
  2. 오프라인 배치 추론 방식이기 때문에 유저의 최신 행동이 즉시 임베딩에 반영되지 않는 신선도(freshness) 문제가 있어요.

유저 임베딩 추론 주기를 줄여 실시간에 가까운 갱신을 하거나, 다운스트림 태스크에 대한 fine-tuning과 distillation으로 user encoder의 표현력을 더 끌어다 쓰는 것 등 이런 한계를 극복하기 위한 시도들은 앞으로의 과제로 남겨두고 있어요.

User Modeling with Contrastive Learning

이제 유저 임베딩을 만들기 위해 저희가 사용한 user encoder 구조를 소개할게요. 모델 구조는 잘 알려진 two-tower 구조를 사용했어요.

  • User Tower: 유저의 액션 시퀀스를 Causal Transformer에 통과시켜 유저 임베딩을 생성해요.
  • Item Tower: 아이템 피처들을 MLP에 통과시켜 아이템 임베딩을 생성해요.
  • 학습: 유저 임베딩과 다음 액션 아이템 임베딩 사이의 InfoNCE loss (contrastive learning)로 학습해요.

LLM이 다음 토큰을 예측하며 언어를 배우듯, 이 모델은 유저의 다음 액션을 예측하며 유저의 취향을 배워요. 유저 시퀀스의 매 시점에서 “이 유저가 다음에 어떤 아이템과 상호 작용을 할까?”를 예측하도록 하고, 배치 내 다른 아이템들은 negative로 사용하는 in-batch negative 방식이에요.

학습 데이터로는 중고거래·알바·부동산·중고차 등 여러 버티컬에서 발생한 클릭, 전환(관심, 채팅 지원 등) 액션을 모두 사용했어요. 기존 추천 모델들이 일부 지면의 짧은 기간 데이터만 사용한 것에 비해, 저희 모델은 모든 버티컬·모든 지면의 장기 데이터를 사용했다는 점이 큰 차이예요. 데이터 양 측면에서는 기존 홈피드 two-tower 후보 모델 대비 약 150배 많은 수백억 개의 유저 행동 로그로 학습했어요.

아이템을 어떻게 표현할 것인가: ID 임베딩 vs 콘텐츠 임베딩

장기 유저 모델링에서 아이템 표현 방식의 선택은 스케일과 서빙 전략을 좌우하는 중요한 결정이에요. 저희는 두 가지 접근을 모두 실험했어요.

Option A: Item ID 임베딩

Item ID를 주요 피처로 사용하는 방식을 먼저 검토했어요. ID 기반 피처는 추천 도메인에서 보편적으로 강력한 성능을 보여주거든요. 하지만 장기 유저 모델링에 적용하기에는 두 가지 한계가 있어요.

첫째, Cold item 문제예요. 학습이 끝난 후에 새로 생성된 아이템은 ID 임베딩이 없어요. 그래서 유저 임베딩을 학습 시점에 고정(frozen)해서 사용하거나 신규 아이템에 대응하기 위해서는 별도의 테크닉이 필요해요. 특히 아이템의 생애주기가 짧은 편인 중고거래 버티컬에서는 이 문제에 대응하기가 더 까다로워요.

둘째, GPU 메모리 제약이에요. 장기 데이터를 학습하면 수억 개 이상의 아이템 ID가 필요한데, 이 임베딩 테이블이 GPU 메모리의 대부분을 차지해요. 그 결과 Transformer 자체의 크기를 키우기 어려웠어요. ID 기반 모델의 경우 전체 파라미터의 99% 이상을 임베딩 테이블이 차지하고, Transformer는 1%도 되지 않았죠. Compositional Embedding이나 Unified Embedding과 같은 hash trick을 사용하면 gpu 메모리 사용량을 줄일 수 있었으나, 성능 문제로 채택되지 못하는 경우도 있었어요. 이런 한계를 극복하기 위한 GPU Embedding table sharding 등의 시도를 과제로 남겨두고 있어요.

Option B: 콘텐츠 임베딩

이런 한계 때문에 저희는 별도의 LLM 기반 임베딩 모델이 게시글의 메타 데이터로부터 만들어낸 콘텐츠 임베딩을 아이템 피처로 사용하는 방식으로 전환했어요.

콘텐츠 임베딩을 사용하면 두 가지 문제가 한꺼번에 해결돼요.

  • Cold item 표현 개선: 새 아이템도 메타 데이터만 있으면 임베딩을 만들 수 있으므로, LLM 기반 임베딩 모델이 충분히 강력하다면, 유저 임베딩을 정보 손실 없이 주기적으로 갱신할 수 있어요.
  • GPU 메모리 확보: 임베딩 테이블이 필요 없으므로 GPU 메모리를 Transformer 스케일업에 온전히 사용할 수 있어요. 실제로 Transformer 파라미터를 Item ID 임베딩 사용할 때 대비 1,000배 키울 수 있었어요.

다만 쉽지만은 않았어요. 콘텐츠 임베딩은 별도의 임베딩 모델로 미리 생성해 파일로 저장해두고, 학습 데이터의 각 example에는 아이템 ID가 들어있어요. 학습 시에 아이템 ID에 해당하는 콘텐츠 임베딩을 파일에서 찾아서 join 해야 하는데, 두 가지 메모리 문제가 있었어요. 수억 개 아이템의 임베딩 파일은 수백 GB에 달해 통째로 메모리에 올리기 어렵고, 아이템 ID로 파일 내 임베딩의 위치를 찾기 위한 매핑 역시 수억 건 규모라 Python dict 같은 자료구조로는 그것만으로도 수십 GB의 메모리를 차지했어요.

그래서 저희는 두 가지 방법을 조합해서 해결했어요.

  • memmap (Memory-Mapped File): 임베딩 파일 전체를 메모리에 올리지 않고, 필요한 부분만 디스크에서 읽어오는 방식이에요. 특히, DDP (분산학습) 시에는 여러 프로세스가 OS의 page cache를 공유할 수 있어서 효율적이었어요.
  • bbhash (Minimal Perfect Hash): 아이템 ID → 파일 내 위치 매핑에 사용했어요. bbhash는 키 하나당 약 3비트만 사용하는 해시 함수로, Python dict 대비 메모리를 약 97% 절감할 수 있었어요.

이 두 가지를 조합해 대규모 콘텐츠 임베딩을 머신의 물리 메모리 크기에 무관하게 학습에 활용할 수 있었고, 콘텐츠 임베딩 기반 장기 유저 모델을 현실적인 비용으로 학습할 수 있었어요.

지역 기반 서비스에서의 in-batch negatives

여기부터는 저희 프로젝트에서 가장 흥미로운 챌린지였어요. Contrastive learning에서 일반적으로 in-batch negatives를 사용하는데, 이것의 기본 가정은 “배치 내 다른 아이템 = 볼 수 있었는데 선택하지 않은 것”이에요. 하지만 당근은 지역 기반 서비스이기 때문에 이 가정이 깨져요.

Feasible Negative와 Impossible Negative

당근에서 거래의 86% 이상은 반경 5km 이내에서 발생해요. 유저는 자기 동네 근처의 게시글만 볼 수 있으니, 서울 강남의 유저가 부산의 중고 물품을 보는 건 불가능해요. 하지만 랜덤으로 배치를 구성하면, 배치에는 전국 각지의 유저와 아이템이 섞여 들어와요. 이때 배치 내 negative로 사용되는 아이템은 두 종류로 나뉘어요.

  • Feasible negatives: 유저가 “볼 수 있었는데” 선택하지 않은 아이템. 이것이 의미 있는 학습 신호예요.
  • Impossible negatives: 유저가 애초에 “볼 수 없는” 아이템. 플랫폼 정책에 의해 노출이 불가능한 것이지, 유저 취향과는 관련이 없어요.
당근에서의 노출 가능성을 나타낸 그림이에요. 유저 𝑢는 자신의 노출 범위(viewable cells) 안에 있는 아이템(𝑖₁, 𝑖₂, 𝑖₃)만 홈피드에서 볼 수 있어요. 노출 범위 밖의 아이템(빨간 점)은 유저에게 노출되지 않아요.

당근에서의 노출 가능성을 나타낸 그림이에요. 유저 𝑢는 자신의 노출 범위(viewable cells) 안에 있는 아이템(𝑖₁, 𝑖₂, 𝑖₃)만 홈피드에서 볼 수 있어요. 노출 범위 밖의 아이템(빨간 점)은 유저에게 노출되지 않아요.

문제는 랜덤 배치에서 약 98%가 impossible negatives였다는 점이에요. 모델이 학습하는 비교의 상당 부분이 “취향”이 아니라 “노출 불가능”을 구분하는 데 쓰이고 있었고, 그 결과 contrastive learning의 학습 신호가 크게 희석됐어요.

해결책: Region-Constrained Batch Sampling (RCBS)

해결 방법은 의외로 간단했어요. 모델이나 loss를 그대로 두고, 배치 구성 방식만 바꿨어요. 같은 지역의 유저끼리 배치를 묶으면 배치 내 아이템들이 서로 볼 수 있는 범위 안에 있게 되거든요.

기존 random batching과 Region-Constrained Batch Sampling(RCBS)을 비교한 그림이에요. 유저 𝑢에 대해 RCBS는 같은 지역의 유저들(파란 셀)로 미니배치를 구성해서, random batching 대비 impossible negatives(빨간 셀)를 크게 줄여줘요.

기존 random batching과 Region-Constrained Batch Sampling(RCBS)을 비교한 그림이에요. 유저 𝑢에 대해 RCBS는 같은 지역의 유저들(파란 셀)로 미니배치를 구성해서, random batching 대비 impossible negatives(빨간 셀)를 크게 줄여줘요.

유저의 지역 정보로 배치를 묶어주니, impossible negatives 비율이 98%에서 30%으로 줄었어요. 나머지 30%는 유저마다 노출 반경이 다르거나, 이사 등으로 과거에 다른 지역에서 활동한 기록이 있는 경우 등등에 해당해요.

단순히 impossible negatives를 줄인 것 외에 부가 효과도 있었어요. Feasible negatives는 “유저가 볼 수 있었는데 선택하지 않은” 아이템이기 때문에 impossible negatives보다 더 어려운(harder) negative 역할을 해요. 같은 동네의 비슷한 아이템들 사이에서 유저의 진짜 취향을 구분해야 하니까요. 실제로 RCBS 방식으로 평가했을 때 Random 평가보다 점수가 낮게 나왔는데, 이는 feasible negatives가 더 어려운 negative임을 보여줘요.

다른 방법이 아닌 batch sampling으로 해결한 이유?

가장 먼저 떠오르는 방법은 impossible negatives를 배치 내에서 mask out하는 거예요. 유저가 물리적으로 접근할 수 없는 아이템을 loss 계산에서 제외하는 방식이죠. 하지만 배치의 98%가 impossible negatives인 상황에서 이들을 모두 mask out하면 effective batch size가 극단적으로 작아져요. Contrastive learning에서 배치 사이즈는 성능에 직결되는 핵심 요소인데, 대부분의 negative를 날려버리면 학습 자체가 매우 비효율적이에요. 그래서 negative를 걸러내는 대신, 배치 구성 자체를 바꿔서 처음부터 feasible negatives가 많아지도록 하는 RCBS가 더 효율적인 해결책이었어요.

Hard negative mining도 생각해 봤지만, 한 유저의 hard negative가 다른 유저에게는 impossible negative가 될 수 있어요. 즉, 유저마다 feasibility를 고려해서 negative를 따로 mining해야 하는데, 이는 구현이 복잡하고 비용이 많이 들어요. 반면 RCBS는 같은 지역의 유저들로 배치를 구성하는 것만으로도 in-batch에서 harder negative가 자연스럽게 등장할 수 있기 때문에, 별도의 mining 없어도 비슷한 효과를 얻을 수 있는 더 간단한 방법이었어요.

랭킹·후보·광고에 적용하기

홈피드/광고 랭킹 모델에서 유저 임베딩의 효과를 실험하기 위해 단순히 유저 피처로 추가했어요. 유저 임베딩에 projection layer를 통과시킨 후 기존 피처들과 concat 하는 방식이에요. 장기 유저 모델링이 유저의 장기적인 취향 시그널을, 기존 랭킹 모델이 단기적인 실시간 시그널을 각각 담당하는 식으로 역할이 분리되기를 기대했어요.

홈피드/광고 후보(retrieval) 모델에는 여러 가지 방법을 시도했어요. 그중 성능이 가장 좋았던 건 랭킹 모델에서처럼 기존 모델에 유저 임베딩을 피처로 추가하는 것이 아닌, 유저 임베딩만으로 후보군을 제공하는 방법이었어요. 서로 다른 성질의 후보군이 추천의 다양성을 높여준 것으로 보여요.

유저 임베딩 갱신

콘텐츠 임베딩 기반 모델에서는 새 아이템에 대해서도 좋은 임베딩을 얻을 수 있으므로, 최적의 유저 임베딩 갱신 주기를 찾기 위한 실험을 했어요. 오프라인에서는 고정, 24시간 갱신, 12시간 갱신 간에 유의미한 차이가 보이지 않았지만, 온라인 A/B 테스트에서는 고정보다는 주기적 추론이, 주기적 추론에서는 추론 주기가 짧을수록 더 좋은 성능을 보였어요. 비용과 성능의 trade-off를 고려해 24시간 주기로 결정했어요.

또 갱신 주기 이내에 계산을 마치기 위해 추론 파이프라인은 beam pipeline으로 구현하여 GCP dataflow 위에서 GPU로 추론했어요. 또한, 전체 유저의 임베딩을 추론하는 대신, 갱신 주기 안에 액션을 해서 갱신이 필요한 유저의 임베딩만 추론하여 추론 비용과 시간을 최적화했어요.

유저 임베딩의 성능을 최대로 활용하려면 실시간 추론에 가까워져야 하기에, 이를 지원하는건 앞으로 풀어야 할 큰 엔지니어링 챌린지 중 하나예요.

실험 결과

오프라인 결과

유저 모델링 pretraining 단계에서 RCBS의 효과를 보기 위해서, random batch로 학습 시킨 모델 (Random-Train), 같은 coarse 지역 셀에 속한 유저들로 구성한 batch로 학습시킨 모델 (RCBS-Train(coarse)), 그리고 같은 fine 지역 셀에 속한 유저들로 구성한 batch로 학습시킨 모델 (RCBS-Train(fine)), 이렇게 세 가지 버전의 성능을 비교했어요.

그리고 feasible negatives가 실제로 harder negative인지를 확인하기 위해 평가도 두 가지 배치로 나눠서 진행했어요. 하나는 feasible negative의 비율이 낮은 random batch 에서의 Random-Eval Recall이고, 다른 하나는 feasible negative 비율이 높은 같은 fine 지역 셀에 속한 유저들로 구성한 batch 에서의 RCBS-Eval (fine) Recall이에요. 각 batch 에서의 impossible negative 비율도 함께 측정했어요.

유저 모델링 pretraining 오프라인 평가

실험 결과 RCBS를 설계할 때의 직관인, impossible negatives를 줄이면 contrastive learning 학습 신호의 질이 올라갈 것이다는 것을 확인할 수 있었어요. Impossible negative 비율이 낮을수록 Recall이 일관되게 높아졌고, RCSB-Train (fine)은 Random-Train 대비 Recall@10이 Random-Eval에서 +49%, RCBS-Eval (fine)에서 +70% 개선됐어요.

또한 같은 모델이라도 RCBS-Eval에서의 점수가 Random-Eval보다 항상 낮게 나왔는데, 이는 feasible negatives가 impossible negatives보다 harder negative라는 것을 실험적으로 보여줘요.

다운스트림 태스크에서도 RCBS-Train (fine) 유저 임베딩이 일관되게 더 좋은 성능을 보였어요. 홈피드 랭킹에서 Random-Train 유저 임베딩의 개선폭이 미미한 반면, RCBS-Train (fine) 유저 임베딩은 유의미한 개선을 가져왔다는 점이 인상적이에요. 똑같이 장기 유저 로그를 활용하더라도 어떻게 학습시켰냐에 따라 성능이 크게 차이 났어요.

다운스트림 태스크 오프라인 평가

온라인 A/B 테스트

오프라인 실험에서 가장 성능이 좋았던 RCBS-Train (fine) 유저 임베딩을 홈피드 및 광고 후보/랭킹에 적용한 온라인 실험을 했어요. 실험 결과 trade-off 없이 여러 지표가 함께 개선된 걸 관측했고, 그 결과 여러 차례의 배포까지 이어졌어요.

아래 표는 여러 차례의 A/B 테스트의 누적 지표 변화예요. 클릭과 노출뿐 아니라 DAV(Daily Active Viewers), 앱 체류시간, 광고 매출까지 전방위적으로 개선됐어요. 특히 중고거래 채팅, 체류시간, DAV는 깊은 연결이 늘었다는 의미여서 고무적인 결과였어요.

온라인 A/B 테스트 누적 지표 변화

마치며

이 프로젝트를 통해, 잘 알려진 방법을 그대로 가져다 쓰는 것이 아니라 서비스 도메인을 이해하고 그에 맞게 설계하는 것이 중요하다는 걸 다시 한번 느꼈어요. 유저 모델링 뿐만 아니라, 당근 각 팀의 ML 엔지니어들이 서비스 곳곳에서 이러한 설계에 많은 노력을 기울이고 있어요.

앞으로는 더 많은 지면과 버티컬로 확장하며 모델과 데이터 스케일을 키워나갈 예정이에요. 엔지니어링 측면에서는 유저 임베딩 추론 주기를 단축하고 추론 효율을 개선하는 것이 다음 과제예요.

이 글의 일러스트는 Irene 이 도와주셨어요. 감사해요!

당근에서는 추천, 검색, 광고 등 다양한 도메인에서 서비스 특성을 반영한 ML 설계, 대규모 데이터·학습·추론 파이프라인, large-scale 모델링 등 흥미로운 문제를 풀고 있어요. 이런 문제를 함께 풀어갈 ML Engineer를 찾고 있으니, 관심이 있다면 아래 채용 공고를 확인해 보세요!

👉️ 2026 당근 ML 직군 채용 바로가기

‘로컬’ 슈퍼 앱에서 장기 유저 모델링은 어떻게 달라질까? was originally published in 당근 테크 블로그 on Medium, where people are continuing the conversation by highlighting and responding to this story.

← 목록으로