Lecture 6

Graph Neural Networks 1 - GNN Model
LEC06
Author

mhkim9714

Published

July 27, 2022

6.1 Introduction to Graph Neural Networks

Recap: Shallow Encoders

이전 강의에서 배운 내용을 다시 떠올려 봅시다. 다양한 downstream task를 머신러닝으로 푸는 과정에서 비정형 데이터인 그래프 인풋을 활용하기 위해 그래프를 임베딩하는 방법을 공부했었습니다.

Intuition 그래프 상에서 similar한 노드끼리 임베딩 공간에서도 가깝도록 임베딩 하자!

임베딩 공간에서의 노드 간 similarity는 간단하게 코사인 유사도를 통해 구할 수 있지만, 1) 원래 그래프 상에서의 노드 간 similarity와 2) 노드를 임베딩 벡터로 mapping하는 encoder은 우리가 새로 정의해야 합니다.

  1. Encoder: Shallow Encoder

    먼저, 인풋 그래프의 노드를 d차원의 벡터로 임베딩하기 위해 가장 간단한 look-up table 방식인 Shallow Encoder를 다뤘습니다. 예를 들어, 노드의 갯수가 \(\|V\|\)인 경우 임베딩 행렬의 크기는 \(\|V\|\times d\) 가 됩니다.

  2. Similarity Function: Random Walk (DeepWalk, Node2vec)
    또한, Random Walk상에서 co-occur 되는 두 노드는 그래프 상 similar한 노드라고 정의하였습니다. Random Walk의 전략에 따라 서로 다른 DeepWalk와 Node2vec 등의 방법을 배웠던 것 기억 나시나요?

Limitations of Shallow Encoder

이렇듯 Shallow Encoder을 통해서도 성공적으로 노드와 그래프를 임베딩할 수 있지만, 다음과 같은 한계점 때문에 보다 더 고도화된 Encoder를 재정의 할 필요가 있습니다.

  • \(O(\|V\|)\) 파라미터가 필요함
    그래프의 크기가 커지면 커질수록, 즉 노드의 갯수 \(\|V\|\)가 증가함에 따라, 임베딩 행렬의 크기도 선형적으로 증가합니다. 또한 각 노드가 모두 서로 다른 d 차원의 임베딩 벡터를 가지기 때문에 파라미터 공유도 일어나지 않습니다.

  • Transductivity

    • Transductive Learning
      그래프 학습 관점에서 Transductive Learning이란 하나의 그래프 상 일부 노드와 엣지의 ground truth를 아는 상태에서 나머지 노드와 엣지의 값을 추정하는 방식입니다. 학습 과정 중, 모델은 ground truth를 알지 못하는 노드를 포함한 모든 노드와 엣지를 사용합니다.

    • Inductive Learning
      그래프 학습 관점에서 Inductive Learning이란 ground truth를 알고 있는 그래프(들)에 대해 모델을 학습 한 후, 전혀 새로운 그래프의 노드와 엣지의 값을 추정하는 방식입니다. 즉, 학습이 완료된 후에는 모델이 새로운 처음 보는 노드의 값을 추정하는 데에도 적용될 수 있다는 의미이죠.

    Shallow Encoder은 Transductive Learning으로 학습해야 하는 대표적인 케이스입니다. 학습 도중 보지 못한 노드는 look-up table상 존재할 리 없으니 맵핑되는 임베딩 벡터가 없을 것이고, 임베딩 벡터가 없다면 node classification 등의 downstream task에서 예측이 불가능하겠죠? 이런 특성 때문에 시간에 따라 노드가 추가될 수 있는 evolving 그래프와 같은 경우 그래프가 변할 때마다 전체 임베딩을 다시 scratch부터 학습해야 한다는 불편함이 있습니다.

  • 노드 feature을 활용하지 않음
    대부분의 그래프 데이터셋은 우리가 활용할 수 있는 노드 feature이 존재합니다. 예를 들어, 소셜 그래프의 경우, 단순히 철수가 영희가 친구라는 정보 이외에도, 철수는 성균관대학교에 다니는 23세 남학생이라는 정보도 존재합니다. 단순한 노드 간 연결 상태 이외에도 이러한 노드 feature를 고려하여 노드를 임베딩 한다면 정보량이 더 풍부해져 효과적일 것입니다.

Deep Graph Encoders

이제 지금껏 다뤄왔던 간단한 look-up table로 이루어진 encoder에서 벗어나, 좀 더 복잡한 형태의 Deep Encoder을 공부해봅시다.

