본문으로 건너뛰기
Kreath Archive
TechProjectsBooksAbout
TechProjectsBooksAbout

내비게이션

  • Tech
  • Projects
  • Books
  • About
  • Tags

카테고리

  • AI / ML
  • 웹 개발
  • 프로그래밍
  • 개발 도구

연결

  • GitHub
  • Email
  • RSS
© 2026 Kreath Archive. All rights reserved.Built with Next.js + MDX
홈TechProjectsBooksAbout
//
  1. 홈
  2. 테크
  3. 7장: 지식 그래프 임베딩
2026년 3월 27일·AI / ML·

7장: 지식 그래프 임베딩

TransE, DistMult, ComplEx 등 관계 예측 모델과 Node2Vec, GraphSAGE 등 노드 임베딩 기법, PyTorch Geometric을 활용한 구현까지 지식 그래프 임베딩의 핵심을 다룹니다.

17분943자7개 섹션
knowledge-graphaidata-engineering
공유
knowledge-graph7 / 10
12345678910
이전6장: GraphRAG — 그래프 기반 검색 증강 생성다음8장: 지식 그래프 쿼리와 추론

학습 목표

  • **Knowledge Graph Embedding(지식 그래프 임베딩)**의 개념과 필요성을 이해합니다
  • TransE, TransR, DistMult, ComplEx 등 관계 예측 모델을 비교합니다
  • Node2Vec, GraphSAGE 등 노드 임베딩 기법을 파악합니다
  • **Link Prediction(링크 프레딕션)**의 원리와 활용을 이해합니다
  • PyTorch Geometric과 DGL을 활용한 구현 방법을 익힙니다

그래프 임베딩이란

**Graph Embedding(그래프 임베딩)**은 그래프의 노드, 엣지, 또는 전체 구조를 연속적인 벡터 공간에 매핑하는 기법입니다. 이를 통해 그래프의 구조적 정보를 머신러닝 모델에서 직접 활용할 수 있습니다.

그래프에서 가까운 노드(A, B, C)는 벡터 공간에서도 가까이 위치하고, 멀리 떨어진 노드(D, E)는 벡터 공간에서도 다른 영역에 위치합니다.

임베딩이 필요한 이유

  • 머신러닝 호환성: 대부분의 ML 모델은 고정 길이 벡터 입력을 요구합니다
  • 효율적 유사도 계산: 벡터 간 코사인 유사도로 노드 간 유사성을 빠르게 계산합니다
  • 링크 프레딕션: 아직 연결되지 않은 노드 간의 잠재적 관계를 예측합니다
  • 노드 분류: 레이블이 없는 노드의 타입을 예측합니다
  • 클러스터링: 유사한 노드 그룹을 발견합니다

관계 예측 모델 (Knowledge Graph Embeddings)

Knowledge Graph Embedding(KGE) 모델은 (head, relation, tail) 트리플의 점수를 학습합니다. 존재하는 트리플은 높은 점수를, 존재하지 않는 트리플은 낮은 점수를 갖도록 학습됩니다.

TransE

TransE는 가장 기본적이면서 직관적인 KGE 모델입니다. 관계를 벡터 공간에서의 **이동(translation)**으로 해석합니다.

핵심 아이디어: head + relation ≈ tail

transe_concept.py
python
import numpy as np
 
# 개념적 예시
head = np.array([1.0, 2.0, 3.0])      # "Neo4j" 임베딩
relation = np.array([0.5, -1.0, 0.5])  # "DEPENDS_ON" 임베딩
tail = np.array([1.5, 1.0, 3.5])       # "Java" 임베딩
 
# TransE 점수: head + relation 과 tail의 거리가 가까울수록 좋음
score = np.linalg.norm(head + relation - tail)
# score가 작을수록 해당 트리플이 존재할 가능성이 높음

