웹사이트 검색

그래프 신경망에 대한 심층 탐구


그래프 신경망(GNN)은 복잡하고 상호 연결된 데이터를 이해하는 강력한 딥러닝 아키텍처로 자리 잡았습니다. 이미지나 시퀀스처럼 고정된 크기의 입력 데이터를 처리하는 전통적인 신경망과 달리, GNN은 그래프 내에서 엔티티가 어떻게 연결되고 영향을 주며 상호작용하는지를 포착하는 관계를 이해하도록 설계되었습니다. 이러한 특성 덕분에 GNN은 소셜 네트워크, 분자 화학부터 추천 시스템, 사기 탐지에 이르기까지 구조가 중요한 분야에서 특히 유용합니다.

이 기사에서는 GNN의 핵심 아이디어를 분석하고, 그들이 어떻게 발전해왔는지를 탐구하며, 실제 문제 해결에 어떻게 활용되는지를 강조할 것입니다. 또한 PyTorch 라이브러리를 사용하여 만든 실습 예제를 통해 GNN이 실제로 어떻게 구현되는지도 배울 수 있습니다.

핵심 요점

  • 그래프 신경망(GNN)은 상호 연결된 데이터 내의 관계를 모델링하는 데 매우 효과적이며, 구조와 의존성이 중요한 작업에 이상적입니다.
  • GNN은 전통적인 딥러닝을 그래프 형식으로 확장하여 노드, 엣지 및 이들의 연결로부터 학습할 수 있게 합니다.
  • 인기 있는 GNN 아키텍처인 그래프 컨볼루션 네트워크(GCN), 그래프 어텐션 네트워크(GAT), 그리고 GraphSAGE는 노드 간 정보를 집계하고 전달하는 다양한 방법을 제공합니다.
  • GNN의 실제 응용은 소셜 네트워크 분석, 분자 특성 예측, 추천 시스템, 사기 탐지, 지식 그래프에 걸쳐 있습니다.
  • GNN 구현은 현대 프레임워크인 PyTorch Geometric을 사용하면 데이터 처리, 메시지 전달, 모델 구성 등을 간편하게 할 수 있습니다.
  • 실습 구현은 그래프 데이터 로딩, 모델 정의, 학습 및 결과 평가를 포함한 GNN 워크플로우를 보여줍니다.
  • GNN는 계속해서 빠르게 발전하고 있으며, 이러한 발전은 점점 더 크고 복잡한 그래프를 처리하는 데 있어 확장성, 효율성 및 성능을 향상시키고 있습니다.

그래프 신경망이란 무엇인가요?

그래프 신경망, 줄여서 GNN은 그래프처럼 구조화된 데이터를 다룰 수 있는 비교적 새로운 유형의 신경망입니다. 그래프는 기본적으로 노드로 표현된 여러 객체와 노드를 연결하는 에지로 표현된 객체 간의 관계로 이루어져 있으며, GNN은 에지에 방향이 있는 방향 그래프와 에지에 특정 방향이 없는 무방향 그래프 모두를 처리할 수 있습니다. 이러한 그래프는 크기와 형태가 크게 다를 수도 있습니다. GNN의 아키텍처는 여러 층으로 구성되며, 각 층은 이전 층으로부터 정보를 받아 처리합니다. 우리는 노드와 에지, 그리고 그와 관련된 특성들을 세트로 표현한 그래프를 GNN에 입력으로 제공합니다. 우리가 얻는 것은 입력 그래프의 각 노드에 대한 노드 임베딩 집합입니다. 이 임베딩은 네트워크가 각 노드에 대해 학습한 특징을 나타냅니다. 일반적인 신경망이 벡터, 행렬 또는 텐서로만 연산하는 대신, GNN은 완전한 그래프 구조로 된 데이터와도 작업할 수 있습니다. 이는 소셜 네트워크, 분자 구조 또는 교통 시스템과 같은 네트워크화된 데이터를 다루기에 매우 유연하게 만듭니다. 관련 수학은 복잡하지만, 큰 그림의 아이디어는 그래프를 반복하면서 노드 간 메시지를 전달하여 유용한 표현을 학습한다는 것입니다.