Deep Encoder은 인풋 그래프에 수차례의 비선형적인 transformation을 가하여 end-to-end으로 최종 임베딩을 얻는 방식을 말합니다. 수업 슬라이드에 쓰인 말 그대로,

Deep Encoder = multiple layers of non-linear transformations based on graph structure

로 생각할 수 있겠습니다. 잘 와닿지 않으신다고요? 사실, 인풋 데이터가 우리가 익숙치 않은 형태의 그래프라 그렇지, 오늘날의 머신러닝/딥러닝 모델이 이미지나 텍스트와 같은 정형 데이터를 처리하는 방식과 유사합니다.

위의 두 그림이 유사하다는 점이 한눈에 보이실 겁니다. 이해를 돕기 위해 가장 기본적인 CNN 구조를 생각해 볼까요? 원본 이미지가 여러 convolution layer을 거치며 더욱 더 축약된 feature map을 만드는 방식과 유사하게, 인풋으로 들어온 그래프는 여러 graph convolution layer을 거치며 원본 그래프의 의미를 적절히 축약하는 노드 임베딩을 만드는 것입니다.

또한, 개 고양이 이미지 분류 모델이 지도 학습으로 학습될 때 학습 데이터에 대해 각 이미지가 개인지, 고양이인지 나타내는 클래스 label을 활용하는 것과 같이, 노드 분류 문제의 경우 각 노드에 대한 클래스 label이 있다면 이를 직접 활용하여 encoder를 학습할 수 있습니다.

💡 이 경우 decoder은 노드 클래스 label 입니다.


물론, ground truth label이 존재하지 않는 비지도 학습 상황에서는 기존 Shallow Encoder을 학습하던 방법과 동일하게 Random Walk 등으로 정의되는 인풋 그래프상 노드 similarity를 유지하도록 학습할 수도 있겠죠. 이 부분은 본 강의 말에 다시 다루니까 이해되지 않는대도 걱정 마세요! :)

💡 이 경우 decoder은 임베딩 벡터 간 similarity metric인 벡터 내적 등으로 정의할 수 있습니다. (lecture 4)


이렇게 Deep Encoder을 통해 얻은 노드/그래프 임베딩은 여러 task에서 agnostic하게 활용할 수 있습니다.

  • 학습된 임베딩을 활용할 수 있는 여러 task의 예
    • Node classification
    • Link prediction
    • Community detection
    • Network similarity

Why is it Hard?

아까 언급했듯이 Deep Encoder을 통해 그래프를 임베딩 한다는 개념은 지금껏 우리가 정형 데이터를 처리했던 방식과 비슷하기 때문에 낯설지 않습니다.

그렇다면 그냥 널리 사용되고 있는 CNN이나 RNN을 활용해서 그래프를 임베딩 하면 되지 않을까요?

그럴 수 없습니다.

정형 데이터인 이미지, 텍스트에 비해 비정형 데이터인 그래프는 너무나도 복잡하기 때문이죠. 그래프는 이미지와 같이 (0,0) 등의 기준점을 둘 수 없으며, 텍스트와 같이 명백한 순서가 있지도 않습니다. 그래프는 제각기 다른 사이즈 일 수 있으며 각각의 topological structure 또한 모두 다릅니다. 심지어는 노드 마다 multimodal feature을 가질 수도 있습니다.

따라서, 비정형 그래프 구조에서 각 노드의 구조적 특징 및 노드 feature을 고려하여 적절하게 임베딩 하는 새로운 방법이 필요합니다.

💡 노드의 Multimodal feature
다시 소셜 그래프를 떠올려 봅시다. 각 노드는 철수, 영희를 포함한 개인을 나타내고, 엣지는 각 개인 사이에 친구 관계가 성립하는지를 나타냅니다. 이 때, 철수라는 노드는 프로필 사진(이미지), 자기 소개 글(텍스트) 등 여러 부가적인 feature을 가질 수 있습니다.


6.2 Basics of Deep Learning

이번 파트는 본격적으로 그래프 데이터를 위한 딥러닝을 설명하기에 앞서 딥러닝에 익숙하지 않은 사람들을 위해 딥러닝의 기본 개념을 간단하게 설명하는 부분입니다. 많은 내용을 커버하긴 하지만 딥러닝 초심자들은 CS231n과 같은 딥러닝 강의를 먼저 수강하고 오심을 추천드립니다!

