-
Notifications
You must be signed in to change notification settings - Fork 4
/
Copy pathnets.py
126 lines (99 loc) · 3.96 KB
/
nets.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
import copy
import chainer
import chainer.functions as F
import numpy as np
import scipy.sparse as sp
from chainer import initializers
from chainer import reporter
from chainer.utils.sparse import CooMatrix
from graphs import to_chainer_sparse_variable
def sparse_to_gpu(x, device):
x.data.data = chainer.backends.cuda.to_gpu(x.data.data, device=device)
x.row = chainer.backends.cuda.to_gpu(x.row, device=device)
x.col = chainer.backends.cuda.to_gpu(x.col, device=device)
return x
def sparse_to_cpu(x):
x.data.data = chainer.backends.cuda.to_cpu(x.data.data)
x.row = chainer.backends.cuda.to_cpu(x.row)
x.col = chainer.backends.cuda.to_cpu(x.col)
return x
class TextGCN(chainer.Chain):
def __init__(self, adj, labels, feat_size, dropout=0.5):
super(TextGCN, self).__init__()
n_class = np.max(labels) + 1
initializer = initializers.HeUniform()
with self.init_scope():
self.gconv1 = GraphConvolution(adj.shape[1], feat_size)
self.gconv2 = GraphConvolution(feat_size, n_class)
# This Variable will not be updated because require_grad=False
self.input = to_chainer_sparse_variable(
sp.identity(adj.shape[1]))
self.adj = adj
self.labels = labels
self.dropout = dropout
def _forward(self):
# deep copy object, shallow copy internal arrays
x = copy.deepcopy(self.input)
x.data = F.dropout(x.data, self.dropout)
h = F.relu(self.gconv1(x, self.adj))
h = F.dropout(h, self.dropout)
out = self.gconv2(h, self.adj)
return out
def __call__(self, idx):
out = self._forward()
loss = F.softmax_cross_entropy(out[idx], self.labels[idx])
accuracy = F.accuracy(out[idx], self.labels[idx])
reporter.report({'loss': loss}, self)
reporter.report({'accuracy': accuracy}, self)
return loss
def evaluate(self, idx):
out = self._forward()
loss = F.softmax_cross_entropy(out[idx], self.labels[idx])
accuracy = F.accuracy(out[idx], self.labels[idx])
return float(loss.data), float(accuracy.data)
def predict(self, idx):
out = self._forward()
out = out[idx]
pred = self.xp.argmax(out.data)
return pred
def predict_proba(self, idx):
out = self._forward()
out = out[idx]
return out.data
def to_gpu(self, device=None):
self.adj = sparse_to_gpu(self.adj, device=device)
self.input = sparse_to_gpu(self.input, device=device)
self.labels = chainer.backends.cuda.to_gpu(self.labels, device=device)
return super(TextGCN, self).to_gpu(device=device)
def to_cpu(self):
self.adj = sparse_to_cpu(self.adj)
self.input = sparse_to_cpu(self.input)
self.labels = chainer.backends.cuda.to_cpu(self.labels)
return super(TextGCN, self).to_cpu()
class GraphConvolution(chainer.Link):
def __init__(self, in_size, out_size=None, nobias=True, initialW=None,
initial_bias=None):
super(GraphConvolution, self).__init__()
if out_size is None:
in_size, out_size = None, in_size
self.out_size = out_size
with self.init_scope():
if initialW is None:
initialW = initializers.GlorotUniform()
self.W = chainer.Parameter(initialW, (in_size, out_size))
if nobias:
self.b = None
else:
if initial_bias is None:
initial_bias = 0
bias_initializer = initializers._get_initializer(initial_bias)
self.b = chainer.Parameter(bias_initializer, out_size)
def __call__(self, x, adj):
if isinstance(x, chainer.utils.CooMatrix):
x = F.sparse_matmul(x, self.W)
else:
x = F.matmul(x, self.W)
output = F.sparse_matmul(adj, x)
if self.b is not None:
output += self.b
return output