1๏ธโฃ 6๊ฐ ๋ณต์ต
๐น Main Topic : Graph Neural Networks
โ ๋ณต์ต : Node embedding
โข ๊ทธ๋ํ์์ ์ ์ฌํ ๋ ธ๋๋ค์ด ํจ์ f ๋ฅผ ๊ฑฐ์ณ d ์ฐจ์์ผ๋ก ์๋ฒ ๋ฉ ๋์์ ๋, ์๋ฒ ๋ฉ ๊ณต๊ฐ ๋ด์์ ๊ฐ๊น์ด ์์นํ๋๋ก ๋ง๋๋ ๊ฒ


โช Encoder : ๊ฐ ๋ ธ๋๋ฅผ ์ ์ฐจ์ ๋ฒกํฐ๋ก ๋งคํ
โช Similarity function : ์๋ ๊ทธ๋ํ ๋ด์์์ ๋ ธ๋ ๊ฐ ์ ์ฌ๋์ ์๋ฒ ๋ฉ ๊ณต๊ฐ์์ ๋ ธ๋ ๋ฒกํฐ์ ๋ด์ ๊ฐ์ด ์ ์ฌํ๋๋ก ๋ง๋๋ ํจ์
โข Shallow Encoding (embedding lookup) : ์๋ฒ ๋ฉ ํ๋ ฌ์์ ๋ ธ๋์ ์๋ฒ ๋ฉ ๋ฒกํฐ๋ฅผ ๊ฐ ์นผ๋ผ์ ๋ด์, ๋จ์ํ ๋ฒกํฐ๋ฅผ ์ฝ์ด์ค๋ ๋ฐฉ์ โ ๐คจ ๋ ธ๋ ๊ฐ์ ํ๋ผ๋ฏธํฐ๋ฅผ ๊ณต์ ํ์ง ์๊ธฐ ๋๋ฌธ์ ๋ ธ๋์ ๊ฐ์๊ฐ ์ฆ๊ฐํ ์๋ก ํ๋ ฌ์ ํฌ๊ธฐ๊ฐ ๊ณ์ ๋์ด๋๊ฒ ๋๋ฉฐ, ํ๋ จ ๊ณผ์ ์์ ๋ณด์ง ๋ชปํ ๋ ธ๋๋ ์๋ฒ ๋ฉ์ ์์ฑํ ์ ์๋ค. ๋ํ ๋ ธ๋์ feature ์ ๋ณด๋ ํฌํจ๋์ง ์๋๋ค.
โก GNN
โข ๋จ์ํ look up ํ๋ ์๋ฒ ๋ฉ ๋ฐฉ์์ ํ๊ณ๋ฅผ ๊ทน๋ณตํ๊ณ ์ ๋ค์ค ๋ ์ด์ด๋ก ๊ตฌ์ฑ๋ encoder ๋ฅผ ํ์ฉ
โข Task : Node classification, Link prediction, Community detection, network similarity

๐ ๊ทธ๋ฌ๋ ๋ฌธ์ ๊ฐ ์๋ค
โช ๋คํธ์ํฌ๋ ์์์ ํฌ๊ธฐ๋ฅผ ๊ฐ์ง๊ณ ์์ผ๋ฉฐ ๋ณต์กํ topological ๊ตฌ์กฐ๋ฅผ ๊ฐ์ง๋ค.
โช ํน์ ํ ๊ธฐ์ค์ ์ด๋ ์ ํด์ง ์์๊ฐ ์๋ค.
โช ๋์ ์ด๋ฉฐ multimodal feature ๋ฅผ ๊ฐ์ง๋ค.

๐น Deep learning for Graphs
โ Notation