Machine Learning as Optimization

먼저 간단한 지도 학습 문제를 생각해 봅시다. 지도 학습(Supervised Learning)이란 데이터에 대한 ground truth label이 존재하는 경우를 일컫는데, 다시 말해 input \(x\)가 주어졌을 때, label \(y\)를 예측하는 문제라고 할 수 있습니다. 이러한 task는 아래와 같은 식을 통해 최적화 문제로 바꾸어 해결할 수 있습니다.

위 식을 이해하기 위해 먼저 구성 요소에 대해 하나씩 짚어보겠습니다.

\(\theta\) : 우리가 최적화(학습) 하려는 파라미터들

최종적으로 우리가 학습하고자 하는 파라미터 값입니다. 예를 들어 앞의 Shallow Encoder에서는 학습으로 결정되는 \(\|V\|\times d\) 사이즈의 임베딩 look-up table이 \(\theta\)에 해당하겠죠.

\(\mathcal{L}\) : Loss 함수

Loss 함수는 ground truth label \(y\)와 머신러닝 모델이 예측한 label \(f(x)\)의 차이를 계산하는 metric 입니다. 회귀(Regression) 문제에서 주로 사용되는 L2 loss와 분류(Classification) 문제에서 주로 사용되는 Cross entropy loss 이외에도 L1 loss, Huber loss, Hinge loss 등 다양한 loss 함수가 존재합니다. 대표적인 loss 함수인 L2 loss와 Cross entropy loss의 수식은 각각 다음과 같습니다.

L2 loss

Cross entropy loss

결국 우리가 원하는 것은 모델이 예측한 label이 정답 ground truth label에 가까워지는 것이기 때문에, 이 loss 함수 값이 작으면 작을수록 우리의 모델이 더 정확한 예측을 한다는 의미입니다.

그럼 이제 위에서 공부한 각 구성 요소를 바탕으로 다시 이 최적화 식을 해석해 봅시다. 결국 우리가 풀고자 하는 머신러닝 문제는, 정답 label \(y\)와 모델이 예측한 label \(f(x)\)의 차이를 나타내는 loss 함수를 최소화 하는 방향으로 모델 파라미터 \(\theta\)를 최적화하는 문제로 해석할 수 있습니다.

Gradient Descent

지금까진 두루뭉술하게만 보였던 머신러닝 문제를 동일한 의미인 최적화 문제로 재정의했습니다. 그렇다면 이 최적화 문제를 어떻게 해결해야 할까요?