그래프 신경망은 어떻게 작동하나요?

그래프 신경망, 줄여서 GNN은 네트워크 내 노드 간의 패턴을 학습하는 것과 관련이 있습니다. 주요 아이디어는 각 노드가 주변 노드에 메시지를 전달하여 자신에 대한 정보를 공유하는 것입니다.

  • GNN에서는 각 노드가 연결된 노드들과 정보를 교환하면서 모델이 전체 그래프 구조를 점진적으로 이해할 수 있도록 돕습니다.
  • 각 노드는 자신의 특성과 이웃 노드의 특성을 사용하여 '메시지'를 생성합니다.
  • 동시에, 인접한 노드들은 자신들의 메시지를 생성하여 다시 보냅니다.
  • 노드가 이러한 메시지를 받으면 모든 들어오는 정보를 집계하여 내부 상태를 업데이트합니다.
  • 이 반복적인 메시지 전달은 지식이 그래프를 통해 흐르도록 하여, 노드가 자신의 바로 인접한 이웃을 넘어서는 그래프의 일부에 대해 학습할 수 있게 합니다.
  • 이 과정을 여러 층으로 쌓음으로써, GNN은 더 복잡하고 깊은 관계를 학습할 수 있습니다.
  • 층이 추가될수록 모델은 그래프의 보다 풍부하고 의미 있는 특징 표현을 만들어냅니다.

PyTorch에서 그래프 신경망 구현하기

코라 데이터셋

Cora 데이터셋은 그래프 표현 학습을 연구하는 연구자들 사이에서 널리 사용되는 벤치마크입니다. 이 데이터셋에는 여러 과학 논문이 포함되어 있으며, '사례 기반', '유전 알고리즘', '신경망', '확률적 방법', '강화 학습', '규칙 학습'과 같은 7가지 범주로 나뉩니다. Cora 데이터셋은 오랫동안 존재해 왔으며 이 분야의 많은 프로젝트에서 여전히 주요 자원으로 활용되고 있습니다. 이 데이터셋은 모델이 문서의 텍스트 내용과 문서 간 인용 네트워크를 얼마나 효과적으로 분석할 수 있는지를 평가할 수 있는 수단을 제공합니다. 많은 주목할 만한 그래프 신경망 논문들이 이러한 이중 과제의 성능을 평가하기 위해 Cora를 사용했습니다. Cora는 출판물을 노드로, 이들 간의 인용을 노드를 연결하는 엣지로 구성된 그래프 형태로 만들어져 있습니다. 각 문서는 그 내용물을 나타내는 특징 벡터와 연관되어 있습니다. 여기서의 과제는 인용 그래프, 내용 벡터, 그리고 그들 간의 관계를 살펴보면서 주어진 출판물이 일곱 클래스 중 어느 클래스에 속하는지 예측할 수 있는 모델을 개발하는 것입니다.

데이터 전처리

다음 명령어로 PyTorch Geometric 라이브러리를 설치합니다:

pip install torch_geometric

그런 다음 PyTorch Geometric 라이브러리를 사용하여 데이터셋을 로드하고 전처리할 수 있습니다.

from torch_geometric.datasets import Planetoid
import torch_geometric.transforms as T

dataset = Planetoid(root='data/Cora', name='Cora', transform=T.NormalizeFeatures())

Planetoid 클래스는 Cora 데이터셋을 불러오고 특징 벡터를 정규화합니다. 우리는 데이터셋을 사용하여 전처리된 데이터를 얻을 수 있으며, 이는 다음과 같은 속성을 가진 Data 객체를 제공합니다:

  • x: 형태가 ‘(num_nodes, num_features)’인 노드 특성 행렬
  • edge_index: 모양이 ‘(2, num_edges)’인 엣지 연결 행렬
  • y: 형태가 ‘(num_nodes)’인 노드 라벨 벡터
  • train_mask, val_mask, test_mask: 어떤 노드가 학습, 검증, 테스트에 사용되는지를 나타내는 불리언 마스크입니다.

모델 아키텍처

그래프 신경망을 구축할 때, 올바른 모델 아키텍처를 선택하는 것이 매우 중요합니다. 여기서는 PyTorch의 torch_geometric 라이브러리를 사용한 기본 구현을 살펴보겠습니다. 우리는 그래프 합성곱 네트워크(graph convolutional network)를 활용할 예정인데, 이는 다양한 그래프 학습 작업을 위한 견고한 출발점이 됩니다.

import torch
import torch.nn.functional as F
from torch_geometric.nn import GCNConv

class GNN(torch.nn.Module):
    def __init__(self, in_channels, hidden_channels, out_channels):
        super(GNN, self).__init__()
        # Define the first graph convolutional layer
        self.conv1 = GCNConv(in_channels, hidden_channels)
        # Define the second graph convolutional layer
        self.conv2 = GCNConv(hidden_channels, out_channels)
        # Define the linear layer
        self.linear = torch.nn.Linear(out_channels, out_channels)

    def forward(self, x, edge_index):
        # Apply the first graph convolutional layer
        x = self.conv1(x, edge_index)
        # Apply the ReLU activation function
        x = F.relu(x)
        # Apply the second graph convolutional layer
        x = self.conv2(x, edge_index)
        # Apply the ReLU activation function
        x = F.relu(x)
        # Apply the linear layer
        x = self.linear(x)
        # Apply the log softmax activation function
        return F.log_softmax(x, dim=1)
  • 위 코드에서 우리는 torch와 torch.nn.functional을 가져와서 몇 가지 유용한 신경망 모듈과 함수에 접근할 수 있었습니다. 그 다음, torch와 nn.Module을 상속받는 GNN 클래스를 정의했습니다.
  • init 메서드에서 우리는 PyTorch Geometric의 GCNConv 모듈을 사용하여 두 개의 컨볼루션 레이어를 정의했습니다. 이를 통해 그래프 컨볼루션을 쉽게 구현할 수 있습니다. 또한 간단한 선형 레이어를 추가했습니다.
  • 순방향 전달은 먼저 입력을 두 개의 컨볼루션 레이어를 통해 통과시키며, 매번 ReLU 활성화를 적용합니다. 그런 다음 선형 레이어를 거치고 마지막으로 출력 값을 압축하기 위해 로그 소프트맥스를 적용합니다.

몇 줄의 코드만으로 멋진 그래프 신경망을 만들 수 있어요!

분명히, 이것은 단순한 예제이지만, PyTorch와 PyTorch Geometric이 그래프 신경망 아키텍처를 빠르게 프로토타입하고 반복할 수 있게 해주는 방식을 볼 수 있습니다. GCNConv 레이어는 그래프 구조를 우리의 모델에 쉽게 통합할 수 있게 해줍니다.

훈련

학습을 위해 크로스 엔트로피 손실 함수와 Adam 옵티마이저를 사용할 것입니다. Data 객체에 있는 마스크 속성을 이용하여 데이터를 학습, 검증, 테스트 세트로 나눌 수 있습니다.

# Set the device to CUDA if available, otherwise use CPU
device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
# Define the GNN model with the specified input, hidden, and output dimensions, and move it to the device
model = GNN(dataset.num_features, 16, dataset.num_classes).to(device)
# Define the Adam optimizer with the specified learning rate and weight decay
optimizer = torch.optim.Adam(model.parameters(), lr=0.01, weight_decay=5e-4)

# Define the training function
def train():
    # Set the model to training mode
    model.train()
    # Zero the gradients of the optimizer
    optimizer.zero_grad()
    # Perform a forward pass of the model on the training nodes
    out = model(dataset.x.to(device), dataset.edge_index.to(device))
    # Compute the negative log-likelihood loss on the training nodes
    loss = F.nll_loss(out[dataset.train_mask], dataset.y[dataset.train_mask])
    # Compute the gradients of the loss with respect to the model parameters
    loss.backward()
    # Update the model parameters using the optimizer
    optimizer.step()
    # Return the loss as a scalar value
    return loss.item()