TransE의 특징을 정리하면 다음과 같습니다.

  • 장점: 간단하고 효율적이며, 1:1 관계에 효과적
  • 한계: 1:N, N:1, N:N 관계를 잘 표현하지 못함
  • 예시: (Neo4j, DEPENDS_ON, Java) -- Java에 의존하는 기술이 여러 개일 때 한계 발생

TransR

TransR은 TransE의 한계를 극복하기 위해, 엔티티와 관계를 별도의 벡터 공간에서 표현합니다.

핵심 아이디어: 관계별 변환 행렬 M_r을 도입하여, M_r * head + relation ≈ M_r * tail

transr_concept.py
python
import numpy as np
 
# TransR: 관계별 변환 행렬을 통해 다른 공간으로 프로젝션
entity_dim = 50    # 엔티티 벡터 차원
relation_dim = 30  # 관계 벡터 차원
 
head = np.random.randn(entity_dim)
tail = np.random.randn(entity_dim)
relation = np.random.randn(relation_dim)
M_r = np.random.randn(relation_dim, entity_dim)  # 변환 행렬
 
# 엔티티를 관계 공간으로 프로젝션
head_projected = M_r @ head
tail_projected = M_r @ tail
 
score = np.linalg.norm(head_projected + relation - tail_projected)

DistMult

DistMult는 관계를 대각 행렬로 표현하여 엔티티 간의 유사도를 측정합니다.

핵심 아이디어: score = head * relation * tail (요소별 곱의 합)

distmult_concept.py
python
import numpy as np
 
head = np.array([0.5, 0.3, 0.8])
relation = np.array([1.2, 0.1, 0.9])  # 대각 행렬의 대각 원소
tail = np.array([0.4, 0.7, 0.6])
 
# DistMult 점수: 요소별 곱의 합
score = np.sum(head * relation * tail)
# 점수가 높을수록 해당 트리플이 존재할 가능성이 높음
  • 장점: 계산이 빠르고, 대칭 관계를 잘 표현
  • 한계: 비대칭 관계를 표현하지 못함 (score(h,r,t) == score(t,r,h))

ComplEx

ComplEx는 DistMult를 복소수 공간으로 확장하여 비대칭 관계도 표현할 수 있습니다.

complex_concept.py
python
import numpy as np
 
# ComplEx: 복소수 벡터 사용
head = np.array([0.5+0.3j, 0.8+0.1j, 0.2+0.6j])
relation = np.array([1.0+0.5j, 0.3+0.7j, 0.9+0.2j])
tail = np.array([0.4+0.2j, 0.7+0.5j, 0.6+0.3j])
 
# ComplEx 점수: Re(head * relation * conj(tail))의 합
score = np.real(np.sum(head * relation * np.conj(tail)))

모델 비교

모델점수 함수대칭 관계비대칭 관계1:N 관계복잡도
TransEhead + rel - tail 거리불가가능약함낮음
TransR관계별 프로젝션 + 거리가능가능가능높음
DistMult요소별 곱의 합가능불가가능낮음
ComplEx복소수 곱의 실수부 합가능가능가능중간
Info

실전에서는 ComplEx가 가장 균형 잡힌 선택입니다. 대칭/비대칭 관계를 모두 처리할 수 있으며, 계산 복잡도도 합리적입니다. 대규모 그래프에서는 TransE의 단순성이 장점이 될 수 있습니다.


노드 임베딩

KGE 모델이 트리플 단위의 관계를 학습하는 것과 달리, 노드 임베딩 기법은 그래프의 전체 구조를 반영하여 각 노드의 벡터 표현을 학습합니다.

Node2Vec

Node2Vec는 그래프 위에서 **Random Walk(랜덤 워크)**를 수행하고, Word2Vec과 유사한 방식으로 노드 임베딩을 학습합니다.

node2vec_example.py
python
from node2vec import Node2Vec
import networkx as nx
 
# 그래프 생성
G = nx.Graph()
G.add_edges_from([
    ("Neo4j", "Cypher"),
    ("Neo4j", "GDS"),
    ("Neo4j", "GraphRAG"),
    ("GraphRAG", "LangChain"),
    ("GraphRAG", "벡터검색"),
    ("Python", "Neo4j"),
    ("Python", "LangChain"),
])
 
# Node2Vec 모델 학습
node2vec = Node2Vec(
    G,
    dimensions=64,   # 임베딩 차원
    walk_length=30,   # 랜덤 워크 길이
    num_walks=200,    # 노드당 워크 횟수
    p=1,              # 되돌아가기 확률 제어
    q=1,              # 탐색 깊이 제어
    workers=4
)
model = node2vec.fit(window=10, min_count=1, batch_words=4)
 
# 유사 노드 검색
similar = model.wv.most_similar("Neo4j", topn=3)
for node, similarity in similar:
    print(f"  {node}: {similarity:.3f}")

Node2Vec의 핵심 파라미터는 다음과 같습니다.

  • p (Return Parameter): 이전 노드로 되돌아갈 확률을 제어합니다. p가 클수록 되돌아가지 않으려 합니다
  • q (In-Out Parameter): BFS와 DFS의 균형을 조절합니다. q가 작으면 DFS(깊이 탐색), 크면 BFS(너비 탐색)에 가까워집니다

GraphSAGE

**GraphSAGE(Graph Sample and Aggregate)**는 이웃 노드의 특성을 집계하여 노드 임베딩을 생성하는 GNN(Graph Neural Network, 그래프 신경망) 모델입니다.

Node2Vec와 달리 GraphSAGE는 다음과 같은 장점이 있습니다.

  • 귀납적 학습(Inductive): 학습 시 보지 못한 새로운 노드에도 임베딩을 생성할 수 있습니다
  • 노드 특성 활용: 노드의 속성(텍스트, 숫자 등)을 임베딩에 반영합니다
  • 확장성: 전체 그래프가 아닌 이웃 샘플만 사용하므로 대규모 그래프에 적합합니다

FastRP

Neo4j GDS에서 제공하는 **FastRP(Fast Random Projection)**는 빠른 노드 임베딩 생성 알고리즘입니다.

fastrp_neo4j.cypher
cypher
// Neo4j GDS에서 FastRP 실행
CALL gds.graph.project('techGraph', 'Technology', 'DEPENDS_ON')
 
CALL gds.fastRP.stream('techGraph', {
  embeddingDimension: 128,
  iterationWeights: [0.0, 1.0, 1.0, 0.5]
})
YIELD nodeId, embedding
WITH gds.util.asNode(nodeId) AS node, embedding
RETURN node.name, embedding
LIMIT 5

Link Prediction (링크 프레딕션)

**Link Prediction(링크 프레딕션)**은 그래프에서 아직 연결되지 않은 노드 쌍 사이에 관계가 존재할 가능성을 예측하는 작업입니다. 지식 그래프 완성(Knowledge Graph Completion)의 핵심 기법입니다.

활용 사례

  • 추천: "이 사용자가 관심을 가질 만한 기술은?"
  • 지식 발견: "이 두 개념 사이에 숨겨진 관계가 있는가?"
  • 그래프 품질 향상: "누락된 관계를 자동으로 보완"

PyTorch Geometric을 활용한 구현

link_prediction.py
python
import torch
from torch_geometric.data import Data
from torch_geometric.nn import SAGEConv
import torch.nn.functional as F
 
class LinkPredictor(torch.nn.Module):
    """GraphSAGE 기반 링크 프레딕션 모델입니다."""
 
    def __init__(self, in_channels: int, hidden_channels: int, out_channels: int):
        super().__init__()
        self.conv1 = SAGEConv(in_channels, hidden_channels)
        self.conv2 = SAGEConv(hidden_channels, out_channels)
 
    def encode(self, x: torch.Tensor, edge_index: torch.Tensor) -> torch.Tensor:
        """노드 임베딩을 생성합니다."""
        x = self.conv1(x, edge_index)
        x = F.relu(x)
        x = F.dropout(x, p=0.5, training=self.training)
        x = self.conv2(x, edge_index)
        return x
 
    def decode(self, z: torch.Tensor, edge_label_index: torch.Tensor) -> torch.Tensor:
        """두 노드 간의 링크 확률을 계산합니다."""
        src = z[edge_label_index[0]]
        dst = z[edge_label_index[1]]
        return (src * dst).sum(dim=-1)
 
    def forward(self, x: torch.Tensor, edge_index: torch.Tensor,
                edge_label_index: torch.Tensor) -> torch.Tensor:
        z = self.encode(x, edge_index)
        return self.decode(z, edge_label_index)