(출처: https://ieeexplore.ieee.org/abstract/document/9298092)

우리는 일반적으로 Loss 함수로 convex function(볼록 함수)를 활용합니다. 이 loss 함수의 값이 작아지는 방향으로 모델 파라미터 \(\theta\) 를 업데이트 하기 위해, \(\theta\)에 대한 \(\mathcal{L}\)의 기울기를 구한 후, 기울기가 작아지는 방향으로 \(\theta\)를 업데이트 해줍니다.

(위 그림에서 Cost를 \(\mathcal{L}\), Weights를 \(\theta\)로 보시면 됩니다!)

이를 다시 Gradient 벡터라는 개념으로 정리해서 이야기 해보겠습니다. Gradient 벡터란 위의 식과 같이 \(\theta\)에 대한 \(\mathcal{L}\)의 편미분, 즉 기울기 값으로 구성된 벡터로써, 가장 빠르게 \(\mathcal{L}\)이 증가하는 방향을 나타내는 방향 도함수 벡터입니다.

💡 Gradient is the directional derivative in the direction of largest increase


일단 Gradient를 구했으면 이제 할 일은 모델 파라미터 \(\theta\)를 gradient의 반대방향으로, 즉 \(\mathcal{L}\)이 작아지는 방향으로, 반복적으로 업데이트 하는 것입니다.

위 식에서 \(\eta\)는 learning rate로, 한번 파라미터를 업데이트 시 얼마나 변경할 것인지 보폭을 나타내는 값입니다. 이는 학습 과정 동안 동일하게 유지할 수도 있고, 목적에 따라 계속 변하게 할 수도 있습니다. 이론적으로 모델 파라미터의 업데이트는 loss 함수의 local minimum에 도달하여 gradient가 0이 될 때까지 진행하는 것이 맞지만, 실전에서는 검증 데이터셋에서의 성능이 더 이상 증가하지 않는 기점에서 모델 파라미터 업데이트를 중단합니다.

Stochastic Gradient Descent (SGD)

Gradient Descent의 문제점

Gradient descent 방법으로 최적화 문제를 푸는 것은 이론적으론 무결하지만 현실적으로는 어렵습니다. 앞서 언급했듯이, Gradient 벡터를 계산하기 위해서는 전체 데이터에 대한 loss 값을 구해야 하기 때문에 몇십억개의 데이터를 갖는 오늘날의 데이터셋에 적용하기에는 계산적으로 무리가 있습니다.

(출처: https://www.slideshare.net/w0ong/ss-82372826)

따라서 전체 데이터셋을 작은 미니 배치로 나누어 모델 파라미터를 업데이트하는 SGD 방법이 등장하게 되었습니다. 미니 배치 마다 gradient를 구하고 모델 파라미터를 업데이트하는 것이 전체 데이터셋을 활용한 모델 업데이트 정도를 근사할 수 있기 때문이죠.

💡 SGD is unbiased estimator of full gradient


오늘날의 최적화 optimizer은 SGD의 여러 발전된 형태로써, Adam, Adagrad, Adadelta, RMSprop 등이 있습니다.

Back-propagation

지금까지 머신러닝 문제를 최적화 문제로 재정의하고, 최적화 문제를 풀기 위해 gradient를 활용해 모델 파라미터를 업데이트 하는 방법에 대해서 배웠습니다. 잘 따라오고 계신가요?

이제부터는 실질적으로 머신러닝 모델이 주어졌을 때, gradient를 계산하는 방법에 대해 알아보겠습니다. 오늘날의 머신러닝/딥러닝 모델은 아주 복잡한 형태를 가지지만, 일단 이해의 편의를 돕기 위해 가장 간단한 linear function를 예시로 설명하겠습니다.

Case 1

첫번째로 우리의 머신러닝 모델이 단순한 선형 변환 함수인 경우를 다뤄보겠습니다.

선형 변환 함수가 벡터 형태이든 행렬 형태이든 관계 없이 gradient는 이렇게 간단히 구할 수 있습니다.

Case 2

두번째로 조금 더 복잡한 형태의 모델로 확장해보겠습니다. (물론 아직 엄청 단순한 형태긴 하지만..) 이 경우에는 \(W_{1}\)\(W_{2}\)에 대해 모두 gradient를 구해야 합니다. 여기서 우리가 고등학교 때 배운 합성함수 미분에서의 연쇄법칙이 사용됩니다.

💡 Chain Rule (연쇄법칙)


연쇄법칙에 따라 gradient가 \(\mathcal{L}\)\(f(x)\)\(W_{2}\)\(W_{1}\) 을 따라 차례로 거꾸로 흐르면서 계산됩니다. 이렇게 말단에서부터 앞쪽까지 gradient가 흘러오기 때문에 역전파(back-propagation)이라는 이름이 붙었다고 합니다.

Non-linearity

지금까지 예시로써 다뤄본 두 케이스는 사실 모두 선형 모델로써, 비선형적인 데이터를 잘 모델링할 수 없습니다. 따라서 오늘날의 머신러닝 모델은 비선형적인 활성 함수(Activation function)를 도입함으로써 이러한 문제를 해결합니다. 대표적인 비선형 함수로는 ReLU, Sigmoid 등이 있습니다.

Multi-layer Perceptron (MLP)

MLP란 한 layer마다 선형 변환과 비선형 변환이 합쳐진 가장 기본적인 형태의 머신러닝 모델이라고 볼 수 있습니다. 위 식은 MLP 한 layer을 나타내는데, layer \(l\) 의 인풋으로 들어온 \(x^{(l)}\)\(W_{l}\)이 곱해져 선형 변환 된 후 bias 항이 더해집니다. 최종적으로 비선형 함수를 거친 아웃풋이 layer \(l+1\)의 인풋으로 전달됩니다. 이를 그림으로 나타내면 다음과 같습니다.

Summary

지금까지 간단하게 배운 딥러닝의 기본 개념을 정리해보고, 본격적인 오늘 강의의 주제로 넘어가겠습니다.

  • 머신러닝 문제는 최적화 문제로 풀 수 있습니다.

  • 모델 \(f\)는 간단한 선형 함수, MLP, 또는 다른 형태의 신경망일 수 있습니다. (e.g., 추후에 다룰 GNN도 가능합니다)
  • 먼저 전체 데이터셋을 미니배치로 나누어 인풋 \(x\)으로 사용합니다.
  • 순전파(Forward Propagation): \(x\)가 주어졌을 때 loss 함수 값 \(\mathcal{L}\) 구하기
  • 역전파(Backward Propagation): 연쇄법칙으로 gradient \(\nabla_{\theta}\mathcal{L}\) 구하기
  • SGD를 활용하여 반복적으로 모델 파라미터 \(\theta\)를 최적화합니다.

6.3 Deep Learning for Graphs

이제 본격적으로 이번 강의의 메인 주제였던 딥러닝을 활용한 그래프 데이터 임베딩 방법에 대해 공부해 봅시다. 참고로 Deep Encoder은 그래프 뉴럴 네트워크(GNN)으로도 부르기 때문에 혼재해서 사용하더라도 헷갈리지 않으시길 바랍니다.

Setup

들어가기에 앞서 반복적으로 활용할 notation에 대해 간략히 설명하고 시작하겠습니다. 앞으로 아래 기호를 쭉 사용하여 설명을 할 예정이니 잘 알아두시기 바랍니다.

  • \(V\): 노드 집합
  • \(A\): 인접 행렬 (Adjacency matrix)
  • \(X \in \mathbb{R}^{m\times \|V\|}\): 노드 features
  • \(v\): 노드 집합에 포함된 한 노드, \(N(v)\): \(v\)의 이웃 노드

그래프 구조는 엣지의 방향성 및 가중 여부에 따라 여러 종류로 분류할 수 있지만, 이해를 위해 여기서는 가장 간단한 undirected & unweighted 그래프로 설명하겠습니다. 따라서 인접 행렬은 0과 1로 이루어진, 대각 방향으로 symmetric한 행렬이라고 생각하실 수 있습니다.

또한, 이전의 Shallow Encoder과는 달리 이제 노드 feature도 함께 고려하여 노드 임베딩을 학습한다는 점에 유의하시기 바랍니다.

  • 사실 대부분의 그래프 데이터셋은 노드 feature을 포함하고 있지만, 만에 하나 없는 경우라면 다음과 같은 벡터/값을 노드 feature로 사용하기도 합니다.
    • 노드의 one-hot 인코딩 벡터
    • 상수 벡터 [1, 1, …, 1]
    • 노드 차수(degree)

Naive Approach

딥러닝 모델을 활용하여 그래프 및 노드를 임베딩 하기 위해 가장 쉽게 생각할 수 있는 방법은 단순하게 그래프의 구조적인 특성을 나타내는 인접 행렬과 노드 feature 행렬을 그냥 이어 붙여서 딥러닝 모델에 던져주는 것입니다.

위와 같은 undirected 그래프의 각 노드가 2차원의 feature를 각각 가지고 있다면, 단순히 두 행렬을 이어 붙여서 만든 7차원의 벡터를 뉴럴 네트워크에 전달하면 각 노드를 간단히 임베딩 할 수 있을 것입니다. 하지만 이러한 방법에는 다음과 같은 문제가 존재합니다.

  • \(O(\|V\|)\) 파라미터가 필요함
    노드 feature이 \(d\)차원이라고 가정하면, 각 노드가 뉴럴 네트워크에 입력되는 차원이 \(\|V\|+d\) 이겠죠? 따라서 그래프의 노드 갯수에 비례하여 모델의 파라미터가 증가합니다.
  • 다른 사이즈의 그래프에는 적용할 수 없음
    위와 같은 그래프에 대해 뉴럴 네트워크를 기껏 학습시켜 놓았는데, 100개의 노드로 구성된 새로운 그래프가 인풋으로 들어온다면, 인풋 차원이 맞지 않아 학습시킨 임베딩 모델을 활용할 수 없을 것입니다.
  • 노드 순서가 바뀌면 동일 노드의 임베딩이 달라질 수 있음
    위 그래프에서 노드 순서를 A→B→C→D→E에서 B→E→A→C→D 등으로 바꾼다면, 이에 따라 인접 행렬도 바뀌게 됩니다. 이렇게 된다면 같은 A 노드를 임베딩 하기 위해 인풋으로 활용되는 7차원의 벡터가 달라지기 때문에 임베딩 결과 값도 달라질 것입니다.

From Images to Graphs

그렇다면 기존 CNN 모델에서 아이디어를 차용해보는 건 어떨까요?

이미지를 다루는 CNN은 위와 같이 고정된 사이즈의 convolution 필터를 사용하여 이미지를 주욱 훑습니다. 여기서의 convolution 필터는 붉은 원으로 표시된 타겟 픽셀의 주위 픽셀 정보를 축약하는 역할을 합니다. 사실 이미지가 특수한 형태의 그래프로 해석될 수 있음을 생각해보면, 그래프 데이터에서도 타겟 노드의 임베딩을 만들기 위해 주변 노드의 정보를 사용한다는 아이디어는 나쁘지 않아 보입니다.

하지만 그래프에서는 CNN에서와 같이 고정된 크기의 필터(?)를 사용할 수 없습니다. 어떤 노드는 한두개의 이웃 노드를 가지지만 또 어떤 노드는 수백수천개의 이웃 노드를 가질 수 있기 때문이죠.

그렇다면 그래프를 임베딩 할 때 타겟 노드의 이웃 노드에서 정보를 전달받아 이를 활용하여 타겟 노드의 임베딩을 업데이트 하되, 타겟 노드마다 이웃 노드의 갯수가 다를 수 있는 점을 고려하여 각기 다른 computation graph를 갖도록 하는 것이 좋겠습니다!

다음과 같은 아이디어를 근간으로 Graph Convolutional Network가 등장하게 되었습니다. 남은 강의에서는 이 GCN을 디테일하게 설명하고 있습니다.

Idea: Aggregate Neighbors

주요 Idea: 이웃 노드 정보를 가지고 타겟 노드 임베딩을 생성하자!

왼쪽과 같은 그래프에서 우리가 임베딩하고 싶은 타겟 노드가 노란색의 A 노드라고 생각해 봅시다. 그렇다면 A 노드의 이웃 노드, 그리고 그 이웃 노드들의 이웃 노드를 가지고 오른쪽과 같은 computation graph가 생깁니다.

타겟 노드 A는 직속 이웃인 노드 B, C, D로부터 메시지를 전달 받고, 모든 메시지를 합친 후 어떠한 변환을 거쳐 본인의 임베딩으로 활용합니다. 우측 그림에서 회색 박스로 표시된 뉴럴 네트워크가 바로 이러한 1) 메시지 변환, 2) 이웃 노드로부터 온 메시지를 통합하는 두 과정을 수행하게 됩니다. 이 뉴럴 네트워크 내의 모델 파라미터가 최종적인 우리의 학습 대상이 되는 것입니다.

