[논문 리뷰] Neural Graph Collaborative Filtering

정준환·2022년 11월 20일
0

논문리뷰

목록 보기
5/5

흐름과 이해를 위주로 정리해 논문과 비교하여 빠진 내용이 있을 수 있습니다.

등장 배경


Collaborative Filtering을 활용한 여러가지 추천 방법들이 존재한다. kNN 기법을 활용한 user 혹은 item based CF, Matrix Factorization, Neural Collaborative Filtering 등등...

CF에서의 핵심은 아래 두가지다.

  • 나와 비슷한 사람이 좋아하는 아이템을 추천
  • 내가 좋아한 아이템과 비슷한 아이템 추천

user, item간의 유사도를 측정하는 것이 핵심이라고 할 수 있고, MF 계열의 모델은 이를 나름대로 수행해왔다.

위 그림은 대략적으로 Factorization 계열 모델을 설명한다. 물론 context를 반영할 수도 있고, inner product가 아닌 NCF와 같이 neural network의 구조를 사용할 수도 있지만, 아주 기본적인 모델을 예시로 들었다.

앞서 말했듯이, user, item간의 유사도를 학습하는 것이 핵심이다. 그런데 위 그림에서 알 수 있듯 이를 반영하는 부분이 model에 나타나있지 않다. 즉, 기존의 모델들은 이러한 관계를 직접적으로 학습하지는 않고, y~\tilde yyy의 차이를 이용해 간접적으로 학습하게 된다.

논문에서 발췌한 그림이다. 왼쪽 그림에서 u1u_1을 기준으로 생각하면 오른쪽과 같은 그래프를 만들 수 있다. i1,i2,i3i_1, i_2, i_3과 직접적으로 연결되어있고, i2,i3i_2, i_3을 구매한 u2,u3u_2, u_3와는 한단계 건너 연결되어 있다. 이런 상황에서 i4,i5i_4, i_5 중 하나를 u1u_1에게 추천해야 한다면, i4 or 5u1i_{4 \text{ or } 5} \rarr u_1 를 나타내는 경로는 아래와 같다.

  • i4i_4: (i4u2i2u1i_4 \rarr u_2 \rarr i_2 \rarr u_1), (i4u3i3u1i_4 \rarr u_3 \rarr i_3 \rarr u_1)
  • i5i_5: (i5u2i2u1i_5 \rarr u_2 \rarr i_2 \rarr u_1)

rating과 같은 요소들을 무시한다면, 경로가 더 많은 i4i_4를 추천하는 것이 좀 더 reasonable하다. 이 때 주의해야 할 사항이 두가지 있다.

  1. 너무 멀리 떨어진 경우까지 고려하면 오히려 정확도가 떨어질 수 있다.
  2. 가까운 요소의 중요도가 멀리 떨어진 요소의 중요도보다 더 크다.

해당 내용을 단지 y~\tilde yyy의 차이만을 이용해 간접적으로 embedding에 반영하던 기존 모델들과 달리 NGCF는 위의 설명한 내용을 embedding 과정에서 직접적으로 학습하는 방법을 제시한다.

Neural Graph Collaborative Filtering


시작하기에 앞서 몇가지 용어를 정리하고 넘어가자.

  • layer는 얼마나 멀리 떨어진 node까지 embedding에 반영할 것인지를 의미한다.
  • message 라는 개념이 등장한다. mui\bold m_{u \larr i} 처럼 쓰는데, 말 그대로 iiuu에 전달한 메세지, 정보 정도로 이해하면 된다.

이제 출발 할 준비가 끝났다. NGCF는 어떻게 상호작용을 embedding에 직접적으로 반영할 수 있는 것 일까? 간단한 예시를 위해 layer가 한개인 경우를 먼저 보자.

message부터 시작한다. message는 아래와 같이 정의된다.

mui=f(ei,eu,pui)(1)\bold m_{u \larr i} = f(\bold e_i, \bold e_u, p_{ui}) \tag{1}

어떤 아이템 ii가 어떤 유저 uu에게 전달하는 message는 각각의 embedding ei,eu\bold e_i, \bold e_u와 decay puip_{ui}에 대한 ff라는 함수인 것이다. NGCF에서는 이를 아래와 같이 정의했다.