학습 루프

train_link_predictor.py
python
from torch_geometric.utils import negative_sampling
 
def train_epoch(model: LinkPredictor, data: Data,
                optimizer: torch.optim.Optimizer) -> float:
    """1 에포크 학습을 수행합니다."""
    model.train()
    optimizer.zero_grad()
 
    # 노드 임베딩 생성
    z = model.encode(data.x, data.edge_index)
 
    # 포지티브 + 네거티브 샘플링
    pos_edge_index = data.edge_label_index
    neg_edge_index = negative_sampling(
        edge_index=data.edge_index,
        num_nodes=data.num_nodes,
        num_neg_samples=pos_edge_index.size(1)
    )
 
    edge_label_index = torch.cat([pos_edge_index, neg_edge_index], dim=-1)
    edge_label = torch.cat([
        torch.ones(pos_edge_index.size(1)),
        torch.zeros(neg_edge_index.size(1))
    ])
 
    # 예측 및 손실 계산
    pred = model.decode(z, edge_label_index).sigmoid()
    loss = F.binary_cross_entropy(pred, edge_label)
 
    loss.backward()
    optimizer.step()
 
    return loss.item()
Warning

링크 프레딕션 모델을 학습할 때, 테스트 데이터의 엣지가 학습 그래프에 포함되지 않도록 주의해야 합니다. 시간 기반 분할(과거 관계로 학습, 미래 관계 예측)이 실전에서 가장 신뢰할 수 있는 평가 방법입니다.


임베딩 활용 패턴

패턴 1: 유사 엔티티 검색

similar_entities.py
python
from sklearn.metrics.pairwise import cosine_similarity
import numpy as np
 
def find_similar_entities(target_embedding: np.ndarray,
                          all_embeddings: dict[str, np.ndarray],
                          top_k: int = 5) -> list[tuple[str, float]]:
    """타겟 엔티티와 가장 유사한 엔티티를 찾습니다."""
    names = list(all_embeddings.keys())
    vectors = np.array(list(all_embeddings.values()))
 
    similarities = cosine_similarity(
        target_embedding.reshape(1, -1), vectors
    )[0]
 
    top_indices = np.argsort(similarities)[::-1][:top_k]
    return [(names[i], float(similarities[i])) for i in top_indices]

패턴 2: 그래프 임베딩 + 텍스트 임베딩 결합

combined_embeddings.py
python
import numpy as np
 
def combine_embeddings(graph_emb: np.ndarray,
                       text_emb: np.ndarray,
                       alpha: float = 0.5) -> np.ndarray:
    """그래프 임베딩과 텍스트 임베딩을 가중 결합합니다."""
    # 차원 정규화
    graph_norm = graph_emb / (np.linalg.norm(graph_emb) + 1e-8)
    text_norm = text_emb / (np.linalg.norm(text_emb) + 1e-8)
 
    # 차원이 다른 경우 프로젝션 (실제로는 학습된 프로젝션 사용)
    if graph_norm.shape != text_norm.shape:
        # 간단한 제로 패딩 예시 (실전에서는 학습된 변환 사용)
        max_dim = max(len(graph_norm), len(text_norm))
        graph_padded = np.pad(graph_norm, (0, max_dim - len(graph_norm)))
        text_padded = np.pad(text_norm, (0, max_dim - len(text_norm)))
        return alpha * graph_padded + (1 - alpha) * text_padded
 
    return alpha * graph_norm + (1 - alpha) * text_norm