# Define the testing function
@torch.no_grad()
def test():
    # Set the model to evaluation mode
    model.eval()
    # Perform a forward pass of the model on all nodes
    out = model(dataset.x.to(device), dataset.edge_index.to(device))
    # Compute the predicted labels by taking the argmax of the output scores
    pred = out.argmax(dim=1)
    # Compute the training, validation, and testing accuracies
    train_acc = pred[dataset.train_mask].eq(dataset.y[dataset.train_mask]).sum().item() / dataset.train_mask.sum().item()
    val_acc = pred[dataset.val_mask].eq(dataset.y[dataset.val_mask]).sum().item() / dataset.val_mask.sum().item()
    test_acc = pred[dataset.test_mask].eq(dataset.y[dataset.test_mask]).sum().item() / dataset.test_mask.sum().item()
    # Return the accuracies as a tuple
    return train_acc, val_acc, test_acc

# Train the model for 500 epochs
for epoch in range(1, 500):
    # Perform a single training iteration and get the loss
    loss = train()
    # Evaluate the model on the training, validation, and testing sets and get the accuracies
    train_acc, val_acc, test_acc = test()
    # Print the epoch number, loss, and accuracies
    print(f'Epoch: {epoch:03d}, Loss: {loss:.4f}, Train Acc: {train_acc:.4f}, Val Acc: {val_acc:.4f}, Test Acc: {test_acc:.4f}')

train 함수는 한 번의 학습을 수행하고 손실 값을 반환합니다. test 함수는 모델이 학습, 검증, 테스트 세트에서 얼마나 잘 수행되는지 확인하고 정확도를 반환합니다. 우리는 모델을 500 에포크 동안 학습시키고 각 에포크에서 학습 및 테스트 정확도를 출력했습니다.

GNN 모델의 정확도를 계산합니다

아래 코드는 모델이 전체 데이터셋에서 얼마나 정확한지 계산하는 함수를 정의합니다. compute_accuracy() 함수는 모델을 평가 모드로 전환하고, 순전파를 수행하며, 각 노드에 대한 라벨을 예측합니다. 그런 다음 이 예측된 라벨을 실제 라벨과 비교하여 올바른 예측 수를 계산합니다. 이후 올바른 예측 수를 데이터셋의 총 노드 수로 나누어 정확도 백분율을 구합니다.

@torch.no_grad()
def compute_accuracy():
    model.eval()
    out = model(dataset.x.to(device), dataset.edge_index.to(device))
    pred = out.argmax(dim=1)
    correct = pred.eq(dataset.y.to(device)).sum().item()
    total = dataset.y.shape[0]
    accuracy = correct / total
    return accuracy

accuracy = compute_accuracy()
print(f"Accuracy: {accuracy:.4f}")

이 경우, 모델의 Cora 데이터셋에 대한 정확도는 0.8006이었습니다. 이는 모델이 약 80%의 경우에 클래스 레이블을 올바르게 예측할 수 있었다는 것을 의미합니다. 꽤 괜찮은 수치이지만 완벽하지는 않습니다. 정확도는 모델이 전체적으로 얼마나 잘 수행되고 있는지 빠르게 높은 수준에서 보여줍니다. 하지만 모델이 어디에서 잘하고 있고 어디에서 어려움을 겪고 있는지를 진정으로 이해하려면 더 깊이 분석해야 합니다.

모델의 효과를 더 깊이 이해하기 위해서는 정밀도, 재현율, F1 점수, 혼동 행렬과 같은 다른 평가 지표를 고려하는 것이 좋습니다. 이러한 지표들은 모델이 긍정 및 부정 사례를 올바르게 식별하는 능력이나 불균형 데이터셋을 처리하는 능력 등 다양한 측면에서 성능에 대한 통찰을 제공합니다. 따라서 80%의 정확도는 준수하지만, 이 모델을 대단한 성공이라고 단정하기 전에 더 많은 맥락을 확인하는 것이 필요합니다. 정확도 지표만으로는 내부에서 실제로 일어나는 일을 완전히 이해하기 어렵습니다. 하지만 성능을 평가하는 출발점으로는 좋은 지표입니다.

평가

우리는 정확도, 정밀도, 재현율, F1 점수 같은 것을 사용해서 GNN의 성능을 평가할 수 있습니다. 하지만 t-SNE를 사용해서 모델이 학습한 노드 임베딩을 시각화할 수도 있습니다. 이것은 고차원 임베딩을 2D로 투영하여 시각화할 수 있게 해줍니다.

# Import the necessary libraries
from sklearn.manifold import TSNE
import matplotlib.pyplot as plt

# Set the model to evaluation mode
model.eval()

# Perform a forward pass of the model on the dataset
out = model(dataset.x.to(device), dataset.edge_index.to(device))

# Apply t-SNE to the output feature matrix to obtain a 2D embedding
emb = TSNE(n_components=2).fit_transform(out.cpu().detach().numpy())

# Create a figure with a specified size
plt.figure(figsize=(10,10))

# Create a scatter plot of the embeddings, color-coded by the true labels
plt.scatter(emb[:,0], emb[:,1], c=dataset.y, cmap='jet')

# Display the plot
plt.show()

참고: 독자는 위 코드를 실행할 수 있습니다. 이 코드는 해석할 수 있는 산점도를 표시합니다. 이 코드는 t-SNE를 사용하여 학습된 노드 임베딩을 2D 산점도로 보여주는데, 이는 고차원 데이터를 시각화하는 스마트한 방법입니다. 무슨 일이 일어나고 있는지 차근차근 살펴보겠습니다:

  • 플롯의 각 점은 데이터셋의 한 노드를 나타냅니다. x축과 y축은 t-SNE가 임베딩을 압축한 두 차원입니다. 각 점의 색상은 데이터셋에서 해당 노드의 실제 레이블을 나타냅니다.
  • 유사한 임베딩을 가진 노드는 유사한 레이블을 가져야 하므로, 그래프 상에서 서로 가까이 모이게 됩니다. 반대로, 매우 다른 임베딩을 가진 노드는 아마도 다른 레이블을 가지게 될 것이므로, 그래프 상에서 서로 멀리 떨어지게 됩니다.
  • 전반적으로, 이 플롯은 학습된 임베딩을 기반으로 노드 간의 관계를 명확하게 보여줍니다. 일부 기본적인 유사성을 공유하는 그룹이 형성되는 것을 확인할 수 있습니다. 이는 모델 내부를 들여다보고 개념이 어떻게 조직되고 있는지 이해하는 데 유용한 방법입니다.

잠재적 과제와 고려사항

  • 2708개의 노드와 5429개의 엣지를 가진 Cora 데이터셋은 비교적 작은 편으로 간주됩니다. 이는 GNN의 효율성을 저해할 수 있으며, 데이터 증강이나 전이 학습과 같은 보다 고급 방법의 채택이 필요할 수 있습니다.
  • Cora 데이터셋은 하나의 노드 유형과 하나의 엣지 유형으로 구성되어 있어 동질 네트워크를 이룹니다. 이는 다양한 노드와 엣지 유형이 포함된 더 복잡한 네트워크에 적용할 때 GNN의 활용 가능성을 제한할 수 있습니다.
  • 은닉층의 수, 은닉 유닛의 수, 학습률과 같은 하이퍼파라미터의 적절한 값을 선택하는 것은 GNN의 성능에 큰 영향을 미칠 수 있으며, 신중한 조정이 필요합니다.

자주 묻는 질문

  • 1. 그래프 신경망(GNN)이란 무엇인가요?

GNN은 그래프 구조 데이터를 처리하도록 설계된 신경망입니다. 이는 이웃 노드로부터 정보를 집계하여 노드, 엣지 또는 그래프 수준의 표현을 학습합니다.

  • 2. GNN은 기존 신경망과 어떻게 다른가요?

전통적인 네트워크는 격자 형태의 데이터(이미지, 시퀀스)를 처리하는 반면, GNN은 소셜 네트워크나 분자 그래프와 같은 불규칙하고 상호 연결된 구조를 모델링할 수 있습니다.

  • 3. GNN은 어떤 유형의 문제에 사용되나요?

이들은 일반적으로 노드 분류, 링크 예측, 그래프 분류, 추천 시스템, 사기 탐지, 분자 특성 예측에 사용됩니다.

  • 4. GNN에서 메시지 전달이란 무엇인가요?

메시지 전달은 노드가 이웃과 정보를 교환하고, 임베딩을 업데이트하며, 문맥적 관계를 학습하는 핵심 메커니즘입니다.

  • 5. GNN은 매우 큰 그래프에도 잘 확장되나요?

메모리 및 이웃 확장으로 인해 스케일링이 어려울 수 있습니다. 샘플링(GraphSAGE), 미니 배치 처리, 분산 학습과 같은 기술이 도움이 됩니다.

  • 6. GNN을 구현하는 데 가장 좋은 프로그래밍 라이브러리는 무엇인가요?

인기 있는 프레임워크에는 GNN 모델을 구축하기 위한 준비된 레이어와 유틸리티를 제공하는 PyTorch Geometric (PyG)와 Deep Graph Library (DGL)가 있습니다.

  • 7. GNN은 실시간 애플리케이션에 적합한가요?

네, 모델 복잡도에 따라 달라집니다. 경량 아키텍처와 샘플링 기반 접근 방식은 거의 실시간 성능을 달성하는 데 도움이 됩니다.

  • 8. GNN은 동적이거나 진화하는 그래프를 처리할 수 있나요?

네, 동적 GNN 변형은 시간에 따라 변하는 그래프를 처리할 수 있어 교통 예측, 시간 기반 추천, 이상 탐지 등에 유용합니다.

  • 9. GNN에 필요한 데이터 전처리는 무엇인가요?

일반적으로 인접 정보, 노드/엣지 특성을 준비하고, 선택한 라이브러리에 맞게 그래프가 제대로 포맷되어 있는지 확인해야 합니다.

  • 10. GNN는 해석할 수 있나요?

주목 메커니즘과 GNNExplainer 같은 도구를 통해 중요한 노드와 엣지를 강조하며 해석 가능성이 향상되고 있습니다.

결론

이 글에서는 그래프 신경망(GNN)의 핵심 개념을 살펴보고, 이를 다양한 분야에 어떻게 적용할 수 있는지 탐구했습니다. GNN은 그래프 구조 데이터를 다루는 데 특별히 적합하여, 소셜 네트워크, 분자 그래프, 교통 시스템 등에서 발견되는 복잡한 관계를 모델이 이해하고 추론할 수 있도록 합니다.

이 아이디어를 실제로 보여주기 위해, 우리는 그래프 학습의 벤치마크인 인기 있는 Cora 데이터셋을 사용했습니다. 이 데이터셋에서 각 출판물은 노드로 표현되며, 그 사이의 인용 관계가 엣지를 형성합니다. 우리의 목표는 각 논문의 텍스트 특징과 인용 링크를 모두 활용하여 논문의 카테고리를 예측하는 것이었습니다.

우리는 PyTorch Geometric 라이브러리를 사용하여 데이터셋을 준비하고, 특징 벡터를 정규화한 후 데이터를 훈련, 검증, 테스트 세트로 나누었습니다. 이후 그래프 컨볼루션 레이어를 사용한 간단한 GNN을 구축하고, 그 뒤에 선형 분류기를 추가한 후 Adam 옵티마이저를 사용하여 교차 엔트로피 손실로 모델을 학습시켰습니다. 마지막으로 모델의 성능을 정확도로 평가했습니다.

탐구할 수 있는 추가적인 기술과 개선 사항이 많이 있지만, 이 프로젝트는 GNN이 어떻게 작동하는지와 복잡한 관계형 데이터 학습에 얼마나 효과적인지를 이해하는 데 좋은 입문 기회를 제공합니다.

자료

  • 처음부터 신경망 구축하기: 1부
  • 딥러닝이란 무엇인가요? 초보자를 위한 신경망 가이드
  • 딥러닝 아키텍처 설명: ResNet, InceptionV3, SqueezeNet
  • PyTorch 101: PyTorch로 딥러닝 배우기

Linux-Console.net 커뮤니티와 함께 학습해 주셔서 감사합니다.