본문 바로가기
추천 시스템 논문

LightGCN 논문 리뷰

by 블쭌 2021. 3. 29.
728x90
  • Abstract

협업필터링에 대해서 GCN은 최신 알고리즘이다. 그러나 추천에 대해서 GCN의 경우 이유를 납득할만하지 못했고 해당 논문에서 GCN의 2가지 특징, feature transformation과 nonlinear activation들이 협업필터링 성능에 크게 기여하지 않는다는것을 확인했다. 더 최악인것은 이들을 추가했을 경우 학습이 더 어려워지고 추천 성능은 더 떨어졌다.

 

해당 논문에서는 GCN을 간소화해서 간결하고 정확한 LightGCN모델을 제안했다. 특히 LightGCN은 user-item interaction graph에서 선형적으로 전파하면서 user, item Embedding을 학습시켰고 모든 레이어에서 학습 된 임베딩의 가중치 합을 최종 임베딩으로 사용했다.


  • Introduction

NGCF와 동일한 train/test split, evaluation 상황에서 실험해본 결과, featur-transformation과 nonlinear activation은 오히려 모델을 복잡하게 만들었고 추가하니 오히려 성능이 더 떨어졌다. 결국 neighborhood aggregation이라는 가장 중요한 요소를 찾아냈다. 


  • Light GCN

먼저 GCN의 기본 아이디어는 노드에 대한 표현을 graph에서 feature들을 smoothing을 통해 나타내는 것이다.

target node의 표현을 해당 node의 neighborhood feature들을 모을수있고 아래와 같이 식으로 표현이 가능하다.

k+1번째 target node의 표현은 k번째 user의 embedding과 그 user의 이웃 item을 aggregate하는것이라고 생각하면 될 것 같다.


LightGCN의 도식화이다. 기존 NGCF에서 간략하게 만들어서 왼쪽 user embedding과 오른쪽 item embedding에서 layer를 거칠때마다 단순 Normalized sum만 다음 layer로 넘어가게 된다. 기존의 다른 feature transformation이나 non-linear activation은 다 제거했다.


위의 식은 LightGCN에서 propogation rule이다. N_u와 N_i 각각 루트를 씌우고 역수를 취한 normalization term은 동일하고 이는 graph convolution 연산이 증가함에따라 embedding의 scale이 커지는것을 막아주는 역할이다. 여기에 L1-norm과 같은것을 적용해도 괜찮으나 gcn에서 사용된 normalization term을 사용했을 때 실험적으로 성능이 좋다고 한다. 또한 위에서말한 합(시그마)만 다음 레이어로 넘어가는것을 볼 수 있다.


또한 LGC에서 가장 주목할만한것은 단지 연결된 이웃노드만 사용했고 타겟노드 그 자체는 사용하지 않았기 때문에 self-connection이 필요없다


LGC 모델에서 학습되는 파라미터는 0번째 레이어이다. 모든 user에 대한 0번째 embedding과 모든 item에 대한 0번째 embedding이 학습되는 파라미터일 뿐이다. 왜냐하면 그 다음 레이어는 바로 위의 propagation rule에 의해서 전파되기 때문이다. 계속 전파가 이루어지고 K번째 이후에 각 layer마다 얻어진 embedding을 결합해서 최종 user, item embedding을 생성한다. 생각해보면 확실히 학습하는 parameter도 적기 때문에 학습도 빠르고 실험적으로 성능도 좋다고하니 정말 말그대로 Light하면서 최고의 모델인것같다.

 

a_k는 흔히 말하는 parameter로 분석가가 직접 설정하는것이다. 해당 논문에서는 1/(K+1)의 값으로 설정했을때가 가장 좋았다고 말했다. 또한 Light라는 모델이름과 지금까지 논문에서 설명한것과 마찬가지로 복잡해지기 싫었기 때문에 해당 파라미터의 값을 최적화하는 불필요한 작업은 진행하지 않았다. 

 

self.user_embedding = nn.Embedding(self.num_users, self.emb_dim)
self.item_embedding = nn.Embedding(self.num_items, self.emb_dim)
nn.init.normal_(self.user_embedding.weight, 0, 0.01)
nn.init.normal_(self.item_embedding.weight, 0, 0.01)

 

self.user_embedding = nn.Embedding(self.num_users, self.emb_dim)
self.item_embedding = nn.Embedding(self.num_items, self.emb_dim)
nn.init.normal_(self.user_embedding.weight, 0, 0.01)
nn.init.normal_(self.item_embedding.weight, 0, 0.01)

self.weight_dict = nn.ParameterDict()
layers = [self.emb_dim] * (self.num_layers + 1)
for k in range(len(layers) - 1):
self.weight_dict.update(
{'W_gc_%d' % k: nn.Parameter(nn.init.normal_(torch.empty(layers[k], layers[k + 1])))})
self.weight_dict.update({'b_gc_%d' % k: nn.Parameter(nn.init.normal_(torch.empty(1, layers[k + 1])))})

self.weight_dict.update(
{'W_bi_%d' % k: nn.Parameter(nn.init.normal_(torch.empty(layers[k], layers[k + 1])))})
self.weight_dict.update({'b_bi_%d' % k: nn.Parameter(nn.init.normal_(torch.empty(1, layers[k + 1])))})

위에는 LightGCN의 가중치 초기화이고 밑에는 NGCF의 가중치 초기화 코드이다. 확실히 LightGCN이 가볍고 학습되는 파라미터는 0번째 레이어인지 이해 할 수 있다.


마지막 embedding을 표현하기 위해서 layer 결합을 진행한 이유는 다음과 같다.

(1) layer가 많이 쌓일수록 embeddings들은 점차 과부화되기 때문에 단순히 마지막 layer를 사용하는것은 문제가있다. 

 

(2) 각각의 층의 embedding은 다른 점을 포착하기 때문이다. 예를들어, 첫번째 layer는 상호작용하는 user와 item의 smooth를 도와준다. 두번째 layer는 중복되는 item을 가지고 있는 user를 smooth하게 해주고 세번째 층은 더 높은 고차원의 특징을 파악한다. 이처럼 이들을 결합하는것은 더 포괄적인 표현이 가능하다는 것이다.

 

(3) 서로 다른 계층의 임베딩을 가중 합과 결합하면 그래프 컨볼루션과 자체 연결의 효과를 포착할 수 있다.


모델 예측은 위와 같이 final user와 final item의 내적으로 정의된다. 이는 또한 추천 생성에 대해서 score ranking하는데 사용된다. 

u_embedding, i_embedding = self.lightgcn_embedding(self.Graph)

user_latent = F.embedding(user, u_embedding)
pos_latent = F.embedding(pos, i_embedding)

pos_score = torch.mul(user_latent, pos_latent).sum(1)

자세한 코드는 아래 깃헙을 참고해주세요~

 

github.com/bladejun/Recommend_System_Pytorch

 

 

bladejun/Recommend_System_Pytorch

Recommend System Model by Pytorch. Contribute to bladejun/Recommend_System_Pytorch development by creating an account on GitHub.

github.com

728x90

댓글