여기서 또 눈여겨 보아야 할 점이 있습니다. 여지껏 우리는 노란색 A 노드를 타겟 노드로 한 computation graph만 보았는데, 그렇다면 B, C, D 등 다른 타겟 노드에 대해서도 동일한 computation graph를 가질까요?

아닙니다. 노드마다 이웃 노드의 갯수와 종류가 다르기 때문에 당연히 노드마다 서로 다른 computation graph를 가지게 됩니다.

Deep Model: Many Layers

Layer의 수

Deep Encoder은 여러 layer로 구성할 수 있는데, 한 layer이 직속 이웃 노드에 대한 정보를 aggregate하는 것이기 때문에 layer을 두 개 쌓는다면 직속 이웃 노드에 대한 이웃 노드, 즉 타겟 노드로부터 2-hop 떨어진 노드의 정보까지 활용하겠다는 의미로 해석할 수 있습니다. 위 그림에서도 잘 나타나 있는데, 2개의 layer로 구성된 모델을 사용하기 때문에 타겟 노드 A로부터 2-hop 떨어진 노드 E, F의 정보도 임베딩 생성에 활용되는 것을 볼 수 있습니다.

노드 임베딩 초기화

또한, 보통 Layer-0에서 최초 노드 임베딩으로 노드 feature을 사용합니다. 모든 노드 임베딩은 layer을 거칠수록 이웃 노드의 정보를 변환하고 합친 후 업데이트 됩니다. 결국 모든 layer을 거치고 나면 최종 노드 임베딩이 생성되어 우리가 downstream task를 위해 사용하게 되는 것이죠.