패턴 3: Neo4j에 임베딩 저장 및 활용

embedding_in_neo4j.cypher
cypher
// GDS로 생성한 임베딩을 노드 속성으로 저장
CALL gds.fastRP.write('techGraph', {
  embeddingDimension: 128,
  writeProperty: 'graphEmbedding'
})
 
// 저장된 임베딩으로 유사 노드 검색
MATCH (target:Technology {name: "Neo4j"})
MATCH (other:Technology)
WHERE other.name <> target.name
WITH target, other,
     gds.similarity.cosine(target.graphEmbedding, other.graphEmbedding) AS similarity
RETURN other.name, similarity
ORDER BY similarity DESC
LIMIT 5

정리

이번 장에서는 지식 그래프 임베딩의 이론과 실전을 다루었습니다.

  • KGE 모델(TransE, TransR, DistMult, ComplEx)은 트리플의 타당성을 벡터 공간에서 평가합니다
  • 노드 임베딩(Node2Vec, GraphSAGE, FastRP)은 그래프 구조를 반영한 노드 벡터를 생성합니다
  • 링크 프레딕션은 누락된 관계를 발견하여 지식 그래프를 완성합니다
  • 그래프 임베딩과 텍스트 임베딩의 결합은 GraphRAG의 검색 품질을 향상시킵니다
  • Neo4j GDS의 FastRP를 통해 그래프 임베딩을 쉽게 생성하고 활용할 수 있습니다

다음 장 미리보기: 8장에서는 지식 그래프 쿼리와 추론을 다룹니다. Cypher 고급 패턴, 그래프 알고리즘의 실전 활용, 그리고 자연어를 Cypher로 변환하는 Text2Cypher 기법을 살펴봅니다.

이 글이 도움이 되셨나요?

관련 주제 더 보기

#knowledge-graph#ai#data-engineering

관련 글

AI / ML

8장: 지식 그래프 쿼리와 추론

Cypher 고급 쿼리 패턴, PageRank/커뮤니티 감지/중심성 등 그래프 알고리즘의 실전 활용, LLM과 그래프 추론의 결합, Text2Cypher 자연어 변환까지 다룹니다.

2026년 3월 29일·16분
AI / ML

6장: GraphRAG — 그래프 기반 검색 증강 생성

Microsoft GraphRAG의 아키텍처, 커뮤니티 요약, 글로벌/로컬 검색 전략, Neo4j GraphRAG Python 라이브러리, 그리고 벡터+그래프+키워드 하이브리드 검색을 다룹니다.

2026년 3월 25일·16분
AI / ML

9장: 프로덕션 파이프라인 구축

지식 그래프의 증분 업데이트, 데이터 품질 검증, 스케일링 전략, 모니터링, 비용 최적화, 그리고 Graphiti를 활용한 실시간 KG 업데이트까지 프로덕션 운영의 핵심을 다룹니다.

2026년 3월 31일·20분
이전 글6장: GraphRAG — 그래프 기반 검색 증강 생성
다음 글8장: 지식 그래프 쿼리와 추론

댓글

목차

약 17분 남음
  • 학습 목표
  • 그래프 임베딩이란
    • 임베딩이 필요한 이유
  • 관계 예측 모델 (Knowledge Graph Embeddings)
    • TransE
    • TransR
    • DistMult
    • ComplEx
    • 모델 비교
  • 노드 임베딩
    • Node2Vec
    • GraphSAGE
    • FastRP
  • Link Prediction (링크 프레딕션)
    • 활용 사례
    • PyTorch Geometric을 활용한 구현
    • 학습 루프
  • 임베딩 활용 패턴
    • 패턴 1: 유사 엔티티 검색
    • 패턴 2: 그래프 임베딩 + 텍스트 임베딩 결합
    • 패턴 3: Neo4j에 임베딩 저장 및 활용
  • 정리