Unverified Commit 67f93144 authored by Muhyun Kim's avatar Muhyun Kim Committed by GitHub
Browse files

user guide korean version (#3559)


Co-authored-by: default avatarzhjwy9343 <6593865@qq.com>
parent d2ef2433
.. _guide_ko-training-link-prediction:
5.3 링크 예측
-----------
:ref:`(English Version) <guide-training-link-prediction>`
어떤 노드들 사이에 에지가 존재하는지 아닌지를 예측하고 싶은 경우가 있고, 이를 *링크 예측 과제*라고 한다.
개요
~~~~~~~~~
GNN 기반의 링크 예측 모델은 노드 :math:`u` :math:`v` 간의 연결 가능도(likelihood) :math:`\boldsymbol{h}_u^{(L)}` 함수로 표현하는데, 여기서 :math:`\boldsymbol{h}_v^{(L)}` 멀티-레이어 GNN 통해서 계단된 노드 representation이다.
.. math::
y_{u,v} = \phi(\boldsymbol{h}_u^{(L)}, \boldsymbol{h}_v^{(L)})
:math:`y_{u,v}` 노드 :math:`u` :math:`v` 사이의 점수를 한다.
링크 예측 모델을 학습시키는 것은 에지로 연결된 노드들에 대한 점수와 임의의 노드 쌍에 대한 점수를 비교하면서 이뤄진다. 예를 들어, 노드 :math:`u` :math:`v` 사이에 에지가 존재하는 경우 노드 :math:`u` :math:`v` 사이의 점수가 노드 :math:`u` 임의의 *노이즈* 분표 :math:`v' \sim P_n(v)`에 따라 샘플링된 노드 :math:`v'` 간의 점수보다 높도록 하는 학습이다.
위를 달성하기 위한 다양한 loss 함수가 있다. 가지 예는 다음과 같다:
- Cross-entropy loss:
:math:`\mathcal{L} = - \log \sigma (y_{u,v}) - \sum_{v_i \sim P_n(v), i=1,\dots,k}\log \left[ 1 - \sigma (y_{u,v_i})\right]`
- BPR loss:
:math:`\mathcal{L} = \sum_{v_i \sim P_n(v), i=1,\dots,k} - \log \sigma (y_{u,v} - y_{u,v_i})`
- Margin loss:
:math:`\mathcal{L} = \sum_{v_i \sim P_n(v), i=1,\dots,k} \max(0, M - y_{u, v} + y_{u, v_i})`,
where :math:`M` is a constant hyperparameter.
여기서 :math:`M` 상수 하이퍼-파라메터이다.
`implicit feedback <https://arxiv.org/ftp/arxiv/papers/1205/1205.2618.pdf>`__ 이나 `noise-contrastive estimation <http://proceedings.mlr.press/v9/gutmann10a/gutmann10a.pdf>`__ 알고 있다면, 아이디어는 친숙할 것이다.
:math:`u` :math:`v` 사이의 점수를 계산하는 뉴럴 네트워크 모델은 :ref:`위에서 설명한 <guide-training-edge-classification>` 에지 리그레션 모델과 동일하다.
다음은 dot product 사용해서 에지들의 점수를 계산하는 예제이다.
.. code:: python
class DotProductPredictor(nn.Module):
def forward(self, graph, h):
# h contains the node representations computed from the GNN defined
# in the node classification section (Section 5.1).
with graph.local_scope():
graph.ndata['h'] = h
graph.apply_edges(fn.u_dot_v('h', 'h', 'score'))
return graph.edata['score']
학습
~~~~~
점수를 예측하는 모델은 그래프들에 적용되기 때문에, 네가티브 샘들은 별도의 그래프로 표현되어야 한다. , 그것은 에지들이 모두 네가티브 노드들의 쌍들로만 구성된 그래프이다.
아래 코드는 네가티브 샘들로 구성된 그래프를 만드는 예제이다. 에지 :math:`(u,v)` :math:`k` 개의 네가티브 셈플들 :math:`(u,v_i)` 갖는다. 여기서 :math:`v_i` 균등 분포에서 샘플링된다.
.. code:: python
def construct_negative_graph(graph, k):
src, dst = graph.edges()
neg_src = src.repeat_interleave(k)
neg_dst = torch.randint(0, graph.num_nodes(), (len(src) * k,))
return dgl.graph((neg_src, neg_dst), num_nodes=graph.num_nodes())
에지 점수를 예측하는 모델은 에지 분류 또는 에지 리그레션 모델과 같다.
.. code:: python
class Model(nn.Module):
def __init__(self, in_features, hidden_features, out_features):
super().__init__()
self.sage = SAGE(in_features, hidden_features, out_features)
self.pred = DotProductPredictor()
def forward(self, g, neg_g, x):
h = self.sage(g, x)
return self.pred(g, h), self.pred(neg_g, h)
그런 다음, 학습 룹은 반복적으로 네가티브 그래프를 만들고 loss 계산한다.
.. code:: python
def compute_loss(pos_score, neg_score):
# Margin loss
n_edges = pos_score.shape[0]
return (1 - pos_score + neg_score.view(n_edges, -1)).clamp(min=0).mean()
node_features = graph.ndata['feat']
n_features = node_features.shape[1]
k = 5
model = Model(n_features, 100, 100)
opt = torch.optim.Adam(model.parameters())
for epoch in range(10):
negative_graph = construct_negative_graph(graph, k)
pos_score, neg_score = model(graph, negative_graph, node_features)
loss = compute_loss(pos_score, neg_score)
opt.zero_grad()
loss.backward()
opt.step()
print(loss.item())
학습이 종료되면, 노드 representation 다음과 같이 얻을 있다:
.. code:: python
node_embeddings = model.sage(graph, node_features)
노드 임베딩을 사용하는 방법은 여러가지가 있다. 몇가지 예를 들면, 다운스트림 분류기 학습, 관련된 엔터리 추천을 위한 nearest neighbor search 또는 maximum inner product search 같은 것이 있다.
Heterogeneous 그래프들
~~~~~~~~~~~~~~~~~~~~
Heterogeneous 그래프에서의 링크 예측은 homogeneous 그래프에서의 링크 예측과 많이 다르지 않다. 다음 예제는 하나의 에지 타입에 대해서 예측을 수행한다고 가정하고 있는데, 이를 여러 에지 타입으로 확장하는 것은 쉽다.
링크 예측을 위해서 :ref:`앞에서 <guide-training-edge-classification-heterogeneous-graph>` ``HeteroDotProductPredictor`` 재활용해서 에지 타입에 대한 에지의 점수를 계산할 있다.
.. code:: python
class HeteroDotProductPredictor(nn.Module):
def forward(self, graph, h, etype):
# h contains the node representations for each node type computed from
# the GNN defined in the previous section (Section 5.1).
with graph.local_scope():
graph.ndata['h'] = h
graph.apply_edges(fn.u_dot_v('h', 'h', 'score'), etype=etype)
return graph.edges[etype].data['score']
네가티브 샘플링을 수행하기 위해서, 링크 예측을 수행할 에지 타입에 대한 네가티브 그램프를 생성하면 된다.
.. code:: python
def construct_negative_graph(graph, k, etype):
utype, _, vtype = etype
src, dst = graph.edges(etype=etype)
neg_src = src.repeat_interleave(k)
neg_dst = torch.randint(0, graph.num_nodes(vtype), (len(src) * k,))
return dgl.heterograph(
{etype: (neg_src, neg_dst)},
num_nodes_dict={ntype: graph.num_nodes(ntype) for ntype in graph.ntypes})
모델을 heterogeneous 그래프들에서 에지 분류하는 모델과는 약간 다른데, 이유는 링크 예측을 에지 타입을 지정해야하기 때문이다.
.. code:: python
class Model(nn.Module):
def __init__(self, in_features, hidden_features, out_features, rel_names):
super().__init__()
self.sage = RGCN(in_features, hidden_features, out_features, rel_names)
self.pred = HeteroDotProductPredictor()
def forward(self, g, neg_g, x, etype):
h = self.sage(g, x)
return self.pred(g, h, etype), self.pred(neg_g, h, etype)
학습 룹은 homogeneous 그래프에 대한 학습 룹과 비슷하다.
.. code:: python
def compute_loss(pos_score, neg_score):
# Margin loss
n_edges = pos_score.shape[0]
return (1 - pos_score + neg_score.view(n_edges, -1)).clamp(min=0).mean()
k = 5
model = Model(10, 20, 5, hetero_graph.etypes)
user_feats = hetero_graph.nodes['user'].data['feature']
item_feats = hetero_graph.nodes['item'].data['feature']
node_features = {'user': user_feats, 'item': item_feats}
opt = torch.optim.Adam(model.parameters())
for epoch in range(10):
negative_graph = construct_negative_graph(hetero_graph, k, ('user', 'click', 'item'))
pos_score, neg_score = model(hetero_graph, negative_graph, node_features, ('user', 'click', 'item'))
loss = compute_loss(pos_score, neg_score)
opt.zero_grad()
loss.backward()
opt.step()
print(loss.item())
.. _guide_ko-training-node-classification:
5.1 노드 분류/리그래션(Regression)
--------------------------------------------------
:ref:`(English Version) <guide-training-node-classification>`
가장 유명하고 널리 적용되고 있는 그래프 뉴럴 네트워크 중에 하나가 노드 분류이다. 학습/검증/테스트 셋의 노드는 미리 정해진 카테로기들로 중에 하나를 ground truth 카테고리로 분류되어 있다. 노드 regression 비슷하다. 학습/검증/테스트 셋의 노드에 ground truth 수가 할당되어 있다.
개요
~~~~~~
노드를 분류하기 위해서 그래프 뉴럴 네트워크는 :ref:`guide-message-passing` 에서 소개한 메시지 전달 방법을 수행해서 노드 자신의 피쳐 뿐만 아니라 노드의 이웃 노드 에지의 피쳐도 함께 활용한다. 메시지 전달은 여러 반복해서 범위의 이웃들에 대한 정보를 활용할 있다.
뉴럴 네트워크 모델 작성하기
~~~~~~~~~~~~~~~~~~~~
DGL 차례 메시지 전달을 수행하는 가지 빌트인 graph convolution 모듈을 제공한다. 여기서 우리는 GraphSAGE에서 사용되는 graph convolution 모듈인 :class:`dgl.nn.pytorch.SAGEConv` (MXNet TensorFlow에서도 사용 가능) 사용한다.
보통 그래프에 대한 딥러닝 모델에서는 메시지 전달이 여러 수행되는 멀티-레이어 그래프 뉴럴 네트워크가 필요하다. 이는 다음 코드처럼 graph convolution 모듈들을 쌓아서 구현할 있다.
.. code:: python
# Contruct a two-layer GNN model
import dgl.nn as dglnn
import torch.nn as nn
import torch.nn.functional as F
class SAGE(nn.Module):
def __init__(self, in_feats, hid_feats, out_feats):
super().__init__()
self.conv1 = dglnn.SAGEConv(
in_feats=in_feats, out_feats=hid_feats, aggregator_type='mean')
self.conv2 = dglnn.SAGEConv(
in_feats=hid_feats, out_feats=out_feats, aggregator_type='mean')
def forward(self, graph, inputs):
# inputs are features of nodes
h = self.conv1(graph, inputs)
h = F.relu(h)
h = self.conv2(graph, h)
return h
모델은 노드 분류 뿐만 아니라, :ref:`guide-training-edge-classification` , :ref:`guide-training-link-prediction` , 또는 :ref:`guide-training-graph-classification` 같은 다른 다운스트림 테스크들을 위한 히든 노드 표현을 구하기 위해서 사용될 있음을 알아두자.
빌트인 graph convolution 모듈의 전체 목록은 :ref:`apinn` 참고하자.
DGL 뉴럴 네트워크 모듈이 어떻게 동작하는지 그리고 메시지 전달을 활용한 커스텀 뉴럴 네트워크 모듈을 작성하는 방법은 :ref:`guide-nn` 있는 예제들을 참고하자.
학습 (loop)
~~~~~~~~~~~
전체 그래프를 이용한 학습은 단지 위에서 정의된 모델에 forward propagation 그리고 학습 노드들의 groud truth 레이블과 예측을 비교해서 loss 계산하는 것으로 구성된다.
절은 빌드인 데이터셋 :class:`dgl.data.CiteseerGraphDataset` 사용해서 학습 룹을 설명한다. 노드 피처 레이블은 그래프 인스턴스에 저장되어 있고, 학습-검증-테스트 분할 또한 그래프에 이진 마스크로서 저장되어 있다. 이는 :ref:`guide-data-pipeline` 에서 본것과 비슷하다.
.. code:: python
node_features = graph.ndata['feat']
node_labels = graph.ndata['label']
train_mask = graph.ndata['train_mask']
valid_mask = graph.ndata['val_mask']
test_mask = graph.ndata['test_mask']
n_features = node_features.shape[1]
n_labels = int(node_labels.max().item() + 1)
다음은 정확도(accuracy) 모델을 평가하는 예제 코드이다.
.. code:: python
def evaluate(model, graph, features, labels, mask):
model.eval()
with torch.no_grad():
logits = model(graph, features)
logits = logits[mask]
labels = labels[mask]
_, indices = torch.max(logits, dim=1)
correct = torch.sum(indices == labels)
return correct.item() * 1.0 / len(labels)
그리고, 학습 룹은 다음과 같이 작성할 있다.
.. code:: python
model = SAGE(in_feats=n_features, hid_feats=100, out_feats=n_labels)
opt = torch.optim.Adam(model.parameters())
for epoch in range(10):
model.train()
# forward propagation by using all nodes
logits = model(graph, node_features)
# compute loss
loss = F.cross_entropy(logits[train_mask], node_labels[train_mask])
# compute validation accuracy
acc = evaluate(model, graph, node_features, node_labels, valid_mask)
# backward propagation
opt.zero_grad()
loss.backward()
opt.step()
print(loss.item())
# Save model if necessary. Omitted in this example.
`GraphSAGE <https://github.com/dmlc/dgl/blob/master/examples/pytorch/graphsage/train_full.py>`__ end-to-end homogeneous 그래프 노드 분류 예제를 제공한다. 해당 모델은 ``GraphSAGE`` 클래스에 구현되어 있고, 조정가능 레이어 , dropout 확률들, 그리고 커스터마이징이 가능한 aggregation 함수 비선형성 등의 예제가 포함되어 있다.
.. _guide-training-rgcn-node-classification:
Heterogeneous 그래프
~~~~~~~~~~~~~~~~~~
만약 그래프가 heterogeneous(이종)이라면, 여러분은 노드의 모든 에지 타입에 대한 이웃들로부터 메시지를 수집하기를 원할 것이다. 모든 에지 종류에 대해서 에지 타입별로 서로 다른 graph convolution 모듈을 사용한 메시지 전달을 수행하는 것은, :class:`dgl.nn.pytorch.HeteroGraphConv` (MXNet Tensorflow에서도 제공함) 모듈을 사용해서 가능하다.
아래 코드는 heterogeneous graph convolution 정의하는데, 이는 에지 타입에 따라 별도의 graph convolution 수행하고, 모든 노드 타입들에 대한 결과로서 에지 타입에 대한 메시지 aggregation 값들을 합하는 일을 수행한다.
.. code:: python
# Define a Heterograph Conv model
class RGCN(nn.Module):
def __init__(self, in_feats, hid_feats, out_feats, rel_names):
super().__init__()
self.conv1 = dglnn.HeteroGraphConv({
rel: dglnn.GraphConv(in_feats, hid_feats)
for rel in rel_names}, aggregate='sum')
self.conv2 = dglnn.HeteroGraphConv({
rel: dglnn.GraphConv(hid_feats, out_feats)
for rel in rel_names}, aggregate='sum')
def forward(self, graph, inputs):
# inputs are features of nodes
h = self.conv1(graph, inputs)
h = {k: F.relu(v) for k, v in h.items()}
h = self.conv2(graph, h)
return h
``dgl.nn.HeteroGraphConv`` 노드 타입들과 노드 피쳐 텐서들의 사전을 입력으로 받고, 노드 타입과 노드 피쳐의 다른 사전을 리턴한다.
여기서 사용되는 데이터셋은 이미 user item 피쳐를 가지고 있고, 이는 :ref:`heterogeneous graph example <guide-training-heterogeneous-graph-example>` 에서 확인할 있다.
.. code:: python
model = RGCN(n_hetero_features, 20, n_user_classes, hetero_graph.etypes)
user_feats = hetero_graph.nodes['user'].data['feature']
item_feats = hetero_graph.nodes['item'].data['feature']
labels = hetero_graph.nodes['user'].data['label']
train_mask = hetero_graph.nodes['user'].data['train_mask']
Forward propagation 다음과 같이 단순하게 실행된다.
.. code:: python
node_features = {'user': user_feats, 'item': item_feats}
h_dict = model(hetero_graph, {'user': user_feats, 'item': item_feats})
h_user = h_dict['user']
h_item = h_dict['item']
학습 룹은 예측을 계산할 노드 representation들의 사전을 사용하는 것을 제외하고는 homogeneous graph 학습 룹과 동일하다. 예를 들어,``user``노드 만을 예측하고 싶다면, 단지 리턴된 사전에서 ``user`` 노드 임베딩을 추출하면 된다.
.. code:: python
opt = torch.optim.Adam(model.parameters())
for epoch in range(5):
model.train()
# forward propagation by using all nodes and extracting the user embeddings
logits = model(hetero_graph, node_features)['user']
# compute loss
loss = F.cross_entropy(logits[train_mask], labels[train_mask])
# Compute validation accuracy. Omitted in this example.
# backward propagation
opt.zero_grad()
loss.backward()
opt.step()
print(loss.item())
# Save model if necessary. Omitted in the example.
DGL `RGCN <https://github.com/dmlc/dgl/blob/master/examples/pytorch/rgcn-hetero/entity_classify.py>`__ end-to-end 예제를 제공한다. Heterogeneous graph convolution 정의는 `모델 구현 파일 <https://github.com/dmlc/dgl/blob/master/examples/pytorch/rgcn-hetero/model.py>`__ ``RelGraphConvLayer`` 에서 확인할 있다.
.. _guide_ko-training:
5장: 그래프 뉴럴 네트워크 학습하기
==========================
:ref:`(English Version) <guide-training>`
개요
----------------
이 장에서는 :ref:`guide-message-passing` 에서 소개한 메시지 전달 방법과 :ref:`guide-nn` 에서 소개한 뉴럴 네트워크 모듈을 사용해서 작은 그래프들에 대한 노드 분류, 에지 분류, 링크 예측, 그리고 그래프 분류를 위한 그래프 뉴럴 네트워크를 학습하는 방법에 대해서 알아본다.
여기서는 그래프 및 노드 및 에지 피쳐들이 GPU 메모리에 들어갈 수 있는 크기라고 가정한다. 만약 그렇지 않다면, :ref:`guide-minibatch` 를 참고하자.
그리고, 그래프와 노드/에지 피쳐들은 이미 프로세싱되어 있다고 가정한다. 만약 DGL에서 제공되는 데이터셋 또는 :ref:`guide-data-pipeline` 에서 소개한 ``DGLDataset`` 과 호환되는 다른 데이터셋을 사용할 계획이라면, 다음과 같이 단일-그래프 데이터셋을 위한 그래프를 얻을 수 있다.
.. code:: python
import dgl
dataset = dgl.data.CiteseerGraphDataset()
graph = dataset[0]
주의: 이 장의 예제들은 PyTorch를 백엔드로 사용한다.
.. _guide-training-heterogeneous-graph-example:
Heterogeneous 그래프
~~~~~~~~~~~~~~~~~~
때로는 heterogeneous 그래프를 사용할 경우도 있다. 노드 분류, 에지 분류, 그리고 링크 예측 과제들의 예제를 위해서 임의로 만든 heterogeneous 그래프를 사용하겠다.
임의로 생성한 heterogeneous 그래프 ``hetero_graph`` 는 다음과 같은 에지 타입을 갖는다:
- ``('user', 'follow', 'user')``
- ``('user', 'followed-by', 'user')``
- ``('user', 'click', 'item')``
- ``('item', 'clicked-by', 'user')``
- ``('user', 'dislike', 'item')``
- ``('item', 'disliked-by', 'user')``
.. code:: python
import numpy as np
import torch
n_users = 1000
n_items = 500
n_follows = 3000
n_clicks = 5000
n_dislikes = 500
n_hetero_features = 10
n_user_classes = 5
n_max_clicks = 10
follow_src = np.random.randint(0, n_users, n_follows)
follow_dst = np.random.randint(0, n_users, n_follows)
click_src = np.random.randint(0, n_users, n_clicks)
click_dst = np.random.randint(0, n_items, n_clicks)
dislike_src = np.random.randint(0, n_users, n_dislikes)
dislike_dst = np.random.randint(0, n_items, n_dislikes)
hetero_graph = dgl.heterograph({
('user', 'follow', 'user'): (follow_src, follow_dst),
('user', 'followed-by', 'user'): (follow_dst, follow_src),
('user', 'click', 'item'): (click_src, click_dst),
('item', 'clicked-by', 'user'): (click_dst, click_src),
('user', 'dislike', 'item'): (dislike_src, dislike_dst),
('item', 'disliked-by', 'user'): (dislike_dst, dislike_src)})
hetero_graph.nodes['user'].data['feature'] = torch.randn(n_users, n_hetero_features)
hetero_graph.nodes['item'].data['feature'] = torch.randn(n_items, n_hetero_features)
hetero_graph.nodes['user'].data['label'] = torch.randint(0, n_user_classes, (n_users,))
hetero_graph.edges['click'].data['label'] = torch.randint(1, n_max_clicks, (n_clicks,)).float()
# randomly generate training masks on user nodes and click edges
hetero_graph.nodes['user'].data['train_mask'] = torch.zeros(n_users, dtype=torch.bool).bernoulli(0.6)
hetero_graph.edges['click'].data['train_mask'] = torch.zeros(n_clicks, dtype=torch.bool).bernoulli(0.6)
로드맵
----
이 장은 그래프 학습 테스크를 설명하기 위해서 4개의 절로 구성되어 있다.
* :ref:`guide_ko-training-node-classification`
* :ref:`guide_ko-training-edge-classification`
* :ref:`guide_ko-training-link-prediction`
* :ref:`guide_ko-training-graph-classification`
.. toctree::
:maxdepth: 1
:hidden:
:glob:
training-node
training-edge
training-link
training-graph
......@@ -24,6 +24,7 @@ Welcome to Deep Graph Library Tutorials and Documentation
guide/index
guide_cn/index
guide_ko/index
tutorials/large/index
tutorials/cpu/index
tutorials/multi/index
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment