들어가기에 앞서 이 글은 신원용교수님 수업의 과제를 수행하며 정리한 글임을 밝힙니다.
데이터 준비
1. 필요한 라이브러리 import
import torch
import torch.nn.functional as F
from torch_geometric.datasets import Planetoid, CoraFull, Actor
from torch_geometric.nn import GCNConv
2. 데이터 셋 불러오기
# Load the Cora dataset
cora_dataset = Planetoid(root='/tmp/Cora', name='Cora')
cora_data = cora_dataset[0]
# Load the Corafull dataset
corafull_dataset = CoraFull(root='/tmp/Corafull')
corafull_data = corafull_dataset[0]
# Load the Actor dataset
actor_dataset = Actor(root='/tmp/Actor')
actor_data = actor_dataset[0]
추가적으로 데이터셋의 정보를 출력해봤다.
# print dataset info
print(" DATASET || nodes | edges | features ")
print("---------------------------------------")
# Q1-a: Print the number of nodes, edges, and features of the Cora network
print(" {0:9}||{1:7}|{2:7}|{3:9}".format("Cora",cora_data.num_nodes, cora_data.num_edges, cora_data.num_node_features))
# Q1-b: Print the number of nodes, edges, and features of the Corafull network
print(" {0:9}||{1:7}|{2:7}|{3:9}".format("Corafull",corafull_data.num_nodes, corafull_data.num_edges, corafull_data.num_node_features))
# Q1-c: Print the number of nodes, edges, and features of the Actor network
print(" {0:9}||{1:7}|{2:7}|{3:9}".format("Actor",actor_data.num_nodes, actor_data.num_edges, actor_data.num_node_features))
결과
Graph Neural Network(GNNs)
신경망은 데이터에 대한 연산을 수행하는 계층(layer)/모듈(module)로 구성되어 있다. 신경망은 torch.nn
패키지를 사용하여 생성할 수 있다. torch.nn.Module
신경망은 데이터에 대한 연산을 수행하는 계층(layer)/모듈(module)로 구성되어 있다.
torch.nn.Module
은 모든 뉴럴 네트워크 모듈의 기본 클래스이다. 일반적인 모델들은 이 클래스를 상속받아야 한다. 모듈들은 다른 모듈을 또 포함할 수 있다. 이러한 중첩된 구조는 복잡한 아키텍처를 쉽게 구축하고 관리할 수 있다.
init()
메소드에는 신경망 레이어의 구성요소들을 정의하고, forward()
에서는 호출 될 때 수행되는 연산을 정의한다. 이 두가지 메소드는 torch.nn.Module
을 상속받는 모든 클래스에서 반드시 정의해야 하고 override되어야 한다. nn.Module
에서 상속받아 하위 클라스로 처리하는 것은 forward 계산까지 깔끔하게 한 묶음 처리가 가능해지므로 학습 루틴 코딩이 간단해지는 장점이 있을 수 있다.
신경망의 일반적인 학습과정은 다음과 같다.
- 학습 가능한 매개 변수(또는 가중치(weight)를 갖는 신경망을 정의한다.
- 데이터셋(dataset)입력을 반복한다.
- 입력을 신경망에서 전파(process)한다.
- 손실(loss: 출력이 정답으로부터 얼마나 떨어져 있는지)을 계산한다.
- 변화도(gradient)를 신경망의 매개변수들에 역으로 전파한다. (Backpropagation)
- 신경망의 가중치를 갱신한다. 일반적으로 다음과 같은 간단한 규칙을 사용한다.
업데이트된 가중치(weight) = 가중치(weight) - 학습률(learning rate) * 변화도(gradient)
(출처:[3])
예제코드 분석하기
이를 구현하기 위해 pytorch-geometric의 introduction doc에 소개된 예제를 읽어봤다.
1) Class GCN 정의
예제 코드
import torch
import torch.nn.functional as F # 파이토치에서 제공하는 함수
from torch_geometric.nn import GCNConv
class GCN(torch.nn.Module):
def __init__(self):
super().__init__()
self.conv1 = GCNConv(dataset.num_node_features, 16)
self.conv2 = GCNConv(16, dataset.num_classes)
def forward(self, data):
x, edge_index = data.x, data.edge_index
x = self.conv1(x, edge_index)
x = F.relu(x)
x = F.dropout(x, training=self.training)
x = self.conv2(x, edge_index)
return F.log_softmax(x, dim=1)
- Class
GCN
:torch.nn.Module
을 상속받는다. __init__()
: 모델의 구조와 동작을 정의하는 생성자를 정의한다.super()
: 함수를 호출해서 이 클래스가torch.nn.Module
클래스의 속성들을 가지고 초기화 됨forward()
: ClassGCN
에 해당하는 객체를 데이터와 함께 호출하면 자동으로 실행됨model = GCN() model(input_data) # 여기서 forward() 자동 수행
- forward 연산 : H(x)식에 입력 x로부터 예측된 y를 얻는 것
doc에 따르면 non-linearity는 conv
에 integrated 되지 않았기 때문에 이후에 적용되어야한다고 한다.
이 코드는 ReLU를 intermediate non-linearity로 골랐고, softmax를 최종 출력으로 사용했다.
2) 모델 학습 시키기
device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
model = GCN().to(device)
data = dataset[0].to(device)
optimizer = torch.optim.Adam(model.parameters(), lr=0.01, weight_decay=5e-4)
model.train()
for epoch in range(200):
optimizer.zero_grad()
out = model(data)
loss = F.nll_loss(out[data.train_mask], data.y[data.train_mask])
loss.backward()
optimizer.step()
3) 모델 평가하기
model.eval()
pred = model(data).argmax(dim=1)
correct = (pred[data.test_mask] == data.y[data.test_mask]).sum()
acc = int(correct) / int(data.test_mask.sum())
print(f'Accuracy: {acc:.4f}')
>>> Accuracy: 0.8150
reference
[1] 03-05 클래스로 파이토치 모델 구현하기
[2] Module - PyTorch2.0 documentation
[3] Introduction by Example - pytorch_geometric documentation
[4] 3-3 신경망(torch.nn) Model (MNIST) - PyTorch 딥러닝 챗봇