Max Margin Loss with Low Rank Positives (우버)

HanJu Han·2025년 10월 14일

목표: 모델에게 '취향의 순서'를 가르치기

이 손실 함수의 최종 목표는 간단합니다. 모델이 사용자의 상품 선호도를 점수로 예측할 때, "당연히 더 좋아할 상품"의 점수를 "덜 좋아할 상품"이나 "싫어할 상품"의 점수보다 '충분한 격차'를 두고 더 높게 예측하도록 훈련시키는 것입니다.


Step 1. 상황 설정: 이커머스 쇼핑몰 데이터

온라인 패션 쇼핑몰 '스타일허브'의 한 사용자, '김민준' 님의 구매 기록을 예시로 들어보겠습니다.

  • 사용자(User): 김민준
  • 상품 데이터:
    • Positive (긍정): '나이키 에어포스' (5회 구매)
      • 김민준 님이 확실하게 선호하는 상품입니다.
    • Low Rank Positive (낮은 순위 긍정): '무지 반팔티' (1회 구매)
      • 구매한 적은 있지만, '나이키 에어포스'만큼 자주 찾지는 않았습니다. 선호도가 있긴 하지만 상대적으로 낮습니다.
    • Negative (부정): '등산용 스틱' (구매 이력 없음)
      • 김민준 님은 이 상품에 전혀 관심이 없거나, 아직 발견하지 못했습니다.

Step 2. 데이터의 벡터화 (Embedding)

컴퓨터는 '나이키 에어포스'라는 텍스트를 직접 이해하지 못합니다. 따라서 우리는 사용자 '김민준'과 각 상품을 숫자로 이루어진 벡터(Vector)로 변환해야 합니다. 이 과정을 임베딩(Embedding)이라고 합니다.

모델이 학습을 통해 이 벡터 값들을 스스로 찾아내지만, 여기서는 설명을 위해 임의의 2차원 벡터 값을 가정해 보겠습니다.

  • 사용자 U (김민준): zu=[1.0,0.8]z_u = [1.0, 0.8]
  • Positive P (나이키 에어포스): zv=[0.9,0.7]z_v = [0.9, 0.7]
  • Low Rank Positive LRP (무지 반팔티): zl=[0.5,0.4]z_l = [0.5, 0.4]
  • Negative N (등산용 스틱): zn=[0.1,0.2]z_n = [0.1, -0.2]

직관적 이해: 벡터의 방향과 크기가 비슷할수록 '취향이 잘 맞는다'고 해석할 수 있습니다. 현재 김민준 님의 벡터는 '나이키 에어포스' 벡터와 가장 유사하고, '등산용 스틱'과는 가장 다릅니다.

Step 3. 손실 함수와 하이퍼파라미터 설정

이제 우리가 사용할 손실 함수를 다시 살펴보겠습니다.

L=αnmax(0,zuTzv+zuTzn+Δn)+αlmax(0,zuTzv+zuTzl+Δl)L = \alpha_n \max(0, -z_u^T z_v + z_u^T z_n + \Delta_n) + \alpha_l \max(0, -z_u^T z_v + z_u^T z_l + \Delta_l)

계산을 위해 우리가 직접 정해줘야 하는 값들(하이퍼파라미터)을 설정합니다.

  • Negative 마진 (Δn\Delta_n): 1.0 (Positive와 Negative의 점수 차이는 최소 1.0 이상 나야 한다)
  • LRP 마진 (Δl\Delta_l): 0.3 (Positive와 Low Rank Positive의 점수 차이는 최소 0.3 이상 나야 한다)
    • 핵심: Δl<Δn\Delta_l < \Delta_n 입니다. 즉, '전혀 관심 없는 상품'과의 격차를 '가끔 사는 상품'과의 격차보다 더 크게 만들도록 요구하는 것입니다.
  • 가중치 (αn,αl\alpha_n, \alpha_l): 계산의 편의를 위해 둘 다 1로 설정합니다.

Step 4. 단계별 손실(Loss) 계산

이제 위에서 설정한 값들을 수식에 하나씩 대입하여 손실 값을 계산해 보겠습니다.

Part 1: Negative 샘플과의 손실 계산

먼저 수식의 첫 번째 부분, 즉 Positive 샘플과 Negative 샘플 간의 순위를 제대로 매기고 있는지 확인합니다.

LNegative=max(0,zuTzv+zuTzn+Δn)L_{Negative} = \max(0, -z_u^T z_v + z_u^T z_n + \Delta_n)

1. 선호도 점수 계산 (벡터 내적)

  • 김민준 ❤️ 나이키 에어포스 (Positive 점수):
    zuTzv=(1.0×0.9)+(0.8×0.7)=0.9+0.56=1.46z_u^T z_v = (1.0 \times 0.9) + (0.8 \times 0.7) = 0.9 + 0.56 = \mathbf{1.46}
  • 김민준 ❤️ 등산용 스틱 (Negative 점수):
    zuTzn=(1.0×0.1)+(0.8×0.2)=0.10.16=0.06z_u^T z_n = (1.0 \times 0.1) + (0.8 \times -0.2) = 0.1 - 0.16 = \mathbf{-0.06}

2. 수식에 대입하여 손실 계산
LNegative=max(0,1.46+(0.06)+1.0)L_{Negative} = \max(0, -1.46 + (-0.06) + 1.0)
LNegative=max(0,0.52)L_{Negative} = \max(0, -0.52)
LNegative=0L_{Negative} = \mathbf{0}