Aggregator 함수

여기서 타겟 노드 A가 이웃 노드 B, C, D의 메시지를 aggregation 할 때, 노드 B, C, D의 순서와 관계 없이 aggregate된 메시지는 동일해야 합니다. 즉, 메시지를 aggregate하는 함수는 permutation-invariant한 속성을 가져야 한다는 말입니다. 일반적인 GNN은 주로 합, 평균, 맥스 풀링등의 aggregator를 활용합니다.

The Math: Deep Encoder

자, 이제 가장 기본적인 GNN 형태를 정의하고 이를 수식으로 나타내어 알고리즘의 원리를 자세히 들여다보는 시간을 갖겠습니다. 우리의 GNN은 타겟 노드의 이웃 노드 임베딩을 전달받아 이를 평균냄으로써 메시지를 aggregate 합니다. 그 후, 뉴럴 네트워크를 통해 어떠한 변환을 거치고 이를 활용하여 타겟 노드 임베딩을 업데이트 합니다. 이를 수식으로 나타내면 아래와 같습니다.

식이 처음엔 되게 복잡해 보이지만, 하나씩 뜯어보면 사실 아주 간단합니다. 식 전반에 나타나는 \(h_{v}^{(l)}\)\(l\)번째 layer에서 노드 \(v\)의 임베딩을 나타낸다고 보시면 됩니다.

  1. 초록색 수식 블럭 : 첫 노드 임베딩을 노드 feature로 초기화합니다.
  2. 파란색 수식 블럭 : \(l+1\)번째 layer에서의 노드 임베딩을 만들기 위해, 먼저 타겟 노드 \(v\)의 이웃 노드에 대해 \(l\) 번째 layer에서의 노드 임베딩 평균을 구합니다. 그 후, 이웃 노드의 평균 임베딩에 어떠한 transformation \(W_{l}\) 을 가합니다.
  3. 빨간색 수식 블럭 : 타겟 노드의 임베딩을 업데이트할 때 이웃 노드 뿐 아니라, 이전 layer에서 갖고 있던 자기 자신의 임베딩도 활용합니다. 같은 방법으로 \(h_{v}^{(l)}\)에 어떠한 transformation \(B_{l}\) 을 가합니다.
  4. 노란색 수식 블럭 : 최종적으로 비선형 함수를 적용해서 \(l+1\)번째 layer에서의 타겟 노드 임베딩을 구합니다.
  5. 보라색 수식 블럭 : 노드 임베딩 업데이트 과정을 \(L\)번 반복합니다. 이 때 최종적으로 형성된 노드 임베딩은 본인으로부터 L-hop 떨어진 노드의 정보까지 활용하여 만든 것입니다.