โข V : ๋ ธ๋์งํฉ
โข A : ์ธ์ ํ๋ ฌ (์ฐ๊ฒฐ ์ฌ๋ถ๋ฅผ ๋ํ๋ด๋ ๋ฐฉ์ : binary)
โข X : node feature ํ๋ ฌ
โข N(v) : v ์ ์ด์๋ ธ๋ ์งํฉ
โก Convolutional Neworks
โป ์ ๋ฆฌ ์ฐธ๊ณ : https://manywisdom-career.tistory.com/71
[์ธ๊ณต์ง๋ฅ] GNN
Summary โจ Idea for deep learning for graphs โพ Multiple layers of embedding transformation โพ At every layer, use the embedding at previous layer as the input โพ โญโญ Aggregation of neighbors โจ Graph convolutional network โพ Mean aggregaton โ p
manywisdom-career.tistory.com
โข Convolutional ์ฐ์ฐ : Sliding window ๋ฅผ ํตํด ์ป์ ์ ๋ณด๋ฅผ ๋ชจ๋ ๋ํด output ์ ๋์ถ

โข ์ด์๋ ธ๋์ ์ ๋ณด๋ฅผ ๋ณํํ๊ณ ๊ฒฐํฉํ์ฌ ํน์ ๋ ธ๋๋ฅผ ์๋ฒ ๋ฉํ๋ค.

โข Layer-k embedding : k hop ๋งํผ์ ์ด์๋ ธ๋์ ์ ๋ณด๋ฅผ ๊ฐ์ ธ์ ์๋ฒ ๋ฉ ํ๋ค๋ ์๋ฏธ

โข Neighborhood aggregation : ์ด์๋ ธ๋๋ก๋ถํฐ ์ ๋ณด๋ฅผ ์ง๊ณํ๋ ๋ฐฉ์์ ๋คํธ์ํฌ๋ง๋ค ๋ค๋ฅด๋ค. ์ด๋ ์ง๊ณํ๋ ํจ์๋ permutation invariant (์ ๋ ฅ ๋ฐ์ดํฐ์ ์์์ ์ํฅ์ ๋ฐ์ง ์๋) ํจ์์ฌ์ผ ํ๋ฉฐ, ๊ธฐ๋ณธ์ ์ผ๋ก ๋ง์ด ์ฌ์ฉํ๋ ๋ฐฉ์์ ์ ๋ณด๋ฅผ average (ํ๊ท ) ํ๋ ๊ธฐ๋ฒ์ ๋ง์ด ์ฌ์ฉํ๋ค.

โข ์ํ ๊ณต์



๐ Wk, Bk : ํ์ตํ ๊ฐ์ค์น ํ๋ผ๋ฏธํฐ๋ก Wk ๋ ์ด์๋ ธ๋๋ค๋ก๋ถํฐ ์ง๊ณํ ์ ๋ณด์ ๋ํด ๋ถ์ฌํ๋ ๊ฐ์ค์น์ด๊ณ Bk ๋ ํ์ฌ ๊ณ์ฐ์ค์ธ ๋ ธ๋์ ์ด์ ๋ ์ด์ด์์์ (์๊ธฐ ์์ ์) ์๋ฒ ๋ฉ ์ ๋ณด์ ๋ํ ๊ฐ์ค์น์ด๋ค. ์ด ๋ ๊ฐ์ ํตํด ์ด์์ ๋ณด์ ์ง์คํ ์ง, ์๊ธฐ ์์ ์ ๊ฐ์ ๋ณํ์ ์ง์คํ ์ง ๊ฒฐ์ ํ๋ค. ์ด ํ๋ผ๋ฏธํฐ๋ ํน์ ๋ ธ๋๋ฅผ ์๋ฒ ๋ฉํ ๋ ๋ชจ๋ ๋ ธ๋์ ๋ํด ๊ณต์ ๋๋ ๊ฐ์ด๊ธฐ ๋๋ฌธ์, ์๋ก์ด ๋ ธ๋๋ ๊ทธ๋ํ์ ๋ํด์๋ ์ผ๋ฐํ์ํฌ ์ ์๋ค.
โฃ GNN ํ๋ จ๋ฐฉ์
โข Goal : Node embedding Zv
โข input : Graph
โช Unsupervised setting : ๊ทธ๋ํ ๊ตฌ์กฐ๋ฅผ supervision์ผ๋ก ์ฌ์ฉ
โช Supervised setting [Node classification] : node label y ์ ๋ํด, ์ค์ ๋ผ๋ฒจ๊ณผ ๋ ธ๋ ์๋ฒ ๋ฉ ๊ฒฐ๊ณผ๊ฐ ๊ธฐ๋ฐ์ ์์ธก ๋ผ๋ฒจ๊ฐ ์ฌ์ด์ loss function ์ ์ ์ํ์ฌ ํ๋ จ์ ์งํ

