그래프 신경망/CS224W

[CS224W Lecture 3 정리] node2vec 수식부터 negative sampling, p·q 편향 랜덤워크, 그래프 임베딩(anonymous walk)까지

uchanee 2025. 12. 28. 11:41

요즘 그래프 임베딩(DeepWalk/node2vec)을 제대로 이해해보려고 CS224W 슬라이드를 따라가고 있다.


웃긴게 처음에는 모델 구조는 “word2vec이랑 비슷하다” 한 줄로 끝나는데, 수식이 한 번 등장하면 그때부터 뇌정지가 온다.

특히 내가 막혔던 건 이거였다.

  • NR(u가 뭔지 감이 안 잡힘
  • 첫 번째 objective가 왜 갑자기 두 번째 loss로 바뀌는지 이해 안 됨
  • softmax 분모가 왜 문제인지, negative sampling이 뭘 “근사”하는지 모르겠음
  • GD/SGD가 왜 나오는지 알겠는데 "납득"이 안 됨
  • node2vec의 p, q가 그냥 파라미터인지(하이퍼파라미터인지) 감이 없었음

오늘은 이걸 내가 이해한 흐름대로 처음부터 끝까지 정리한다.


1. 일단 목표가 뭐냐: “노드를 벡터로” 만들고 싶다

그래프에서 노드마다 zuz_u라는 벡터(embedding)를 하나씩 만들고,
이 벡터가 “그래프 구조에서의 유사성”을 반영하게 하고 싶다.

직관은 간단하다:

  • 그래프에서 자주 “같은 문맥”에 등장하는 노드들은
  • embedding 공간에서도 가깝게 만들자.

이 “문맥(context)”을 만들기 위해 랜덤워크(random walk)를 돌린다.


2. NR(u)이게 도대체 뭐야? v랑 무슨 관계야?

슬라이드에 이런 식이 나온다:

 

 

여기서 핵심은 N_R(u)

  • : 기준 노드(center node)
  • : 랜덤워크 전략(random walk strategy)
  • NR(u): 전략 R로 랜덤워크를 돌렸을 때,
    u 주변 “문맥”으로 관측된 이웃 노드들의 집합(혹은 멀티셋)

즉,

의 의미는 엄청 단순하다:

“랜덤워크로 만든 u의 문맥 안에 v가 등장했다.”

중요: 여기서 이웃은 1-hop 이웃이 아니라,
walk + window에서 나온 “공동출현(co-occurrence)” 이웃이다.

Word2Vec 비유로 말하면:

  • 문장 속 단어가 있고
  • window 안에 같이 등장하는 단어들이 context인데
  • 그래프에서는 “랜덤워크가 문장 역할”을 한다고 보면 된다.

3. 첫 번째 식 → 두 번째 loss로 왜 바뀌냐 (내가 제일 막혔던 부분)

슬라이드에서 갑자기 다음으로 넘어간다:

이게 마법처럼 바뀌는 게 아니라, 중간에 3가지 발상이 들어간다.

(1) 이웃 전체 확률을 “이웃 원소별 확률”의 곱으로 단순화

보통 다음 가정을 한다:

뜻:
“u의 embedding이 주어지면, 이웃 노드들은 독립적으로 생성된다” 같은 단순 모델.

(2) 로그를 씌우면 곱이 합으로 바뀜

(3) 최대화 문제를 loss 최소화로 바꿈

최대화 → 최소화로 바꾸려고 마이너스 붙임:

이제 해석이 완전 쉬워진다.

“u가 주어졌을 때, 실제로 문맥에 등장한 v들을 높은 확률로 예측하게 만들어라.”


4. P(v∣zu)P(v\mid z_u)를 softmax로 두는 이유

이 확률은 보통 이렇게 둔다:

  • 내적 zu⊤zvz_u^\top z_v가 클수록 v가 u 문맥에 등장할 확률이 커짐
  • 분모로 전체 노드에 대해 정규화(softmax)

여기까지는 이론적으로 완벽한데…


5. 진짜 문제: softmax 분모가 너무 비싸다

이게 문제다.

노드가 100,000개면,

  • 확률 하나 계산할 때 exp를 100,000번…
  • SGD 한 스텝마다 이걸 하면 그냥 끝이다.

그래서 등장하는 게 Negative Sampling.


6. Negative Sampling을 내 머리로 이해한 한 줄

softmax 다중분류를 못 하니까, 이진분류 여러 번으로 바꾼다.

원래 하고 싶었던 것(softmax)

  • “전체 노드 중 정답 v를 맞춰라”

현실적으로 하는 것(negative sampling)

  • “(u,v)가 진짜 이웃이면 1(positive)”
  • “(u,n)이 랜덤으로 뽑힌 가짜면 0(negative)”
  • 이걸 k개 negative에 대해 반복

대표 목적함수는 이런 느낌:

직관:

  • positive pair(u,v): 내적 크게 → sigmoid가 1에 가깝게
  • negative pair(u,n): 내적 작게 → sigmoid가 0에 가깝게

핵심 이득:
전체 노드 대신 정답 1개 + 오답 k개만 보면 되니까
계산량이 O(|V|)에서 로 내려간다.

내가 느낀 비유:

시험을 볼 때 “전교생 10만 명 중 1등을 맞춰라”는 문제 대신
“얘가 정답 후보냐? 아니냐?”를 정답 1명 + 랜덤 오답 몇 명만 두고 판단하는 느낌.


7. GD vs SGD가 왜 나오냐 (슬라이드에서 갑자기 SGD가 등장한 이유)

loss는 모든 (u, v∈N_R(u))에 대해 합쳐져 있다.
즉 데이터가 엄청 많다.

  • GD: 모든 (u,v) 다 보고 한 번 업데이트 → 너무 느림
  • SGD: (u,v) 한 쌍(또는 미니배치)만 뽑아 업데이트 → 현실적

그래서 실전 조합은 거의 고정이다:

SGD + Negative Sampling


8. DeepWalk: “가장 단순한 랜덤워크 문장 생성기”

DeepWalk는 random walk를 그냥 돌린다.

  • 각 노드에서 시작
  • 이웃 중 하나를 균등하게 선택하면서 이동
  • 길이 L짜리 walk 여러 개 만들고
  • 그 walk를 “문장”으로 보고 skip-gram 학습

근데 이 방식은 탐색이 너무 단순해서
“나는 로컬 구조를 더 보고 싶다 / 글로벌 구조를 더 보고 싶다” 같은 조절이 어렵다.

여기서 node2vec가 나온다.


9. node2vec 핵심: BFS 느낌 vs DFS 느낌을 섞어서 학습하기

node2vec는 “편향 랜덤워크(biased random walk)”를 쓴다.

그리고 중요한 건:

다음 스텝에서 어디로 갈지는 “현재 노드”만 보지 않고 “직전 노드”도 기억한다.
(2nd-order random walk)

p, q는 사용자가 정하는 하이퍼파라미터 맞아?

맞다. p와 q는 하이퍼파라미터다.
사용자가 정하고, 데이터/목표에 맞게 튜닝한다.

  • p (return parameter): 바로 직전 노드로 돌아갈 확률 성향
    • p가 작으면 “되돌아가기”가 쉬워짐(가중치가 커지는 방향으로 해석)
    • p가 크면 되돌아가기가 어려움(앞으로 진행)
  • q (in-out parameter): 안쪽(BFS) vs 바깥쪽(DFS) 이동 성향
    • q가 크면 멀리 나가는 걸 억제 → BFS-like(로컬)
    • q가 작으면 멀리 나가는 걸 장려 → DFS-like(글로벌)

슬라이드 그림 해석을 내 방식으로 요약하면:

“지금 w에 왔을 때, 다음 후보 노드 t들이
직전 노드 s1과의 거리(0,1,2)에 따라 가중치가 달라지고
그 가중치를 p,q가 조절한다.”


10. node2vec 알고리즘이 왜 3단계인지

슬라이드에 “node2vec algorithm”이 3줄로 요약된다:

  1. Compute random walk probabilities
  2. Simulate r random walks of length l from each node
  3. Optimize objective using SGD

내 해석은 이렇다:

  • 1단계는 “탐색 규칙(p,q)”를 확정
  • 2단계는 “문장(워크 코퍼스)”를 생성
  • 3단계는 “word2vec처럼 학습(SGD + negative sampling)”

장점:

  • 계산이 선형 시간에 가깝고
  • 노드별로 walk 생성/학습을 병렬화하기 쉽다

11. (확장) 그래프 전체 임베딩: 노드가 아니라 그래프를 벡터로

마지막 강의 파트는 “노드 임베딩 말고 그래프 자체를 임베딩하자”였다.

정리하면 3개.

Approach 1) 노드 임베딩 합/평균