Matrix Formulation

이전에 Random Walk를 행렬 형태로 표현했듯이, 벡터식으로 다뤘던 GNN도 행렬식으로 다시 표현해보겠습니다.

모든 노드 임베딩 벡터를 한데 모아 노드 임베딩 행렬을 만든다면, 이는 아래와 같이 표현할 수 있습니다.

\(H^{L} = {[h_{1}^{(l)} ... h_{\|V\|}^{(l)}]}^T\)

그렇다면 이웃 노드의 임베딩을 합산하는 과정은 그래프의 인접 행렬을 사용하여 아래와 같이 간단하게 나타낼 수 있습니다.

\(\sum_{u\in N_{v}} h_{u}^{(l)} = A_{v:}H^{(l)}\)

만약 대각 행렬을 이렇게 정의한다면, 이 대각 행렬의 역행렬은 다음과 같기 때문에,

\(D_{v,v} = Deg(v) = \|N(v)\|\) , \(D_{v,v}^{-1} = 1/\|N(v)\|\)

이를 활용하면 이웃 노드의 임베딩을 평균내는 연산을 행렬식으로 간단하게 표현할 수 있습니다.

따라서 최종적으로 노드 임베딩 업데이트 함수를 행렬식으로 나타내면 아래와 같습니다.

벡터식으로 이해하기도 어려웠는데 왜 굳이 사서 행렬식으로 변환하냐고요? 사실 행렬식이 가지는 구현상의 이점이 있기 때문입니다. 행렬식을 사용한다면 각 노드에 대한 임베딩을 따로 따로 업데이트 하지 않고 하나의 행렬로써 한번에 업데이트 할 수 있으며, 이 과정에서 \(\tilde{A}\)가 희소 행렬이기 때문에 보다 더 효율적인 행렬 연산이 가능하기 때문에 구현할 때는 행렬식이 더 선호됩니다.

How to train a GNN

오늘 강의의 마지막 부분으로 이렇게 구성한 GNN을 어떻게 학습시켜야 하는지 알아보겠습니다. 시작하기에 앞서 학습의 대상이 되는 파라미터가 무엇인지 짚고 넘어가보죠.

