dmlc--dgl
3317522622
* Add implementation of unsupervised model * [Doc] Update Implementor's information * [doc] add index of infograph * [Feature] QM9_v2 Dataset Support * fix a typo * move qm9dataset from data to examples * Update qm9_v2.py * Infograph -> InfoGraph * add implementation and results of semi-supervised model * Update README.md * Update README.md * fix a typo * Remove the duplicated links. * fix some typos * fix typos * update model.py * update collate fn * remove unused functions * Update model.py * add device option * Update evaluate_embedding.py * Update evaluate_embedding.py * Update unsupervised.py * Fix typos * fix bugs * Update README.md Co-authored-by: Mufei Li <mufeili1996@gmail.com>
83 行
2.0 KiB
Python
83 行
2.0 KiB
Python
''' Credit: https://github.com/fanyun-sun/InfoGraph '''
|
|
|
|
import torch as th
|
|
import torch.nn.functional as F
|
|
|
|
import math
|
|
|
|
def get_positive_expectation(p_samples, average=True):
|
|
"""Computes the positive part of a JS Divergence.
|
|
Args:
|
|
p_samples: Positive samples.
|
|
average: Average the result over samples.
|
|
Returns:
|
|
th.Tensor
|
|
"""
|
|
log_2 = math.log(2.)
|
|
Ep = log_2 - F.softplus(- p_samples)
|
|
|
|
if average:
|
|
return Ep.mean()
|
|
else:
|
|
return Ep
|
|
|
|
|
|
def get_negative_expectation(q_samples, average=True):
|
|
"""Computes the negative part of a JS Divergence.
|
|
Args:
|
|
q_samples: Negative samples.
|
|
average: Average the result over samples.
|
|
Returns:
|
|
th.Tensor
|
|
"""
|
|
log_2 = math.log(2.)
|
|
Eq = F.softplus(-q_samples) + q_samples - log_2
|
|
|
|
if average:
|
|
return Eq.mean()
|
|
else:
|
|
return Eq
|
|
|
|
|
|
def local_global_loss_(l_enc, g_enc, graph_id):
|
|
|
|
num_graphs = g_enc.shape[0]
|
|
num_nodes = l_enc.shape[0]
|
|
|
|
device = g_enc.device
|
|
|
|
pos_mask = th.zeros((num_nodes, num_graphs)).to(device)
|
|
neg_mask = th.ones((num_nodes, num_graphs)).to(device)
|
|
|
|
for nodeidx, graphidx in enumerate(graph_id):
|
|
|
|
pos_mask[nodeidx][graphidx] = 1.
|
|
neg_mask[nodeidx][graphidx] = 0.
|
|
|
|
res = th.mm(l_enc, g_enc.t())
|
|
|
|
E_pos = get_positive_expectation(res * pos_mask, average=False).sum()
|
|
E_pos = E_pos / num_nodes
|
|
E_neg = get_negative_expectation(res * neg_mask, average=False).sum()
|
|
E_neg = E_neg / (num_nodes * (num_graphs - 1))
|
|
|
|
return E_neg - E_pos
|
|
|
|
|
|
def global_global_loss_(sup_enc, unsup_enc):
|
|
|
|
num_graphs = sup_enc.shape[0]
|
|
device = sup_enc.device
|
|
|
|
pos_mask = th.eye(num_graphs).to(device)
|
|
neg_mask = 1 - pos_mask
|
|
|
|
res = th.mm(sup_enc, unsup_enc.t())
|
|
|
|
E_pos = get_positive_expectation(res * pos_mask, average=False)
|
|
E_pos = (E_pos * pos_mask).sum() / pos_mask.sum()
|
|
E_neg = get_negative_expectation(res * neg_mask, average=False)
|
|
E_neg = (E_neg * neg_mask).sum() / neg_mask.sum()
|
|
|
|
return E_neg - E_pos
|