그래프 임베딩 = 그래프 안 노드 임베딩의 sum/avg
심플한데 의외로 잘 됨(분자 그래프 분류 같은 데서 성공 사례 많음)

Approach 2) 슈퍼노드(virtual node)

그래프(또는 subgraph)를 대표하는 빨간 노드를 만들고
모든 노드와 연결한 다음 그 노드 embedding을 그래프 embedding으로 사용

Approach 3) Anonymous Walk Embeddings

여기가 재미있었음.

  • 랜덤워크를 “노드 ID”로 표현하지 않고
  • “처음 방문한 순서(인덱스)”로 표현함
    → 노드 이름이 달라도 구조가 비슷하면 같은 표현이 나옴

그리고 그래프를

  • anonymous walk들의 빈도 분포 벡터로 나타내거나,
  • 더 나아가 anonymous walk 자체도 임베딩하고, 그래프 임베딩 ZGZ_G도 같이 학습할 수 있다.

12. 오늘 공부를 한 문장으로 요약하면

그래프 임베딩은 “랜덤워크로 만든 문장”에서 공동출현 노드들을 맞추는 문제로 바꾼 뒤,
softmax가 비싸서 negative sampling + SGD로 빠르게 학습한다.
node2vec는 여기서 랜덤워크를 p,q로 편향시켜 로컬(BFS)과 글로벌(DFS) 정보를 조절한다.


(내가 다음에 다시 볼 체크리스트)

  • NR(u)N_R(u) = 랜덤워크 문맥에서 얻은 u의 이웃(= co-occurrence)
  • objective → loss 변환 = 독립가정 + log + 최대화→최소화
  • softmax 분모가 비싸서 negative sampling
  • negative sampling = “정답 1 + 오답 k” 이진분류로 근사
  • node2vec p,q = 하이퍼파라미터(탐색 성향 조절)