다음 식에서 학습되는 파라미터는 \(W_{l}\)\(B_{l}\) 입니다. 딸린 subscript를 봐도 알 수 있듯이, 두 파라미터 행렬은 모두 layer마다 따로 존재하며, 한 layer 내에서는 공유됩니다. 이를 간단하게 그림으로 표현하면 아래와 같습니다.

GNN을 학습하는 방법은 여느 딥러닝 학습과 마찬가지로 크게 지도 학습, 비지도 학습 세팅으로 나뉩니다. 이를 하나씩 살펴보도록 합시다.

  1. 지도 학습 세팅

    • 노드 label \(y\)가 존재하는 상황

    • 정답 노드 label \(y\)를 활용하여 \(min_{\theta}\mathcal{L}(y,f(z_v))\)를 풂, 이 때 task에 맞게 L2 loss 혹은 Cross entropy loss 등을 loss 함수를 사용함

    • 예시) 각 노드가 safe한지 혹은 toxic한지 분류하는 node classification → 분류 문제이므로 cross-entropy loss를 사용하고, 노드의 정답 클래스 label을 활용하여 직접 모델 학습 가능

      💡 아래 loss 식에서 \(\sigma(z_v^T\theta)\)는 학습된 노드 임베딩 \(z_v^T\)를 가지고 모델이 예측한 노드 \(v\)의 클래스 확률 을 나타냅니다.

  2. 비지도 학습 세팅

    • 노드 label이 존재하지 않는 상황

    • 3강에서 공부했던 그래프 상 노드 similarity를 supervision으로 활용

      임의의 supervision 시그널을 만들어 비지도 학습 세팅을 지도 학습 세팅으로 바꾸기 위해서 원본 그래프에서의 노드 similarity를 바탕으로 label을 지정해줍니다. 여기서 노드 similarity는 3강에서 다뤘던 Random Walk 등을 활용할 수 있습니다.

      간단하게 DeepWalk로 노드 similarity를 정의하는 경우를 생각해볼까요? 만약 두 노드 \(u\)\(v\)가 랜덤 워크 상에서 co-occur한다면 두 노드는 ’similar’하다고 말할 수 있으며, \(y_{u,v} = 1\)로 임의의 label을 붙입니다. 또한 여기서 \(DEC(z_u,z_v)\)는 학습된 두 노드의 임베딩을 내적함으로써 임베딩 공간에서의 노드 similarity를 측정합니다. Loss 함수로 cross-entropy를 사용함으로써 그래프에서 노드 similarity를 최대한 잘 보존하도록 노드 임베딩을 학습할 수 있게 됩니다.

      💡 원본 그래프에서 similar한 노드는 → similar한 임베딩을 갖도록 합니다

Model Design: Overview

자 그럼, 오늘 배웠던 내용을 한번 쭉 훑어 정리하고 포스트를 마무리하도록 하겠습니다. 그래프를 위한 Deep Encoder, a.k.a. GNN 모델을 만들기 위해서 아래와 같은 단계를 따라가야 합니다.

  1. 이웃 노드 임베딩을 aggregate하는 함수를 정함

  2. Task의 특성에 맞추어 loss 함수를 정의함

  3. 여러 computation graph에 대해 GNN 모델을 학습시킴

  4. 학습된 모델을 갖고 노드에 대한 임베딩을 생성할 수 있음. 이 때, 모든 노드에 대해 뉴럴 네트워크의 파라미터가 공유되기 때문에 학습에 사용되지 않은 노드에 대해서도 임베딩을 생성할 수 있음 (Inductive Capability)

💡 Inductive Capability
1. 새로운 그래프 : 예를 들어 분자 그래프에서, 화합물 A에 대해 학습된 GNN 모델이 화합물 B 그래프에서 임베딩을 만드는데 활용될 수 있음
2. 새로운 노드 : 시간에 따라 evolving 하는 그래프에서 새로운 노드가 추가될 때마다 바로바로 임베딩을 생성할 수 있음

Summary

  • Deep Encoder (GNN)의 핵심 아이디어: 이웃 노드의 정보를 aggregate 함으로써 노드 임베딩을 생성하자!
  • 모델 내 Aggregator과 Transformation 함수를 각각 어떻게 정의하느냐에 따라 모델 구조가 달라질 수 있습니다.
  • 다음 강의에선 GNN variant의 하나인 GraphSAGE를 다룰 것입니다.