2๏ธโฃ ์ฝ๋๋ฆฌ๋ทฐ
https://colab.research.google.com/drive/1DsdBei9OSz4yRZ-KIGEU6iaHflTTRGY-?usp=sharing
cs224w 6๊ฐ ๋ณต์ต๊ณผ์ .ipynb
Colaboratory notebook
colab.research.google.com
๐น Dataset
โข Cora dataset
- ๋ค๋ฅธ ๋ ผ๋ฌธ์ ์ธ์ฉํ๋ ์ฐ๊ฒฐ๊ตฌ์กฐ๋ฅผ ํํํ ๊ฒ : Citation Network
- 2708 ๊ฐ์ ๊ณผํ ๋ถ์ผ ๋ ผ๋ฌธ ์ถ๊ฐ์ ๋ํ ๋ฐ์ดํฐ๋ก, ๊ฐ ๋ ผ๋ฌธ์ 7๊ฐ class ๋ถ๋ฅ ์ค ํ๋์ ์ํ๋ค.
- 5429 ๊ฐ์ ๋งํฌ (์ฃ์ง)๋ก ๊ตฌ์ฑ๋์ด ์๋ค.
- ๊ฐ ๋ ธ๋๋ ๋จ์ด์ฌ์ ์ ๊ธฐ๋ฐ์ผ๋ก 0 (ํด๋น ๋จ์ด๊ฐ ์กด์ฌํ์ง ์์) ํน์ 1 (ํด๋น ๋จ์ด๊ฐ ์กด์ฌํจ) binary ๊ฐ์ ๊ฐ์ง ๋จ์ด๋ฒกํฐ๋ก ์ด๋ฃจ์ด์ ธ ์๋ค. ๋จ์ด์ฌ์ ์ 1433๊ฐ์ ๋จ์ด๋ก ๊ตฌ์ฑ๋์ด ์๋ค ๐ node_features = 1433
- Main Task : node classification (CrossEntropyLoss - ๋ค์ค๋ถ๋ฅ)

โ Data Normalization

โ GCN ๊ณผ์ ์์ ๋ ธ๋ ์ฐจ์๋ก ์ ๊ทํ ํ๋ ๊ณผ์
dataset = Planetoid("/tmp/Cora", name="Cora")
print(f'์ ๊ทํ ์์ด ํ๋ ฌ์ ๊ฐ ํ์ ๊ฐ ํฉ์ฐ ๊ฒฐ๊ณผ : {dataset[0].x.sum(dim=-1)}')
dataset = Planetoid("/tmp/Cora", name="Cora", transform = T.NormalizeFeatures()) #๐พ
print(f'์ ๊ทํ๋ฅผ ์ ์ฉํด ํ๋ ฌ์ ๊ฐ ํ์ ๊ฐ ํฉ์ฐ ๊ฒฐ๊ณผ : {dataset[0].x.sum(dim=-1)}') # dim = axis

โก GCN model architecture
class GCN(torch.nn.Module) :
def __init__(self, num_node_features : int, num_classes : int, hidden_dim : int = 16, dropout_rate : float = 0.5) :
super().__init__()
self.dropout1 = torch.nn.Dropout(dropout_rate)
self.conv1 = GCNConv(num_node_features, hidden_dim)
# (conv1): GCNConv(1433, 16)
self.relu = torch.nn.ReLU(inplace = True)
self.dropout2 = torch.nn.Dropout(dropout_rate)
self.conv2 = GCNConv(hidden_dim, num_classes)
# (conv2): GCNConv(16, 7)
def forward(self, x : Tensor, edge_index : Tensor) -> torch.Tensor :
x = self.dropout1(x)
x = self.conv1(x, edge_index)
x = self.relu(x)
x = self.dropout2(x)
x = self.conv2(x, edge_index)
return x

