1월 4주차 그래프 오마카세
Static and dynamic robustness
- 오늘 다루어볼 네트워크 지식은 ‘robustness’ 입니다. 딥러닝 분야에서와 복잡계 네트워크 분야에서의 ‘robustness’는 모델의 강건함을 측정한다는 동일한 목적이 있으나, 어떤식으로 측정할지 기준치 사전분포 측정과 같은 요소들 때문에 약간 결이 다르다고 볼 수 있습니다.
- ‘robustness’ , 딥러닝 분야에서는 training 데이터셋에 존재치않은 out-of-distribution 데이터를 inference 할 때 퍼포먼스가 얼마만큼 적게 떨어지는지에 대한 지표로 쓰이곤하죠.
- 복잡계 네트워크에서는 ‘static’ , ‘dynamic’ 관점으로 robustness 가 나뉩니다. 차이를 간단하게 말해보자면 특정 노드사이의 엣지가 끊겼을 때, 다시 엣지가 복구가 되는지 안되는지로 보시면 될 것 같아요.
- static → 복구 안됨. dynamic → 복구 됨.
- robustness 의 높고 낮음에 따라 결국 네트워크의 탄력성(reslience) 이 높고 낮음이 결정된다고 볼 수 있습니다. 자주 활용되는 분야인 cybersecurity 예로 들어보자면, reslience가 높다면 특정 컴퓨터에 문제가 발생할 시 그 컴퓨터를 차단하고 그 컴퓨터를 대체할 수단을 찾는 딜레이가 짧다. 라고 보시면 될 것 같습니다.
- 디테일하게 해석해보면 해당 네트워크의 분포부터 power-law , scale-free 인지 그리고 correlated network 인지 여러 condition 을 기반으로 해석을 하곤합니다. 해석시에 사용되는 수치 또한 존재하구요.
- ‘percolation’이라는 수치를 자주 활용하는데요. ‘percolation’에 대해 알려주세요! 라고 chatGPT에 물어보니 The percolation threshold is the point at which a giant connected component, spanning across the network, first appears. A high value of percolation in a network means that there is a high probability for a giant connected component to form, i.e., there is a large connected cluster of nodes in the network. This property has important implications in various fields, including epidemiology, material science, and information dissemination. 라고 답을 해주네요 :)
출처 : Boccaletti, Stefano, et al. "Complex networks: Structure and dynamics." Physics reports 424.4-5 (2006): 175-308.APA
The End of Programming
[https://cacm.acm.org/magazines/2023/1/267976-the-end-of-programming/fulltext?s=09]
- 오마카세 주방장 역시 대중들과 동일한 고민을 하고 있었습니다..! 그래프 오마카세가 chatGPT 에게 대체되면 어쩌지? 라는 고민을요..!
- 그 고민에 대해 견해를 밝힌 글인데요. 상당히 설득력 있습니다. 일단 CS 분야에서의 binary-tree 를 c++로 구현하는 등의 구현 공부들은 이제 가치가 이전대비 적어보인다. 이젠 large model 의 결과물이 왜 그렇게 나왔는지에 대해 우리가 알아가야할 것이다. 라며 parameter 가 4조개가 넘어가고 있는 이 파라미터들을 어떻게 해석하는지가 중요해질것이다. 근데 도전해보는거 좋다 허나 조심해라 상당히 복잡할테니 라는 말을 남깁니다.
- 유명 대가들 또한 chatGPT 에 대해 자신들의 의견들을 남기곤하는데요 최근 podcast 에서 ‘이건 모델이 직접 계산한게 아니라 1+1 = 2 라는 텍스트를 학습한것이고 그에 대한 답을 가져온것이다’ 라는 식으로 언급하며 ‘symbolic ai’ 의 중요성을 다시 이야기합니다.
- 또한 , chatGPT가 쓴글인지 아닌지를 판별하기 위한 모델도 나왔는데요. DetectGPT 입니다. 간단히 말해보자면, 분포가 인간답냐 , 기계답냐 의 차이를 구별해주는 모델이라 보시면 될 것 같습니다.
- 알파고 이 후 AI로 다시 한 번 세계가 들썩이고 있습니다. 이 때 오히려 유행을 따라가기보다 필요할 때 활용하시고, 기본기에 매진하여 자신만의 개성 + 기본기 를 결합한 인재로 거듭나셨으면 합니다.
PODCAST ; [https://open.spotify.com/episode/7xAUMohar0AcKToIBXmgqr]
Graph Fusion in Reciprocal Recommender Systems
[https://ieeexplore.ieee.org/stamp/stamp.jsp?arnumber=10025747]
- reciprocal recommender system 이라는 분야를 처음 접했습니다..! 그래프 오마카세 덕분에 또 공부하게 되네요 :) 간단히 말씀드려보자면 이커머스에서의 추천시스템은 유저-아이템 간의 ‘클릭’ 여부를 label로 두고 prediction 했다면, reciprocal recommender system 는 유저-유저 간의 ‘matching’ 여부를 label 로 둡니다. 상호작용이 발생하느냐 아니냐 로 구별하실수 있을거 같네요. 아서왕 전설검처럼 아이템이 유저를 간택한다는 일이 발생한다면 모르겠으나 실제로 거의 불가에 가까운일이니깐요.
- 유저간의 상호작용에 집중한다! 라는 측면에서 ‘job hunting’ , ‘date matching’ 산업에서 주로 쓰인다고 합니다. pair matching 이 핵심인거죠.
- task 는 2가지로 나뉜다고합니다. ‘send’ ,’reply’ 즉, 승낙 거절과 같은 정보들이 추가되어 prediction 된다고 보시면 될 것 같네요. 눈치가 빠르신분들은 아시겠지만 승낙이 positive link , 거절이 negative link 로 간주되어 진행됩니다.
- graph construction 또한 흥미롭습니다. 기존에는 user(male)-user(female) 를 bipartite graph 로 만드는것은 비슷합니다. 여기에서 edge 의 label 이 총 3개인데요. ‘send’, ‘reply’, ’unconnected’ 반응이 있고 없고 만약 있었다면, 승낙인지 거절인지가 포함된거죠.
- 아이디어가 심플하고 흥미로워서 소개시켜 드립니다. 특히, negative sampling 을 여기에선 어떻게 했을지 유념하시면서 논문 보시는걸 추천드립니다.
Feature selection: Key to enhance node classification with graph neural networks
[https://ietresearch.onlinelibrary.wiley.com/doi/pdf/10.1049/cit2.12166]
- GNN의 성능을 높이고자 selector 과 classifier model 를 joint learning 하는 아키텍쳐를 제안합니다.
- 굉장히 어려워보이지만 selector 라는게 결국 GNN 의 aggregation function 을 combination , permutation 한다고 보시면 될 것 같습니다. 심플하게본다면 , 노드 엣지의 정보가 왔을때 더할지 뺄지 세제곱할지와 같은 형태를 조정해주며 optimal performance 를 찾는다는게 논문의 핵심 아이디어 입니다.
- 저도 늘 상상만해보던 task 를 본 논문에서는 명쾌하게 풀어주었네요. pseudo-code 도 논문에 있어서 대략적인 Overview 도 따라가며 볼 수 있습니다.
- 본 논문의 재미 포인트는 머신러닝 입문에서 주로 배우는 lasso RFE 등을 feature selection baseline 으로 두고 실험비교를 하는 파트라고 볼 수 있겠네요. 참고로 future work 에서 저자가 한계점을 언급하는 부분이 있는데, 한 번 재미삼아 구현해보시는걸 추천드립니다 :)
Everything is Connected: Graph Neural Networks
[https://arxiv.org/pdf/2301.08210.pdf]
- GNN 의 핵심을 담아놓은 논문입니다. 평소 주변분들에게 GNN이 무엇인지 설명하고 싶으셨던 분들이 참고하시면 너무나도 좋을 리소스입니다.
- GNN의 한계점부터 왜 graph data 인지 그리고 gnn 을 공부하고 있는데 자꾸 expressive power 라는 단어가 나오는지 의문이 있으셨던 분들이시라면 그 호기심을 단번에 해소해줄 논문이라 단언합니다. 역시 고수답게 어려운 개념들을 명쾌하고 간결하고 무엇보다도 쉽게 설명되어 있어 두고 두고 되새김할 논문이라 생각되네요.
Understanding Graph based similarity: Simrank, Simrank++
[https://medium.com/@ksdave/understanding-graph-based-similarity-simrank-simrank-91619c88c336]
- structural similarity 의 대명사 Simrank 가 업그레이드 되었네요! Simrank 에 대해 익숙치않으신분들을 위해 잠시 설명드리자면, 노드간 neighbor/connection 가 얼마나 비슷한지 측정하는거라고 보시면 되겠습니다.
- 여기 포스팅에 따르면 기존 simrank 은 단순하게 그래프 유사도 즉, 비슷한 이웃 혹은 연결 구조만 있다면 두 노드가 비슷하다고 측정해버립니다. 이 때 한계점이 두 노드간의 context 를 반영하지 못한다는거죠.
- 그 context 를 반영하기 위해 ‘evidence’라는 아이디어를 도입해 weight를 줌으로써 그 context를 보완한다 라는게 핵심 아이디어 입니다.
- link analysis 하실때, pagerank 를 baseline 으로 importance 측정하셨던 분들에게 재미난 소식이 될 수 도 있겠네요! Simrank 한 번 적용해보시는걸 추천드립니다!
conference
WWW2023 tutorial
[https://www2023.thewebconf.org/program/tutorials/]
- 너무나도 재밌는 튜토리얼들이 한가득인 WWW2023 소식입니다! 특히, 카이스트 신기정 교수 연구실에서 tutorial을 accepted ! 축하드립니다! 그것도 제가 좋아하는 하이퍼그래프 definition 부터 application 까지 broadly 한 범위를 다룹니다 :)
- 추가로 , Continual graph learning. , Lifelong learning Cross-domain Recommender Systems. Towards Out-of-Distiribution Generalization on Graphs. 튜토리얼까지 !! 다소 생소했던 Continual learning + GNN 등 재밌는 요소들이 많아보이네요.
시즌한정메뉴 . BIG GRAPH DATA with PyG
data
CSV load
- 대다수 분들이 활용하고 계실 방법으로 추측됩니다. 2가지 csv 파일만 있으면 가능하죠.
- 노드와 노드가 어떻게 연결되어있는지 src, dst 2가지 컬럼으로 구성되어있는 edge csv 파일
- 노드가 어떤 feature 을 가지고 있는지 node csv 파일
- 간단하지만, 대용량 파일을 한꺼번에 올리려고 시도하실때 OOM 오류와 만나게 됩니다.
- [https://pytorch-geometric.readthedocs.io/en/latest/tutorial/load_csv.html]
InMemoryDataset
def process(self):
# Read data into huge `Data` list.
data_list = [...]
if self.pre_filter is not None:
data_list = [data for data in data_list if self.pre_filter(data)]
if self.pre_transform is not None:
data_list = [self.pre_transform(data) for data in data_list]
########################## point ##########################
data, slices = self.collate(data_list)
torch.save((data, slices), self.processed_paths[0])
- 핵심은 collate 함수입니다. python list 형태로 데이터를 받아와 torch_geometric.data.Data 형태로 바꿔주는 역할을 합니다. 즉 collate 함수 네이밍 그대로 합쳐주는 역할을 합니다.
- 이전 load csv 에서는 load 해주고 Data 형태로 바꿔주는 과정에서 OOM이 발생하는데요. 그 과정을 효율적으로 진행하기 위해 InMemoryDataset방식을 활용합니다.
- [https://pytorch-geometric.readthedocs.io/en/latest/tutorial/create_dataset.html]
Dataset
def process(self):
idx = 0
for raw_path in self.raw_paths:
# Read data from `raw_path`.
data = Data(...)
if self.pre_filter is not None and not self.pre_filter(data):
continue
if self.pre_transform is not None:
data = self.pre_transform(data)
########################## here ! save ##########################
torch.save(data, osp.join(self.processed_dir, f'data_{idx}.pt'))
idx += 1
########################## here ! save ##########################
def len(self):
return len(self.processed_file_names)
########################## here ! load ##########################
def get(self, idx):
data = torch.load(osp.join(self.processed_dir, f'data_{idx}.pt'))
return data
- 위 Inmemorydataset 다른점을 눈치채셨겠지만, process function에서 slicing 해준것을 바로 save 해주고 manually save , load 해줍니다. 이 과정은 심플하게 말씀드리자면 용량이 크니 샘플링을 해주고 그 샘플링 해준 데이터들을 iterative 해준다는 의미입니다.
- customized dataset 이 이해가 잘 안된다 싶으시면 이 블로그를 추천드립니다. 특히 Dataset , Dataloader 이 뭐가 다르며, 무슨 요소때문에 memory efficient 가 되는지 유념하시면서 보시는걸 추천드립니다.
[https://towardsdatascience.com/building-efficient-custom-datasets-in-pytorch-2563b946fd9f]
Sparse tensor
from torch_sparse import coalesce
# Pre-compute graph representations and node features
data.edge_index = coalesce(data.edge_index, data.num_nodes, data.num_nodes)
data.x = data.x.to(device)
data.edge_index = data.edge_index.to(device)
#example
import torch
from torch_sparse import coalesce
index = torch.tensor([[1, 0, 1, 0, 2, 1],
[0, 1, 1, 1, 0, 0]])
value = torch.Tensor([[1, 2], [2, 3], [3, 4], [4, 5], [5, 6], [6, 7]])
index, value = coalesce(index, value, m=3, n=2)
- torch_sparse function을 활용합니다. 간단하게 말씀드리자면 , numpy 의 csr , csc와 같은 형태로 row-wise compresssion technique 을 활용한다고 보시면 되겠습니다.
- 생소하실분들을 위해 깃헙 코드를 가져왔는데요, csr csc 형태와 거의 동일합니다. 익숙하신분들은 감이 오시겠으나 그래도 혹시모르니 활용하시기 전에 모듈 official example 과 주요 function을 보시는걸 추천드립니다.
- [https://github.com/rusty1s/pytorch_sparse/tree/e55e8331ef2881b934036054cbcd39f8efcd4725]
Mini-batching
# Set the mini-batch size
batch_size = 32
# Split the data into mini-batches
num_batches = len(data) // batch_size
data_split = torch.split(data, batch_size)
# Train the network
for epoch in range(200):
total_loss = 0
for batch in data_split:
optimizer.zero_grad()
out = model(batch.x, batch.edge_index)
loss = criterion(out[batch.train_mask], batch.y[batch.train_mask])
total_loss += loss.item()
loss.backward()
optimizer.step()
if epoch % 20 == 0:
print("Epoch: {:03d}, Loss: {:.4f}".format(epoch, total_loss / num_batches))
mini-batch size를 선언해주고 data 의 length 로 나누어줍니다. 그리고 torch split 로 나누어줍니다. 간단하게 생각하면 그래프 하나를 여러 서브그래프로 나누어준다고 보시면 될 거 같아요. 그렇다면 바로 한가지 문제가 떠오를텐데요! 바로 중요한 엣지를 나누어줘서 학습에 성능저하를 줄수도 있겠네? 라는 문제입니다.
그 문제에 관해서는 [cs224w-08gnnapplication] 에서 transductive vs. inductive learning 이라는 항목으로 잘 설명되어 있습니다 :) 혹시보고 이해가 되지 않으시다면 이메일로 문의주세요!
Backend
- 대망의 마지막입니다. 코드부터 보겠습니다.
############### graph structure informatioin ###############
graph_store = CustomGraphStore()
edge_index = torch.tensor([[0, 1, 1, 2], [1, 0, 2, 1]])
# Put edges:
graph_store['edge', 'coo'] = coo
# Access edges:
row, col = graph_store['edge', 'coo']
assert torch.equal(row, edge_index[0])
assert torch.equal(col, edge_index[1])
############### graph feature informatioin ###############
feature_store = CustomFeatureStore()
paper_features = ... # [num_papers, num_paper_features]
author_features = ... # [num_authors, num_author_features]
# Add features:
feature_store['paper', 'x', None] = paper_features
feature_store['author', 'x', None] = author_features
# Access features:
assert torch.equal(feature_store['paper', 'x'], paper_features)
assert torch.equal(feature_store['paper'].x, paper_features)
assert torch.equal(feature_store['author', 'x', 0:20], author_features[0:20])
# `CustomGraphSampler` knows how to sample on `CustomGraphStore`:
node_sampler = CustomGraphSampler(
graph_store=graph_store,
num_neighbors=[10, 20],
...
)
[https://pytorch-geometric.readthedocs.io/en/latest/advanced/remote.html]
- 되게 심플해보이지만 내부를 보면 어지럽습니다. 심플하게 말씀드리자면 , 그래프 node, edge feature 정보는 key-value DB 에 적재, 그래프 structure 정보는 graph DB 에 적재한 뒤 샘플링하며 training 하는 방법입니다.
- 그래프 오마카세 구독자분들은 익숙하실거라 생각되네요. 제가 3주 가까이 large graph dataset 관련 논문들을 리뷰했었는데 그 과정들이 그대로 반영되어 있습니다. 아마존에서는 training 후 발생하는 embedding 값을 neptune 에 적재해서 DB inference 하는데 난이도가 어마무시해보이더라구요.
- 마지막 항목은 사실 올해 제 숙제 중 하나입니다. DB tunning 에 대해서도 알아야한다는 점이 부담되어 지금 구현을 망설이고 있네요. 그래도 빨리 구현해서 오마카세 구독자 분들에게 좋은 그래프 정보를 전달한다는 사명이 있기에 상반기내로 추진해보도록 하겠습니다 …!