3. 결과 해석
손실 값이 0이 나왔습니다. 이것은 "모델이 이미 잘하고 있다"는 의미입니다.
왜냐하면 Positive 점수(1.46)Negative 점수(-0.06) + 마진(1.0) 보다 크기 때문입니다.
(1.46>0.06+1.0    1.46>0.941.46 > -0.06 + 1.0 \implies 1.46 > 0.94)
모델은 이미 두 상품의 선호도 격차를 우리가 설정한 마진(1.0) 이상으로 벌려놓았기 때문에, 이 부분에 대해서는 페널티(손실)를 주지 않습니다.


Part 2: Low Rank Positive 샘플과의 손실 계산

이제 수식의 두 번째 부분, 즉 Positive 샘플과 Low Rank Positive 샘플 간의 미묘한 순위를 잘 맞추고 있는지 확인합니다.

LLRP=max(0,zuTzv+zuTzl+Δl)L_{LRP} = \max(0, -z_u^T z_v + z_u^T z_l + \Delta_l)

1. 선호도 점수 계산

  • 김민준 ❤️ 나이키 에어포스 (Positive 점수): (위에서 계산) 1.46\mathbf{1.46}
  • 김민준 ❤️ 무지 반팔티 (LRP 점수):
    zuTzl=(1.0×0.5)+(0.8×0.4)=0.5+0.32=0.82z_u^T z_l = (1.0 \times 0.5) + (0.8 \times 0.4) = 0.5 + 0.32 = \mathbf{0.82}

2. 수식에 대입하여 손실 계산
LLRP=max(0,1.46+0.82+0.3)L_{LRP} = \max(0, -1.46 + 0.82 + 0.3)
LLRP=max(0,0.34)L_{LRP} = \max(0, -0.34)
LLRP=0L_{LRP} = \mathbf{0}

3. 결과 해석
이 부분의 손실 값도 0이 나왔습니다.
Positive 점수(1.46)LRP 점수(0.82) + 마진(0.3) 보다 크기 때문입니다.
(1.46>0.82+0.3    1.46>1.121.46 > 0.82 + 0.3 \implies 1.46 > 1.12)
모델은 '나이키 에어포스'와 '무지 반팔티' 사이의 미묘한 선호도 차이도 우리가 설정한 마진(0.3) 이상으로 잘 구분하고 있습니다.

최종 손실:
L=(1×LNegative)+(1×LLRP)=0+0=0L = (1 \times L_{Negative}) + (1 \times L_{LRP}) = 0 + 0 = 0

이 경우, 모델은 이미 완벽하게 순위를 학습했으므로 벡터 값을 업데이트할 필요가 없습니다.


Step 5. 모델이 "틀렸을 때"는 어떻게 될까? (학습 과정)

만약 모델이 아직 학습이 덜 되어 벡터 값들이 아래와 같다고 가정해 봅시다. '무지 반팔티'의 벡터가 '나이키 에어포스'보다 김민준 님의 취향에 더 가깝게 잘못 설정된 상황입니다.

  • 사용자 U (김민준): zu=[1.0,0.8]z_u = [1.0, 0.8]
  • Positive P (나이키 에어포스): zv=[0.9,0.7]z_v = [0.9, 0.7]
  • Low Rank Positive LRP (무지 반팔티): zl=[0.8,0.9]z_l = \mathbf{[0.8, 0.9]} (수정된 값)
  • Negative N (등산용 스틱): zn=[0.1,0.2]z_n = [0.1, -0.2]

이때 손실을 다시 계산해 보겠습니다. (Part 1의 Negative 손실은 이전과 동일하게 0입니다.)

Part 2 (재계산): Low Rank Positive 샘플과의 손실

1. 선호도 점수 재계산

  • 김민준 ❤️ 나이키 에어포스 (Positive 점수): 1.46\mathbf{1.46}
  • 김민준 ❤️ 무지 반팔티 (LRP 점수):
    zuTzl=(1.0×0.8)+(0.8×0.9)=0.8+0.72=1.52z_u^T z_l = (1.0 \times 0.8) + (0.8 \times 0.9) = 0.8 + 0.72 = \mathbf{1.52}

    문제 발생! 모델이 LRP 상품('무지 반팔티')의 점수를 Positive 상품('나이키 에어포스')보다 더 높게 예측했습니다. 이것은 명백한 오류입니다.

2. 수식에 대입하여 손실 계산
LLRP=max(0,1.46+1.52+0.3)L_{LRP} = \max(0, -1.46 + 1.52 + 0.3)
LLRP=max(0,0.36)L_{LRP} = \max(0, 0.36)
LLRP=0.36L_{LRP} = \mathbf{0.36}

3. 결과 해석 및 학습 방향
드디어 0이 아닌 손실 값 0.36이 발생했습니다!

  • 최종 손실: L=(1×0)+(1×0.36)=0.36L = (1 \times 0) + (1 \times 0.36) = 0.36
  • 학습 신호: 이 0.36이라는 숫자는 모델에게 "너 지금 틀렸어! 이만큼의 오류가 있으니 수정해!"라고 알려주는 강력한 신호가 됩니다.
  • 업데이트 방향:
    • 모델은 이 손실을 줄이기 위해(0으로 만들기 위해) 벡터 값들을 조정합니다.
    • zuz_u (김민준)와 zvz_v (나이키) 벡터를 서로 더 가깝게 만들어 zuTzvz_u^T z_v 점수를 높입니다.
    • zuz_u (김민준)와 zlz_l (반팔티) 벡터를 서로 더 멀게 만들어 zuTzlz_u^T z_l 점수를 낮춥니다.

이 과정을 수많은 사용자-상품 데이터에 대해 반복하면서, 모델은 점차 모든 상품에 대한 사용자의 상대적인 선호도 순위를 정확하게 예측하는 능력을 갖추게 됩니다. 이것이 바로 Max Margin Loss가 추천 시스템의 성능을 향상시키는 핵심 원리입니다.

profile
시리즈를 기반으로 작성하였습니다.

0개의 댓글