โข Training and Evaluation
def train_step(model : torch.nn.Module, data : Data, optimizer : torch.optim.Optimizer,loss_fn : LossFn) :
Tuple[float, float]
model.train()
optimizer.zero_grad()
mask = data.train_mask
logits = model(data.x, data.edge_index)[mask]
preds = logits.argmax(dim=1)
y = data.y[mask]
loss = loss_fn(logits, y)
acc = (preds == y).sum().item() / y.numel() #โ numel : torch tensor ํฌ๊ธฐ๋ฅผ ๋ฐํ
loss.backward()
optimizer.step()
return loss.item(), acc
@torch.no_grad()
def eval_step(model : torch.nn.Module, data : Data, loss_fn : LossFn, stage : Stage) :
model.eval()
mask = getattr(data, f'{stage}_mask')
logits = model(data.x, data.edge_index)[mask]
preds = logits.argmax(dim=1)
y = data.y[mask]
loss = loss_fn(logits, y)
acc = (preds == y).sum().item() / y.numel() #โ
return loss.item(),acc
โข optimizer.zero_grad() : ํ๋ผ๋ฏธํฐ ์ด๊ธฐํ
โข preds = logits.argmax(dim=1) : ์์ธก๊ฐ ์ธ๋ฑ์ค ๋ฐํ ๐ 7๊ฐ์ class ์ธ๋ฑ์ค ์ค ํ๋๋ฅผ ๋ฐํ

โฃ Train function define and Training
SEED = 42
MAX_EPOCHS = 200
LEARNING_RATE = 0.01
WEIGHT_DECAY = 5e-4
EARLY_STOPPING = 10
def train(model : torch.nn.Module, data : Data, optimizer : torch.optim.Optimizer,
loss_fn : LossFn = torch.nn.CrossEntropyLoss(), max_epochs : int = 200,
early_stopping : int = 10, print_interval : int = 20, verbose : bool = True) :
history = {'loss':[],'val_loss' : [], 'acc' : [], 'val_acc' : []}
for epoch in range(max_epochs) :
loss, acc = train_step(model, data, optimizer, loss_fn)
val_loss, val_acc = eval_step(model, data, loss_fn, 'val')
history['loss'].append(loss)
history['acc'].append(acc)
history["val_loss"].append(val_loss)
history['val_acc'].append(val_acc)
if epoch > early_stopping and val_loss > np.mean(history['val_loss'][-(early_stopping +1) : -1]) :
if verbose :
print('\n ealry stopping ...')
break
if verbose and epoch % print_interval == 0 :
print(f'\nEpoch : {epoch} \n----------- ')
print(f'Train loss : {loss:.4f} | Train acc : {acc:.4f}')
print(f'Val loss : {val_loss : .4f} | Val acc : {val_acc : .4f}')
test_loss, test_acc = eval_step(model, data, loss_fn, "test")
if verbose:
print(f"\nEpoch: {epoch}\n----------")
print(f"Train loss: {loss:.4f} | Train acc: {acc:.4f}")
print(f" Val loss: {val_loss:.4f} | Val acc: {val_acc:.4f}")
print(f" Test loss: {test_loss:.4f} | Test acc: {test_acc:.4f}")
return history
โข loss function ์ ์ ๋ฐ ํ์ดํผํ๋ผ๋ฏธํฐ ์ ์ (max_epoch, early stopping)
โข accuracy, loss ์ถ๋ ฅ ํจ์ ์ ์
torch.manual_seed(SEED)
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
model = GCN(dataset.num_node_features, dataset.num_classes).to(device)
data = dataset[0].to(device)
optimizer = torch.optim.Adam(model.parameters(), lr = LEARNING_RATE, weight_decay = WEIGHT_DECAY)
history = train(model, data, optimizer, max_epochs = MAX_EPOCHS, early_stopping = EARLY_STOPPING)
plt.figure(figsize = (12,4))
plot_history(history, 'GCN')

'1๏ธโฃ AIโขDS > ๐ GNN' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
[cs224w] Frequent Subgraph Mining with GNNs (0) | 2023.01.27 |
---|---|
[cs224w] Theory of Graph Neural Networks (0) | 2023.01.06 |
[CS224W] Message Passing and Node classification (0) | 2022.11.17 |
[CS224W] PageRank (0) | 2022.11.02 |
[CS224W] 1๊ฐ Machine Learning With Graphs (0) | 2022.10.11 |
๋๊ธ