mui=1NuNi(W1ei+W2(eieu))(2)\bold m_{u \larr i} = \frac{1}{\sqrt{|\mathcal N_u| |\mathcal N_i|}} \left(\bold W_1 \bold e_i + \bold W_2 (\bold e_i \odot \bold e_u) \right) \tag{2}

식에서 Nu,Ni\mathcal {N_u, N_i} 는 각각 u,iu, i의 neighbor다. (Figure 1에서 u1u_1의 neighbor는 i1,i2,i3i_1, i_2, i_3 이다.) 즉, iiuu에 주는 message는 아이템 그 자체에 대한 정보(W1ei\bold W_1 \bold e_i)와 해당 아이템 ii와 유저 uu의 상호작용 정보(W2(eieu))\left(\bold W_2 (\bold e_i \odot \bold e_u) \right) 의 합에 어느정도의 decay (1/NuNi)\left(1/\sqrt{|\mathcal N_u| |\mathcal N_i|}\right) 를 주었다고 해석할 수 있다.

Figure 1에서 u1u_1i1,i2,i3i_1, i_2, i_3 3개의 아이템과의 상호작용을 이루었듯이, 하나의 mui\bold m_{u \larr i} 로는 임베딩을 설명하기 힘들다. 따라서 해당 유저와 연결된 모든 아이템, 즉 Nu\mathcal {N_u}에 포함된 모든 ii에 대해 mui\bold m_{u \larr i} 를 계산해준다. 이에 추가적으로 자기 자신에 대한 정보인 muu\bold m_{u \larr u}를 고려하여 다음 단계의 user embedding을 생성한다. 식으로 써보면 아래와 같다.

eu(1)=LeakyReLU(muu+iNumui)(3)\bold e_u ^{(1)} = \text{LeakyReLU}\left(\bold m_{u \larr u} + \sum_{i \in \mathcal {N_u}} \bold m_{u \larr i} \right) \tag{3}

즉, 이러한 과정을 거쳐 생성된 user embedding eu(1)\bold e_u ^{(1)} 은 기존의 user embedding eu\bold e_u 와는 다르게, Nu\mathcal {N_u}에 포함된 ii들과의 상호작용이 반영되어 있음을 알 수 있다. 마찬가지 방법으로 item embedding ei(1)\bold e_i ^{(1)} 를 만들 수 있을 것이고, 이는 기존의 item embedding ei\bold e_i와는 다르게, Ni\mathcal {N_i}에 포함된 uu들과의 상호작용이 반영 될 것이다.

이제 이 과정을 ll개의 layer에 대해서 일반화해보자. 아무런 layer를 거치지 않은 기본 embedding, 우리가 MF, NCF와 같은 모델에서 사용하는 embedding을 0개의 layer를 거쳤다고 해서, eu(0),ei(0)\bold e_u ^{(0)}, \bold e_i ^{(0)} 라고 할 수 있다. l0l \neq 0인 경우에 대한 eu(l),ei(l)\bold e_u ^{(l)}, \bold e_i ^{(l)}은 식 (2), (3)을 이용해 쉽게 얻을 수 있다.

{mui(l)=1NuNi(W1(l)ei(l1)+W2(l)(ei(l1)eu(l1)))muu(l)=W1(l)eu(l1)(4)\begin{cases} \bold m_{u \larr i}^{(l)} &= \frac{1}{\sqrt{|\mathcal N_u| |\mathcal N_i|}} \left(\bold W_1^{(l)} \bold e_i^{(l-1)} + \bold W_2^{(l)} (\bold e_i^{(l-1)} \odot \bold e_u^{(l-1)}) \right) \\ \bold m_{u \larr u}^{(l)} &= \bold W_1^{(l)} \bold e_u^{(l-1)} \end{cases} \tag{4}
eu(l)=LeakyReLU(muu(l)+iNumui(l))(5)\bold e_u ^{(l)} = \text{LeakyReLU}\left(\bold m_{u \larr u}^{(l)} + \sum_{i \in \mathcal {N_u}} \bold m_{u \larr i}^{(l)} \right) \tag{5}

위의 식 (4), (5)를 통해 이제 우리는 ll개의 layer를 통과한 경우에 대한 user, item embedding을 구할 수 있다. 이후 0번째 부터 LL번째 까지의 임베딩을 모두 concatenate한 후, 내적을 이용하여 최종적으로 y^NGCF\hat y_{\text{NGCF}}를 계산한다. 수식으로 써보자면 아래와 같다.

eu=eu(0)eu(L),ei=ei(0)ei(L)(6)\bold e_u^* = \bold e_u^{(0)} \| \cdots \| \bold e_u^{(L)}, \qquad \bold e_i^* =\bold e_i^{(0)}\| \cdots \| \bold e_i^{(L)} \tag{6}
y^NGCF(u,i)=euei(7)\hat y_{\text{NGCF}} (u, i) = {\bold e_u^*}^\intercal \bold e _i^* \tag{7}

위의 Figure 2는 해당 과정을 그림으로 잘 나타낸 것이다. Figure 1의 예시와 함께 보도록 하자.

eu1(0)\bold{e_{u_1}^{(0)}}은 일반적인 방법으로 만드는 벡터다. layer를 한번 거쳐서 나온 각각의 embedding들에 대해서

  • eu1(1)\bold{e_{u_1}^{(1)}}i1,i2,i3i_1, i_2, i_3과의 interaction을,
  • eu2(1)\bold{e_{u_2}^{(1)}}i2,i5i_2, i_5과의 interaction을,
  • eu3(1)\bold{e_{u_3}^{(1)}}i3,i4i_3, i_4과의 interaction을,

담고 있을 것이다. 마찬가지로 item에 대해서도

  • ei1(1)\bold{e_{i_1}^{(1)}}u1u_1과의 interaction을,
  • ei2(1)\bold{e_{i_2}^{(1)}}u1,u2u_1, u_2과의 interaction을,

담고 있을 것이다. (다 적지는 않았지만 i3,i4,i5i_3, i_4, i_5에 대해서도 동일하다.)

그렇다면 layer를 두번 통과한 경우를 살펴보자. eu1(2)\bold{e_{u_1}^{(2)}}eu1(1),ei1(1),ei2(1),ei3(1)\bold{e_{u_1}^{(1)}}, \bold{e_{i_1}^{(1)}}, \bold{e_{i_2}^{(1)}}, \bold{e_{i_3}^{(1)}}를 조합하여 만들어지는 벡터다. 이 때, 각각의 eu(1)\bold{e_u^{(1)}} 또는 ei(1)\bold{e_i^{(1)}}에서 직접적으로 연결된 상호작용을 학습했기 때문에, 이번 경우에는 한 칸 떨어진 상호작용 까지 반영이 가능해진다. 예를 들어 ei2(1)\bold{e_{i_2}^{(1)}}에는 i2i_2u1,u2u_1, u_2에 대한 상호작용 정보가 이미 반영되어있다. 즉, eu1(2)\bold{e_{u_1}^{(2)}}ei2(1)\bold{e_{i_2}^{(1)}}를 이용하여 한 칸 떨어진 u2u_2의 정보까지 반영이 가능해진 것이다. 이를 일반화하면 layer가 늘어날수록, 더 멀리 떨어진 node와의 상호작용을 embedding에 반영할 수 있게된다. 마치 CNN에서 layer를 거칠수록, 멀리 있는 점의 정보를 가져오는 것과 비슷한 맥락이다.

결론


상호작용을 간접적으로 학습하던 기존의 MF계열과 달리, embedding 단에서 직접 학습하다보니, 성능이 뛰어남을 확인할 수 있다. 심지어 마치 CV 분야에서 CNN이 공유된 parameter를 사용하여 parameter 수를 줄인 것처럼, 복잡해보임에도 불구하고 parameter 수는 많이 늘어나지는 않는다. (늘어나긴 한다.)

추후 시간이 난다면 pytorch를 이용한 구현을 포스팅 할 계획이다.

profile
정준환

0개의 댓글